Skip to content

fix(cell): per-turn timeout + watchdog + drop post-summary wrap-up - #140

Merged
coccyx merged 1 commit into
masterfrom
investigation-turn-timeout
Aug 15, 2026
Merged

fix(cell): per-turn timeout + watchdog + drop post-summary wrap-up#140
coccyx merged 1 commit into
masterfrom
investigation-turn-timeout

Conversation

@coccyx

@coccyx coccyx commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes investigations wedging at "thinking" (observed live: a follow-up turn whose LLM stream hung for 8+ minutes with no output), and drops the redundant wrap-up text the model emits beside the summary card.

  • Per-turn timeoutrunRealTurn now bounds the whole turn (LLM stream + tool calls) with a 180s AbortSignal (combined with any caller signal). A hung model or a stalled tool aborts, the turn fails cleanly with a clear error, and the run parks/fails instead of hanging. The signal is threaded through the code tools + checkout fetches, so a stalled checkout_repo aborts too. This is the same root cause behind the "8-of-10 started-but-didn't-conclude" runs.
  • Watchdog alarmInvestigationDO sets a durable 240s alarm at turn start. A DO alarm can't preempt a running handler (single-threaded), so the timeout above handles a live-isolate hang; this covers the other case — the isolate being evicted mid-turn (leaving the row running with no pending alarm). The watchdog re-fires on a fresh isolate and re-runs the turn (no-op if it's no longer running), instead of waiting on the coordinator's 20-min orphan reclaim.
  • Drop the post-summary wrap-up — when a turn calls present_investigation_summary, suppress the accompanying assistant text at emit time. The seed prompt says STOP after the summary, but deepseek routinely adds a redundant sentence next to the card.

Cell-only — needs the cell redeploy. #139 is already on master; this lands there too.

🤖 Generated with Claude Code

Investigations could wedge at "thinking" forever when the LLM stream (or
a stalled tool like a slow checkout) never returned — no per-turn timeout,
so the turn never finished and nothing rescheduled. Also the model often
emits a redundant wrap-up sentence beside the summary card despite the
"STOP after present_investigation_summary" instruction.

- runRealTurn: bound the whole turn (LLM stream + tool calls) with a 180s
  AbortSignal (combined with any caller signal). A hung model/tool aborts,
  the turn fails cleanly with a clear error, and the run parks/fails
  instead of hanging. Thread the signal through the code tools + checkout
  fetches so a stalled checkout aborts too.
- Drop the assistant wrap-up text when the turn calls
  present_investigation_summary — the card IS the report.
- InvestigationDO: set a durable watchdog alarm (240s) at turn start so a
  turn whose isolate is evicted mid-run gets re-run on a fresh isolate
  (no-ops if the row is no longer 'running'), instead of sitting 'running'
  until the coordinator's 20-min orphan reclaim.

Cell-only — needs the cell redeploy.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0158jez4WfWj6ttmaxh3HEbT
@coccyx
coccyx merged commit 97fca24 into master Aug 15, 2026
4 checks passed
@coccyx
coccyx deleted the investigation-turn-timeout branch August 15, 2026 03:41
coccyx added a commit that referenced this pull request Aug 15, 2026
Checking out a large polyglot repo (the OTel demo tarball is ~66 MB)
wedged the InvestigationDO: store() walked every tar entry and did a
synchronous SQLite INSERT per file — up to 6000 files / 48 MB — with no
yield and no abort check. While that ran, the single-threaded DO could
not service status/events, which started returning 502, and #140's
per-turn timeout couldn't help (it aborts fetch/stream, not a sync
loop).

- Filter noise before decode: dependency/build/generated subtrees
  (node_modules, dist, target, gen, vendor, …) and asset/binary
  extensions (png, woff, pdf, wasm, lock, min.js, …). Source is all the
  agent reads.
- Lower caps to 2500 files / 20 MB.
- store() is now async: it yields to the request queue every 200 inserts
  (so status/events interleave mid-checkout) and checks the turn's abort
  signal (so a runaway checkout actually stops).
- checkout_repo result reports what was skipped (no silent caps).
- Unit tests for filtering, caps, and abort.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0158jez4WfWj6ttmaxh3HEbT
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant