[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
@@ -6,7 +6,7 @@ import asyncio
from collections.abc import Sequence
from typing import cast
from agent_framework import ChatMessage, ConcurrentBuilder, WorkflowOutputEvent
from agent_framework import ChatMessage, ConcurrentBuilderWorkflowEvent
from agent_framework.azure import AzureOpenAIChatClient
from azure.identity import AzureCliCredential
from semantic_kernel.agents import Agent, ChatCompletionAgent, ConcurrentOrchestration
@@ -91,7 +91,7 @@ async def run_agent_framework_example(prompt: str) -> Sequence[list[ChatMessage]
outputs: list[list[ChatMessage]] = []
async for event in workflow.run(prompt, stream=True):
if isinstance(event, WorkflowOutputEvent):
if event.type == "output":
outputs.append(cast(list[ChatMessage], event.data))
return outputs
@@ -7,7 +7,7 @@ import sys
from collections.abc import Sequence
from typing import Any, cast
from agent_framework import ChatAgent, ChatMessage, GroupChatBuilder, WorkflowOutputEvent
from agent_framework import ChatAgent, ChatMessage, GroupChatBuilderWorkflowEvent
from agent_framework.azure import AzureOpenAIChatClient, AzureOpenAIResponsesClient
from azure.identity import AzureCliCredential
from semantic_kernel.agents import Agent, ChatCompletionAgent, GroupChatOrchestration
@@ -240,7 +240,7 @@ async def run_agent_framework_example(task: str) -> str:
final_response = ""
async for event in workflow.run(task, stream=True):
if isinstance(event, WorkflowOutputEvent):
if event.type == "output":
data = event.data
if isinstance(data, list) and len(data) > 0:
# Get the final message from the conversation
@@ -8,12 +8,9 @@ from typing import cast
from agent_framework import (
ChatMessage,
HandoffBuilder,
HandoffUserInputRequest,
RequestInfoEvent,
WorkflowEvent,
WorkflowOutputEvent,
)
from agent_framework.orchestrations import HandoffBuilder, HandoffUserInputRequest
from agent_framework.azure import AzureOpenAIChatClient
from azure.identity import AzureCliCredential
from semantic_kernel.agents import Agent, ChatCompletionAgent, HandoffOrchestration, OrchestrationHandoffs
@@ -214,17 +211,17 @@ async def _drain_events(stream: AsyncIterable[WorkflowEvent]) -> list[WorkflowEv
return [event async for event in stream]
def _collect_handoff_requests(events: list[WorkflowEvent]) -> list[RequestInfoEvent]:
requests: list[RequestInfoEvent] = []
def _collect_handoff_requests(events: list[WorkflowEvent]) -> list[WorkflowEvent]:
requests: list[WorkflowEvent] = []
for event in events:
if isinstance(event, RequestInfoEvent) and isinstance(event.data, HandoffUserInputRequest):
if event.type == "request_info" and isinstance(event.data, HandoffUserInputRequest):
requests.append(event)
return requests
def _extract_final_conversation(events: list[WorkflowEvent]) -> list[ChatMessage]:
for event in events:
if isinstance(event, WorkflowOutputEvent):
if event.type == "output":
data = cast(list[ChatMessage], event.data)
return data
return []
@@ -6,7 +6,7 @@ import asyncio
from collections.abc import Sequence
from typing import cast
from agent_framework import ChatAgent, HostedCodeInterpreterTool, MagenticBuilder, WorkflowOutputEvent
from agent_framework import ChatAgent, HostedCodeInterpreterTool, MagenticBuilderWorkflowEvent
from agent_framework.openai import OpenAIChatClient, OpenAIResponsesClient
from semantic_kernel.agents import (
Agent,
@@ -148,7 +148,7 @@ async def run_agent_framework_example(prompt: str) -> str | None:
final_text: str | None = None
async for event in workflow.run(prompt, stream=True):
if isinstance(event, WorkflowOutputEvent):
if event.type == "output":
final_text = cast(str, event.data)
return final_text
@@ -6,8 +6,9 @@ import asyncio
from collections.abc import Sequence
from typing import cast
from agent_framework import ChatMessage, SequentialBuilder, WorkflowOutputEvent
from agent_framework import ChatMessage
from agent_framework.azure import AzureOpenAIChatClient
from agent_framework.orchestrations import SequentialBuilder
from azure.identity import AzureCliCredential
from semantic_kernel.agents import Agent, ChatCompletionAgent, SequentialOrchestration
from semantic_kernel.agents.runtime import InProcessRuntime
@@ -77,7 +78,7 @@ async def run_agent_framework_example(prompt: str) -> list[ChatMessage]:
conversation_outputs: list[list[ChatMessage]] = []
async for event in workflow.run(prompt, stream=True):
if isinstance(event, WorkflowOutputEvent):
if event.type == "output":
conversation_outputs.append(cast(list[ChatMessage], event.data))
return conversation_outputs[-1] if conversation_outputs else []
@@ -11,7 +11,7 @@ from typing import TYPE_CHECKING, ClassVar, cast
######################################################################
# region Agent Framework imports
######################################################################
from agent_framework import Executor, WorkflowBuilder, WorkflowContext, WorkflowOutputEvent, handler
from agent_framework import Executor, WorkflowBuilder, WorkflowContext, handler
from pydantic import BaseModel, Field
######################################################################
@@ -232,7 +232,7 @@ async def run_agent_framework_workflow_example() -> str | None:
final_text: str | None = None
async for event in workflow.run(CommonEvents.START_PROCESS, stream=True):
if isinstance(event, WorkflowOutputEvent):
if event.type == "output":
final_text = cast(str, event.data)
return final_text
@@ -17,7 +17,7 @@ from agent_framework import (
WorkflowBuilder,
WorkflowContext,
WorkflowExecutor,
WorkflowOutputEvent,
handler,
)
from pydantic import BaseModel, Field
@@ -257,7 +257,7 @@ async def run_agent_framework_nested_workflow(initial_message: str) -> Sequence[
results: list[str] = []
async for event in outer_workflow.run(initial_message, stream=True):
if isinstance(event, WorkflowOutputEvent):
if event.type == "output":
results.append(cast(str, event.data))
return results