Repository navigation
fix(responses): surface provider errors and run fallbacks on the completion streaming bridge - #35018
devin-ai-integration[bot] wants to merge 5 commits into
Conversation
…he completion bridge iterator LiteLLMCompletionStreamingIterator subclasses ResponsesAPIStreamingIterator but never runs the base constructor, so it lacks completed_response and _hidden_params. When a provider errors before the first content chunk, the router reads completed_response directly in _extract_partial_responses_usage and raises AttributeError, and the missing _hidden_params makes the proxy pre-wrap the iterator for header attachment so the Responses mid-stream fallback path is skipped entirely. Initialize both on the bridge iterator so provider errors surface and fallbacks run. Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
Note: I can only respond to comments from users who have write access to this repository. ⚙️ Control Options:
|
Greptile SummaryThe PR restores required state on the chat-completions-to-Responses streaming bridge.
Confidence Score: 5/5The PR appears safe to merge with no blocking or non-blocking issues identified. The added iterator state satisfies the existing router consumers, hidden parameters are copied consistently with sibling fallback wrappers, and the bridge’s normal iteration path does not rely on the other base-constructor fields.
|
| Filename | Overview |
|---|---|
| litellm/responses/litellm_completion_transformation/streaming_iterator.py | Initializes the two bridge attributes required by partial-usage extraction and fallback metadata handling; no actionable defect found. |
| tests/router_unit_tests/test_router_aresponses_streaming_fallback.py | Adds focused regression coverage for the real bridge iterator’s pre-first-chunk state and hidden-parameter propagation. |
Reviews (1): Last reviewed commit: "fix(responses): initialize completed_res..." | Re-trigger Greptile
|
E2E verified on a live proxy that the Responses mid-stream fallback path is restored. Ran the LiteLLM proxy against fake Anthropic upstreams where the primary returns T1, the fix, request The overloaded primary fails over to the configured fallback, T2, no fallback configured, request The client receives the clean provider error with no internal Contrast on base commit The provider |
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
…itellm_lit4912_bridge_iterator_base_state
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
|
|
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
|
Closing as stale: no activity in the last 30 days. Feel free to reopen if this is still relevant. |
TLDR
Problem this solves:
/v1/responsesbridge errors masked the provider errorHow it solves it:
_hidden_paramson the bridge iterator so the router keeps it unwrappedUser Flow
Before: a developer streaming
/v1/responsesagainst a Claude deployment with a fallback configured gets an internal error when Anthropic is overloaded, and the fallback never kicks in{"model":"bridge-claude","input":"hi","stream":true}response.createdandresponse.in_progressarrive{"error": {"message": "litellm.MidStreamFallbackError: litellm.InternalServerError: AnthropicError - Overloaded", "code": "500"}}and the configured fallback model is never calledAfter: the same request fails over to the configured fallback
{"model":"bridge-claude","input":"hi","stream":true}response.createdarrives with"metadata":{"model_group":"fallback-echo"}, thenresponse.output_text.deltaevents with the fallback's textresponse.completedreports"model":"fallback-echo"and the stream ends with[DONE]litellm.InternalServerError: AnthropicError - Overloadedinstead of the internalMidStreamFallbackErrorRelevant issues
Linear ticket
Resolves LIT-4912
Pre-Submission checklist
Please complete all items before asking a LiteLLM maintainer to review your PR
uv run pytest tests/test_litellm/<your_test_file>.py -v. Leave the suites (make test-unit-*,make test-unit) to CI: it finishes in ~15 minutes where a laptop takes an hour or more@greptileaito re-request a review after pushing changes)Delays in PR merge?
If you're seeing a delay in your PR being merged, ping the LiteLLM Team on Slack (#pr-review).
Screenshots / Proof of Fix
LiteLLMCompletionStreamingIteratoris the bridge iterator used when a chat-completions provider (Anthropic, Bedrock, Vertex) serves a streaming Responses API request. It subclassesResponsesAPIStreamingIteratorbut never runs the base constructor. Staging has since addedcompleted_response = Noneto it, which fixes theAttributeErrorhalf of the ticket, but_hidden_paramsis still absent. Without itRouter.set_response_headerswraps the iterator inHiddenParamsAsyncIteratorWrapper, the wrapped object fails theisinstance(response, BaseResponsesAPIStreamingIterator)check in_aresponses_with_streaming_fallbacks, and the Responses mid-stream fallback path is skipped entirelyReproducing a real provider emitting
Overloadedbefore the first chunk on demand is not feasible, so the upstream is a local server that deterministically emits an Anthropicmessage_startfollowed by anerrorevent; everything else (proxy, router, bridge, fallback selection) is the real code path end to end.bridge-claudehas a fallback configured tofallback-echo;bridge-claude-nofallbackhas noneBefore (cd9c410)
Fallback configured
curl -sS -N -X POST http://localhost:4000/v1/responses -H "Authorization: Bearer sk-1234" -H "Content-Type: application/json" -d '{"model":"bridge-claude","input":"hi","stream":true}'data: {"error": {"message": "litellm.MidStreamFallbackError: litellm.InternalServerError: AnthropicError - Overloaded", "type": null, "param": null, "code": "500"}}and noHELLO FROM FALLBACKAfter (a634cb9)
Fallback configured
"model":"bridge-claude"response.createdwith"metadata":{"model_group":"fallback-echo"},response.output_text.deltawith"delta":"HELLO FROM FALLBACK",response.completedwith"model":"fallback-echo", thendata: [DONE]No fallback configured
"model":"bridge-claude-nofallback"data: {"error": {"message": "litellm.InternalServerError: AnthropicError - Overloaded", "type": null, "param": null, "code": "500"}}Type
🐛 Bug Fix
Changes
LiteLLMCompletionStreamingIterator.__init__now setsself._hidden_params, copied from the underlyingCustomStreamWrapperwhen present. The branch was merged withlitellm_internal_staging, which already carries thecompleted_response = Noneinitialization, so that part of the original fix dropped out of the diff. The other base attributes are read byFallbackResponsesStreamWrapperthroughgetattr(..., default), so their absence was already toleratedRegression coverage builds a real
LiteLLMCompletionStreamingIterator(not aMagicMockstanding in for it) with no collected chunks and assertsRouter._extract_partial_responses_usagereturnsNonewithout raising, plus that_hidden_paramsis present so the router does not pre-wrap and skip the fallback path. The rest of the test file diff isruff formatoutput at the repo's 120 column limitCaveats (if any)
Low
a634cb9b62, before the staging merge; the runtime change is identicalFinal Attestation
Link to Devin session: https://app.devin.ai/sessions/35369f075dcf46f5b132e31de9cb0124
Open in Devin Desktop: https://app.devin.ai/desktop/session/35369f075dcf46f5b132e31de9cb0124?variant=devin
Requested by: @yassin-berriai