feat: add v0.1 runtime skeleton

This commit is contained in:
Codex
2026-05-29 10:52:41 +08:00
parent 4b33e67484
commit 5deb9fa7fd
20 changed files with 1238 additions and 0 deletions
+19
View File
@@ -0,0 +1,19 @@
import { runOnce, type RunnerOnceOptions } from "./run-once.js";
const managerUrl = process.env.AGENTRUN_MGR_URL;
const runId = process.env.AGENTRUN_RUN_ID;
if (!managerUrl || !runId) {
console.log(JSON.stringify({ ok: false, failureKind: "schema-invalid", message: "AGENTRUN_MGR_URL and AGENTRUN_RUN_ID are required" }));
process.exit(2);
}
const options: RunnerOnceOptions = {
managerUrl,
runId,
};
if (process.env.AGENTRUN_RUNNER_ID) options.runnerId = process.env.AGENTRUN_RUNNER_ID;
if (process.env.AGENTRUN_CODEX_COMMAND) options.codexCommand = process.env.AGENTRUN_CODEX_COMMAND;
if (process.env.AGENTRUN_CODEX_ARGS) options.codexArgs = JSON.parse(process.env.AGENTRUN_CODEX_ARGS) as string[];
if (process.env.CODEX_HOME) options.codexHome = process.env.CODEX_HOME;
const result = await runOnce(options);
console.log(JSON.stringify({ ok: true, data: result }));
+35
View File
@@ -0,0 +1,35 @@
import { ManagerClient } from "../mgr/client.js";
import { runBackendTurn, type BackendAdapterOptions } from "../backend/adapter.js";
import type { CommandRecord, JsonRecord, RunRecord, RunnerRecord } from "../common/types.js";
export interface RunnerOnceOptions extends BackendAdapterOptions {
managerUrl: string;
runId: string;
runnerId?: string;
attemptId?: string;
leaseMs?: number;
}
export async function runOnce(options: RunnerOnceOptions): Promise<JsonRecord> {
const client = new ManagerClient(options.managerUrl);
const runner = await client.post("/api/v1/runners/register", {
id: options.runnerId ?? undefined,
runId: options.runId,
attemptId: options.attemptId ?? `attempt_${Date.now().toString(36)}`,
backendProfile: "codex",
placement: "host-process",
sourceCommit: process.env.AGENTRUN_SOURCE_COMMIT ?? "unknown",
} as JsonRecord) as unknown as RunnerRecord;
const claimed = await client.post(`/api/v1/runs/${options.runId}/claim`, { runnerId: runner.id, leaseMs: options.leaseMs ?? 60_000 }) as unknown as RunRecord;
const commandsResponse = await client.get(`/api/v1/runs/${options.runId}/commands?afterSeq=0&limit=20`) as { items?: CommandRecord[] };
const command = commandsResponse.items?.find((item) => item.state === "pending" && item.type === "turn");
if (!command) {
await client.patch(`/api/v1/runs/${options.runId}/status`, { terminalStatus: "blocked", failureKind: "schema-invalid", failureMessage: "no pending turn command" });
return { runner, claimed, terminalStatus: "blocked", failureKind: "schema-invalid" };
}
await client.post(`/api/v1/commands/${command.id}/ack`, {});
const result = await runBackendTurn(claimed, command, options);
for (const event of result.events) await client.post(`/api/v1/runs/${options.runId}/events`, event as unknown as JsonRecord);
const finalRun = await client.patch(`/api/v1/runs/${options.runId}/status`, { terminalStatus: result.terminalStatus, failureKind: result.failureKind, failureMessage: result.failureMessage }) as unknown as RunRecord;
return { runner, commandId: command.id, terminalStatus: result.terminalStatus, failureKind: result.failureKind, run: finalRun } as JsonRecord;
}