mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-11 22:51:28 +00:00
fix(responses): initialize completed_response on the MCP gateway streaming iterator
MCPEnhancedStreamingIterator has the same shape as the completion bridge that #35413 fixed: it subclasses BaseResponsesAPIStreamingIterator, never calls super().__init__, and never sets completed_response. It only catches StopAsyncIteration around the base iterator, so a MidStreamFallbackError propagates out of __anext__ and the Router reads completed_response off it in _extract_partial_responses_usage, raising AttributeError and masking the provider error. The iterator is reachable there: aresponses dispatches to aresponses_api_with_mcp when the request carries litellm_proxy MCP tools, which returns this iterator for stream=True, and the Router wraps any BaseResponsesAPIStreamingIterator. Initialize it to None alongside the other iterator state. With #35413 merged this was the last BaseResponsesAPIStreamingIterator subclass missing it. Signed-off-by: onatozmenn <onatozmen44@gmail.com>
This commit is contained in:
parent
f64479e74d
commit
b627f12b38
2 changed files with 40 additions and 0 deletions
|
|
@ -274,6 +274,7 @@ class MCPEnhancedStreamingIterator(BaseResponsesAPIStreamingIterator):
|
|||
# Streaming state management
|
||||
self.phase = "initial_response" # initial_response -> mcp_discovery -> (continue_initial_response <-> tool_execution) -> finished
|
||||
self.finished = False
|
||||
self.completed_response: Any | None = None
|
||||
|
||||
# Event queues and generation flags
|
||||
self.mcp_discovery_events: list[ResponsesAPIStreamingResponse] = (
|
||||
|
|
|
|||
|
|
@ -257,3 +257,42 @@ async def test_initial_call_failure_is_stashed_for_eager_reraise(monkeypatch):
|
|||
|
||||
assert iterator._initial_creation_error is not None
|
||||
assert "initial boom" in str(iterator._initial_creation_error)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_mid_stream_error_leaves_completed_response_readable(monkeypatch):
|
||||
"""
|
||||
Regression test: on a mid-stream provider error the Router's fallback path
|
||||
reads `completed_response` off this iterator directly (see
|
||||
Router._extract_partial_responses_usage). This iterator skips
|
||||
super().__init__(), so that read used to raise AttributeError and mask the
|
||||
provider error, stopping the fallback from running.
|
||||
"""
|
||||
from litellm import Router
|
||||
from litellm.exceptions import MidStreamFallbackError
|
||||
|
||||
_mock_mcp_environment(monkeypatch)
|
||||
|
||||
class _ErroringStream:
|
||||
def __aiter__(self):
|
||||
return self
|
||||
|
||||
async def __anext__(self):
|
||||
raise MidStreamFallbackError(
|
||||
message="provider overloaded",
|
||||
model="gpt-4",
|
||||
llm_provider="openai",
|
||||
)
|
||||
|
||||
iterator = MCPEnhancedStreamingIterator(
|
||||
base_iterator=_ErroringStream(),
|
||||
mcp_events=[],
|
||||
tool_server_map={},
|
||||
original_request_params={"model": "gpt-4"},
|
||||
)
|
||||
|
||||
with pytest.raises(MidStreamFallbackError):
|
||||
await iterator.__anext__()
|
||||
|
||||
assert iterator.completed_response is None
|
||||
assert Router._extract_partial_responses_usage(iterator) is None
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue