From 68528068ecb045ec2b70226b8a5d59bae8cb6c3d Mon Sep 17 00:00:00 2001 From: Teknium <127238744+teknium1@users.noreply.github.com> Date: Fri, 10 Apr 2026 03:34:56 -0700 Subject: [PATCH] fix(streaming): update stale-stream timer during Anthropic native streaming (#7117) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The _call_anthropic() streaming path never updated last_chunk_time during the event loop — only once at stream start. The stale stream detector in the outer poll loop uses this timer, so any Anthropic stream longer than 180s was killed even when events were actively arriving. This self-inflicted a RemoteProtocolError that users saw as: '⚠️ Connection to provider dropped (RemoteProtocolError). Reconnecting…' The _call_chat_completions() path already updates last_chunk_time on every chunk (line 4475). This brings _call_anthropic() to parity. Also adds deltas_were_sent tracking to the Anthropic text_delta path so the retry loop knows not to retry after partial delivery (prevents duplicated output on connection drops mid-stream). Reported-by: Discord users (Castellani, Codename_11) --- run_agent.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/run_agent.py b/run_agent.py index d13346247..78ceabe61 100644 --- a/run_agent.py +++ b/run_agent.py @@ -4692,6 +4692,14 @@ class AIAgent: # Use the Anthropic SDK's streaming context manager with self._anthropic_client.messages.stream(**api_kwargs) as stream: for event in stream: + # Update stale-stream timer on every event so the + # outer poll loop knows data is flowing. Without + # this, the detector kills healthy long-running + # Opus streams after 180 s even when events are + # actively arriving (the chat_completions path + # already does this at the top of its chunk loop). + last_chunk_time["t"] = time.time() + if self._interrupt_requested: break @@ -4715,6 +4723,7 @@ class AIAgent: if text and not has_tool_use: _fire_first_delta() self._fire_stream_delta(text) + deltas_were_sent["yes"] = True elif delta_type == "thinking_delta": thinking_text = getattr(delta, "thinking", "") if thinking_text: