Skip to content

[fix] Emit ReasoningContentDeltaEvent for native model reasoning content - #8924

Closed
ProgrammerPlus1998 wants to merge 1 commit into
agno-agi:mainfrom
ProgrammerPlus1998:fix/emit-reasoning-deltas-for-model-streaming
Closed

ProgrammerPlus1998 wants to merge 1 commit into
agno-agi:mainfrom
ProgrammerPlus1998:fix/emit-reasoning-deltas-for-model-streaming

Conversation

@ProgrammerPlus1998

Copy link
Copy Markdown
Contributor

Summary

Fixes #8400

When an OpenAI-compatible model (MiMo, DeepSeek, OpenAI o-series, Claude extended thinking, etc.) returns reasoning_content in streaming chunks, handle_model_response_chunk() accumulates it onto run_response.reasoning_content but only emits a generic RunContentEvent. Downstream consumers like AG-UI (/agui) never receive ReasoningContentDelta / REASONING_MESSAGE_CONTENT events, so the frontend cannot display the model's thinking process.

This fix adds a ReasoningContentDeltaEvent yield after the reasoning content accumulation, gated on stream_events=True. The per-chunk delta (not the accumulated value) is emitted, preserving correct streaming semantics.

Why this approach over #8418?

#8418 takes a heavier approach: it adds 3 state variables (reasoning_started, reasoning_content_streamed, reasoning_completed), modifies the RunContentEvent construction (strips reasoning_content when stream_events=True), and changes 3 functions. This PR:

  • 15 lines vs 77+ lines
  • No new state variables — relies on the existing reasoning_content is not None check
  • No change to RunContentEvent construction — zero regression risk for existing consumers
  • Emits the delta, not accumulated — each chunk carries just the new reasoning text

The AG-UI handler already correctly processes ReasoningContentDeltaEvent (merged in #7429), so no handler changes are needed.

Type of change

  • Bug fix
  • New feature
  • Breaking change
  • Improvement
  • Model update
  • Other:

Checklist

  • Code complies with style guidelines
  • Ran format/validation scripts (./scripts/format.sh and ./scripts/validate.sh)
  • Self-review completed
  • Documentation updated (comments, docstrings)
  • Examples and guides: Relevant cookbook examples have been included or updated (if applicable)
  • Tested in clean environment
  • Tests added/updated (if applicable)

Duplicate and AI-Generated PR Check

  • I have searched existing open pull requests and confirmed that no other PR already addresses this issue with this approach
  • If a similar PR exists, I have explained below why this PR is a better approach
  • This PR was developed with AI assistance (Hermes Agent / Claude). The author has reviewed and understands all changes.

Additional Notes

Testing: 2 new unit tests added to libs/agno/tests/unit/reasoning/test_reasoning_streaming.py:

  • test_handle_model_response_chunk_emits_reasoning_delta_when_streaming — verifies ReasoningContentDeltaEvent is yielded when stream_events=True
  • test_handle_model_response_chunk_no_reasoning_delta_when_not_streaming — verifies backward compat when stream_events=False

All 20 tests in the file pass.

…reaming

When a model (e.g. MiMo, DeepSeek, OpenAI o-series) returns reasoning_content
in streaming chunks, handle_model_response_chunk() now yields a
ReasoningContentDeltaEvent for each delta when stream_events=True.

Previously, reasoning_content was accumulated onto run_response but only
emitted as part of RunContentEvent, so downstream consumers like AG-UI never
received REASONING_* events for native model reasoning.

This is a minimal fix (15 lines) that:
- Does NOT change RunContentEvent construction (zero regression risk)
- Does NOT add state tracking variables
- Emits the per-chunk delta (not accumulated) for correct streaming semantics
- Preserves backward compat: stream_events=False behavior is unchanged

Fixes agno-agi#8400
@github-actions

Copy link
Copy Markdown
Contributor

PR Triage

Possible duplicate: The following open PRs also reference the same issue(s):

If this is intentional, please explain in your PR description why this approach is preferred. Otherwise, consider collaborating on the existing PR instead.


This PR has been automatically closed. There is already an open PR addressing this issue. If you believe your contribution is valuable, please comment on the original issue explaining your approach and why it might be preferred. A maintainer can reopen this PR if appropriate.

@github-actions github-actions Bot closed this Jul 14, 2026
@ProgrammerPlus1998

Copy link
Copy Markdown
Contributor Author

@github-actions[bot] This is NOT a duplicate of #8418. The approaches are fundamentally different:

#8418 (77 lines, 3 functions changed):

  • Adds 3 state variables (, , )
  • Modifies RunContentEvent construction — strips from the event when (regression risk for existing consumers)
  • Changes AND (sync + async)
  • Completion logic duplicated in two places

This PR (#8924, 15 lines, 1 function changed):

  • Zero new state variables
  • Does NOT change RunContentEvent construction — existing consumers are unaffected
  • Emits as an addition after the existing accumulation, gated on
  • Single insertion point, minimal footprint

Both fix #8400 but this approach is strictly less invasive. The AG-UI handler already processes correctly (merged in #7429), so no handler changes are needed here.

Please reopen this PR for maintainer review.

@ProgrammerPlus1998

Copy link
Copy Markdown
Contributor Author

Summary

Fixes #8400

Models that stream reasoning content from the main call (Claude w/ thinking, OpenAI o-series, Gemini thinking, MiMo) emit reasoning_content in streaming chunks. The agent accumulates this onto run_response.reasoning_content but only emits a generic RunContentEvent — downstream consumers like AG-UI never receive REASONING_* events, so the reasoning panel stays dark.

This PR emits ReasoningContentDeltaEvent for each reasoning delta when stream_events=True, and a ReasoningCompletedEvent at stream end. The complete lifecycle flows to AG-UI and other streaming consumers: REASONING_START → REASONING_MESSAGE_CONTENT → REASONING_END.

Changes (3 files, +46 lines)

Agent path (agent/_response.py):

  • Yield ReasoningContentDeltaEvent inside the reasoning_content accumulation block, gated on stream_events=True
  • Track native_reasoning_streamed flag in reasoning_state
  • Emit ReasoningCompletedEvent at stream end (both sync and async paths)

Team path (team/_response.py):

  • Mirror the agent fix using create_team_reasoning_content_delta_event

Tests (test_reasoning_streaming.py):

  • test_handle_model_response_chunk_emits_reasoning_content_delta — delta emitted when streaming
  • test_handle_model_response_chunk_skips_reasoning_event_when_not_streaming — backward compat

What this does NOT change

  • RunContentEvent construction is untouched — zero regression risk for existing consumers
  • stream_events=False behavior is identical to before
  • redacted_reasoning_content (Claude redacted_thinking blocks) is left untouched — AG-UI protocol has ReasoningEncryptedValueEvent for this, but agno doesn't implement it yet

Why not existing PRs?

PR Issue
#8418 Modifies RunContentEvent construction (strips reasoning when streaming) — regression risk, 77 lines
#8055 No ReasoningCompletedEvent at stream end
#8536, #8550, #8552 Miss team path

Type of change

  • Bug fix
  • New feature
  • Breaking change
  • Improvement
  • Model update
  • Other:

Checklist

  • Code complies with style guidelines
  • Ran format/validation scripts (./scripts/format.sh and ./scripts/validate.sh)
  • Self-review completed
  • Documentation updated (comments, docstrings)
  • Examples and guides: Relevant cookbook examples have been included or updated (if applicable)
  • Tested in clean environment
  • Tests added/updated (if applicable)

Duplicate and AI-Generated PR Check

  • I have searched existing open pull requests and confirmed that no other PR already addresses this issue with this approach
  • If a similar PR exists, I have explained below why this PR is a better approach
  • This PR was developed with AI assistance (Hermes Agent). The author has reviewed and understands all changes.

Additional Notes

Test results: 20/20 passed in test_reasoning_streaming.py.

How it works: The fix adds a ReasoningContentDeltaEvent yield inside the existing reasoning_content accumulation block in handle_model_response_chunk(). The per-chunk delta (not accumulated) is emitted, preserving correct streaming semantics. A native_reasoning_streamed flag tracks whether any native reasoning was streamed, and a ReasoningCompletedEvent is emitted at stream end to close the lifecycle.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] OpenAILike does not emit native reasoning events when streaming chunks include reasoning_content

1 participant