Python: Fix workflow samples for bugbash: part 1 (#4055)

* Fix workflow samples for bugbash: part 1

* Fix mypy

* Fix tests
This commit is contained in:
Tao Chen
2026-02-18 15:08:53 -08:00
committed by GitHub
Unverified
parent 2dfe90306b
commit 7cee839982
11 changed files with 132 additions and 113 deletions
@@ -3,6 +3,7 @@
import asyncio
import json
import os
from collections.abc import AsyncIterable
from dataclasses import dataclass, field
from typing import Annotated
@@ -12,7 +13,6 @@ from agent_framework import (
AgentExecutorRequest,
AgentExecutorResponse,
AgentResponse,
AgentResponseUpdate,
Executor,
Message,
WorkflowBuilder,
@@ -246,6 +246,31 @@ def display_agent_run_update(event: WorkflowEvent, last_executor: str | None) ->
print(update, end="", flush=True)
async def consume_stream(stream: AsyncIterable[WorkflowEvent]) -> dict[str, str] | None:
"""Consume a workflow event stream, printing outputs and returning any pending human responses."""
requests: list[WorkflowEvent] = []
async for event in stream:
if event.type == "request_info" and isinstance(event.data, DraftFeedbackRequest):
# Stash the request so we can prompt the human after the stream completes.
requests.append(event)
if requests:
pending_responses: dict[str, str] = {}
for request in requests:
print("\n----- Writer draft -----")
print(request.data.draft_text.strip())
print("\nProvide guidance for the editor (or 'approve' to accept the draft).")
answer = input("Human feedback: ").strip() # noqa: ASYNC250
if answer.lower() == "exit":
print("Exiting...")
exit(0)
pending_responses[request.request_id] = answer
return pending_responses
return None
async def main() -> None:
"""Run the workflow and bridge human feedback between two agents."""
@@ -267,66 +292,23 @@ async def main() -> None:
.build()
)
# Switch to turn on agent run update display.
# By default this is off to reduce clutter during human input.
display_agent_run_update_switch = False
print(
"Interactive mode. When prompted, provide a short feedback note for the editor.",
flush=True,
)
pending_responses: dict[str, str] | None = None
completed = False
initial_run = True
# Initiate the first run of the workflow.
# Runs are not isolated; state is preserved across multiple calls to run.
stream = workflow.run(
"Create a short launch blurb for the LumenX desk lamp. Emphasize adjustability and warm lighting.",
stream=True,
)
pending_responses = await consume_stream(stream)
while not completed:
last_executor: str | None = None
if initial_run:
stream = workflow.run(
"Create a short launch blurb for the LumenX desk lamp. Emphasize adjustability and warm lighting.",
stream=True,
)
initial_run = False
elif pending_responses is not None:
stream = workflow.run(stream=True, responses=pending_responses)
pending_responses = None
else:
break
requests: list[tuple[str, DraftFeedbackRequest]] = []
async for event in stream:
if (
event.type == "output"
and isinstance(event.data, AgentResponseUpdate)
and display_agent_run_update_switch
):
display_agent_run_update(event, last_executor)
if event.type == "request_info" and isinstance(event.data, DraftFeedbackRequest):
# Stash the request so we can prompt the human after the stream completes.
requests.append((event.request_id, event.data))
last_executor = None
elif event.type == "output" and not isinstance(event.data, AgentResponseUpdate):
# Only mark as completed for final outputs, not streaming updates
last_executor = None
response = event.data
final_text = getattr(response, "text", str(response))
print(final_text, flush=True, end="")
completed = True
if requests and not completed:
responses: dict[str, str] = {}
for request_id, request in requests:
print("\n----- Writer draft -----")
print(request.draft_text.strip())
print("\nProvide guidance for the editor (or 'approve' to accept the draft).")
answer = input("Human feedback: ").strip() # noqa: ASYNC250
if answer.lower() == "exit":
print("Exiting...")
return
responses[request_id] = answer
pending_responses = responses
# Run until there are no more requests
while pending_responses is not None:
stream = workflow.run(stream=True, responses=pending_responses)
pending_responses = await consume_stream(stream)
print("Workflow complete.")
@@ -26,18 +26,6 @@ Prerequisites:
"""
def clear_and_redraw(buffers: dict[str, str], agent_order: list[str]) -> None:
"""Clear terminal and redraw all agent outputs grouped together."""
# ANSI escape: clear screen and move cursor to top-left
print("\033[2J\033[H", end="")
print("===== Concurrent Agent Streaming (Live) =====\n")
for name in agent_order:
print(f"--- {name} ---")
print(buffers.get(name, ""))
print()
print("", end="", flush=True)
async def main() -> None:
# 1) Create three domain agents using AzureOpenAIResponsesClient
client = AzureOpenAIResponsesClient(
@@ -106,7 +106,7 @@ async def main() -> None:
# and escalation paths for human review.
worker = Worker(
id="worker",
chat_client=AzureOpenAIResponsesClient(
client=AzureOpenAIResponsesClient(
project_endpoint=os.environ["AZURE_AI_PROJECT_ENDPOINT"],
deployment_name=os.environ["AZURE_AI_MODEL_DEPLOYMENT_NAME"],
credential=AzureCliCredential(),
@@ -161,7 +161,7 @@ async def main() -> None:
request_id = agent_request.request_id
# Mock a human response approval for demonstration purposes.
human_response = ReviewResponse(request_id=request_id, feedback="Approved", approved=True)
human_response = ReviewResponse(request_id=request_id, feedback="", approved=True)
# Create the function call result object to send back to the agent.
human_review_function_result = Content.from_function_result(