fix(context_compressor): treat httpcore streaming premature-close as transient (salvage #22653)#22846
Merged
Conversation
… error Problem: When a provider or proxy drops a streaming response mid-flight (httpcore raises RemoteProtocolError: "incomplete chunked read", "peer closed connection", "response ended prematurely", etc.), _generate_summary would not classify it as a transient error. Instead of retrying on the main model, it entered the generic 60-second cooldown, leaving context growing unbounded until the cooldown expired. Issue #18458. Root cause: _is_connection_error in auxiliary_client.py did not match httpcore's streaming premature-close error substrings. context_compressor.py's _generate_summary except block never called _is_connection_error, so those errors fell through to the 60-second generic cooldown rather than triggering the retry-on-main fallback path used for timeouts. Fix: 1. auxiliary_client.py — extend _is_connection_error keyword list with: "incomplete chunked read", "peer closed connection", "response ended prematurely", "unexpected eof", "remoteprotocolerror", "localprotocolerror". Also guard the `from openai import ...` with try/except ImportError so the function works in environments without the openai package. 2. context_compressor.py — import _is_connection_error and call it in _generate_summary's except block as _is_streaming_closed. Include _is_streaming_closed in the fallback-to-main condition (alongside _is_model_not_found, _is_timeout, _is_json_decode) and use the shorter 30s transient cooldown for streaming-closed errors. Tests: 4 new regression tests in TestStreamingClosedFallback: - test_incomplete_chunked_read_falls_back_to_main - test_peer_closed_connection_falls_back_to_main - test_streaming_closed_on_main_uses_short_cooldown (stash-verified) - test_non_streaming_unknown_error_still_uses_long_cooldown Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Contributor
🔎 Lint report:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Salvage of #22653 —
httpcore.RemoteProtocolErrorfrom streaming premature-close is now classified as a transient/connection error in the auxiliary client and routed to the short-cooldown / aux→main fallback path incontext_compressor.Root cause
agent/auxiliary_client.py::_is_connection_errorsubstring list covered classic socket errors but missed httpcore's "incomplete chunked read", "peer closed connection without sending complete message body", "response ended prematurely", "unexpected eof".agent/context_compressor.py::_generate_summary's except block didn't even call_is_connection_error— only_is_model_not_found,_is_timeout,_is_json_decode. So mid-stream connection drops fell into the unknown-error path with the long 60s cooldown.Changes (contributor commit)
agent/auxiliary_client.py: extend_is_connection_errorsubstring list + add class-name fallbacks ("remoteprotocolerror", "localprotocolerror"). Wrapfrom openai import APIConnectionError, APITimeoutErrorin try/except so the function works in venvs without openai installed.agent/context_compressor.py::_generate_summary: classify_is_streaming_closedalongside existing transient classes, route to the same aux→main fallback + 30s short-cooldown path.Validation
Closes #18458 via salvage.