Skip to content

Conversation

@chenaoxd
Copy link

@chenaoxd chenaoxd commented Jan 6, 2026

Motivation and Context

The TextReasoningContent type exists in agent-framework for representing extended thinking/reasoning content from LLMs (e.g., Anthropic's extended thinking, OpenAI's reasoning). However, the AG-UI Event Bridge does not handle this content type, meaning thinking content is silently dropped when streaming to AG-UI clients.

Additionally, OpenAI-compatible APIs (like Kimi, DeepSeek) return reasoning content in a custom field (e.g., reasoning_content) rather than the standard response format. The current OpenAIChatClient has no way to extract this content.

Description

This PR adds two related features:

1. AG-UI Event Bridge (_events.py)

  • Handle TextReasoningContent by emitting AG-UI thinking events:
    • ThinkingStartEventThinkingTextMessageStartEventThinkingTextMessageContentEventThinkingTextMessageEndEventThinkingEndEvent
  • Support protected_data field extraction for OpenAI's reasoning_details format
  • Follow the existing pattern where START/CONTENT events are emitted in the bridge, and END events are emitted by the orchestrator (consistent with TextMessageEndEvent)

2. OpenAI Chat Client (_chat_client.py)

  • Add optional reasoning_field parameter to OpenAIChatClient
  • When set (e.g., reasoning_field="reasoning_content"), extract content from that field and emit TextReasoningContent
  • Enables support for Kimi, DeepSeek, and other OpenAI-compatible APIs with extended thinking

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.
    • no

@moonbox3 moonbox3 added the python label Jan 6, 2026
if reasoning_details := getattr(choice.delta, "reasoning_details", None):
contents.append(TextReasoningContent(None, protected_data=json.dumps(reasoning_details)))
# Handle custom reasoning field for OpenAI-compatible APIs (e.g., Kimi, DeepSeek)
if reasoning_field := getattr(self, "reasoning_field", None):
Copy link
Member

Choose a reason for hiding this comment

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

How would a user discover what the reasoning field name is for other API's then openai?

Copy link
Author

@chenaoxd chenaoxd Jan 6, 2026

Choose a reason for hiding this comment

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

If I understand your question correctly, users would typically refer to the provider's documentation.

For example, DeepSeek documents reasoning_content here: https://api-docs.deepseek.com/guides/thinking_mode

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.

3 participants