mirror of
https://github.com/microsoft/agent-framework.git
synced 2026-06-16 21:04:09 +08:00
[BREAKING] Python: Refactor workflow events to unified discriminated union pattern (#3690)
* Refactor events * Merge main * Fixes * Cleanup * Update samples and tests * Remove unused imports * PR feedback * Merge main. Add properties for events to help typing * Formatting * Cleanup * use builtins.type to avoid shadowing by WorkflowEvent.type attribute * Final improvements
This commit is contained in:
committed by
GitHub
Unverified
parent
09f59b21ad
commit
0f3f4dbcaf
@@ -7,7 +7,7 @@ the task in a round-robin fashion.
|
||||
|
||||
import asyncio
|
||||
|
||||
from agent_framework import AgentResponseUpdate, WorkflowOutputEvent
|
||||
from agent_framework import AgentResponseUpdate
|
||||
|
||||
|
||||
async def run_autogen() -> None:
|
||||
@@ -55,8 +55,8 @@ async def run_autogen() -> None:
|
||||
|
||||
async def run_agent_framework() -> None:
|
||||
"""Agent Framework's SequentialBuilder for sequential agent orchestration."""
|
||||
from agent_framework import SequentialBuilder
|
||||
from agent_framework.openai import OpenAIChatClient
|
||||
from agent_framework.orchestrations import SequentialBuilder
|
||||
|
||||
client = OpenAIChatClient(model_id="gpt-4.1-mini")
|
||||
|
||||
@@ -83,15 +83,14 @@ async def run_agent_framework() -> None:
|
||||
print("[Agent Framework] Sequential conversation:")
|
||||
current_executor = None
|
||||
async for event in workflow.run("Create a brief summary about electric vehicles", stream=True):
|
||||
if isinstance(event, WorkflowOutputEvent):
|
||||
if event.type == "output" 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:
|
||||
print() # Newline after previous agent's message
|
||||
print(f"---------- {event.executor_id} ----------")
|
||||
current_executor = event.executor_id
|
||||
if isinstance(event.data, AgentResponseUpdate):
|
||||
print(event.data.text, end="", flush=True)
|
||||
print(event.data.text, end="", flush=True)
|
||||
print() # Final newline after conversation
|
||||
|
||||
|
||||
@@ -100,9 +99,9 @@ async def run_agent_framework_with_cycle() -> None:
|
||||
from agent_framework import (
|
||||
AgentExecutorRequest,
|
||||
AgentExecutorResponse,
|
||||
AgentResponseUpdate,
|
||||
WorkflowBuilder,
|
||||
WorkflowContext,
|
||||
WorkflowOutputEvent,
|
||||
executor,
|
||||
)
|
||||
from agent_framework.openai import OpenAIChatClient
|
||||
@@ -154,7 +153,10 @@ async def run_agent_framework_with_cycle() -> None:
|
||||
print("[Agent Framework with Cycle] Cyclic conversation:")
|
||||
current_executor = None
|
||||
async for event in workflow.run("Create a brief summary about electric vehicles", stream=True):
|
||||
if isinstance(event, WorkflowOutputEvent) and isinstance(event.data, AgentResponseUpdate):
|
||||
if event.type == "output" and not isinstance(event.data, AgentResponseUpdate):
|
||||
print("\n---------- Workflow Output ----------")
|
||||
print(event.data)
|
||||
elif event.type == "output" 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,7 +7,7 @@ which agent should speak next based on the conversation context.
|
||||
|
||||
import asyncio
|
||||
|
||||
from agent_framework import AgentResponseUpdate, WorkflowOutputEvent
|
||||
from agent_framework import AgentResponseUpdate
|
||||
|
||||
|
||||
async def run_autogen() -> None:
|
||||
@@ -61,8 +61,8 @@ async def run_autogen() -> None:
|
||||
|
||||
async def run_agent_framework() -> None:
|
||||
"""Agent Framework's GroupChatBuilder with LLM-based speaker selection."""
|
||||
from agent_framework import GroupChatBuilder
|
||||
from agent_framework.openai import OpenAIChatClient
|
||||
from agent_framework.orchestrations import GroupChatBuilder
|
||||
|
||||
client = OpenAIChatClient(model_id="gpt-4.1-mini")
|
||||
|
||||
@@ -102,7 +102,7 @@ async def run_agent_framework() -> None:
|
||||
print("[Agent Framework] Group chat conversation:")
|
||||
current_executor = None
|
||||
async for event in workflow.run("How do I connect to a PostgreSQL database using Python?", stream=True):
|
||||
if isinstance(event, WorkflowOutputEvent) and isinstance(event.data, AgentResponseUpdate):
|
||||
if event.type == "output" 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,7 +7,8 @@ to other specialized agents based on the task requirements.
|
||||
|
||||
import asyncio
|
||||
|
||||
from agent_framework import AgentResponseUpdate, HandoffAgentUserRequest, WorkflowOutputEvent
|
||||
from agent_framework import WorkflowEvent
|
||||
from orderedmultidict import Any
|
||||
|
||||
|
||||
async def run_autogen() -> None:
|
||||
@@ -98,12 +99,11 @@ async def run_autogen() -> None:
|
||||
async def run_agent_framework() -> None:
|
||||
"""Agent Framework's HandoffBuilder for agent coordination."""
|
||||
from agent_framework import (
|
||||
HandoffBuilder,
|
||||
RequestInfoEvent,
|
||||
AgentResponseUpdate,
|
||||
WorkflowRunState,
|
||||
WorkflowStatusEvent,
|
||||
)
|
||||
from agent_framework.openai import OpenAIChatClient
|
||||
from agent_framework.orchestrations import HandoffAgentUserRequest, HandoffBuilder
|
||||
|
||||
client = OpenAIChatClient(model_id="gpt-4.1-mini")
|
||||
|
||||
@@ -159,10 +159,10 @@ async def run_agent_framework() -> None:
|
||||
|
||||
current_executor = None
|
||||
stream_line_open = False
|
||||
pending_requests: list[RequestInfoEvent] = []
|
||||
pending_requests: list[WorkflowEvent] = []
|
||||
|
||||
async for event in workflow.run(scripted_responses[0], stream=True):
|
||||
if isinstance(event, WorkflowOutputEvent) and isinstance(event.data, AgentResponseUpdate):
|
||||
if event.type == "output" 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:
|
||||
@@ -173,10 +173,10 @@ async def run_agent_framework() -> None:
|
||||
stream_line_open = True
|
||||
if event.data:
|
||||
print(event.data.text, end="", flush=True)
|
||||
elif isinstance(event, RequestInfoEvent):
|
||||
elif event.type == "request_info":
|
||||
if isinstance(event.data, HandoffAgentUserRequest):
|
||||
pending_requests.append(event)
|
||||
elif isinstance(event, WorkflowStatusEvent):
|
||||
elif event.type == "status":
|
||||
if event.state in {WorkflowRunState.IDLE_WITH_PENDING_REQUESTS} and stream_line_open:
|
||||
print()
|
||||
stream_line_open = False
|
||||
@@ -188,13 +188,13 @@ async def run_agent_framework() -> None:
|
||||
print("---------- user ----------")
|
||||
print(user_response)
|
||||
|
||||
responses = {req.request_id: user_response for req in pending_requests}
|
||||
responses: dict[str, Any] = {req.request_id: user_response for req in pending_requests} # type: ignore
|
||||
pending_requests = []
|
||||
current_executor = None
|
||||
stream_line_open = False
|
||||
|
||||
async for event in workflow.send_responses_streaming(responses):
|
||||
if isinstance(event, WorkflowOutputEvent) and isinstance(event.data, AgentResponseUpdate):
|
||||
if event.type == "output" 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:
|
||||
@@ -205,10 +205,10 @@ async def run_agent_framework() -> None:
|
||||
stream_line_open = True
|
||||
if event.data:
|
||||
print(event.data.text, end="", flush=True)
|
||||
elif isinstance(event, RequestInfoEvent):
|
||||
elif event.type == "request_info":
|
||||
if isinstance(event.data, HandoffAgentUserRequest):
|
||||
pending_requests.append(event)
|
||||
elif isinstance(event, WorkflowStatusEvent):
|
||||
elif event.type == "status":
|
||||
if (
|
||||
event.state in {WorkflowRunState.IDLE_WITH_PENDING_REQUESTS, WorkflowRunState.IDLE}
|
||||
and stream_line_open
|
||||
|
||||
@@ -12,10 +12,9 @@ from typing import cast
|
||||
from agent_framework import (
|
||||
AgentResponseUpdate,
|
||||
ChatMessage,
|
||||
MagenticOrchestratorEvent,
|
||||
MagenticProgressLedger,
|
||||
WorkflowOutputEvent,
|
||||
WorkflowEvent,
|
||||
)
|
||||
from agent_framework.orchestrations import MagenticProgressLedger
|
||||
|
||||
|
||||
async def run_autogen() -> None:
|
||||
@@ -67,8 +66,8 @@ async def run_autogen() -> None:
|
||||
|
||||
async def run_agent_framework() -> None:
|
||||
"""Agent Framework's MagenticBuilder for orchestrated collaboration."""
|
||||
from agent_framework import MagenticBuilder
|
||||
from agent_framework.openai import OpenAIChatClient
|
||||
from agent_framework.orchestrations import MagenticBuilder
|
||||
|
||||
client = OpenAIChatClient(model_id="gpt-4.1-mini")
|
||||
|
||||
@@ -110,10 +109,10 @@ async def run_agent_framework() -> None:
|
||||
|
||||
# Run complex task
|
||||
last_message_id: str | None = None
|
||||
output_event: WorkflowOutputEvent | None = None
|
||||
output_event: WorkflowEvent | None = None
|
||||
print("[Agent Framework] Magentic conversation:")
|
||||
async for event in workflow.run("Research Python async patterns and write a simple example", stream=True):
|
||||
if isinstance(event, WorkflowOutputEvent) and isinstance(event.data, AgentResponseUpdate):
|
||||
if event.type == "output" and isinstance(event.data, AgentResponseUpdate):
|
||||
message_id = event.data.message_id
|
||||
if message_id != last_message_id:
|
||||
if last_message_id is not None:
|
||||
@@ -122,21 +121,21 @@ async def run_agent_framework() -> None:
|
||||
last_message_id = message_id
|
||||
print(event.data, end="", flush=True)
|
||||
|
||||
elif isinstance(event, MagenticOrchestratorEvent):
|
||||
print(f"\n[Magentic Orchestrator Event] Type: {event.event_type.name}")
|
||||
if isinstance(event.data, ChatMessage):
|
||||
print(f"Please review the plan:\n{event.data.text}")
|
||||
elif isinstance(event.data, MagenticProgressLedger):
|
||||
print(f"Please review progress ledger:\n{json.dumps(event.data.to_dict(), indent=2)}")
|
||||
elif event.type == "magentic_orchestrator":
|
||||
print(f"\n[Magentic Orchestrator Event] Type: {event.data.event_type.name}")
|
||||
if isinstance(event.data.content, ChatMessage):
|
||||
print(f"Please review the plan:\n{event.data.content.text}")
|
||||
elif isinstance(event.data.content, MagenticProgressLedger):
|
||||
print(f"Please review progress ledger:\n{json.dumps(event.data.content.to_dict(), indent=2)}")
|
||||
else:
|
||||
print(f"Unknown data type in MagenticOrchestratorEvent: {type(event.data)}")
|
||||
print(f"Unknown data type in MagenticOrchestratorEvent: {type(event.data.content)}")
|
||||
|
||||
# Block to allow user to read the plan/progress before continuing
|
||||
# Note: this is for demonstration only and is not the recommended way to handle human interaction.
|
||||
# Please refer to `with_plan_review` for proper human interaction during planning phases.
|
||||
await asyncio.get_event_loop().run_in_executor(None, input, "Press Enter to continue...")
|
||||
|
||||
elif isinstance(event, WorkflowOutputEvent):
|
||||
elif event.type == "output":
|
||||
output_event = event
|
||||
|
||||
if not output_event:
|
||||
|
||||
Reference in New Issue
Block a user