[BREAKING] Python: Fix workflow as agent streaming output (#3649)

* WIP: with_output_from

* Add with_output_from to other modules; next: workflow as agent

* WIP: remove agent run events

* orchestrations

* WIP: update samples; next start at guessing_game_With_human_input.py

* Update all samples

* WIP: consolidate workflow as agent streaming vs non-streaming

* Consolidate workflow as agent streaming vs non-streaming

* Move request info event processing to a share method

* Final pass on the samples

* Fix mypy

* Fix mypy

* Comments

---------

Co-authored-by: Evan Mattson <35585003+moonbox3@users.noreply.github.com>
This commit is contained in:
Tao Chen
2026-02-04 16:16:45 -08:00
committed by GitHub
Unverified
parent 907654a489
commit a971d24f1e
68 changed files with 2652 additions and 2247 deletions
@@ -7,6 +7,8 @@ the task in a round-robin fashion.
import asyncio
from agent_framework import AgentResponseUpdate, WorkflowOutputEvent
async def run_autogen() -> None:
"""AutoGen's RoundRobinGroupChat for sequential agent orchestration."""
@@ -53,7 +55,7 @@ async def run_autogen() -> None:
async def run_agent_framework() -> None:
"""Agent Framework's SequentialBuilder for sequential agent orchestration."""
from agent_framework import AgentRunUpdateEvent, SequentialBuilder
from agent_framework import SequentialBuilder
from agent_framework.openai import OpenAIChatClient
client = OpenAIChatClient(model_id="gpt-4.1-mini")
@@ -81,14 +83,14 @@ async def run_agent_framework() -> None:
print("[Agent Framework] Sequential conversation:")
current_executor = None
async for event in workflow.run_stream("Create a brief summary about electric vehicles"):
if isinstance(event, AgentRunUpdateEvent):
if isinstance(event, WorkflowOutputEvent):
# Print executor name header when switching to a new agent
if current_executor != event.executor_id:
if current_executor is not None:
print() # Newline after previous agent's message
print(f"---------- {event.executor_id} ----------")
current_executor = event.executor_id
if event.data:
if isinstance(event.data, AgentResponseUpdate):
print(event.data.text, end="", flush=True)
print() # Final newline after conversation
@@ -98,7 +100,6 @@ async def run_agent_framework_with_cycle() -> None:
from agent_framework import (
AgentExecutorRequest,
AgentExecutorResponse,
AgentRunUpdateEvent,
WorkflowBuilder,
WorkflowContext,
WorkflowOutputEvent,
@@ -153,10 +154,7 @@ async def run_agent_framework_with_cycle() -> None:
print("[Agent Framework with Cycle] Cyclic conversation:")
current_executor = None
async for event in workflow.run_stream("Create a brief summary about electric vehicles"):
if isinstance(event, WorkflowOutputEvent):
print("\n---------- Workflow Output ----------")
print(event.data)
elif isinstance(event, AgentRunUpdateEvent):
if isinstance(event, WorkflowOutputEvent) and isinstance(event.data, AgentResponseUpdate):
# Print executor name header when switching to a new agent
if current_executor != event.executor_id:
if current_executor is not None:
@@ -7,6 +7,8 @@ which agent should speak next based on the conversation context.
import asyncio
from agent_framework import AgentResponseUpdate, WorkflowOutputEvent
async def run_autogen() -> None:
"""AutoGen's SelectorGroupChat with LLM-based speaker selection."""
@@ -59,7 +61,7 @@ async def run_autogen() -> None:
async def run_agent_framework() -> None:
"""Agent Framework's GroupChatBuilder with LLM-based speaker selection."""
from agent_framework import AgentRunUpdateEvent, GroupChatBuilder
from agent_framework import GroupChatBuilder
from agent_framework.openai import OpenAIChatClient
client = OpenAIChatClient(model_id="gpt-4.1-mini")
@@ -100,7 +102,7 @@ async def run_agent_framework() -> None:
print("[Agent Framework] Group chat conversation:")
current_executor = None
async for event in workflow.run_stream("How do I connect to a PostgreSQL database using Python?"):
if isinstance(event, AgentRunUpdateEvent):
if isinstance(event, WorkflowOutputEvent) and isinstance(event.data, AgentResponseUpdate):
# Print executor name header when switching to a new agent
if current_executor != event.executor_id:
if current_executor is not None:
@@ -7,6 +7,8 @@ to other specialized agents based on the task requirements.
import asyncio
from agent_framework import AgentResponseUpdate, HandoffAgentUserRequest, WorkflowOutputEvent
async def run_autogen() -> None:
"""AutoGen's Swarm pattern with human-in-the-loop handoffs."""
@@ -96,9 +98,7 @@ async def run_autogen() -> None:
async def run_agent_framework() -> None:
"""Agent Framework's HandoffBuilder for agent coordination."""
from agent_framework import (
AgentRunUpdateEvent,
HandoffBuilder,
HandoffUserInputRequest,
RequestInfoEvent,
WorkflowRunState,
WorkflowStatusEvent,
@@ -139,7 +139,7 @@ async def run_agent_framework() -> None:
name="support_handoff",
participants=[triage_agent, billing_agent, tech_support],
)
.set_coordinator(triage_agent)
.with_start_agent(triage_agent)
.add_handoff(triage_agent, [billing_agent, tech_support])
.with_termination_condition(lambda conv: sum(1 for msg in conv if msg.role == "user") > 3)
.build()
@@ -162,7 +162,7 @@ async def run_agent_framework() -> None:
pending_requests: list[RequestInfoEvent] = []
async for event in workflow.run_stream(scripted_responses[0]):
if isinstance(event, AgentRunUpdateEvent):
if isinstance(event, WorkflowOutputEvent) and isinstance(event.data, AgentResponseUpdate):
# Print executor name header when switching to a new agent
if current_executor != event.executor_id:
if stream_line_open:
@@ -174,7 +174,7 @@ async def run_agent_framework() -> None:
if event.data:
print(event.data.text, end="", flush=True)
elif isinstance(event, RequestInfoEvent):
if isinstance(event.data, HandoffUserInputRequest):
if isinstance(event.data, HandoffAgentUserRequest):
pending_requests.append(event)
elif isinstance(event, WorkflowStatusEvent):
if event.state in {WorkflowRunState.IDLE_WITH_PENDING_REQUESTS} and stream_line_open:
@@ -194,7 +194,7 @@ async def run_agent_framework() -> None:
stream_line_open = False
async for event in workflow.send_responses_streaming(responses):
if isinstance(event, AgentRunUpdateEvent):
if isinstance(event, WorkflowOutputEvent) and isinstance(event.data, AgentResponseUpdate):
# Print executor name header when switching to a new agent
if current_executor != event.executor_id:
if stream_line_open:
@@ -206,7 +206,7 @@ async def run_agent_framework() -> None:
if event.data:
print(event.data.text, end="", flush=True)
elif isinstance(event, RequestInfoEvent):
if isinstance(event.data, HandoffUserInputRequest):
if isinstance(event.data, HandoffAgentUserRequest):
pending_requests.append(event)
elif isinstance(event, WorkflowStatusEvent):
if (
@@ -10,7 +10,7 @@ import json
from typing import cast
from agent_framework import (
AgentRunUpdateEvent,
AgentResponseUpdate,
ChatMessage,
MagenticOrchestratorEvent,
MagenticProgressLedger,
@@ -113,7 +113,7 @@ async def run_agent_framework() -> None:
output_event: WorkflowOutputEvent | None = None
print("[Agent Framework] Magentic conversation:")
async for event in workflow.run_stream("Research Python async patterns and write a simple example"):
if isinstance(event, AgentRunUpdateEvent):
if isinstance(event, WorkflowOutputEvent) and isinstance(event.data, AgentResponseUpdate):
message_id = event.data.message_id
if message_id != last_message_id:
if last_message_id is not None: