diff --git a/src/openai/lib/streaming/responses/_responses.py b/src/openai/lib/streaming/responses/_responses.py index 6975a9260d..513ca5dbb5 100644 --- a/src/openai/lib/streaming/responses/_responses.py +++ b/src/openai/lib/streaming/responses/_responses.py @@ -328,18 +328,20 @@ def accumulate_event(self, event: RawResponseStreamEvent) -> ParsedResponseSnaps return self._create_initial_response(event) if event.type == "response.output_item.added": - if event.item.type == "function_call": + item = event.item + if item is None: + return snapshot + + if item.type == "function_call": snapshot.output.append( - construct_type_unchecked( - type_=cast(Any, ParsedResponseFunctionToolCall), value=event.item.to_dict() - ) + construct_type_unchecked(type_=cast(Any, ParsedResponseFunctionToolCall), value=item.to_dict()) ) - elif event.item.type == "message": + elif item.type == "message": snapshot.output.append( - construct_type_unchecked(type_=cast(Any, ParsedResponseOutputMessage), value=event.item.to_dict()) + construct_type_unchecked(type_=cast(Any, ParsedResponseOutputMessage), value=item.to_dict()) ) else: - snapshot.output.append(event.item) + snapshot.output.append(item) elif event.type == "response.content_part.added": output = snapshot.output[event.output_index] if output.type == "message": diff --git a/tests/lib/responses/test_responses.py b/tests/lib/responses/test_responses.py index 8e5f16df95..5bba1fe2c1 100644 --- a/tests/lib/responses/test_responses.py +++ b/tests/lib/responses/test_responses.py @@ -8,6 +8,8 @@ from openai import OpenAI, AsyncOpenAI from openai._utils import assert_signatures_in_sync +from openai.types.responses import Response, ResponseCreatedEvent, ResponseOutputItemAddedEvent +from openai.lib.streaming.responses._responses import ResponseStreamState from ...conftest import base_url from ..snapshots import make_snapshot_request @@ -61,3 +63,35 @@ def test_parse_method_definition_in_sync(sync: bool, client: OpenAI, async_clien checking_client.responses.parse, exclude_params={"tools"}, ) + + +def test_response_stream_ignores_null_output_item_added() -> None: + response = Response.model_construct( + id="resp_123", + created_at=0.0, + model="gpt-4o", + object="response", + output=[], + parallel_tool_calls=True, + tool_choice="auto", + tools=[], + ) + state = ResponseStreamState(input_tools=[], text_format=str) + + state.handle_event( + ResponseCreatedEvent.model_construct( + type="response.created", + sequence_number=0, + response=response, + ) + ) + events = state.handle_event( + ResponseOutputItemAddedEvent.model_construct( + type="response.output_item.added", + sequence_number=1, + output_index=0, + item=None, + ) + ) + + assert [event.type for event in events] == ["response.output_item.added"]