Skip to content

Commit fa80d56

Browse files
committed
Give an exhausted timeout its own reply preamble
The vendored DefaultDirector's ERROR_PREAMBLE map has no timeout entry and falls back to the fatal ('unrecoverable inference error') wording. CL-6910 makes an exhausted timeout the routine terminal state instead of a rarity, so intercept it in ChatDirector and reply with accurate, calm wording instead of patching the vendored map.
1 parent 95a233b commit fa80d56

2 files changed

Lines changed: 35 additions & 0 deletions

File tree

src/agent/director.test.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1218,4 +1218,20 @@ describe("ChatDirector inference-error recovery (CL-6910)", () => {
12181218
}
12191219
expect(inferCount).toBe(2); // MAX_INFERENCE_RECOVERIES
12201220
});
1221+
1222+
test("timeout category produces the timeout preamble, not the fatal fallback", async () => {
1223+
const director = createChatDirector("system", [], {
1224+
onTasksChange: () => {},
1225+
provider: providerlessPolicy,
1226+
});
1227+
const capabilities = makeCapabilities();
1228+
1229+
const actions = actionsArray(
1230+
await director.decide(inferenceErrorEvent("timeout"), mockState, capabilities),
1231+
);
1232+
const reply = actions.find((a) => a.type === "reply");
1233+
expect(reply).toBeDefined();
1234+
expect((reply as { content: string }).content).toContain("did not respond in time");
1235+
expect((reply as { content: string }).content).not.toContain("unrecoverable inference error");
1236+
});
12211237
});

src/agent/director.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -707,6 +707,25 @@ class ChatDirectorImpl extends DefaultDirector {
707707
];
708708
}
709709

710+
// The vendored DefaultDirector's inference.error preamble map
711+
// (vendor/intx-inference/src/default-director.ts, ERROR_PREAMBLE) has no
712+
// `timeout` entry, so it falls back to the `fatal` wording ("...
713+
// unrecoverable inference error"). Before CL-6910, a `timeout` reaching
714+
// the director was rare (the harness retried it first, then the director
715+
// recovered it again — see the block above), so operators almost never
716+
// saw that fallback text. Now an exhausted `timeout` routinely lands here
717+
// as a terminal reply, so the misleading "unrecoverable" wording would
718+
// become the routine message for an ordinary timeout. Intercept it here
719+
// with accurate, calm wording rather than patching the vendored map.
720+
if (event.type === "inference.error" && event.error.category === "timeout") {
721+
return [
722+
capabilities.checkpoint("inference-error"),
723+
capabilities.reply(
724+
"This agent's request timed out because the inference provider did not respond in time. The request was retried and gave up.",
725+
),
726+
];
727+
}
728+
710729
// Both nudge budgets are monotonic per inbound user message rather than
711730
// resetting on "real" tool work. Classifying a tool call as progress is
712731
// gameable: a weak model learns that any tool call (including a no-op

0 commit comments

Comments
 (0)