fix: emit reasoning events in AGUI interface - #7429
Conversation
Map Agno reasoning events to AG-UI protocol reasoning event types instead of generic STEP_STARTED/STEP_FINISHED. This enables CopilotKit frontends to render "Thought for N seconds" with expandable reasoning content. - Emit REASONING_START, REASONING_MESSAGE_START, REASONING_MESSAGE_CONTENT, REASONING_MESSAGE_END, and REASONING_END events during reasoning - Handle both Agent (RunEvent) and Team (TeamRunEvent) reasoning events - Close orphaned reasoning sessions on stream completion/abort - Bump ag-ui-protocol dependency to >=0.1.15 for reasoning event types Fixes #7216
ab03e61 to
57d3b9e
Compare
- Use isinstance() dispatch for Agent/Team reasoning event types - Handle ReasoningContentDeltaEvent (native model reasoning) as true streaming delta - Handle ReasoningStepEvent (ReasoningTools) by formatting chunk.content (single step) instead of using accumulated reasoning_content field which duplicated text - Emit REASONING_START/REASONING_MESSAGE_START in fallback when content arrives without preceding reasoning_started event - Pass reasoning_message_id through synthetic completion path to close orphaned sessions - Remove redundant STEP_STARTED/STEP_FINISHED wrapping (replaced by REASONING_* events) - Bump ag-ui-protocol dependency to >=0.1.15 for reasoning event types - Update test to verify REASONING_* event types and ordering
57d3b9e to
22de607
Compare
PR Review: fix: emit reasoning events in AGUI interfaceOverall: Good PR. The approach is sound - mapping Agno reasoning events to AG-UI Issues1. Potential dispatch ordering bug (Medium) The 2. Duplicate START event emission pattern (Low - style) The fallback 3. Missing test coverage for The test only covers 4. Missing test for orphaned reasoning cleanup (Low) The 5. The function returns What looks good
VerdictThe implementation is correct and well-structured. The main ask would be adding a test for the |
…oning - Test ReasoningStepEvent path with 2 steps: verifies no accumulated content duplication, each delta contains only its own step, and step numbers are present - Test orphaned reasoning cleanup: verifies REASONING_END is emitted when stream ends without ReasoningCompletedEvent
|
Thanks for the thorough review! Here's how we addressed each point: 1. Dispatch ordering (Medium) — Verified: all 4 reasoning event types have unique 2. Duplicate START emission pattern (Low/Style) — Considered extracting a helper, but the 3 branches have different control flow around the same 2-line append: A helper would only factor out 2 3. Missing ReasoningStepEvent test (Medium) — Added 4. Missing orphaned cleanup test (Low) — Added 5. Trailing 35/35 tests passing, all CI green. |
Summary
REASONING_START,REASONING_MESSAGE_CONTENT, etc.) usingisinstance()dispatch for type-safe Agent and Team event handlingReasoningContentDeltaEventwith true streaming deltasReasoningStepEventwith structuredReasoningStepcontent, formatted as text delta per step (avoids accumulated content duplication)REASONING_START/REASONING_MESSAGE_STARTwhen content arrives without a precedingreasoning_startedeventSTEP_STARTED/STEP_FINISHEDwrapping — replaced by dedicatedREASONING_*events (ag-ui-protocol ≥0.1.15)ag-ui-protocoldependency to>=0.1.15for reasoning event typesWhy Two Reasoning Paths?
Agno has two distinct reasoning producers that emit different event types:
reasoning_contentfieldReasoningContentDeltaEventREASONING_MESSAGE_CONTENT.deltaReasoningStepEventchunk.content(singleReasoningStep) as delta textThe AG-UI SDK concatenates deltas:
targetMessage.content += delta(source). Sending accumulated content as delta duplicates text.Bugs Fixed
ReasoningStepEvent.reasoning_contentis accumulated (all steps so far), but AG-UI SDK concatenates deltas. Sending accumulated content as delta caused step 1 to appear multiple times. Fixed by formattingchunk.content(the singleReasoningStepobject) directly via_format_reasoning_step_delta().run_completed) didn't passreasoning_message_id, leavingREASONING_STARTunclosed. Fixed by threadingreasoning_message_idthrough both sync and async completion paths.REASONING_MESSAGE_CONTENTemitted without precedingREASONING_START/REASONING_MESSAGE_STARTwhenreasoning_content_deltaarrived beforereasoning_started. Fixed by emitting START events in fallback path.STEP_STARTED/STEP_FINISHEDemitted alongsideREASONING_*events. Removed since dedicated reasoning events replace the generic step markers.Test Matrix
All scenarios tested on both AG-UI Dojo and os.agno.com:
Raw SSE Event Sequence (ReasoningTools, complex query)
Each step appears exactly once — no accumulated duplication.
Type of change
Checklist
./scripts/format.sh./scripts/validate.shREASONING_*event sequence for both native reasoning and ReasoningToolstargetMessage.content += delta(concatenation), validating delta approachTest plan
pytest libs/agno/tests/unit/app/test_agui_app.py— 33 pass/aguiendpoint, verifyREASONING_*events in SSE streamFixes #7216