Skip to content

Python: preserve AgentResponse metadata in WorkflowAgent streaming - #8464

Merged
Eduard van Valkenburg (eavanvalkenburg) merged 2 commits into
microsoft:mainfrom
ryo-whaletech:fix/workflow-agent-response-metadata
Sep 21, 2026
Merged

Eduard van Valkenburg (eavanvalkenburg) merged 2 commits into
microsoft:mainfrom
ryo-whaletech:fix/workflow-agent-response-metadata

Conversation

@ryo-whaletech

Copy link
Copy Markdown
Contributor

Motivation & Context

WorkflowAgent converts an AgentResponse emitted by a workflow into streaming AgentResponseUpdate objects. The message content is preserved, but response-level metadata is currently dropped during that conversion.

This is the AgentResponse sibling of the metadata-forwarding behavior fixed in #7999, which also identified this branch as possible follow-up scope.

Description & Review Guide

  • What are the major changes?

    • Preserve agent_id, finish_reason, continuation_token, and additional_properties from a message-bearing AgentResponse on the final generated update.
    • Add deterministic two-message regression coverage through the public WorkflowBuilderas_agent() → streaming run() path.
  • What is the impact of these changes?

    • This additively preserves metadata without changing message conversion, message ordering, stream cardinality, other converter branches, non-streaming behavior, or public APIs.
  • What do you want reviewers to focus on?

    • For an AgentResponse containing multiple messages, this change places response-level metadata on the final generated update. Please confirm that this matches the intended streaming projection semantics.

Related Issue

Fixes #8463

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.

Copilot AI balanced review requested due to automatic review settings September 17, 2026 13:15
@agent-framework-automation agent-framework-automation Bot added the python Usage: [Issues, PRs], Target: Python label Sep 17, 2026

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.

🟢 Approval recommended

The focused implementation preserves metadata without changing update cardinality or ordering and is adequately covered.

Pull request overview

Preserves AgentResponse metadata when workflows emit streaming updates.

Changes:

  • Attaches response metadata to the final generated update.
  • Adds two-message regression coverage through the public streaming API.
File summaries
File Description
python/packages/core/agent_framework/_workflows/_agent.py Forwards response-level metadata.
python/packages/core/tests/workflow/test_workflow_agent.py Verifies metadata and ordering.
Review details
  • Files reviewed: 2/2 changed files
  • Comments generated: 0
  • Review effort level: Balanced

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

@he-yufeng

Copy link
Copy Markdown
Contributor

One residual gap downstream of this conversion, verified against your branch direction: agent_id still does not survive stream-to-final aggregation, even with the metadata stamped on the last update.

_process_update in agent_framework/_types.py (the tail at 2099-2112) promotes finish_reason and continuation_token from update to response, and additional_properties merges a few lines earlier, but nothing ever copies update.agent_id into response.agent_id. Empirically, running the #8463 reproducer through as_agent(...).run(stream=True) with this conversion in place gives update.agent_id == "source-agent" on the stream while stream.get_final_response().agent_id is None — the other three fields arrive intact.

The one-line fix mirrors the finish_reason guard right below it: if update.agent_id is not None: response.agent_id = update.agent_id (guarded, so a metadata-less trailing update does not clobber a value an earlier update set). Might be worth folding into this PR so the #8463 contract holds end to end rather than only at the update level.

@moonbox3

Copy link
Copy Markdown
Contributor

One residual gap downstream of this conversion, verified against your branch direction: agent_id still does not survive stream-to-final aggregation, even with the metadata stamped on the last update.

_process_update in agent_framework/_types.py (the tail at 2099-2112) promotes finish_reason and continuation_token from update to response, and additional_properties merges a few lines earlier, but nothing ever copies update.agent_id into response.agent_id. Empirically, running the #8463 reproducer through as_agent(...).run(stream=True) with this conversion in place gives update.agent_id == "source-agent" on the stream while stream.get_final_response().agent_id is None — the other three fields arrive intact.

The one-line fix mirrors the finish_reason guard right below it: if update.agent_id is not None: response.agent_id = update.agent_id (guarded, so a metadata-less trailing update does not clobber a value an earlier update set). Might be worth folding into this PR so the #8463 contract holds end to end rather than only at the update level.

could you have a look at this WhaleTech (@ryo-whaletech) ?

@ryo-whaletech

Copy link
Copy Markdown
Contributor Author

Thanks for catching this. I reproduced the gap through get_final_response() and confirmed that agent_id was the only one of the four fields not propagated during stream-to-final aggregation.

I added regression coverage for the end-to-end path as well as the aggregation behavior, then applied the guarded propagation so a trailing update with agent_id=None does not erase an earlier value. The related core and workflow-agent tests pass locally.

Merged via the queue into microsoft:main with commit 2d85a90 Sep 21, 2026
42 checks passed
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]: WorkflowAgent drops response metadata when streaming an AgentResponse output

5 participants