fix: use idle timeout for codex turns

This commit is contained in:
AgentRun Codex
2026-06-11 12:52:46 +08:00
parent dafcfc7ce4
commit f49695a821
11 changed files with 115 additions and 72 deletions
+14 -10
View File
@@ -33,18 +33,21 @@ const selfTest: SelfTestCase = async (context: SelfTestContext) => {
await sleep(36);
const inactiveLive = (await commandResult(client, inactive)).liveness as JsonRecord;
assert.equal(inactiveLive.phase, "runner-stdio-inactive");
assert.ok(["approaching-hard-timeout", "overdue"].includes(String((inactiveLive.timeoutBudget as JsonRecord).state)));
assert.ok(["approaching-idle-timeout", "overdue"].includes(String((inactiveLive.timeoutBudget as JsonRecord).state)));
assert.equal(((inactiveLive.timeoutBudget as JsonRecord).timeoutKind), "idle");
const terminal = await createActiveRun(client, context, "timeout-liveness-terminal", 50);
await client.post(`/api/v1/runs/${terminal.runId}/events`, { type: "error", payload: { commandId: terminal.commandId, failureKind: "backend-timeout", phase: "turn:hard-timeout", message: "codex stdio turn hard timed out after 50ms" } });
await client.patch(`/api/v1/commands/${terminal.commandId}/status`, { terminalStatus: "failed", failureKind: "backend-timeout", failureMessage: "codex stdio turn hard timed out after 50ms" });
await client.patch(`/api/v1/runs/${terminal.runId}/status`, { terminalStatus: "failed", failureKind: "backend-timeout", failureMessage: "codex stdio turn hard timed out after 50ms" });
await client.post(`/api/v1/runs/${terminal.runId}/events`, { type: "error", payload: { commandId: terminal.commandId, failureKind: "backend-timeout", phase: "turn:idle-timeout", message: "codex stdio turn idle timed out after 50ms without activity" } });
await client.patch(`/api/v1/commands/${terminal.commandId}/status`, { terminalStatus: "failed", failureKind: "backend-timeout", failureMessage: "codex stdio turn idle timed out after 50ms without activity" });
await client.patch(`/api/v1/runs/${terminal.runId}/status`, { terminalStatus: "failed", failureKind: "backend-timeout", failureMessage: "codex stdio turn idle timed out after 50ms without activity" });
const terminalResult = await commandResult(client, terminal);
const terminalLive = terminalResult.liveness as JsonRecord;
assert.equal(terminalResult.terminalStatus, "failed");
assert.equal(terminalLive.phase, "terminal");
assert.equal(((terminalLive.timeoutBudget as JsonRecord).state), "timed-out");
assert.equal(((terminalResult.terminalClassification as JsonRecord).category), "execution-hard-timeout");
assert.equal(((terminalLive.timeoutBudget as JsonRecord).timeoutKind), "idle");
assert.equal(((terminalResult.terminalClassification as JsonRecord).category), "execution-idle-timeout");
assert.equal(((terminalResult.terminalClassification as JsonRecord).idleTimeout), true);
assert.equal(((terminalResult.terminalClassification as JsonRecord).providerEvidence), "insufficient");
assert.equal(((terminalLive.terminalClassification as JsonRecord).providerInterruptionKnown), false);
assert.ok((terminalLive.recoveryActions as JsonRecord[]).some((action) => action.action === "resume-session"));
@@ -52,13 +55,13 @@ const selfTest: SelfTestCase = async (context: SelfTestContext) => {
const noSession = await createActiveRun(client, context, "timeout-liveness-no-session", 50, { session: false });
await client.post(`/api/v1/runs/${noSession.runId}/events`, { type: "backend_status", payload: { commandId: noSession.commandId, phase: "codex-app-server-closed", message: "stdio closed before terminal result" } });
await client.post(`/api/v1/runs/${noSession.runId}/events`, { type: "terminal_status", payload: { commandId: noSession.commandId, terminalStatus: "failed", failureKind: "backend-timeout", message: "codex stdio turn hard timed out after 50ms" } });
await client.patch(`/api/v1/commands/${noSession.commandId}/status`, { terminalStatus: "failed", failureKind: "backend-timeout", failureMessage: "codex stdio turn hard timed out after 50ms" });
await client.post(`/api/v1/runs/${noSession.runId}/events`, { type: "terminal_status", payload: { commandId: noSession.commandId, terminalStatus: "failed", failureKind: "backend-timeout", message: "codex stdio turn idle timed out after 50ms without activity" } });
await client.patch(`/api/v1/commands/${noSession.commandId}/status`, { terminalStatus: "failed", failureKind: "backend-timeout", failureMessage: "codex stdio turn idle timed out after 50ms without activity" });
const noSessionResult = await commandResult(client, noSession);
const noSessionLive = noSessionResult.liveness as JsonRecord;
const noSessionClassification = noSessionResult.terminalClassification as JsonRecord;
const noSessionDiagnosis = noSessionResult.diagnosis as JsonRecord;
assert.equal(noSessionClassification.category, "execution-hard-timeout");
assert.equal(noSessionClassification.category, "execution-idle-timeout");
assert.equal(noSessionClassification.providerEvidence, "observed-transport-disconnect");
assert.equal(noSessionClassification.providerInterruptionKnown, false);
assert.equal(noSessionDiagnosis.category, "terminal-command-open-run");
@@ -111,12 +114,13 @@ const selfTest: SelfTestCase = async (context: SelfTestContext) => {
const commander = await client.get("/api/v1/queue/commander?queue=timeout-liveness&readerId=timeout-liveness") as JsonRecord;
const commanderItem = ((commander.items as JsonRecord[]) ?? []).find((item) => item.id === task.id) as JsonRecord;
assert.equal(((commanderItem.supervisor as JsonRecord).phase), "terminal");
assert.equal((((commanderItem.supervisor as JsonRecord).diagnosis as JsonRecord).category), "execution-hard-timeout");
assert.equal((((commanderItem.supervisor as JsonRecord).diagnosis as JsonRecord).category), "execution-idle-timeout");
assert.equal((((commanderItem.supervisor as JsonRecord).timeoutBudget as JsonRecord).state), "timed-out");
assert.equal((((commanderItem.supervisor as JsonRecord).timeoutBudget as JsonRecord).timeoutKind), "idle");
const commanderSummary = summarizeQueueCommanderSnapshot(commander, { limit: 5 });
const summaryItem = ((commanderSummary.items as JsonRecord[]) ?? []).find((item) => item.id === task.id) as JsonRecord;
assert.equal(((summaryItem.supervisor as JsonRecord).phase), "terminal");
assert.equal((((summaryItem.supervisor as JsonRecord).terminalClassification as JsonRecord).category), "execution-hard-timeout");
assert.equal((((summaryItem.supervisor as JsonRecord).terminalClassification as JsonRecord).category), "execution-idle-timeout");
assert.equal((((summaryItem.supervisor as JsonRecord).terminalClassification as JsonRecord).providerEvidence), "insufficient");
assert.equal(JSON.stringify(commanderSummary).includes("hwpod workspace apply-patch"), false, "commander summary must stay compact and avoid dumping command bodies");
assert.equal(JSON.stringify(summaryItem).includes("fullRecordBytes"), false, "commander item must not add bookkeeping noise");