Skip to content

Conversation

KanchiShimono
Copy link

Motivation and Context

This PR fixes issues when TextReasoningContent in ChatMessage is converted to OpenAI Responses API input format.

Two distinct problems:

  1. Input schema violation (400 error)

    • _openai_content_parser converts TextReasoningContent incorrectly for Responses API input
    • summary must be array format, not object
    • TextReasoningContent must be placed at message level, not inside content array
    Reproduction code and error
    async with OpenAIResponsesClient().create_agent(
        name="DocsAgent"
        tools=MCPStreamableHTTPTool(name="MCP", url="https://learn.microsoft.com/api/mcp"),
    ) as agent:
        query = "How to create an Azure storage account using az cli?"
        async for chunk in agent.run_stream(
            query,
            additional_chat_options={"reasoning": {"effort": "high", "summary": "auto"}},
        ):
            pass
    Error code: 400 - {'error': {'message': "Invalid value: 'reasoning'. Supported values are: 'input_text', 'input_image', ...", 'param': 'input[2].content[0].type', 'code': 'invalid_value'}}
    
  2. Duplicate streaming content

    • _create_streaming_response_content handles both response.reasoning_summary_text.delta and .done events
    • .done contains complete text already streamed via .delta, causing duplication

Description

Fixes:

  1. _openai_content_parser:
    • Changed summary from object to array format
    • Placed TextReasoningContent at correct hierarchy
  2. _create_streaming_response_content:
    • Added explicit case statement with pass to intentionally ignore .done event

Tests:

  • Updated assertions for array-based summary schema
  • Added test to verify .done event is intentionally ignored (prevents regression)

Contribution Checklist

  • The code builds clean without any errors or warnings
  • The PR follows the Contribution Guidelines
  • All unit tests pass, and I have added new tests where possible
  • Is this a breaking change? If yes, add "[BREAKING]" prefix to the title of the PR.

@github-actions github-actions bot changed the title Fix OpenAI Responses API TextReasoningContent handling Python: Fix OpenAI Responses API TextReasoningContent handling Oct 8, 2025
@markwallace-microsoft
Copy link
Member

markwallace-microsoft commented Oct 9, 2025

Python Test Coverage

Python Test Coverage Report •
FileStmtsMissCoverMissing
packages/core/agent_framework/openai
   _responses_client.py4106983%141–142, 145–146, 152–153, 156, 163, 195, 204, 216, 246, 274–275, 298, 391, 396, 473, 478, 482–484, 505, 508, 523–524, 528–530, 578, 598–599, 612–613, 629–630, 668, 670, 714, 718, 720, 729, 731, 740–741, 754, 756, 829–835, 852–857, 876, 894, 904, 906, 924–925, 927–929
TOTAL10364170783% 

Python Unit Test Overview

Tests Skipped Failures Errors Time
1277 98 💤 0 ❌ 0 🔥 29.121s ⏱️

@mattgotteiner
Copy link
Member

Thanks @KanchiShimono this works great!

@KanchiShimono
Copy link
Author

@mattgotteiner
Thank you for your reply.

It seems that the Windows test workflow is failing due to a timeout while installing ruff.
Since this issue appears to be unrelated to the changes in this PR, I believe rerunning the workflow should make it pass.

@dmytrostruk
Copy link
Member

dmytrostruk commented Oct 16, 2025

@KanchiShimono Thanks for your contribution!

In this PR: #1509, I skipped TextReasoningContent completely, since it's not compatible with gpt-oss models, and during my testing I didn't find a case when we need to send TextReasoningContent back to the model, specifically in OpenAI Responses API (please correct me if I'm wrong). But if there is a case when we actually need to send TextReasoningContent back to the model, maybe we can send it back as TextContent instead.

I already pulled latest changes from main in this PR, so please check the latest changes and see if Input schema violation (400 error) that you described in PR description is already fixed when we skip TextReasoningContent. Thanks!

@KanchiShimono
Copy link
Author

@dmytrostruk Thank you for your reply.

The Input schema violation (400 error) no longer occurs.
I also discovered that in gpt-oss, raw ReasoningText events (not ReasoningSummaryText) are returned, so I added a commit to fix the duplication between delta and done events for those as well.

It seems that when the model's final response is a Function Call, we should send TextReasoningContent back to the model. This behavior appears to be consistent between closed models like GPT-5 and gpt-oss.
The OpenAI Cookbook states the following:

If a turn includes a function call (which may require an extra round trip outside the API), you do need to include the reasoning items—either via previous_response_id or by explicitly adding the reasoning item to input.

In the gpt-oss Responses API server implementation, the ReasoningItem is also sent back to the model only when the last response was a Function Call.

It might be good to support passing TextReasoningContent as well in the future for this use case.

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants