Python: Add samples syntax checking with pyright (#3710)

* Add samples syntax checking with pyright

- Add pyrightconfig.samples.json with relaxed type checking but import validation
- Add samples-syntax poe task to check samples for syntax and import errors
- Add samples-syntax to check and pre-commit-check tasks
- Fix 78 sample errors:
  - Update workflow builder imports to use agent_framework_orchestrations
  - Change content type isinstance checks to content.type comparisons
  - Use Content factory methods instead of removed content type classes
  - Fix TypedDict access patterns for Annotation
  - Fix various API mismatches (normalize_messages, ChatMessage.text, role)

* fixed a bunch of samples and tweaks to pre-commit

* updated lock

* updated lock

* fixes

* added lint to samples
This commit is contained in:
Eduard van Valkenburg
2026-02-07 08:10:47 +01:00
committed by GitHub
Unverified
parent 74ac470a56
commit 390f93344c
83 changed files with 606 additions and 498 deletions
@@ -1,11 +1,13 @@
# Copyright (c) Microsoft. All rights reserved.
"""Client application for interacting with a Durable Task hosted agent.
This client connects to the Durable Task Scheduler and sends requests to
registered agents, demonstrating how to interact with agents from external processes.
Prerequisites:
Prerequisites:
- The worker must be running with the agent registered
- Set AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_CHAT_DEPLOYMENT_NAME
- Set AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_CHAT_DEPLOYMENT_NAME
(plus AZURE_OPENAI_API_KEY or Azure CLI authentication)
- Durable Task Scheduler must be running
"""
@@ -29,12 +31,12 @@ def get_client(
log_handler: logging.Handler | None = None
) -> DurableAIAgentClient:
"""Create a configured DurableAIAgentClient.
Args:
taskhub: Task hub name (defaults to TASKHUB env var or "default")
endpoint: Scheduler endpoint (defaults to ENDPOINT env var or "http://localhost:8080")
log_handler: Optional logging handler for client logging
Returns:
Configured DurableAIAgentClient instance
"""
@@ -59,7 +61,7 @@ def get_client(
def run_client(agent_client: DurableAIAgentClient) -> None:
"""Run client interactions with the Joker agent.
Args:
agent_client: The DurableAIAgentClient instance
"""
@@ -1,11 +1,13 @@
# Copyright (c) Microsoft. All rights reserved.
"""Single Agent Sample - Durable Task Integration (Combined Worker + Client)
This sample demonstrates running both the worker and client in a single process.
The worker is started first to register the agent, then client operations are
performed against the running worker.
Prerequisites:
- Set AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_CHAT_DEPLOYMENT_NAME
Prerequisites:
- Set AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_CHAT_DEPLOYMENT_NAME
(plus AZURE_OPENAI_API_KEY or Azure CLI authentication)
- Durable Task Scheduler must be running (e.g., using Docker)
@@ -1,3 +1,5 @@
# Copyright (c) Microsoft. All rights reserved.
"""Worker process for hosting a single Azure OpenAI-powered agent using Durable Task.
This worker registers agents as durable entities and continuously listens for requests.
@@ -1,12 +1,14 @@
# Copyright (c) Microsoft. All rights reserved.
"""Client application for interacting with multiple hosted agents.
This client connects to the Durable Task Scheduler and interacts with two different
agents (WeatherAgent and MathAgent), demonstrating how to work with multiple agents
each with their own specialized capabilities and tools.
Prerequisites:
Prerequisites:
- The worker must be running with both agents registered
- Set AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_CHAT_DEPLOYMENT_NAME
- Set AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_CHAT_DEPLOYMENT_NAME
(plus AZURE_OPENAI_API_KEY or Azure CLI authentication)
- Durable Task Scheduler must be running
"""
@@ -30,12 +32,12 @@ def get_client(
log_handler: logging.Handler | None = None
) -> DurableAIAgentClient:
"""Create a configured DurableAIAgentClient.
Args:
taskhub: Task hub name (defaults to TASKHUB env var or "default")
endpoint: Scheduler endpoint (defaults to ENDPOINT env var or "http://localhost:8080")
log_handler: Optional logging handler for client logging
Returns:
Configured DurableAIAgentClient instance
"""
@@ -60,7 +62,7 @@ def get_client(
def run_client(agent_client: DurableAIAgentClient) -> None:
"""Run client interactions with both WeatherAgent and MathAgent.
Args:
agent_client: The DurableAIAgentClient instance
"""
@@ -1,11 +1,13 @@
# Copyright (c) Microsoft. All rights reserved.
"""Multi-Agent Sample - Durable Task Integration (Combined Worker + Client)
This sample demonstrates running both the worker and client in a single process
for multiple agents with different tools. The worker registers two agents
(WeatherAgent and MathAgent), each with their own specialized capabilities.
Prerequisites:
- Set AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_CHAT_DEPLOYMENT_NAME
Prerequisites:
- Set AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_CHAT_DEPLOYMENT_NAME
(plus AZURE_OPENAI_API_KEY or Azure CLI authentication)
- Durable Task Scheduler must be running (e.g., using Docker)
@@ -1,3 +1,5 @@
# Copyright (c) Microsoft. All rights reserved.
"""Worker process for hosting multiple agents with different tools using Durable Task.
This worker registers two agents - a weather assistant and a math assistant - each
@@ -7,7 +7,7 @@ This client demonstrates:
2. Streaming the response from Redis in real-time
3. Handling reconnection and cursor-based resumption
Prerequisites:
Prerequisites:
- The worker must be running with the TravelPlanner agent registered
- Set AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_CHAT_DEPLOYMENT_NAME
- Redis must be running
@@ -59,12 +59,12 @@ def get_client(
log_handler: logging.Handler | None = None
) -> DurableAIAgentClient:
"""Create a configured DurableAIAgentClient.
Args:
taskhub: Task hub name (defaults to TASKHUB env var or "default")
endpoint: Scheduler endpoint (defaults to ENDPOINT env var or "http://localhost:8080")
log_handler: Optional log handler for client logging
Returns:
Configured DurableAIAgentClient instance
"""
@@ -89,7 +89,7 @@ def get_client(
async def stream_from_redis(thread_id: str, cursor: str | None = None) -> None:
"""Stream agent responses from Redis.
Args:
thread_id: The conversation/thread ID to stream from
cursor: Optional cursor to resume from. If None, starts from beginning.
@@ -132,7 +132,7 @@ async def stream_from_redis(thread_id: str, cursor: str | None = None) -> None:
def run_client(agent_client: DurableAIAgentClient) -> None:
"""Run client interactions with the TravelPlanner agent.
Args:
agent_client: The DurableAIAgentClient instance
"""
@@ -8,8 +8,8 @@ with reliable Redis-based streaming for agent responses.
The worker is started first to register the TravelPlanner agent with Redis streaming
callback, then client operations are performed against the running worker.
Prerequisites:
- Set AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_CHAT_DEPLOYMENT_NAME
Prerequisites:
- Set AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_CHAT_DEPLOYMENT_NAME
(plus AZURE_OPENAI_API_KEY or Azure CLI authentication)
- Durable Task Scheduler must be running (e.g., using Docker)
- Redis must be running (e.g., docker run -d --name redis -p 6379:6379 redis:latest)
@@ -5,8 +5,8 @@
This worker registers the TravelPlanner agent with the Durable Task Scheduler
and uses RedisStreamCallback to persist streaming responses to Redis for reliable delivery.
Prerequisites:
- Set AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_CHAT_DEPLOYMENT_NAME
Prerequisites:
- Set AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_CHAT_DEPLOYMENT_NAME
(plus AZURE_OPENAI_API_KEY or Azure CLI authentication)
- Start a Durable Task Scheduler (e.g., using Docker)
- Start Redis (e.g., docker run -d --name redis -p 6379:6379 redis:latest)
@@ -145,7 +145,7 @@ class RedisStreamCallback(AgentResponseCallbackProtocol):
def create_travel_agent() -> "ChatAgent":
"""Create the TravelPlanner agent using Azure OpenAI.
Returns:
ChatAgent: The configured TravelPlanner agent with travel planning tools.
"""
@@ -174,12 +174,12 @@ def get_worker(
log_handler: logging.Handler | None = None
) -> DurableTaskSchedulerWorker:
"""Create a configured DurableTaskSchedulerWorker.
Args:
taskhub: Task hub name (defaults to TASKHUB env var or "default")
endpoint: Scheduler endpoint (defaults to ENDPOINT env var or "http://localhost:8080")
log_handler: Optional log handler for worker logging
Returns:
Configured DurableTaskSchedulerWorker instance
"""
@@ -202,10 +202,10 @@ def get_worker(
def setup_worker(worker: DurableTaskSchedulerWorker) -> DurableAIAgentWorker:
"""Set up the worker with the TravelPlanner agent and Redis streaming callback.
Args:
worker: The DurableTaskSchedulerWorker instance
Returns:
DurableAIAgentWorker with agent and callback registered
"""
@@ -1,12 +1,14 @@
# Copyright (c) Microsoft. All rights reserved.
"""Client application for starting a single agent chaining orchestration.
This client connects to the Durable Task Scheduler and starts an orchestration
that runs a writer agent twice sequentially on the same thread, demonstrating
how conversation context is maintained across multiple agent invocations.
Prerequisites:
Prerequisites:
- The worker must be running with the writer agent and orchestration registered
- Set AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_CHAT_DEPLOYMENT_NAME
- Set AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_CHAT_DEPLOYMENT_NAME
(plus AZURE_OPENAI_API_KEY or Azure CLI authentication)
- Durable Task Scheduler must be running
"""
@@ -30,12 +32,12 @@ def get_client(
log_handler: logging.Handler | None = None
) -> DurableTaskSchedulerClient:
"""Create a configured DurableTaskSchedulerClient.
Args:
taskhub: Task hub name (defaults to TASKHUB env var or "default")
endpoint: Scheduler endpoint (defaults to ENDPOINT env var or "http://localhost:8080")
log_handler: Optional logging handler for client logging
Returns:
Configured DurableTaskSchedulerClient instance
"""
@@ -58,7 +60,7 @@ def get_client(
def run_client(client: DurableTaskSchedulerClient) -> None:
"""Run client to start and monitor the orchestration.
Args:
client: The DurableTaskSchedulerClient instance
"""
@@ -1,3 +1,5 @@
# Copyright (c) Microsoft. All rights reserved.
"""Single Agent Orchestration Chaining Sample - Durable Task Integration
This sample demonstrates chaining two invocations of the same agent inside a Durable Task
@@ -10,8 +12,8 @@ Components used:
- DurableTaskSchedulerClient and orchestration for sequential agent invocations
- Thread management to maintain conversation context across invocations
Prerequisites:
- Set AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_CHAT_DEPLOYMENT_NAME
Prerequisites:
- Set AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_CHAT_DEPLOYMENT_NAME
(plus AZURE_OPENAI_API_KEY or Azure CLI authentication)
- Durable Task Scheduler must be running (e.g., using Docker emulator)
@@ -1,11 +1,13 @@
# Copyright (c) Microsoft. All rights reserved.
"""Worker process for hosting a single agent with chaining orchestration using Durable Task.
This worker registers a writer agent and an orchestration function that demonstrates
chaining behavior by running the agent twice sequentially on the same thread,
preserving conversation context between invocations.
Prerequisites:
- Set AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_CHAT_DEPLOYMENT_NAME
Prerequisites:
- Set AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_CHAT_DEPLOYMENT_NAME
(plus AZURE_OPENAI_API_KEY or Azure CLI authentication)
- Start a Durable Task Scheduler (e.g., using Docker)
"""
@@ -31,10 +33,10 @@ WRITER_AGENT_NAME = "WriterAgent"
def create_writer_agent() -> "ChatAgent":
"""Create the Writer agent using Azure OpenAI.
This agent refines short pieces of text, enhancing initial sentences
and polishing improved versions further.
Returns:
ChatAgent: The configured Writer agent
"""
@@ -51,7 +53,7 @@ def create_writer_agent() -> "ChatAgent":
def get_orchestration():
"""Get the orchestration function for this sample.
Returns:
The orchestration function to register with the worker
"""
@@ -62,18 +64,18 @@ def single_agent_chaining_orchestration(
context: OrchestrationContext, _: str
) -> Generator[Task[AgentResponse], AgentResponse, str]:
"""Orchestration that runs the writer agent twice on the same thread.
This demonstrates chaining behavior where the output of the first agent run
becomes part of the input for the second run, all while maintaining the
conversation context through a shared thread.
Args:
context: The orchestration context
_: Input parameter (unused)
Yields:
Task[AgentRunResponse]: Tasks that resolve to AgentRunResponse
Returns:
str: The final refined text from the second agent run
"""
@@ -123,12 +125,12 @@ def get_worker(
log_handler: logging.Handler | None = None
) -> DurableTaskSchedulerWorker:
"""Create a configured DurableTaskSchedulerWorker.
Args:
taskhub: Task hub name (defaults to TASKHUB env var or "default")
endpoint: Scheduler endpoint (defaults to ENDPOINT env var or "http://localhost:8080")
log_handler: Optional logging handler for worker logging
Returns:
Configured DurableTaskSchedulerWorker instance
"""
@@ -151,10 +153,10 @@ def get_worker(
def setup_worker(worker: DurableTaskSchedulerWorker) -> DurableAIAgentWorker:
"""Set up the worker with agents and orchestrations registered.
Args:
worker: The DurableTaskSchedulerWorker instance
Returns:
DurableAIAgentWorker with agents and orchestrations registered
"""
@@ -1,12 +1,14 @@
# Copyright (c) Microsoft. All rights reserved.
"""Client application for starting a multi-agent concurrent orchestration.
This client connects to the Durable Task Scheduler and starts an orchestration
that runs two agents (physicist and chemist) concurrently, then retrieves and
displays the aggregated results.
Prerequisites:
Prerequisites:
- The worker must be running with both agents and orchestration registered
- Set AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_CHAT_DEPLOYMENT_NAME
- Set AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_CHAT_DEPLOYMENT_NAME
(plus AZURE_OPENAI_API_KEY or Azure CLI authentication)
- Durable Task Scheduler must be running
"""
@@ -30,12 +32,12 @@ def get_client(
log_handler: logging.Handler | None = None
) -> DurableTaskSchedulerClient:
"""Create a configured DurableTaskSchedulerClient.
Args:
taskhub: Task hub name (defaults to TASKHUB env var or "default")
endpoint: Scheduler endpoint (defaults to ENDPOINT env var or "http://localhost:8080")
log_handler: Optional logging handler for client logging
Returns:
Configured DurableTaskSchedulerClient instance
"""
@@ -58,7 +60,7 @@ def get_client(
def run_client(client: DurableTaskSchedulerClient, prompt: str = "What is temperature?") -> None:
"""Run client to start and monitor the orchestration.
Args:
client: The DurableTaskSchedulerClient instance
prompt: The prompt to send to both agents
@@ -1,3 +1,5 @@
# Copyright (c) Microsoft. All rights reserved.
"""Multi-Agent Orchestration Sample - Durable Task Integration (Combined Worker + Client)
This sample demonstrates running both the worker and client in a single process for
@@ -7,8 +9,8 @@ concurrent multi-agent orchestration. The worker registers two domain-specific a
The orchestration uses OrchestrationAgentExecutor to execute agents concurrently
and aggregate their responses.
Prerequisites:
- Set AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_CHAT_DEPLOYMENT_NAME
Prerequisites:
- Set AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_CHAT_DEPLOYMENT_NAME
(plus AZURE_OPENAI_API_KEY or Azure CLI authentication)
- Durable Task Scheduler must be running (e.g., using Docker)
@@ -1,11 +1,13 @@
# Copyright (c) Microsoft. All rights reserved.
"""Worker process for hosting multiple agents with orchestration using Durable Task.
This worker registers two domain-specific agents (physicist and chemist) and an orchestration
function that runs them concurrently. The orchestration uses OrchestrationAgentExecutor
function that runs them concurrently. The orchestration uses OrchestrationAgentExecutor
to execute agents in parallel and aggregate their responses.
Prerequisites:
- Set AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_CHAT_DEPLOYMENT_NAME
Prerequisites:
- Set AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_CHAT_DEPLOYMENT_NAME
(plus AZURE_OPENAI_API_KEY or Azure CLI authentication)
- Start a Durable Task Scheduler (e.g., using Docker)
"""
@@ -33,7 +35,7 @@ CHEMIST_AGENT_NAME = "ChemistAgent"
def create_physicist_agent() -> "ChatAgent":
"""Create the Physicist agent using Azure OpenAI.
Returns:
ChatAgent: The configured Physicist agent
"""
@@ -45,7 +47,7 @@ def create_physicist_agent() -> "ChatAgent":
def create_chemist_agent() -> "ChatAgent":
"""Create the Chemist agent using Azure OpenAI.
Returns:
ChatAgent: The configured Chemist agent
"""
@@ -57,14 +59,14 @@ def create_chemist_agent() -> "ChatAgent":
def multi_agent_concurrent_orchestration(context: OrchestrationContext, prompt: str) -> Generator[Task[Any], Any, dict[str, str]]:
"""Orchestration that runs both agents in parallel and aggregates results.
Uses DurableAIAgentOrchestrationContext to wrap the orchestration context and
access agents via the OrchestrationAgentExecutor.
Args:
context: The orchestration context
prompt: The prompt to send to both agents
Returns:
dict: Dictionary with 'physicist' and 'chemist' response texts
"""
@@ -115,12 +117,12 @@ def get_worker(
log_handler: logging.Handler | None = None
) -> DurableTaskSchedulerWorker:
"""Create a configured DurableTaskSchedulerWorker.
Args:
taskhub: Task hub name (defaults to TASKHUB env var or "default")
endpoint: Scheduler endpoint (defaults to ENDPOINT env var or "http://localhost:8080")
log_handler: Optional logging handler for worker logging
Returns:
Configured DurableTaskSchedulerWorker instance
"""
@@ -143,10 +145,10 @@ def get_worker(
def setup_worker(worker: DurableTaskSchedulerWorker) -> DurableAIAgentWorker:
"""Set up the worker with agents and orchestrations registered.
Args:
worker: The DurableTaskSchedulerWorker instance
Returns:
DurableAIAgentWorker with agents and orchestrations registered
"""
@@ -1,11 +1,13 @@
# Copyright (c) Microsoft. All rights reserved.
"""Client application for starting a spam detection orchestration.
This client connects to the Durable Task Scheduler and starts an orchestration
that uses conditional logic to either handle spam emails or draft professional responses.
Prerequisites:
Prerequisites:
- The worker must be running with both agents, orchestration, and activities registered
- Set AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_CHAT_DEPLOYMENT_NAME
- Set AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_CHAT_DEPLOYMENT_NAME
(plus AZURE_OPENAI_API_KEY or Azure CLI authentication)
- Durable Task Scheduler must be running
"""
@@ -28,12 +30,12 @@ def get_client(
log_handler: logging.Handler | None = None
) -> DurableTaskSchedulerClient:
"""Create a configured DurableTaskSchedulerClient.
Args:
taskhub: Task hub name (defaults to TASKHUB env var or "default")
endpoint: Scheduler endpoint (defaults to ENDPOINT env var or "http://localhost:8080")
log_handler: Optional logging handler for client logging
Returns:
Configured DurableTaskSchedulerClient instance
"""
@@ -60,7 +62,7 @@ def run_client(
email_content: str = "Hello! I wanted to reach out about our upcoming project meeting."
) -> None:
"""Run client to start and monitor the spam detection orchestration.
Args:
client: The DurableTaskSchedulerClient instance
email_id: The email ID
@@ -1,3 +1,5 @@
# Copyright (c) Microsoft. All rights reserved.
"""Multi-Agent Orchestration with Conditionals Sample - Durable Task Integration
This sample demonstrates conditional orchestration logic with two agents:
@@ -7,8 +9,8 @@ This sample demonstrates conditional orchestration logic with two agents:
The orchestration branches based on spam detection results, calling different
activity functions to handle spam or send legitimate email responses.
Prerequisites:
- Set AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_CHAT_DEPLOYMENT_NAME
Prerequisites:
- Set AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_CHAT_DEPLOYMENT_NAME
(plus AZURE_OPENAI_API_KEY or Azure CLI authentication)
- Durable Task Scheduler must be running (e.g., using Docker)
@@ -1,3 +1,5 @@
# Copyright (c) Microsoft. All rights reserved.
"""Worker process for hosting spam detection and email assistant agents with conditional orchestration.
This worker registers two domain-specific agents (spam detector and email assistant) and an
@@ -51,7 +53,7 @@ class EmailPayload(BaseModel):
def create_spam_agent() -> "ChatAgent":
"""Create the Spam Detection agent using Azure OpenAI.
Returns:
ChatAgent: The configured Spam Detection agent
"""
@@ -63,7 +65,7 @@ def create_spam_agent() -> "ChatAgent":
def create_email_agent() -> "ChatAgent":
"""Create the Email Assistant agent using Azure OpenAI.
Returns:
ChatAgent: The configured Email Assistant agent
"""
@@ -75,11 +77,11 @@ def create_email_agent() -> "ChatAgent":
def handle_spam_email(context: ActivityContext, reason: str) -> str:
"""Activity function to handle spam emails.
Args:
context: The activity context
reason: The reason why the email was marked as spam
Returns:
str: Confirmation message
"""
@@ -89,11 +91,11 @@ def handle_spam_email(context: ActivityContext, reason: str) -> str:
def send_email(context: ActivityContext, message: str) -> str:
"""Activity function to send emails.
Args:
context: The activity context
message: The email message to send
Returns:
str: Confirmation message
"""
@@ -103,17 +105,17 @@ def send_email(context: ActivityContext, message: str) -> str:
def spam_detection_orchestration(context: OrchestrationContext, payload_raw: Any) -> Generator[Task[Any], Any, str]:
"""Orchestration that detects spam and conditionally drafts email responses.
This orchestration:
1. Validates the input payload
2. Runs the spam detection agent
3. If spam: calls handle_spam_email activity
4. If legitimate: runs email assistant agent and calls send_email activity
Args:
context: The orchestration context
payload_raw: The input payload dictionary
Returns:
str: Result message from activity functions
"""
@@ -198,12 +200,12 @@ def get_worker(
log_handler: logging.Handler | None = None
) -> DurableTaskSchedulerWorker:
"""Create a configured DurableTaskSchedulerWorker.
Args:
taskhub: Task hub name (defaults to TASKHUB env var or "default")
endpoint: Scheduler endpoint (defaults to ENDPOINT env var or "http://localhost:8080")
log_handler: Optional logging handler for worker logging
Returns:
Configured DurableTaskSchedulerWorker instance
"""
@@ -226,10 +228,10 @@ def get_worker(
def setup_worker(worker: DurableTaskSchedulerWorker) -> DurableAIAgentWorker:
"""Set up the worker with agents, orchestrations, and activities registered.
Args:
worker: The DurableTaskSchedulerWorker instance
Returns:
DurableAIAgentWorker with agents, orchestrations, and activities registered
"""
@@ -1,11 +1,13 @@
# Copyright (c) Microsoft. All rights reserved.
"""Client application for starting a human-in-the-loop content generation orchestration.
This client connects to the Durable Task Scheduler and demonstrates the HITL pattern
by starting an orchestration, sending approval/rejection events, and monitoring progress.
Prerequisites:
Prerequisites:
- The worker must be running with the agent, orchestration, and activities registered
- Set AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_CHAT_DEPLOYMENT_NAME
- Set AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_CHAT_DEPLOYMENT_NAME
(plus AZURE_OPENAI_API_KEY or Azure CLI authentication)
- Durable Task Scheduler must be running
"""
@@ -34,12 +36,12 @@ def get_client(
log_handler: logging.Handler | None = None
) -> DurableTaskSchedulerClient:
"""Create a configured DurableTaskSchedulerClient.
Args:
taskhub: Task hub name (defaults to TASKHUB env var or "default")
endpoint: Scheduler endpoint (defaults to ENDPOINT env var or "http://localhost:8080")
log_handler: Optional logging handler for client logging
Returns:
Configured DurableTaskSchedulerClient instance
"""
@@ -64,7 +66,7 @@ def _log_completion_result(
metadata: OrchestrationState | None,
) -> None:
"""Log the orchestration completion result.
Args:
metadata: The orchestration metadata
"""
@@ -94,7 +96,7 @@ def _wait_and_log_completion(
timeout: int = 60
) -> None:
"""Wait for orchestration completion and log the result.
Args:
client: The DurableTaskSchedulerClient instance
instance_id: The orchestration instance ID
@@ -116,7 +118,7 @@ def send_approval(
feedback: str = ""
) -> None:
"""Send approval or rejection event to the orchestration.
Args:
client: The DurableTaskSchedulerClient instance
instance_id: The orchestration instance ID
@@ -148,14 +150,14 @@ def wait_for_notification(
timeout_seconds: int = 10
) -> bool:
"""Wait for the orchestration to reach a notification point.
Polls the orchestration status until it appears to be waiting for approval.
Args:
client: The DurableTaskSchedulerClient instance
instance_id: The orchestration instance ID
timeout_seconds: Maximum time to wait
Returns:
True if notification detected, False if timeout
"""
@@ -202,7 +204,7 @@ def wait_for_notification(
def run_interactive_client(client: DurableTaskSchedulerClient) -> None:
"""Run an interactive client that prompts for user input and handles approval workflow.
Args:
client: The DurableTaskSchedulerClient instance
"""
@@ -1,3 +1,5 @@
# Copyright (c) Microsoft. All rights reserved.
"""Human-in-the-Loop Orchestration Sample - Durable Task Integration
This sample demonstrates the HITL pattern with a WriterAgent that generates content
@@ -7,8 +9,8 @@ and waits for human approval. The orchestration handles:
- Iterative refinement based on feedback
- Activity functions for notifications and publishing
Prerequisites:
- Set AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_CHAT_DEPLOYMENT_NAME
Prerequisites:
- Set AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_CHAT_DEPLOYMENT_NAME
(plus AZURE_OPENAI_API_KEY or Azure CLI authentication)
- Durable Task Scheduler must be running (e.g., using Docker)
@@ -1,11 +1,13 @@
# Copyright (c) Microsoft. All rights reserved.
"""Worker process for hosting a writer agent with human-in-the-loop orchestration.
This worker registers a WriterAgent and an orchestration function that implements
a human-in-the-loop review workflow. The orchestration pauses for external events
(human approval/rejection) with timeout handling, and iterates based on feedback.
Prerequisites:
- Set AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_CHAT_DEPLOYMENT_NAME
Prerequisites:
- Set AZURE_OPENAI_ENDPOINT and AZURE_OPENAI_CHAT_DEPLOYMENT_NAME
(plus AZURE_OPENAI_API_KEY or Azure CLI authentication)
- Start a Durable Task Scheduler (e.g., using Docker)
"""
@@ -54,7 +56,7 @@ class HumanApproval(BaseModel):
def create_writer_agent() -> "ChatAgent":
"""Create the Writer agent using Azure OpenAI.
Returns:
ChatAgent: The configured Writer agent
"""
@@ -73,7 +75,7 @@ def create_writer_agent() -> "ChatAgent":
def notify_user_for_approval(context: ActivityContext, content: dict[str, str]) -> str:
"""Activity function to notify user for approval.
Args:
context: The activity context
content: The generated content dictionary
@@ -88,7 +90,7 @@ def notify_user_for_approval(context: ActivityContext, content: dict[str, str])
def publish_content(context: ActivityContext, content: dict[str, str]) -> str:
"""Activity function to publish approved content.
Args:
context: The activity context
content: The generated content dictionary
@@ -105,7 +107,7 @@ def content_generation_hitl_orchestration(
payload_raw: Any
) -> Generator[Task[Any], Any, dict[str, str]]:
"""Human-in-the-loop orchestration for content generation with approval workflow.
This orchestration:
1. Generates initial content using WriterAgent
2. Loops up to max_review_attempts times:
@@ -115,14 +117,14 @@ def content_generation_hitl_orchestration(
d. If rejected: incorporates feedback and regenerates
e. If timeout: raises TimeoutError
3. Raises RuntimeError if max attempts exhausted
Args:
context: The orchestration context
payload_raw: The input payload
Returns:
dict: Result with published content
Raises:
ValueError: If input is invalid or agent returns no content
TimeoutError: If human approval times out
@@ -285,12 +287,12 @@ def get_worker(
log_handler: logging.Handler | None = None
) -> DurableTaskSchedulerWorker:
"""Create a configured DurableTaskSchedulerWorker.
Args:
taskhub: Task hub name (defaults to TASKHUB env var or "default")
endpoint: Scheduler endpoint (defaults to ENDPOINT env var or "http://localhost:8080")
log_handler: Optional logging handler for worker logging
Returns:
Configured DurableTaskSchedulerWorker instance
"""
@@ -313,10 +315,10 @@ def get_worker(
def setup_worker(worker: DurableTaskSchedulerWorker) -> DurableAIAgentWorker:
"""Set up the worker with agents, orchestrations, and activities registered.
Args:
worker: The DurableTaskSchedulerWorker instance
Returns:
DurableAIAgentWorker with agents, orchestrations, and activities registered
"""