This commit is contained in:
devin-ai-integration[bot] 2026-08-27 18:57:53 -05:00 committed by GitHub
commit c2af50e479
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 46 additions and 1 deletions

View file

@ -88,7 +88,12 @@ class LiteLLMCompletionStreamingIterator(ResponsesAPIStreamingIterator):
self.request_input: str | ResponseInputParam = request_input
self.responses_api_request: ResponsesAPIOptionalRequestParams = responses_api_request
self.custom_llm_provider: str | None = custom_llm_provider
self.litellm_metadata: dict | None = litellm_metadata or {}
self.litellm_metadata = litellm_metadata or {}
self.completed_response: Any | None = None
_wrapper_hidden_params = getattr(litellm_custom_stream_wrapper, "_hidden_params", None)
self._hidden_params: dict[str, Any] = (
dict(_wrapper_hidden_params) if isinstance(_wrapper_hidden_params, dict) else {}
)
# Store lightweight dict snapshots for stream_chunk_builder to reduce
# repeated Pydantic attribute access in end-of-stream assembly.
self.collected_chat_completion_chunks: list[dict[str, object]] = []

View file

@ -509,3 +509,43 @@ async def test_aresponses_client_error_event_skips_fallback():
assert exc_info.value.status_code == 400
mock_fallback.assert_not_awaited()
# -------- regression: real bridge iterator honors the base contract (LIT-4912) --------
def test_extract_partial_responses_usage_real_bridge_iterator_pre_first_chunk():
"""
Regression for LIT-4912.
When a provider errors before the first content chunk, the completion-bridge
iterator reaches _extract_partial_responses_usage with no collected chunks.
A real LiteLLMCompletionStreamingIterator (not a MagicMock standing in for
it) must expose the base-class contract so usage extraction returns None
instead of raising AttributeError on completed_response, and must carry
_hidden_params so the router does not pre-wrap it for header attachment and
thereby skip the mid-stream fallback path entirely.
"""
from litellm.responses.litellm_completion_transformation.streaming_iterator import (
LiteLLMCompletionStreamingIterator,
)
from litellm.responses.streaming_iterator import BaseResponsesAPIStreamingIterator
class _FakeStreamWrapper:
def __init__(self) -> None:
self.logging_obj = MagicMock()
self._hidden_params = {"model_id": "deployment-123"}
iterator = LiteLLMCompletionStreamingIterator(
model="anthropic/claude-3-5-sonnet-latest",
litellm_custom_stream_wrapper=_FakeStreamWrapper(),
request_input="hi",
responses_api_request={},
)
assert isinstance(iterator, BaseResponsesAPIStreamingIterator)
assert iterator.completed_response is None
assert iterator._hidden_params == {"model_id": "deployment-123"}
assert not iterator.collected_chat_completion_chunks
assert Router._extract_partial_responses_usage(iterator) is None