Python: Introduce add_agent functionality and added output_response to AgentExecutor; agent streaming behavior to follow workflow invocation (#1184)

* refactor AgentExecutor, add output_response flag for switching on or off workflow output for each agent.

* introduce add_agent

* make default agent's streaming to false

* address comments

* fix test

* add is_streaming to RunnerContext and WorkflowContext

* fix add_agent return

* fix tests

* address comments

* resolve conflict

* update to address comments

* fix
This commit is contained in:
Eric Zhu
2025-10-07 09:11:40 -07:00
committed by GitHub
Unverified
parent 959e5842c2
commit d01d9afb92
15 changed files with 572 additions and 314 deletions
@@ -16,12 +16,13 @@ A Writer agent generates content, then a Reviewer agent critiques it.
The workflow uses streaming so you can observe incremental AgentRunUpdateEvent chunks as each agent produces tokens.
Purpose:
Show how to wire chat agents directly into a WorkflowBuilder pipeline where agents are auto wrapped as executors.
Show how to wire chat agents into a WorkflowBuilder pipeline using add_agent
with settings for streaming and workflow outputs.
Demonstrate:
- Automatic streaming of agent deltas via AgentRunUpdateEvent.
- A simple console aggregator that groups updates by executor id and prints them as they arrive.
- The workflow completes when idle and outputs are available in events.get_outputs().
- Automatic streaming of agent deltas via AgentRunUpdateEvent when using run_stream().
- Add an agent via WorkflowBuilder.add_agent() with output_response=True to emit final AgentRunResponse.
- Agents adapt to workflow mode: run_stream() emits incremental updates, run() emits complete responses.
Prerequisites:
- Azure AI Agent Service configured, along with the required environment variables.
@@ -66,8 +67,17 @@ async def main() -> None:
"Provide the feedback in the most concise manner possible."
),
)
workflow = WorkflowBuilder().set_start_executor(writer).add_edge(writer, reviewer).build()
# Add agents to workflow with custom settings using add_agent.
# Agents adapt to workflow mode: run_stream() for incremental updates, run() for complete responses.
# Reviewer agent emits final AgentRunResponse as a workflow output.
workflow = (
WorkflowBuilder()
.add_agent(writer, id="Writer")
.add_agent(reviewer, id="Reviewer", output_response=True)
.set_start_executor(writer)
.add_edge(writer, reviewer)
.build()
)
last_executor_id: str | None = None
@@ -13,12 +13,13 @@ A Writer agent generates content, then a Reviewer agent critiques it.
The workflow uses streaming so you can observe incremental AgentRunUpdateEvent chunks as each agent produces tokens.
Purpose:
Show how to wire chat agents directly into a WorkflowBuilder pipeline where agents are auto wrapped as executors.
Show how to wire chat agents into a WorkflowBuilder pipeline using add_agent
with settings for streaming and workflow outputs.
Demonstrate:
- Automatic streaming of agent deltas via AgentRunUpdateEvent.
- A simple console aggregator that groups updates by executor id and prints them as they arrive.
- The workflow completes when idle and outputs are available in events.get_outputs().
- Automatic streaming of agent deltas via AgentRunUpdateEvent when using run_stream().
- Add an agent via WorkflowBuilder.add_agent() with output_response=True to emit final AgentRunResponse.
- Agents adapt to workflow mode: run_stream() emits incremental updates, run() emits complete responses.
Prerequisites:
- Azure OpenAI configured for AzureOpenAIChatClient with required environment variables.
@@ -32,7 +33,7 @@ async def main():
# Create the Azure chat client. AzureCliCredential uses your current az login.
chat_client = AzureOpenAIChatClient(credential=AzureCliCredential())
# Define two domain specific chat agents. The builder will wrap these as executors.
# Define two domain specific chat agents.
writer_agent = chat_client.create_agent(
instructions=(
"You are an excellent content writer. You create new content and edit contents based on the feedback."
@@ -50,11 +51,21 @@ async def main():
)
# Build the workflow using the fluent builder.
# Add agents to workflow with custom settings using add_agent.
# Agents adapt to workflow mode: run_stream() for incremental updates, run() for complete responses.
# Reviewer agent emits final AgentRunResponse as a workflow output.
# Set the start node and connect an edge from writer to reviewer.
workflow = WorkflowBuilder().set_start_executor(writer_agent).add_edge(writer_agent, reviewer_agent).build()
workflow = (
WorkflowBuilder()
.add_agent(writer_agent, id="Writer")
.add_agent(reviewer_agent, id="Reviewer", output_response=True)
.set_start_executor(writer_agent)
.add_edge(writer_agent, reviewer_agent)
.build()
)
# Stream events from the workflow. We aggregate partial token updates per executor for readable output.
last_executor_id = None
last_executor_id: str | None = None
events = workflow.run_stream("Create a slogan for a new electric SUV that is affordable and fun to drive.")
async for event in events:
@@ -62,14 +73,14 @@ async def main():
# AgentRunUpdateEvent contains incremental text deltas from the underlying agent.
# Print a prefix when the executor changes, then append updates on the same line.
eid = event.executor_id
if eid != last_executor_id: # type: ignore[reportUnnecessaryComparison]
if eid != last_executor_id:
if last_executor_id is not None:
print()
print(f"{eid}:", end=" ", flush=True)
last_executor_id = eid
print(event.data, end="", flush=True)
elif isinstance(event, WorkflowOutputEvent):
print("===== Final Output =====")
print("\n===== Final output =====")
print(event.data)
"""