pastilhasandClaude Opus 5 33d96f19ee end a turn that has gone silent, instead of generating forever
A turn could stop producing events and stay `isGenerating` indefinitely. Nothing
covered it: the idle timer answers the opposite question — how long a session with
NO turn in flight may sit before collection — and every client showed a spinner
with no timeout of its own, so a wedged turn presented as a chat that was still
thinking.

On 2026-08-08 one ran for seventeen minutes inside an auto-compaction, reached
over the socket to an iPad, and was indistinguishable there from a dead app. The
compaction is silent by design (the PreCompact hook is the only announcement, and
the code's own comment allows 2.5 minutes), so there was nothing to distinguish it
from.

A stall watchdog now rides every emitted event: any sign of life pushes the
deadline back, and expiry ends the turn the way a real failure would — isGenerating
off, idle re-armed, and an `error` the client can render. The agent process is
deliberately left alive, since it may still be working and the next turn resumes
it; what this guarantees is that the client is TOLD, which is the part that was
missing.

The budgets are generous rather than tight — ten minutes of silence normally,
twenty while compacting, re-armed from the PreCompact hook because that hook fires
as the long silence begins and the deadline the turn is holding was sized for
ordinary work. Killing a turn that was about to succeed is worse than the hang this
prevents.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-08 10:01:10 +01:00
2026-02-16 19:34:35 +00:00
2026-02-16 19:34:35 +00:00
2026-02-16 19:34:35 +00:00
2026-02-22 03:35:26 +00:00
2026-02-16 19:34:35 +00:00
2026-02-16 19:34:35 +00:00
S
Description
No description provided
42 MiB
Languages
TypeScript 90.9%
Shell 4.7%
JavaScript 4.1%
CSS 0.2%
HTML 0.1%