SSE heartbeat (≤30s) during model reasoning to prevent 'Connection closed mid-response' / stream-watchdog stalls on long (esp. Agent-tool) turns

Open 💬 4 comments Opened Jun 22, 2026 by WouterDeBot

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_MS is 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.

View original on GitHub ↗

This issue has 4 comments on GitHub. Read the full discussion on GitHub ↗