mirror of
https://github.com/PR0M3TH3AN/TORCH.git
synced 2026-10-27 07:51:52 +00:00
Add scheduler handoff runner for selected prompts
This commit is contained in:
1 parent
aac32c83bd
commit
26b65f273f
3 files changed
+147
-2
No files matched your search
@@ -0,0 +1,74 @@
|
||||
#!/usr/bin/env node
|
||||
import fs from 'node:fs/promises';
|
||||
import path from 'node:path';
|
||||
import { spawn } from 'node:child_process';
|
||||
|
||||
const REQUIRED_ENV = ['SCHEDULER_PROMPT_PATH', 'SCHEDULER_AGENT', 'SCHEDULER_CADENCE'];
|
||||
|
||||
function fail(message, code = 1) {
|
||||
console.error(`[scheduler] ${message}`);
|
||||
process.exit(code);
|
||||
}
|
||||
|
||||
function resolveRunner(promptMarkdown) {
|
||||
const customRunner = process.env.SCHEDULER_AGENT_RUNNER_COMMAND?.trim();
|
||||
if (customRunner) {
|
||||
return { command: 'bash', args: ['-lc', customRunner] };
|
||||
}
|
||||
|
||||
const platform = (process.env.AGENT_PLATFORM || 'codex').trim().toLowerCase();
|
||||
if (platform === 'codex') {
|
||||
return { command: 'codex', args: ['exec', promptMarkdown] };
|
||||
}
|
||||
|
||||
if (platform === 'claude') {
|
||||
return { command: 'claude', args: ['-p', promptMarkdown] };
|
||||
}
|
||||
|
||||
fail(`Unsupported AGENT_PLATFORM="${platform}". Set SCHEDULER_AGENT_RUNNER_COMMAND to override.`);
|
||||
}
|
||||
|
||||
async function main() {
|
||||
for (const key of REQUIRED_ENV) {
|
||||
if (!process.env[key] || !String(process.env[key]).trim()) {
|
||||
fail(`Missing required environment variable ${key}.`);
|
||||
}
|
||||
}
|
||||
|
||||
const promptPath = path.resolve(process.cwd(), process.env.SCHEDULER_PROMPT_PATH);
|
||||
let promptMarkdown;
|
||||
|
||||
try {
|
||||
promptMarkdown = await fs.readFile(promptPath, 'utf8');
|
||||
} catch {
|
||||
fail(`Unable to read scheduler prompt at ${promptPath}.`);
|
||||
}
|
||||
|
||||
if (!promptMarkdown.trim()) {
|
||||
fail(`Scheduler prompt at ${promptPath} is empty.`);
|
||||
}
|
||||
|
||||
const runner = resolveRunner(promptMarkdown);
|
||||
const child = spawn(runner.command, runner.args, {
|
||||
cwd: process.cwd(),
|
||||
env: {
|
||||
...process.env,
|
||||
SCHEDULER_PROMPT_PATH: promptPath,
|
||||
SCHEDULER_PROMPT_MARKDOWN: promptMarkdown,
|
||||
},
|
||||
stdio: 'inherit',
|
||||
});
|
||||
|
||||
child.on('error', (error) => {
|
||||
if (error.code === 'ENOENT') {
|
||||
fail(`Runner command not found: ${runner.command}`, 127);
|
||||
}
|
||||
fail(`Runner execution failed: ${error.message}`);
|
||||
});
|
||||
|
||||
child.on('close', (code) => {
|
||||
process.exit(code ?? 1);
|
||||
});
|
||||
}
|
||||
|
||||
main();
|
||||
@@ -0,0 +1,71 @@
|
||||
import { test } from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import fs from 'node:fs/promises';
|
||||
import os from 'node:os';
|
||||
import path from 'node:path';
|
||||
import { spawn } from 'node:child_process';
|
||||
|
||||
const SCRIPT_PATH = path.resolve('scripts/agent/run-selected-prompt.mjs');
|
||||
|
||||
function runScript({ cwd, env }) {
|
||||
return new Promise((resolve) => {
|
||||
const child = spawn(process.execPath, [SCRIPT_PATH], {
|
||||
cwd,
|
||||
env,
|
||||
stdio: ['ignore', 'pipe', 'pipe'],
|
||||
});
|
||||
|
||||
let stdout = '';
|
||||
let stderr = '';
|
||||
|
||||
child.stdout.on('data', (chunk) => {
|
||||
stdout += chunk.toString();
|
||||
});
|
||||
|
||||
child.stderr.on('data', (chunk) => {
|
||||
stderr += chunk.toString();
|
||||
});
|
||||
|
||||
child.on('close', (code) => {
|
||||
resolve({ code: code ?? 1, stdout, stderr });
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
test('runs selected scheduler prompt through configured runner command', async () => {
|
||||
const root = await fs.mkdtemp(path.join(os.tmpdir(), 'run-selected-prompt-'));
|
||||
const promptPath = path.join(root, 'prompt.md');
|
||||
await fs.writeFile(promptPath, '# hello from prompt\n', 'utf8');
|
||||
|
||||
const result = await runScript({
|
||||
cwd: root,
|
||||
env: {
|
||||
...process.env,
|
||||
SCHEDULER_PROMPT_PATH: promptPath,
|
||||
SCHEDULER_AGENT: 'agent-a',
|
||||
SCHEDULER_CADENCE: 'daily',
|
||||
SCHEDULER_AGENT_RUNNER_COMMAND: 'node -e "if(!process.env.SCHEDULER_PROMPT_MARKDOWN.includes(\'hello from prompt\')) process.exit(6)"',
|
||||
},
|
||||
});
|
||||
|
||||
assert.equal(result.code, 0, `stdout: ${result.stdout}\nstderr: ${result.stderr}`);
|
||||
});
|
||||
|
||||
test('propagates non-zero runner exit code', async () => {
|
||||
const root = await fs.mkdtemp(path.join(os.tmpdir(), 'run-selected-prompt-fail-'));
|
||||
const promptPath = path.join(root, 'prompt.md');
|
||||
await fs.writeFile(promptPath, '# will fail\n', 'utf8');
|
||||
|
||||
const result = await runScript({
|
||||
cwd: root,
|
||||
env: {
|
||||
...process.env,
|
||||
SCHEDULER_PROMPT_PATH: promptPath,
|
||||
SCHEDULER_AGENT: 'agent-b',
|
||||
SCHEDULER_CADENCE: 'weekly',
|
||||
SCHEDULER_AGENT_RUNNER_COMMAND: 'node -e "process.exit(7)"',
|
||||
},
|
||||
});
|
||||
|
||||
assert.equal(result.code, 7, `stdout: ${result.stdout}\nstderr: ${result.stderr}`);
|
||||
});
|
||||
+2
-2
@@ -19,8 +19,8 @@
|
||||
"weekly": "bug-reproducer-agent"
|
||||
},
|
||||
"handoffCommandByCadence": {
|
||||
"daily": "test -n \"$SCHEDULER_AGENT\" && test -n \"$SCHEDULER_CADENCE\" && test -n \"$SCHEDULER_PROMPT_PATH\" && test -f \"$SCHEDULER_PROMPT_PATH\" && echo \"HANDOFF_OK cadence=$SCHEDULER_CADENCE agent=$SCHEDULER_AGENT prompt=$SCHEDULER_PROMPT_PATH\"",
|
||||
"weekly": "test -n \"$SCHEDULER_AGENT\" && test -n \"$SCHEDULER_CADENCE\" && test -n \"$SCHEDULER_PROMPT_PATH\" && test -f \"$SCHEDULER_PROMPT_PATH\" && echo \"HANDOFF_OK cadence=$SCHEDULER_CADENCE agent=$SCHEDULER_AGENT prompt=$SCHEDULER_PROMPT_PATH\""
|
||||
"daily": "node scripts/agent/run-selected-prompt.mjs",
|
||||
"weekly": "node scripts/agent/run-selected-prompt.mjs"
|
||||
},
|
||||
"memoryPolicyByCadence": {
|
||||
"daily": {
|
||||
|
||||
Reference in new issue
Block a user