Skip to content

fix(OpenAI): stream every output item a non-streamed response parses - #833

Merged
iBotPeaches merged 2 commits into
openai-php:mainfrom
skybleak333:responses-stream-output-items
Nov 9, 2026
Merged

iBotPeaches merged 2 commits into
openai-php:mainfrom
skybleak333:responses-stream-output-items

Conversation

@skybleak333

Copy link
Copy Markdown
Contributor

What:

  • Bug Fix
  • New Feature

Description:

Streaming a response that calls a custom tool ({"type": "custom"}) ends with UnhandledMatchError: Unhandled match case 'custom_tool_call' on its response.output_item.added event. A local_shell_call item does the same. create() parses both, because OutputObjects::parse() knows them, but Streaming\OutputItem has its own copy of that match and the copy fell behind. #787 and #789 fixed the same gap for one type each.

OutputItem now uses OutputObjects::parse(), so a new output type only has to be added in one place. An unknown item type in a stream now throws the same UnexpectedValueException as create() instead of UnhandledMatchError.

The custom tool input also streams in its own events, response.custom_tool_call_input.delta and .done (delta, done in openai-python), so they are added too: without them the stream failed one event later with UnknownEventException. I left out obfuscation, since openai-python only declares it on shell_call_command.delta.

I also ran it through Guzzle against a local server that sends the events as SSE. On main the stream stops right after the reasoning item, with this branch every event arrives, up to response.completed.

Streaming\OutputItem had its own copy of the item type match from OutputObjects, and the copy fell behind: a custom_tool_call or local_shell_call item threw UnhandledMatchError and ended the stream, while create() parsed the same items.
OutputItem now uses OutputObjects::parse(), so both stay in sync, and an unknown item type throws the same UnexpectedValueException as in create().

Also adds the response.custom_tool_call_input.delta and .done events. Without them, a custom tool stream still failed with UnknownEventException.

@iBotPeaches iBotPeaches left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This makes sense to me. I vaguely thought the shapes were different for streaming, but all those entities look to be calling same non-streaming obj.

@iBotPeaches
iBotPeaches merged commit 44b1c15 into openai-php:main Nov 9, 2026
14 checks passed
skybleak333 added a commit to skybleak333/skybleak333 that referenced this pull request Nov 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants