Skip to content

Python: fix: surface AG-UI workflow intermediate events as reasoning - #8003

Merged
Evan Mattson (moonbox3) merged 3 commits into
microsoft:mainfrom
manjunathshiva:python-agui-intermediate-reasoning-8000
Sep 4, 2026
Merged

Python: fix: surface AG-UI workflow intermediate events as reasoning#8003
Evan Mattson (moonbox3) merged 3 commits into
microsoft:mainfrom
manjunathshiva:python-agui-intermediate-reasoning-8000

Conversation

@manjunathshiva

Copy link
Copy Markdown
Contributor

Motivation & Context

The AG-UI workflow runner only processed output and data workflow events, so intermediate events — the modern designation produced by executors listed under intermediate_output_from — fell through to the generic CustomEvent fallback (_workflow_run.py, the if event_type in {"output", "data"} branch). As a result, intermediate workflow output was emitted as CustomEvent(name="intermediate") instead of AG-UI reasoning events, so consumers (CopilotKit, assistant-ui, …) could not render it as a collapsible "thinking" block.

AGENT_FORWARDED_EVENT_TYPES in _workflows/_events.py already lists output, intermediate, and data (the deprecated alias for intermediate), so the AG-UI layer was silently dropping a forwarded event type into the diagnostics fallback.

Description & Review Guide

  • What are the major changes?

    • Add "intermediate" to the handled event set in run_workflow_stream so intermediate events are no longer routed to the generic CustomEvent fallback.
    • Route intermediate text content through a new _as_reasoning_content() helper that re-tags it as text_reasoning, so it emits via the existing _emit_text_reasoning path (REASONING_* events). Non-text content (tool calls/results, etc.) passes through unchanged and still emits as its native AG-UI events.
    • The deprecated "data" alias is handled identically to "intermediate", matching its definition in _events.py as the intermediate compatibility alias.
    • "output" keeps the existing terminal-message behavior, including the last_assistant_text de-duplication (reasoning is a separate channel, so that de-dup does not apply to intermediate output).
    • This is the AG-UI-layer fix (Option B in the issue). It deliberately does not touch WorkflowAgent._convert_workflow_event_to_agent_response_updates() (Option A), which is being addressed under Python: [Bug]: WorkflowAgent drops response metadata when forwarding AgentResponseUpdate #7952.
  • What is the impact of these changes?

    • Intermediate workflow output now renders as reasoning in AG-UI clients instead of a generic custom event.
    • Behavior note for reviewers: the deprecated type="data" alias previously rendered as a final assistant message; it now renders as reasoning, aligning the deprecated path with its intermediate replacement. If you would prefer to keep data → final message for strict backward-compat, that is a one-line change (drop "data" from is_intermediate) plus removing the alias test — happy to adjust either way.
  • What do you want reviewers to focus on?

    • The data-alias rendering decision above.

Related Issue

Fixes #8000

Contribution Checklist

  • The code builds clean without any errors or warnings
  • All unit tests pass, and I have added new tests where possible
  • The PR follows the Contribution Guidelines
  • This PR is linked to an issue and there is no other open PR for this issue (see Related Issue above).
  • This is not a breaking change. If it is a breaking change, add the breaking change label (or add "[BREAKING]" to the title prefix, before or after any language prefix) — a workflow keeps the label and title prefix in sync automatically.

The AG-UI workflow runner only handled "output" and "data" workflow
events, so "intermediate" events (the modern designation produced by
executors listed under intermediate_output_from) fell through to the
generic CustomEvent fallback instead of being converted to AG-UI
reasoning events.

Add "intermediate" to the handled set and route intermediate text
content to text_reasoning so consumers render it as a collapsible
"thinking" block rather than a final assistant message. The deprecated
"data" alias is treated the same as "intermediate" (per its definition
as the intermediate compatibility alias in _events.py). "output" keeps
the terminal-message behavior, and non-text content (tool calls and
results) still emits as its native AG-UI events.

Fixes microsoft#8000

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

Reasoning conversion currently drops encrypted protected_data metadata.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

Routes intermediate workflow text through AG-UI’s reasoning pipeline.

Changes:

  • Handles intermediate and deprecated data events as reasoning.
  • Adds regression tests for intermediate and terminal output behavior.
File summaries
File Description
_workflow_run.py Converts intermediate text into reasoning content.
test_workflow_run.py Tests intermediate and deprecated alias routing.
Review details
  • Files reviewed: 2/2 changed files
  • Comments generated: 1
  • Review effort level: Balanced

💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.

Comment thread python/packages/ag-ui/agent_framework_ag_ui/_workflow_run.py
Comment thread python/packages/ag-ui/agent_framework_ag_ui/_workflow_run.py
Comment thread python/packages/ag-ui/agent_framework_ag_ui/_workflow_run.py
Comment thread python/packages/ag-ui/agent_framework_ag_ui/_workflow_run.py
Follow-up to the intermediate-reasoning change on this branch, addressing
maintainer review:

- Preserve protected_data when re-tagging intermediate text as reasoning so
  the ReasoningEncryptedValueEvent and the snapshot encryptedValue survive.
- Close any open reasoning block (and assistant text message) before every
  terminal event (RUN_FINISHED / RUN_ERROR) and before a request_info tool
  call, via an idempotent _drain_open_blocks() helper. Previously the
  post-loop cleanup emitted the reasoning end events after the terminal
  event, so a client that stopped at RUN_FINISHED never saw them; a
  request_info tool call could likewise sit inside an unclosed reasoning
  block.
- Keep role-less AgentResponseUpdate text (and tool content) instead of
  dropping it to a CUSTOM workflow_output. Explicit non-assistant roles and
  approval requests stay excluded.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

python Usage: [Issues, PRs], Target: Python

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Python: [Bug]: AG-UI workflow runner ignores "intermediate" events

3 participants