Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/openai/lib/streaming/responses/_responses.py
Original file line number Diff line number Diff line change
Expand Up @@ -328,7 +328,9 @@ 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":
if event.item is None:
pass
Comment on lines +331 to +332

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve output indexes when an item is null

When a compatible provider emits a null item and then continues with another output item, this pass leaves snapshot.output one element shorter than the server's output indexes. Subsequent response.content_part.added, text-delta, or function-call-delta events index this list using event.output_index, so they can raise IndexError or update the wrong item. Preserve the missing slot's index or track and ignore dependent events by server index rather than shifting later outputs.

Useful? React with 👍 / 👎.

elif event.item.type == "function_call":
snapshot.output.append(
construct_type_unchecked(
type_=cast(Any, ParsedResponseFunctionToolCall), value=event.item.to_dict()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class Agent(BaseModel):
class BetaResponseOutputItemAddedEvent(BaseModel):
"""Emitted when a new output item is added."""

item: BetaResponseOutputItem
item: Optional[BetaResponseOutputItem] = None
"""The output item that was added.

For reasoning items, `encrypted_content` may be incomplete while the item is in
Expand Down
2 changes: 1 addition & 1 deletion src/openai/types/responses/response.py
Original file line number Diff line number Diff line change
Expand Up @@ -486,7 +486,7 @@ def output_text(self) -> str:
for output in self.output:
if output.type == "message":
for content in output.content:
if content.type == "output_text":
if content.type == "output_text" and content.text is not None:
texts.append(content.text)
Comment on lines +489 to 490

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Guard null text before structured parsing

For callers using responses.parse(..., text_format=...) or responses.stream(..., text_format=...), parse_response() processes the response before this property can be used and still calls parse_text(item.text, ...) unconditionally. The same output_text block with text: null therefore passes None to Pydantic's JSON parser and raises, so the affected response remains unusable in structured-output paths; skip parsing or normalize null text in parse_response() as well.

Useful? React with 👍 / 👎.


return "".join(texts)
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# File generated from our OpenAPI spec by Castiron. See CONTRIBUTING.md for details.

from typing import Optional
from typing_extensions import Literal

from ..._models import BaseModel
Expand All @@ -11,7 +12,7 @@
class ResponseOutputItemAddedEvent(BaseModel):
"""Emitted when a new output item is added."""

item: ResponseOutputItem
item: Optional[ResponseOutputItem] = None
"""The output item that was added.

For reasoning items, `encrypted_content` may be incomplete while the item is in
Expand Down