diff --git a/litellm/responses/streaming_iterator.py b/litellm/responses/streaming_iterator.py index da8ff2cd207..58b0f218f71 100644 --- a/litellm/responses/streaming_iterator.py +++ b/litellm/responses/streaming_iterator.py @@ -1157,7 +1157,8 @@ class BaseResponsesAPIStreamingIterator: def _note_yielded_event(self, event: ResponsesAPIStreamingResponse) -> None: self._yielded_first_chunk = True - if event.type not in PRE_OUTPUT_LIFECYCLE_EVENT_TYPES: + event_type: Final[object] = getattr(event, "type", None) + if event_type not in PRE_OUTPUT_LIFECYCLE_EVENT_TYPES: self._output_started = True def _fallback_error(self, original: Exception) -> MidStreamFallbackError: diff --git a/tests/unit/responses/test_streaming_iterator.py b/tests/unit/responses/test_streaming_iterator.py index 5072f3d3108..b1859ddf33c 100644 --- a/tests/unit/responses/test_streaming_iterator.py +++ b/tests/unit/responses/test_streaming_iterator.py @@ -25,6 +25,7 @@ from litellm.integrations.custom_logger import CustomLogger from litellm.litellm_core_utils.core_helpers import UPSTREAM_USAGE_COST, billed_usage_cost from litellm.litellm_core_utils.litellm_logging import Logging as LiteLLMLoggingObj from litellm.llms.base_llm.responses.transformation import BaseResponsesAPIConfig +from litellm.llms.openai.responses.transformation import OpenAIResponsesAPIConfig from litellm.responses.streaming_iterator import ( CachedResponsesAPIStreamingIterator, MockResponsesAPIStreamingIterator, @@ -415,6 +416,20 @@ async def test_complete_stream_still_ends_normally(trailer): assert logging_obj.async_failure_handler.await_count == 0 +@pytest.mark.asyncio +async def test_event_without_a_type_reaches_the_caller_instead_of_ending_the_stream(): + iterator: Final = _make_iterator( + sse_events=[_CREATED_EVENT, _sse_event({"note": "hook output without a type"})], + logging_obj=_failure_tracking_logging_obj(), + config=OpenAIResponsesAPIConfig(), + ) + + await iterator.__anext__() + untyped: Final = await iterator.__anext__() + + assert untyped.model_extra == {"note": "hook output without a type"} + + @pytest.mark.parametrize("trailing_error", _TRAILING_ERRORS, ids=type) def test_sync_transport_error_before_any_output_raises_fallback_error(trailing_error): logging_obj: Final = _failure_tracking_logging_obj()