fix: enforce codex turn hard timeout

This commit is contained in:
lyon
2026-06-22 07:18:11 +08:00
parent 30bce7eb69
commit 3f0f577c24
3 changed files with 72 additions and 6 deletions
+19 -3
View File
@@ -119,8 +119,11 @@ process.exit(1);
const materialized = ((resultEnvelope.resourceBundleRef as JsonRecord).materialized as JsonRecord);
assert.deepEqual(((materialized.tools as JsonRecord).names), ["apply_patch", "hwpod", "tran", "trans"]);
assert.equal(((materialized.tools as JsonRecord).installed), true);
assert.deepEqual((((materialized.tools as JsonRecord).runtimeTools as JsonRecord).names), ["agentrun-git"]);
assert.equal(((((materialized.tools as JsonRecord).runtimeTools as JsonRecord).items as JsonRecord[])[0]?.overridesResourceTool), false);
const runtimeToolNames = (((materialized.tools as JsonRecord).runtimeTools as JsonRecord).names) as string[];
assert.ok(runtimeToolNames.includes("agentrun-git"));
const runtimeToolItems = (((materialized.tools as JsonRecord).runtimeTools as JsonRecord).items as JsonRecord[]);
const agentrunGitRuntimeTool = runtimeToolItems.find((item) => item.name === "agentrun-git");
assert.equal(agentrunGitRuntimeTool?.overridesResourceTool, false);
assert.deepEqual(((materialized.skillDirs as JsonRecord).names), ["dad-dev", "hwpod-cli", "hwpod-ctl"]);
const requiredSkillItems = ((materialized.requiredSkills as JsonRecord).items as JsonRecord[]);
assert.deepEqual(((materialized.requiredSkills as JsonRecord).names), ["dad-dev"]);
@@ -273,6 +276,19 @@ process.exit(1);
assert.equal(idleEnvelope.failureKind, "backend-timeout");
assert.match(String(idleEnvelope.failureMessage ?? idleEnvelope.message ?? ""), /did not emit turn\/completed/u);
const outputWithoutTerminal = await createHwlabRun(client, context, bundle, "hwlab-session-output-without-terminal", "start a tool that keeps printing without terminal", "hwlab-command-output-without-terminal", 500);
const outputWithoutTerminalRunner = runOnce({ managerUrl: server.baseUrl, runId: outputWithoutTerminal.runId, commandId: outputWithoutTerminal.commandId, codexCommand: context.fakeCodexCommand, codexArgs: context.fakeCodexArgs, codexHome: context.codexHome, env: { CODEX_HOME: context.codexHome, AGENTRUN_FAKE_CODEX_MODE: "tool-output-without-terminal", AGENTRUN_WORKSPACE_ROOT: path.join(context.tmp, "workspaces-output-without-terminal") }, oneShot: true, pollIntervalMs: 50 });
await waitForCommandState(client, outputWithoutTerminal.runId, outputWithoutTerminal.commandId, "acknowledged");
await waitForEvent(client, outputWithoutTerminal.runId, (event) => event.type === "command_output", "command output without terminal");
await waitForCommandState(client, outputWithoutTerminal.runId, outputWithoutTerminal.commandId, "failed");
const outputWithoutTerminalResult = await outputWithoutTerminalRunner as JsonRecord;
assert.equal(outputWithoutTerminalResult.terminalStatus, "failed");
assert.equal(outputWithoutTerminalResult.failureKind, "backend-timeout");
const outputWithoutTerminalEnvelope = await client.get(`/api/v1/runs/${outputWithoutTerminal.runId}/commands/${outputWithoutTerminal.commandId}/result`) as JsonRecord;
assert.equal(outputWithoutTerminalEnvelope.terminalStatus, "failed");
assert.equal(outputWithoutTerminalEnvelope.failureKind, "backend-timeout");
assert.match(String(outputWithoutTerminalEnvelope.failureMessage ?? outputWithoutTerminalEnvelope.message ?? ""), /hard timed out/u);
const runningCancel = await createHwlabRun(client, context, bundle, "hwlab-session-cancel-running", "cancel running", "hwlab-command-cancel-running", 10_000);
const running = runOnce({ managerUrl: server.baseUrl, runId: runningCancel.runId, codexCommand: context.fakeCodexCommand, codexArgs: context.fakeCodexArgs, codexHome: context.codexHome, env: { CODEX_HOME: context.codexHome, AGENTRUN_FAKE_CODEX_MODE: "missing-terminal", AGENTRUN_WORKSPACE_ROOT: path.join(context.tmp, "workspaces-running-cancel") }, oneShot: true });
await waitForCommandState(client, runningCancel.runId, runningCancel.commandId, "acknowledged");
@@ -280,7 +296,7 @@ process.exit(1);
const runningResult = await running;
assert.equal(runningResult.terminalStatus, "cancelled");
return { name: "hwlab-manual-dispatch", tests: ["runner-job-idempotency", "pending-cancel", "result-envelope", "session-ref-resume", "resource-gitbundle-materialization", "gitbundle-ref-resolution", "gitbundle-tools-path", "gitbundle-skill-dir-assembly", "resource-prompt-required-blocker", "resource-required-skill-blocker", "same-run-runner-multiturn", "running-steer", "missing-terminal-after-tool-auto-stop", "running-cancel"] };
return { name: "hwlab-manual-dispatch", tests: ["runner-job-idempotency", "pending-cancel", "result-envelope", "session-ref-resume", "resource-gitbundle-materialization", "gitbundle-ref-resolution", "gitbundle-tools-path", "gitbundle-skill-dir-assembly", "resource-prompt-required-blocker", "resource-required-skill-blocker", "same-run-runner-multiturn", "running-steer", "missing-terminal-after-tool-auto-stop", "tool-output-hard-timeout", "running-cancel"] };
} finally {
await new Promise<void>((resolve) => server.server.close(() => resolve()));
}