Python: Workflow run state and structured error events, sample updates, tests (#725)

* Add workflow event types to surface workflow state, status, and failures.

* Address PR feedback

* Updates to use new workflow run state enums
This commit is contained in:
Evan Mattson
2025-09-16 10:36:25 +09:00
committed by GitHub
Unverified
parent e7cd03b32e
commit 68b76e6726
12 changed files with 463 additions and 26 deletions
@@ -104,11 +104,14 @@ async def main():
# provides the WorkflowCompletedEvent emitted by the terminal node.
events = await workflow.run("hello world")
print(events.get_completed_event())
# Summarize the final run state (e.g., COMPLETED)
print("Final state:", events.get_final_state())
"""
Sample Output:
WorkflowCompletedEvent(data=DLROW OLLEH)
Final state: WorkflowRunState.COMPLETED
"""
@@ -59,6 +59,8 @@ async def main():
print(f"{event.executor_id}: {event.data}")
print(f"{'=' * 60}\n{events.get_completed_event()}")
# Summarize the final run state (e.g., COMPLETED)
print("Final state:", events.get_final_state())
"""
Sample Output:
@@ -4,7 +4,17 @@ import asyncio
from agent_framework import ChatAgent, ChatMessage
from agent_framework.azure import AzureChatClient
from agent_framework.workflow import Executor, WorkflowBuilder, WorkflowCompletedEvent, WorkflowContext, handler
from agent_framework.workflow import (
Executor,
ExecutorFailedEvent,
WorkflowBuilder,
WorkflowCompletedEvent,
WorkflowContext,
WorkflowFailedEvent,
WorkflowRunState,
WorkflowStatusEvent,
handler,
)
from azure.identity import AzureCliCredential
"""
@@ -107,20 +117,41 @@ async def main():
workflow = WorkflowBuilder().set_start_executor(writer).add_edge(writer, reviewer).build()
# Run the workflow with the user's initial message and stream events as they occur.
# Events include executor invoke and completion, as well as the terminal WorkflowCompletedEvent.
# In addition to executor events and WorkflowCompletedEvent, this also surfaces run-state and errors.
async for event in workflow.run_stream(
ChatMessage(role="user", text="Create a slogan for a new electric SUV that is affordable and fun to drive.")
):
print(event)
if isinstance(event, WorkflowStatusEvent):
if event.state == WorkflowRunState.IN_PROGRESS:
print("State: IN_PROGRESS")
elif event.state == WorkflowRunState.COMPLETED:
print("State: COMPLETED")
elif event.state == WorkflowRunState.IN_PROGRESS_PENDING_REQUESTS:
print("State: IN_PROGRESS_PENDING_REQUESTS (requests in flight)")
elif event.state == WorkflowRunState.IDLE:
print("State: IDLE (no active work)")
elif event.state == WorkflowRunState.IDLE_WITH_PENDING_REQUESTS:
print("State: IDLE_WITH_PENDING_REQUESTS (prompt user or UI now)")
else:
print(f"State: {event.state}")
elif isinstance(event, ExecutorFailedEvent):
print(f"Executor failed: {event.executor_id} {event.details.error_type}: {event.details.message}")
elif isinstance(event, WorkflowFailedEvent):
details = event.details
print(f"Workflow failed: {details.error_type}: {details.message}")
else:
print(event)
"""
Sample Output:
State: IN_PROGRESS
ExecutorInvokeEvent(executor_id=writer)
ExecutorCompletedEvent(executor_id=writer)
ExecutorInvokeEvent(executor_id=reviewer)
WorkflowCompletedEvent(data=Drive the Future. Affordable Adventure, Electrified.)
ExecutorCompletedEvent(executor_id=reviewer)
State: COMPLETED
"""