[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:
Evan Mattson
2026-02-06 16:47:20 +09:00
committed by GitHub
Unverified
parent 09f59b21ad
commit 0f3f4dbcaf
127 changed files with 1646 additions and 1703 deletions
@@ -7,15 +7,12 @@ from agent_framework import (
AgentResponse,
ChatAgent,
ChatMessage,
RequestInfoEvent,
WorkflowEvent,
WorkflowOutputEvent,
WorkflowRunState,
WorkflowStatusEvent,
tool,
)
from agent_framework.azure import AzureOpenAIChatClient
from agent_framework.orchestrations import HandoffAgentUserRequest, HandoffBuilder, HandoffSentEvent
from agent_framework.orchestrations import HandoffAgentUserRequest, HandoffBuilder
from azure.identity import AzureCliCredential
"""Sample: Simple handoff workflow.
@@ -102,35 +99,35 @@ def create_agents(chat_client: AzureOpenAIChatClient) -> tuple[ChatAgent, ChatAg
return triage_agent, refund_agent, order_agent, return_agent
def _handle_events(events: list[WorkflowEvent]) -> list[RequestInfoEvent]:
def _handle_events(events: list[WorkflowEvent]) -> list[WorkflowEvent[HandoffAgentUserRequest]]:
"""Process workflow events and extract any pending user input requests.
This function inspects each event type and:
- Prints workflow status changes (IDLE, IDLE_WITH_PENDING_REQUESTS, etc.)
- Displays final conversation snapshots when workflow completes
- Prints user input request prompts
- Collects all RequestInfoEvent instances for response handling
- Collects all request_info events for response handling
Args:
events: List of WorkflowEvent to process
Returns:
List of RequestInfoEvent representing pending user input requests
List of WorkflowEvent[HandoffAgentUserRequest] representing pending user input requests
"""
requests: list[RequestInfoEvent] = []
requests: list[WorkflowEvent[HandoffAgentUserRequest]] = []
for event in events:
if isinstance(event, HandoffSentEvent):
# HandoffSentEvent: Indicates a handoff has been initiated
print(f"\n[Handoff from {event.source} to {event.target} initiated.]")
elif isinstance(event, WorkflowStatusEvent) and event.state in {
if event.type == "handoff_sent":
# handoff_sent event: Indicates a handoff has been initiated
print(f"\n[Handoff from {event.data.source} to {event.data.target} initiated.]")
elif event.type == "status" and event.state in {
WorkflowRunState.IDLE,
WorkflowRunState.IDLE_WITH_PENDING_REQUESTS,
}:
# WorkflowStatusEvent: Indicates workflow state changes
print(f"\n[Workflow Status] {event.state.name}")
elif isinstance(event, WorkflowOutputEvent):
# WorkflowOutputEvent: Contains contents generated by the workflow
# Status event: Indicates workflow state changes
print(f"\n[Workflow Status] {event.state}")
elif event.type == "output":
# Output event: Contains contents generated by the workflow
data = event.data
if isinstance(data, AgentResponse):
for message in data.messages:
@@ -139,7 +136,7 @@ def _handle_events(events: list[WorkflowEvent]) -> list[RequestInfoEvent]:
continue
speaker = message.author_name or message.role
print(f"- {speaker}: {message.text}")
else:
elif event.type == "output":
# The output of the handoff workflow is a collection of chat messages from all participants
conversation = cast(list[ChatMessage], event.data)
if isinstance(conversation, list):
@@ -148,11 +145,9 @@ def _handle_events(events: list[WorkflowEvent]) -> list[RequestInfoEvent]:
speaker = message.author_name or message.role
print(f"- {speaker}: {message.text or [content.type for content in message.contents]}")
print("===================================")
elif isinstance(event, RequestInfoEvent):
# RequestInfoEvent: Workflow is requesting user input
if isinstance(event.data, HandoffAgentUserRequest):
_print_handoff_agent_user_request(event.data.agent_response)
requests.append(event)
elif event.type == "request_info" and isinstance(event.data, HandoffAgentUserRequest):
_print_handoff_agent_user_request(event.data.agent_response)
requests.append(cast(WorkflowEvent[HandoffAgentUserRequest], event))
return requests