Skip to content

response.reasoning_summary_text.delta incorrectly uses ResponseAudioDeltaEvent #2311

Closed

Description

@simonw

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

Activity

  1. lemeb commented on Apr 21, 2025

    @lemeb

    Can confirm on my end! Very weird.

  2. lemeb commented on Apr 21, 2025

    @lemeb

    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

  3. lemeb commented on Apr 23, 2025

    @lemeb

    ok, seems like it was fixed by 6321004!

  4. moonbox3 commented on May 27, 2025

    @moonbox3

    This is happening again in #2382 and #2383

  5. apurvsibal commented on Jun 12, 2025

    @apurvsibal

    +1

  6. abhinav-wingback commented on Aug 5, 2025

    @abhinav-wingback

    +1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingopenapi

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions