[BREAKING] Python: Merge send_responses into run method (#3720)

* Streamline workflow run api with send responses in one method

* Fixes

* Address copilot feedback
This commit is contained in:
Evan Mattson
2026-02-06 22:32:38 +00:00
committed by GitHub
parent 15256bb616
commit a17f13598b
39 changed files with 561 additions and 335 deletions
@@ -199,7 +199,7 @@ async def main() -> None:
)
# Initiate the first run of the workflow.
# Runs are not isolated; state is preserved across multiple calls to run or send_responses_streaming.
# 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,
@@ -209,7 +209,7 @@ async def main() -> None:
while pending_responses is not None:
# Run the workflow until there is no more human feedback to provide,
# in which case this workflow completes.
stream = workflow.send_responses_streaming(pending_responses)
stream = workflow.run(stream=True, responses=pending_responses)
pending_responses = await process_event_stream(stream)
print("\nWorkflow complete.")
@@ -249,7 +249,7 @@ async def main() -> None:
)
# Initiate the first run of the workflow.
# Runs are not isolated; state is preserved across multiple calls to run or send_responses_streaming.
# Runs are not isolated; state is preserved across multiple calls to run.
events = await workflow.run(incoming_email)
request_info_events = events.get_request_info_events()
@@ -276,7 +276,7 @@ async def main() -> None:
print("Performing automatic approval for demo purposes...")
responses[request_info_event.request_id] = data.to_function_approval_response(approved=True)
events = await workflow.send_responses(responses)
events = await workflow.run(responses=responses)
request_info_events = events.get_request_info_events()
# The output should only come from conclude_workflow executor and it's a single string
@@ -183,14 +183,14 @@ async def main() -> None:
)
# Initiate the first run of the workflow.
# Runs are not isolated; state is preserved across multiple calls to run or send_responses_streaming.
# Runs are not isolated; state is preserved across multiple calls to run.
stream = workflow.run("Analyze the impact of large language models on software development.", stream=True)
pending_responses = await process_event_stream(stream)
while pending_responses is not None:
# Run the workflow until there is no more human feedback to provide,
# in which case this workflow completes.
stream = workflow.send_responses_streaming(pending_responses)
stream = workflow.run(stream=True, responses=pending_responses)
pending_responses = await process_event_stream(stream)
@@ -147,7 +147,7 @@ async def main() -> None:
)
# Initiate the first run of the workflow.
# Runs are not isolated; state is preserved across multiple calls to run or send_responses_streaming.
# Runs are not isolated; state is preserved across multiple calls to run.
stream = workflow.run(
"Discuss how our team should approach adopting AI tools for productivity. "
"Consider benefits, risks, and implementation strategies.",
@@ -158,7 +158,7 @@ async def main() -> None:
while pending_responses is not None:
# Run the workflow until there is no more human feedback to provide,
# in which case this workflow completes.
stream = workflow.send_responses_streaming(pending_responses)
stream = workflow.run(stream=True, responses=pending_responses)
pending_responses = await process_event_stream(stream)
@@ -29,7 +29,7 @@ the workflow completes when idle with no pending work.
Purpose:
Show how to integrate a human step in the middle of an LLM workflow by using
`request_info` and `send_responses_streaming`.
`request_info` and `run(responses=..., stream=True)`.
Demonstrate:
- Alternating turns between an AgentExecutor and a human, driven by events.
@@ -42,11 +42,11 @@ Prerequisites:
- Basic familiarity with WorkflowBuilder, executors, edges, events, and streaming runs.
"""
# How human-in-the-loop is achieved via `request_info` and `send_responses_streaming`:
# How human-in-the-loop is achieved via `request_info` and `run(responses=..., stream=True)`:
# - An executor (TurnManager) calls `ctx.request_info` with a payload (HumanFeedbackRequest).
# - The workflow run pauses and emits a with the payload and the request_id.
# - The application captures the event, prompts the user, and collects replies.
# - The application calls `send_responses_streaming` with a map of request_ids to replies.
# - The application calls `run(stream=True, responses=...)` with a map of request_ids to replies.
# - The workflow resumes, and the response is delivered to the executor method decorated with @response_handler.
# - The executor can then continue the workflow, e.g., by sending a new message to the agent.
@@ -205,14 +205,14 @@ async def main() -> None:
).build()
# Initiate the first run of the workflow.
# Runs are not isolated; state is preserved across multiple calls to run or send_responses_streaming.
# Runs are not isolated; state is preserved across multiple calls to run.
stream = workflow.run("start", stream=True)
pending_responses = await process_event_stream(stream)
while pending_responses is not None:
# Run the workflow until there is no more human feedback to provide,
# in which case this workflow completes.
stream = workflow.send_responses_streaming(pending_responses)
stream = workflow.run(stream=True, responses=pending_responses)
pending_responses = await process_event_stream(stream)
"""
@@ -13,8 +13,8 @@ using the standard request_info pattern for consistency.
Demonstrate:
- Configuring request info with `.with_request_info()`
- Handling with AgentInputRequest data
- Injecting responses back into the workflow via send_responses_streaming
- Handling request_info events with AgentInputRequest data
- Injecting responses back into the workflow via run(responses=..., stream=True)
Prerequisites:
- Azure OpenAI configured for AzureOpenAIChatClient with required environment variables
@@ -122,14 +122,14 @@ async def main() -> None:
)
# Initiate the first run of the workflow.
# Runs are not isolated; state is preserved across multiple calls to run or send_responses_streaming.
# Runs are not isolated; state is preserved across multiple calls to run.
stream = workflow.run("Write a brief introduction to artificial intelligence.", stream=True)
pending_responses = await process_event_stream(stream)
while pending_responses is not None:
# Run the workflow until there is no more human feedback to provide,
# in which case this workflow completes.
stream = workflow.send_responses_streaming(pending_responses)
stream = workflow.run(stream=True, responses=pending_responses)
pending_responses = await process_event_stream(stream)