Repository navigation
Python: fix(core): start a new message when the author changes in streamed updates - #9353
Conversation
There was a problem hiding this comment.
🟢 Approval recommended
The focused implementation matches the documented behavior and includes comprehensive regression coverage.
0 open findings
What changed in this PR
Fixes streamed multi-agent updates being merged across author changes.
Changes:
- Splits messages when non-empty author names differ.
- Adds regression coverage for author transitions and shared message IDs.
| File | Description |
|---|---|
python/packages/core/agent_framework/_types.py |
Detects author changes during update aggregation. |
python/packages/core/tests/core/test_types.py |
Tests author-based message boundaries and edge cases. |
🧠 Review effort: Balanced
💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.
Bicheng (Kenneth) (BichengWang)
left a comment
There was a problem hiding this comment.
Reviewed head 76f3dcb21543302a5727f766b56e7df43f11e0d0 against base 1b9879c58ac950ef235471209b4c5cb402972bab.
I checked the existing review and exercised the public workflow path with two deterministic agents through SequentialBuilder(..., output_from="all").build().as_agent(). On the base, get_final_response() combines both replies into one message attributed to the reviewer; on this head it matches the non-streaming writer/reviewer messages, including a continuation chunk without an author.
I also checked function-call fragments: an authorless continuation still completes the first author's arguments, while a second author using the same call ID starts a separate call. The base concatenates the two argument objects into invalid JSON; this head keeps {"a":1} and {"b":2} in their respective messages. Usage-only updates from the current author retain the aggregated token counts and response ID without adding a message. This supports placing the boundary check before content merging.
Please consider adding the public sequential-workflow case as a regression test alongside the direct aggregation tests: it also covers the workflow adapter's author propagation and stream finalizer.
Offline validation on macOS arm64/Python 3.14.7: test_types.py, test_sequential.py, test_workflow_agent.py, and test_workflow_agent_intermediate.py passed (528 tests; one experimental-feature warning). Ruff 0.16.10 lint and format checks passed on both changed files. The full workspace, provider integrations, and type-checker suites were not run. I found no correctness blocker in the behavior exercised here.
|
Bicheng (Kenneth) (@BichengWang) Thanks for the thorough check. Added the public sequential-workflow streaming case as a regression test in 877a792 (test_sequential_as_agent_streaming_keeps_one_message_per_agent); it fails on the base and passes here. |
Motivation & Context
_process_update, which combines streamed updates into messages forChatResponse.from_updates,AgentResponse.from_updatesandget_final_response(), started a new message only when the role or a non-emptymessage_idchanged. Most chat clients do not setmessage_idon streaming updates, so updates from different authors were merged into one message attributed to the last author. A streamed sequential workflow agent returned one "reviewer" message with the writer's text in it, while the same non-streamed run returned two messages.Description & Review Guide
_process_updatealso starts a new message when both the update and the last message have a non-emptyauthor_nameand they differ, the same pattern as themessage_idcheck next to it. Regression tests: two authors give two messages (forChatResponseandAgentResponse), a chunk without an author stays in the current message, a message without an author takes the author of a later chunk instead of splitting, interleaved authors keep each run of updates with its author, and two authors that share amessage_idgive two messages. An orchestrations test streamsSequentialBuilder(..., output_from="all").build().as_agent()and checks thatget_final_response()returns one message per agent, the same as the non-streaming run.author_name, do not change. All package tests pass (poe test -A).author_nameon the first chunk only, or a message that gets its author from a later chunk, still forms one message. Two intended behavior changes: interleaved updates from parallel agents (for example a streamed concurrent workflow) now give one message per run of updates from the same author instead of one merged message attributed to the last author, and two authors that share amessage_idnow give two messages with that id instead of one.Related Issue
Fixes #9352
No other open PR covers this issue.
AI Assistance
AI assistance details: issue analysis, implementation, tests, and this PR description.
Contribution Checklist
breaking changelabel (or add "[BREAKING]" to the title prefix, before or after any language prefix) — a workflow keeps the label and title prefix in sync automatically.