Skip to content

response.reasoning_summary_text.delta incorrectly uses ResponseAudioDeltaEvent #2311

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
1 task done
simonw opened this issue Apr 17, 2025 · 4 comments
Closed
1 task done
Labels
bug Something isn't working openapi

Comments

@simonw
Copy link

simonw commented Apr 17, 2025

Confirm this is an issue with the Python library and not an underlying OpenAI API

  • This is an issue with the Python library

Describe the bug

In the streaming output the response.reasoning_summary_text.delta event is represented using ResponseAudioDeltaEvent for some reason.

To Reproduce

Try running this (STR created with the help of o4-mini):

python -c 'import openai,os
for event in openai.OpenAI(api_key=os.getenv("OPENAI_API_KEY")).responses.create(
    model="o3",
    input=[{"role":"user","content":"Why is the sky blue?"}],
    reasoning={"summary":"auto"},
    stream=True,
):
    print(event)'

The output includes lines like this:

ResponseAudioDeltaEvent(delta='**Expl', type='response.reasoning_summary_text.delta', item_id='rs_680044dcbd9881918572b2b1a63ca6a903b0150bf71ce6fa', output_index=0, summary_index=0)

ResponseAudioDeltaEvent looks wrong. Something like ResponseReasoningSummaryDeltaEvent would make more sense.

OS

macOS

Python version

Python 3.13.2

Library version

openai==1.75.0

@simonw simonw added the bug Something isn't working label Apr 17, 2025
@lemeb
Copy link

lemeb commented Apr 21, 2025

Can confirm on my end! Very weird.

@lemeb
Copy link

lemeb commented Apr 21, 2025

Ok, I think I figured what's going on:

Because events of type response.reasoning_summary_text.delta don't have any data structure associated with it, the discriminator mapping fails.

This line of code:

discriminator = _build_discriminated_union_meta(union=type_, meta_annotations=meta)

Will yield this:

Click to see the value of `disciminator`
{'error': <class 'openai.types.responses.response_error_event.ResponseErrorEvent'>,
 'response.audio.delta': <class 'openai.types.responses.response_audio_delta_event.ResponseAudioDeltaEvent'>,
 'response.audio.done': <class 'openai.types.responses.response_audio_done_event.ResponseAudioDoneEvent'>,
 'response.audio.transcript.delta': <class 'openai.types.responses.response_audio_transcript_delta_event.ResponseAudioTranscriptDeltaEvent'>,
 'response.audio.transcript.done': <class 'openai.types.responses.response_audio_transcript_done_event.ResponseAudioTranscriptDoneEvent'>,
 'response.code_interpreter_call.code.delta': <class 'openai.types.responses.response_code_interpreter_call_code_delta_event.ResponseCodeInterpreterCallCodeDeltaEvent'>,
 'response.code_interpreter_call.code.done': <class 'openai.types.responses.response_code_interpreter_call_code_done_event.ResponseCodeInterpreterCallCodeDoneEvent'>,
 'response.code_interpreter_call.completed': <class 'openai.types.responses.response_code_interpreter_call_completed_event.ResponseCodeInterpreterCallCompletedEvent'>,
 'response.code_interpreter_call.in_progress': <class 'openai.types.responses.response_code_interpreter_call_in_progress_event.ResponseCodeInterpreterCallInProgressEvent'>,
 'response.code_interpreter_call.interpreting': <class 'openai.types.responses.response_code_interpreter_call_interpreting_event.ResponseCodeInterpreterCallInterpretingEvent'>,
 'response.completed': <class 'openai.types.responses.response_completed_event.ResponseCompletedEvent'>,
 'response.content_part.added': <class 'openai.types.responses.response_content_part_added_event.ResponseContentPartAddedEvent'>,
 'response.content_part.done': <class 'openai.types.responses.response_content_part_done_event.ResponseContentPartDoneEvent'>,
 'response.created': <class 'openai.types.responses.response_created_event.ResponseCreatedEvent'>,
 'response.failed': <class 'openai.types.responses.response_failed_event.ResponseFailedEvent'>,
 'response.file_search_call.completed': <class 'openai.types.responses.response_file_search_call_completed_event.ResponseFileSearchCallCompletedEvent'>,
 'response.file_search_call.in_progress': <class 'openai.types.responses.response_file_search_call_in_progress_event.ResponseFileSearchCallInProgressEvent'>,
 'response.file_search_call.searching': <class 'openai.types.responses.response_file_search_call_searching_event.ResponseFileSearchCallSearchingEvent'>,
 'response.function_call_arguments.delta': <class 'openai.types.responses.response_function_call_arguments_delta_event.ResponseFunctionCallArgumentsDeltaEvent'>,
 'response.function_call_arguments.done': <class 'openai.types.responses.response_function_call_arguments_done_event.ResponseFunctionCallArgumentsDoneEvent'>,
 'response.in_progress': <class 'openai.types.responses.response_in_progress_event.ResponseInProgressEvent'>,
 'response.incomplete': <class 'openai.types.responses.response_incomplete_event.ResponseIncompleteEvent'>,
 'response.output_item.added': <class 'openai.types.responses.response_output_item_added_event.ResponseOutputItemAddedEvent'>,
 'response.output_item.done': <class 'openai.types.responses.response_output_item_done_event.ResponseOutputItemDoneEvent'>,
 'response.output_text.annotation.added': <class 'openai.types.responses.response_text_annotation_delta_event.ResponseTextAnnotationDeltaEvent'>,
 'response.output_text.delta': <class 'openai.types.responses.response_text_delta_event.ResponseTextDeltaEvent'>,
 'response.output_text.done': <class 'openai.types.responses.response_text_done_event.ResponseTextDoneEvent'>,
 'response.refusal.delta': <class 'openai.types.responses.response_refusal_delta_event.ResponseRefusalDeltaEvent'>,
 'response.refusal.done': <class 'openai.types.responses.response_refusal_done_event.ResponseRefusalDoneEvent'>,
 'response.web_search_call.completed': <class 'openai.types.responses.response_web_search_call_completed_event.ResponseWebSearchCallCompletedEvent'>,
 'response.web_search_call.in_progress': <class 'openai.types.responses.response_web_search_call_in_progress_event.ResponseWebSearchCallInProgressEvent'>,
 'response.web_search_call.searching': <class 'openai.types.responses.response_web_search_call_searching_event.ResponseWebSearchCallSearchingEvent'>}

And so this code will not return anything:

if discriminator and is_mapping(value):
variant_value = value.get(discriminator.field_alias_from or discriminator.field_name)
if variant_value and isinstance(variant_value, str):
variant_type = discriminator.mapping.get(variant_value)
if variant_type:
return construct_type(type_=variant_type, value=value)

Which means you rely on this fallback code, which essentially ends up selecting the first element in the mapping (ResponseAudioDeltaEvent), and coerce a construction.

# if the data is not valid, use the first variant that doesn't fail while deserializing
for variant in args:
try:
return construct_type(value=value, type_=variant)
except Exception:
continue

@lemeb
Copy link

lemeb commented Apr 23, 2025

ok, seems like it was fixed by 6321004!

@moonbox3
Copy link

This is happening again in #2382 and #2383

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working openapi
Projects
None yet
Development

No branches or pull requests

4 participants