Skip to content

Commit d28ad2d

Browse files
authored
Track agent name with updates for workflow agent (#3146)
1 parent 88968da commit d28ad2d

File tree

2 files changed

+81
-0
lines changed

2 files changed

+81
-0
lines changed

python/packages/core/agent_framework/_workflows/_agent.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,9 @@ def _convert_workflow_event_to_agent_update(
309309
if isinstance(executor, AgentExecutor) and not executor.output_response:
310310
return None
311311
if update:
312+
# Enrich with executor identity if author_name is not already set
313+
if not update.author_name:
314+
update.author_name = executor_id
312315
return update
313316
return None
314317

python/packages/core/tests/workflow/test_workflow_agent.py

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -702,6 +702,84 @@ async def start_executor(messages: list[ChatMessage], ctx: WorkflowContext) -> N
702702
assert unique_text_count == 1, f"Response should appear exactly once, but appeared {unique_text_count} times"
703703

704704

705+
class TestWorkflowAgentAuthorName:
706+
"""Test cases for author_name enrichment in WorkflowAgent (GitHub issue #1331)."""
707+
708+
async def test_agent_run_update_event_gets_executor_id_as_author_name(self):
709+
"""Test that AgentRunUpdateEvent gets executor_id as author_name when not already set.
710+
711+
This validates the fix for GitHub issue #1331: agent responses should include
712+
identification of which agent produced them in multi-agent workflows.
713+
"""
714+
# Create workflow with executor that emits AgentRunUpdateEvent without author_name
715+
executor1 = SimpleExecutor(id="my_executor_id", response_text="Response", emit_streaming=False)
716+
workflow = WorkflowBuilder().set_start_executor(executor1).build()
717+
agent = WorkflowAgent(workflow=workflow, name="Test Agent")
718+
719+
# Collect streaming updates
720+
updates: list[AgentRunResponseUpdate] = []
721+
async for update in agent.run_stream("Hello"):
722+
updates.append(update)
723+
724+
# Verify at least one update was received
725+
assert len(updates) >= 1
726+
727+
# Verify author_name is set to executor_id
728+
assert updates[0].author_name == "my_executor_id"
729+
730+
async def test_agent_run_update_event_preserves_existing_author_name(self):
731+
"""Test that existing author_name is preserved and not overwritten."""
732+
733+
class AuthorNameExecutor(Executor):
734+
"""Executor that sets author_name explicitly."""
735+
736+
@handler
737+
async def handle_message(self, message: list[ChatMessage], ctx: WorkflowContext[list[ChatMessage]]) -> None:
738+
# Emit update with explicit author_name
739+
update = AgentRunResponseUpdate(
740+
contents=[TextContent(text="Response with author")],
741+
role=Role.ASSISTANT,
742+
author_name="custom_author_name", # Explicitly set
743+
message_id=str(uuid.uuid4()),
744+
)
745+
await ctx.add_event(AgentRunUpdateEvent(executor_id=self.id, data=update))
746+
747+
executor = AuthorNameExecutor(id="executor_id")
748+
workflow = WorkflowBuilder().set_start_executor(executor).build()
749+
agent = WorkflowAgent(workflow=workflow, name="Test Agent")
750+
751+
# Collect streaming updates
752+
updates: list[AgentRunResponseUpdate] = []
753+
async for update in agent.run_stream("Hello"):
754+
updates.append(update)
755+
756+
# Verify author_name is preserved (not overwritten with executor_id)
757+
assert len(updates) >= 1
758+
assert updates[0].author_name == "custom_author_name"
759+
760+
async def test_multiple_executors_have_distinct_author_names(self):
761+
"""Test that multiple executors in a workflow have their own author_name."""
762+
# Create workflow with two executors
763+
executor1 = SimpleExecutor(id="first_executor", response_text="First", emit_streaming=False)
764+
executor2 = SimpleExecutor(id="second_executor", response_text="Second", emit_streaming=False)
765+
766+
workflow = WorkflowBuilder().set_start_executor(executor1).add_edge(executor1, executor2).build()
767+
agent = WorkflowAgent(workflow=workflow, name="Multi-Executor Agent")
768+
769+
# Collect streaming updates
770+
updates: list[AgentRunResponseUpdate] = []
771+
async for update in agent.run_stream("Hello"):
772+
updates.append(update)
773+
774+
# Should have updates from both executors
775+
assert len(updates) >= 2
776+
777+
# Verify each update has the correct author_name matching its executor
778+
author_names = [u.author_name for u in updates]
779+
assert "first_executor" in author_names
780+
assert "second_executor" in author_names
781+
782+
705783
class TestWorkflowAgentMergeUpdates:
706784
"""Test cases specifically for the WorkflowAgent.merge_updates static method."""
707785

0 commit comments

Comments
 (0)