feat: render streaming reasoning content#594
Open
Shinyaigeek wants to merge 1 commit into
Open
Conversation
Consume AG-UI REASONING_MESSAGE_* events end-to-end. The stream processor now accumulates reasoning deltas into a colocated AssistantMessage.reasoning field, and the Shell / CopilotShell / BottomTray / OpenUIChat surfaces render it inside a collapsible "Behind the scenes" panel via a shared ReasoningSection component. - types: extend AssistantMessage with an optional `reasoning` field and swap the Message union's assistant branch so narrowing exposes it - processStreamedMessage: handle REASONING_MESSAGE_CONTENT/CHUNK, ignoring the reasoning-only messageId (preserved across the TEXT_MESSAGE_START id swap) - identityMessageFormat: strip the client-only `reasoning` field from outbound history so it is not echoed back to the backend each turn - react-ui: new Reasoning/ component dir (ReasoningContent + ReasoningSection), applied to all assistant render surfaces; exported from the package root Tests: reasoning accumulation, id-swap preservation, absence, and the identityMessageFormat strip. Addresses thesysdev#414 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
@ag-ui/corefully defines theReasoningMessagetype and theREASONING_MESSAGE_START / CONTENT / ENDevent sequence, but neither@openuidev/react-headlessnor@openuidev/react-uiconsumed them, so reasoning/thinking output was silently dropped end-to-end (#414).This wires reasoning through, colocated on the assistant turn (a
reasoningfield onAssistantMessage) rather than as a separate message — matching how the streaming layer already folds text and tool calls into a single assistant message, and how the format converters already treat reasoning.What changed
react-headlesstypes/message.ts— extendAssistantMessagewith an optionalreasoningfield; swap theMessageunion's assistant branch sorole === "assistant"narrowing exposes it.stream/processStreamedMessage.ts— handleREASONING_MESSAGE_CONTENT/CHUNK, accumulating deltas intocurrentMessage.reasoning. The reasoning-onlymessageIdis intentionally ignored; a laterTEXT_MESSAGE_STARTswaps in the real assistant id and the spread preserves the accumulated reasoning.types/messageFormat.ts— the defaultidentityMessageFormatnow strips the client-onlyreasoningfield intoApi, so accumulated thinking is not echoed back to the backend on every subsequent turn.react-uiReasoning/component dir:ReasoningContent(markdown) and a sharedReasoningSection(the collapsibleBehindTheScenespanel).Shell,CopilotShell,BottomTray(viaReasoningSection) andOpenUIChat(nested in its existing merged tool-call panel).Design notes
toolCallsComplete={!!message.content}).Out of scope (follow-ups)
loadThread/ the format converters) — currently the live-stream path only.reasoningstring concatenates blocks).Testing
processStreamedMessage: reasoning accumulation, preservation across theTEXT_MESSAGE_STARTid swap, and absence (no reasoning events).identityMessageFormat: stripsreasoningoutbound, leaves other messages untouched.pnpm testgreen (react-headless), typecheck + build green (both packages).Closes #414
🤖 Generated with Claude Code