Surface AG-UI REASONING_MESSAGE_CHUNK events as reasoning content - #936
Conversation
The client onEvent switch handles ReasoningMessageContentEvent but not the semantically equivalent ReasoningMessageChunkEvent, which the AG-UI decoder also produces (decoder EventTypeReasoningMessageChunk). A server that streams reasoning as chunk events therefore has its reasoning silently dropped. Add a ReasoningMessageChunkEvent case that emits a TextReasoningContent, reusing the last chunk MessageID for chunks that omit it - mirroring the existing TextMessageChunkEvent handling and ReasoningMessageContentEvent.
There was a problem hiding this comment.
Pull request overview
Adds support in the AG-UI provider for streaming reasoning deltas sent as REASONING_MESSAGE_CHUNK events, so chunked reasoning is surfaced to collectors instead of being dropped.
Changes:
- Handle
*aguiEvents.ReasoningMessageChunkEventintoolCallAccumulator.onEventby emittingmessage.TextReasoningContentupdates. - Add a unit test that streams reasoning chunk events and asserts the concatenated reasoning is surfaced.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| provider/aguiprovider/agui.go | Adds a switch-case to map ReasoningMessageChunkEvent into TextReasoningContent response updates (with MessageID continuation logic). |
| provider/aguiprovider/agui_test.go | Adds a test asserting chunked reasoning is collected and exposed as TextReasoningContent. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Quim Muntal (qmuntal)
left a comment
There was a problem hiding this comment.
Fix copilot feedback.
This comment has been minimized.
This comment has been minimized.
ReasoningMessageChunkEvent reused toolCallAccumulator.lastChunkMessageID, which TextMessageChunkEvent also uses. A stream interleaving text and reasoning chunks where a reasoning chunk omits MessageID would inherit the last text chunk's MessageID (and vice versa), mixing reasoning into a text message. Track a separate lastReasoningChunkMessageID, and add a test that interleaves text and reasoning chunks with an omitted reasoning MessageID.
API Consistency Review — PR #936Scope: User-visible behavior (AG-UI client event handling)
Result: Aligned / no parity issues. Neither Python nor .NET upstream ship an AG-UI client that consumes streaming chunk events, so there is no cross-repo equivalent to diverge from. The fix completes the symmetric event-handling set in the Go client (text chunk ↔ reasoning chunk) and aligns
|
Problem
The AG-UI client's
onEventswitch (provider/aguiprovider/agui.go) handlesReasoningMessageContentEventandTextMessageChunkEvent, but has no case forReasoningMessageChunkEvent— the chunk-form encoding of reasoning that the AG-UI decoder also produces (decoder.gocaseEventTypeReasoningMessageChunk). A server that streams reasoning asREASONING_MESSAGE_CHUNKevents therefore has its reasoning silently dropped (falls through to the default).This is the reasoning counterpart of the already-handled
TEXT_MESSAGE_CHUNKcase.Fix
Add a
*aguiEvents.ReasoningMessageChunkEventcase that emits amessage.TextReasoningContentfrom the chunk delta, reusing the last seen chunkMessageIDwhen a chunk omits it — mirroring the existingTextMessageChunkEventhandling and theReasoningMessageContentEventmapping.Test
TestAGUIAgentRun_SurfacesReasoningMessageChunkEventsstreams twoREASONING_MESSAGE_CHUNKevents and asserts the concatenated reasoning is surfaced asTextReasoningContent. Fails before the fix (empty), passes after.Note:
TOOL_CALL_CHUNKis intentionally not addressed here — the AG-UI Go decoder has no case for it, so it never reaches the client.