Add resident Persona scheduler organ
This commit is contained in:
parent
73df50da1e
commit
288781239c
5 changed files with 118 additions and 1 deletions
11
apps/persona-scheduler/package.json
Normal file
11
apps/persona-scheduler/package.json
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"name": "@voidbot/persona-scheduler",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"dependencies": {
|
||||
"@voidbot/config": "0.1.0",
|
||||
"dotenv": "^16.4.0"
|
||||
}
|
||||
}
|
||||
76
apps/persona-scheduler/src/index.ts
Normal file
76
apps/persona-scheduler/src/index.ts
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
import "dotenv/config";
|
||||
|
||||
import { spawn } from "node:child_process";
|
||||
import { resolve } from "node:path";
|
||||
|
||||
import { loadConfig } from "@voidbot/config";
|
||||
|
||||
const config = loadConfig();
|
||||
const intervalMs = Math.max(1, config.repoFaceHeartbeats.intervalMinutes) * 60_000;
|
||||
const turnEnginePath = resolve(process.cwd(), "scripts", "run-repo-face-heartbeats.ts");
|
||||
|
||||
let stopping = false;
|
||||
let activeTick: Promise<void> | undefined;
|
||||
let timer: NodeJS.Timeout | undefined;
|
||||
|
||||
function runTick(): Promise<void> {
|
||||
if (activeTick) {
|
||||
console.warn("Persona scheduler skipped a pulse because the previous turn-selection tick is still active.");
|
||||
return activeTick;
|
||||
}
|
||||
|
||||
activeTick = new Promise<void>((done) => {
|
||||
const startedAt = new Date().toISOString();
|
||||
const child = spawn(process.execPath, [turnEnginePath], {
|
||||
cwd: process.cwd(),
|
||||
env: process.env,
|
||||
stdio: ["ignore", "pipe", "pipe"],
|
||||
});
|
||||
let stdout = "";
|
||||
let stderr = "";
|
||||
child.stdout.setEncoding("utf8");
|
||||
child.stderr.setEncoding("utf8");
|
||||
child.stdout.on("data", (chunk: string) => { stdout += chunk; });
|
||||
child.stderr.on("data", (chunk: string) => { stderr += chunk; });
|
||||
child.once("error", (error) => {
|
||||
console.error(`Persona scheduler tick failed to start: ${error.message}`);
|
||||
});
|
||||
child.once("close", (code, signal) => {
|
||||
const output = stdout.trim();
|
||||
if (code === 0) {
|
||||
console.log(`Persona scheduler tick completed (started ${startedAt}).${output ? ` ${output}` : ""}`);
|
||||
} else {
|
||||
console.error(
|
||||
`Persona scheduler tick failed (started ${startedAt}, code ${String(code)}, signal ${String(signal)}).${stderr.trim() ? ` ${stderr.trim()}` : ""}`,
|
||||
);
|
||||
}
|
||||
done();
|
||||
});
|
||||
}).finally(() => {
|
||||
activeTick = undefined;
|
||||
});
|
||||
return activeTick;
|
||||
}
|
||||
|
||||
function scheduleNext(): void {
|
||||
if (stopping) return;
|
||||
timer = setTimeout(async () => {
|
||||
await runTick();
|
||||
scheduleNext();
|
||||
}, intervalMs);
|
||||
timer.unref();
|
||||
}
|
||||
|
||||
async function shutdown(signal: string): Promise<void> {
|
||||
if (stopping) return;
|
||||
stopping = true;
|
||||
if (timer) clearTimeout(timer);
|
||||
console.log(`Persona scheduler stopping after ${signal}.`);
|
||||
await activeTick;
|
||||
}
|
||||
|
||||
process.once("SIGINT", () => { void shutdown("SIGINT"); });
|
||||
process.once("SIGTERM", () => { void shutdown("SIGTERM"); });
|
||||
|
||||
console.log(`Persona scheduler owns the resident ${config.repoFaceHeartbeats.intervalMinutes}-minute turn pulse.`);
|
||||
void runTick().then(scheduleNext);
|
||||
16
apps/persona-scheduler/tsconfig.json
Normal file
16
apps/persona-scheduler/tsconfig.json
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"rootDir": "src",
|
||||
"outDir": "dist"
|
||||
},
|
||||
"include": [
|
||||
"src/**/*.ts"
|
||||
],
|
||||
"references": [
|
||||
{
|
||||
"path": "../../packages/config"
|
||||
}
|
||||
]
|
||||
}
|
||||
12
package-lock.json
generated
12
package-lock.json
generated
|
|
@ -33,6 +33,14 @@
|
|||
"ffmpeg-static": "^5.3.0"
|
||||
}
|
||||
},
|
||||
"apps/persona-scheduler": {
|
||||
"name": "@voidbot/persona-scheduler",
|
||||
"version": "0.1.0",
|
||||
"dependencies": {
|
||||
"@voidbot/config": "0.1.0",
|
||||
"dotenv": "^16.4.0"
|
||||
}
|
||||
},
|
||||
"apps/worker": {
|
||||
"name": "@voidbot/worker",
|
||||
"version": "0.1.0",
|
||||
|
|
@ -1163,6 +1171,10 @@
|
|||
"resolved": "packages/core",
|
||||
"link": true
|
||||
},
|
||||
"node_modules/@voidbot/persona-scheduler": {
|
||||
"resolved": "apps/persona-scheduler",
|
||||
"link": true
|
||||
},
|
||||
"node_modules/@voidbot/providers": {
|
||||
"resolved": "packages/providers",
|
||||
"link": true
|
||||
|
|
|
|||
|
|
@ -24,7 +24,9 @@
|
|||
},
|
||||
{
|
||||
"path": "./apps/worker"
|
||||
},
|
||||
{
|
||||
"path": "./apps/persona-scheduler"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue