mirror of
https://github.com/microsoft/agent-framework.git
synced 2026-06-16 21:04:09 +08:00
Python: Workflow event source updates (#789)
* Workflow event source updates * Add WorkflowLifecycleEvent TypeAlias. Update docstrings * Updates * Rename --------- Co-authored-by: Chris <66376200+crickman@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
Unverified
parent
6a66ad517a
commit
960196cd52
@@ -29,7 +29,8 @@ Purpose:
|
||||
Show how to wrap chat agents created by AzureChatClient inside workflow executors, wire them with WorkflowBuilder,
|
||||
and consume streaming events from the workflow. Demonstrate the @handler pattern with typed inputs and typed
|
||||
WorkflowContext[T] outputs, and finish by emitting a WorkflowCompletedEvent from the terminal node while printing
|
||||
intermediate events for observability.
|
||||
intermediate events for observability. The streaming loop also surfaces WorkflowEvent.origin so you can
|
||||
distinguish runner-generated lifecycle events from executor-generated data-plane events.
|
||||
|
||||
Prerequisites:
|
||||
- Azure OpenAI configured for AzureChatClient with required environment variables.
|
||||
@@ -123,36 +124,42 @@ async def main():
|
||||
ChatMessage(role="user", text="Create a slogan for a new electric SUV that is affordable and fun to drive.")
|
||||
):
|
||||
if isinstance(event, WorkflowStatusEvent):
|
||||
prefix = f"State ({event.origin.value}): "
|
||||
if event.state == WorkflowRunState.IN_PROGRESS:
|
||||
print("State: IN_PROGRESS")
|
||||
print(prefix + "IN_PROGRESS")
|
||||
elif event.state == WorkflowRunState.COMPLETED:
|
||||
print("State: COMPLETED")
|
||||
print(prefix + "COMPLETED")
|
||||
elif event.state == WorkflowRunState.IN_PROGRESS_PENDING_REQUESTS:
|
||||
print("State: IN_PROGRESS_PENDING_REQUESTS (requests in flight)")
|
||||
print(prefix + "IN_PROGRESS_PENDING_REQUESTS (requests in flight)")
|
||||
elif event.state == WorkflowRunState.IDLE:
|
||||
print("State: IDLE (no active work)")
|
||||
print(prefix + "IDLE (no active work)")
|
||||
elif event.state == WorkflowRunState.IDLE_WITH_PENDING_REQUESTS:
|
||||
print("State: IDLE_WITH_PENDING_REQUESTS (prompt user or UI now)")
|
||||
print(prefix + "IDLE_WITH_PENDING_REQUESTS (prompt user or UI now)")
|
||||
else:
|
||||
print(f"State: {event.state}")
|
||||
print(prefix + str(event.state))
|
||||
elif isinstance(event, WorkflowCompletedEvent):
|
||||
print(f"Workflow completed ({event.origin.value}): {event.data}")
|
||||
elif isinstance(event, ExecutorFailedEvent):
|
||||
print(f"Executor failed: {event.executor_id} {event.details.error_type}: {event.details.message}")
|
||||
print(
|
||||
f"Executor failed ({event.origin.value}): "
|
||||
f"{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}")
|
||||
print(f"Workflow failed ({event.origin.value}): {details.error_type}: {details.message}")
|
||||
else:
|
||||
print(event)
|
||||
print(f"{event.__class__.__name__} ({event.origin.value}): {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
|
||||
State (RUNNER): IN_PROGRESS
|
||||
ExecutorInvokeEvent (RUNNER): ExecutorInvokeEvent(executor_id=writer)
|
||||
ExecutorCompletedEvent (RUNNER): ExecutorCompletedEvent(executor_id=writer)
|
||||
ExecutorInvokeEvent (RUNNER): ExecutorInvokeEvent(executor_id=reviewer)
|
||||
Workflow completed (EXECUTOR): Drive the Future. Affordable Adventure, Electrified.
|
||||
ExecutorCompletedEvent (RUNNER): ExecutorCompletedEvent(executor_id=reviewer)
|
||||
State (RUNNER): COMPLETED
|
||||
"""
|
||||
|
||||
|
||||
|
||||
@@ -275,15 +275,15 @@ async def main():
|
||||
|
||||
Running workflow with initial message...
|
||||
UpperCaseExecutor: 'hello world' -> 'HELLO WORLD'
|
||||
Event: ExecutorInvokeEvent(executor_id=upper_case_executor)
|
||||
Event: ExecutorInvokedEvent(executor_id=upper_case_executor)
|
||||
Event: ExecutorCompletedEvent(executor_id=upper_case_executor)
|
||||
ReverseTextExecutor: 'HELLO WORLD' -> 'DLROW OLLEH'
|
||||
Event: ExecutorInvokeEvent(executor_id=reverse_text_executor)
|
||||
Event: ExecutorInvokedEvent(executor_id=reverse_text_executor)
|
||||
Event: ExecutorCompletedEvent(executor_id=reverse_text_executor)
|
||||
LowerAgent (shared_state): original_input='hello world', upper_output='HELLO WORLD'
|
||||
Event: ExecutorInvokeEvent(executor_id=submit_lower)
|
||||
Event: ExecutorInvokeEvent(executor_id=lower_agent)
|
||||
Event: ExecutorInvokeEvent(executor_id=finalize)
|
||||
Event: ExecutorInvokedEvent(executor_id=submit_lower)
|
||||
Event: ExecutorInvokedEvent(executor_id=lower_agent)
|
||||
Event: ExecutorInvokedEvent(executor_id=finalize)
|
||||
Event: WorkflowCompletedEvent(data=dlrow olleh)
|
||||
|
||||
Checkpoint summary:
|
||||
@@ -300,9 +300,9 @@ async def main():
|
||||
|
||||
Resuming from checkpoint: a78c345a-e5d9-45ba-82c0-cb725452d91b
|
||||
LowerAgent (shared_state): original_input='hello world', upper_output='HELLO WORLD'
|
||||
Resumed Event: ExecutorInvokeEvent(executor_id=submit_lower)
|
||||
Resumed Event: ExecutorInvokeEvent(executor_id=lower_agent)
|
||||
Resumed Event: ExecutorInvokeEvent(executor_id=finalize)
|
||||
Resumed Event: ExecutorInvokedEvent(executor_id=submit_lower)
|
||||
Resumed Event: ExecutorInvokedEvent(executor_id=lower_agent)
|
||||
Resumed Event: ExecutorInvokedEvent(executor_id=finalize)
|
||||
Resumed Event: WorkflowCompletedEvent(data=dlrow olleh)
|
||||
""" # noqa: E501
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ The second reverses the text and completes the workflow. Events are printed as t
|
||||
Purpose:
|
||||
Show how to declare executors with the @executor decorator, connect them with WorkflowBuilder,
|
||||
pass intermediate values using ctx.send_message, and signal completion with ctx.add_event by emitting a
|
||||
WorkflowCompletedEvent. Demonstrate how streaming exposes ExecutorInvokeEvent and WorkflowCompletedEvent
|
||||
WorkflowCompletedEvent. Demonstrate how streaming exposes ExecutorInvokedEvent and WorkflowCompletedEvent
|
||||
for observability.
|
||||
|
||||
Prerequisites:
|
||||
@@ -72,9 +72,9 @@ async def main():
|
||||
"""
|
||||
Sample Output:
|
||||
|
||||
Event: ExecutorInvokeEvent(executor_id=upper_case_executor)
|
||||
Event: ExecutorInvokedEvent(executor_id=upper_case_executor)
|
||||
Event: ExecutorCompletedEvent(executor_id=upper_case_executor)
|
||||
Event: ExecutorInvokeEvent(executor_id=reverse_text_executor)
|
||||
Event: ExecutorInvokedEvent(executor_id=reverse_text_executor)
|
||||
Event: WorkflowCompletedEvent(data=DLROW OLLEH)
|
||||
Event: ExecutorCompletedEvent(executor_id=reverse_text_executor)
|
||||
Workflow completed with result: DLROW OLLEH
|
||||
|
||||
Reference in New Issue
Block a user