SSE heartbeat (≤30s) during model reasoning to prevent 'Connection closed mid-response' / stream-watchdog stalls on long (esp. Agent-tool) turns
Summary
Long-running turns — especially Agent-tool subagent dispatches — frequently fail with:
API Error: Connection closed mid-response. The response above may be incomplete.Agent stalled: no progress for <N>s (stream watchdog did not recover)
These happen during long silent model-reasoning spans, when the SSE response stream emits no bytes for an extended period. An intermediary (NAT/proxy/VPN) drops the idle connection, or the server closes it, and there is no client-side recovery for background/Agent-tool dispatches.
Request
Emit a periodic SSE heartbeat / comment line (≤30s) during model reasoning so the byte stream never goes idle long enough to be evicted or closed. This is the only true prevention — client-side keepalive (TCP keepidle) and watchdog-timeout tuning only mitigate or detect; they cannot stop an idle stream from being dropped mid-reasoning.
Why existing mechanisms don't cover this
- The TCP keepalive path (e.g. lowering macOS
net.inet.tcp.keepidle) only addresses NAT idle-eviction, not server-side closes or H2-layer silence. CLAUDE_ASYNC_AGENT_STALL_TIMEOUT_MSis a kill threshold, not a recovery.- The stream-retry behavior (
tengu_streaming_stale_connection_retry) appears to apply only to the foreground streaming path — Agent-tool subagent dispatches get no retry path regardless of flag state. Multi-agent / orchestration workloads (where one parent fans out many long-running subagents) are therefore the most exposed and the least covered.
Impact
In an autonomous multi-agent orchestrator, a single mid-reasoning close kills a subagent that may have run for many minutes. Mitigations (frequent commits, micro-dispatching, auto-resume) reduce data loss but cannot prevent the close. A server-side heartbeat would eliminate the failure class for all consumers, foreground and background alike.
Alternative / complementary ask
If a heartbeat isn't feasible, expose a client-settable retry/resume for background (Agent-tool) dispatches — equivalent to the foreground stale-connection retry — so orchestrators can recover transparently.
Environment
- Observed on macOS (darwin), Claude Code CLI, both foreground turns and
Agent-tool subagent dispatches. - Reproduces most reliably on long agent turns with extended reasoning between tool calls.
This issue has 4 comments on GitHub. Read the full discussion on GitHub ↗