Skip to content

Latest commit

 

History

History

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

README.md

Durable Task Samples

This directory contains samples for durable agent hosting using the Durable Task Scheduler. These samples demonstrate the worker-client architecture pattern, enabling distributed agent execution with persistent conversation state.

Warning

Breaking change on this branch. The unreleased schema-v2 runtime requires DURABLE_AGENTS_DEPLOYMENT_MODE=isolated_v2 before a sample host starts. Set it only for a new, empty, uniquely named task hub with upgraded clients and no old or unrelated workers. Do not use default, an old shared hub, or upgrade a live hub in place. Start fresh workflow instances after this update, even when upgrading from an earlier v2 build. Protocol 2 is unchanged, but older v2 in-flight instances and recorded histories are unsupported and may fail under the revised HITL checkpoints and mixed parent/child scheduling. The marker checks start admission, not feature or replay compatibility. Keep old runs on their original deployment if they must finish. This is an operator acknowledgement, not proof of isolation or production readiness. There is no automatic isolation check, compatibility fallback, or history migration. Follow Environment Configuration for standalone and Azure Functions setup.

Import convention

These samples import the durable hosting types directly from the extension packages, agent_framework_durabletask and agent_framework_azurefunctions.

from agent_framework_durabletask import DurableAIAgentWorker, DurableWorkflowClient
from agent_framework_azurefunctions import AgentFunctionApp

For backward compatibility these entry-point types are also re-exported from agent_framework.azure in the core agent-framework package, so existing from agent_framework.azure import ... code keeps working. New and updated samples should use the direct package imports shown above rather than the agent_framework.azure shim.

Quick Prerequisites Checklist

Install and verify these tools before Running the Samples:

  • Docker – run the Durable Task Scheduler emulator locally
  • uv – manage Python dependencies (optional but recommended)
  • Azure CLI – authenticate with az login for AzureCliCredential

Windows (PowerShell):

winget install Docker.DockerDesktop
irm https://astral.sh/uv/install.ps1 | iex
winget install Microsoft.AzureCLI

macOS / Linux:

# Docker: https://docs.docker.com/get-docker/
curl -LsSf https://astral.sh/uv/install.sh | sh
# Azure CLI: https://learn.microsoft.com/cli/azure/install-azure-cli

Verify:

docker --version
uv --version
az account show

Sample Catalog

Basic Patterns

  • 01_single_agent: Host a single conversational agent and interact with it via a client. Demonstrates basic worker-client architecture and agent state management.
  • 02_multi_agent: Host multiple domain-specific agents (physicist and chemist) and route requests to the appropriate agent based on the question topic.
  • 03_single_agent_streaming: Enable reliable, resumable streaming using Redis Streams with agent response callbacks. Demonstrates non-blocking agent execution and cursor-based resumption for disconnected clients.

Orchestration Patterns

Workflow Hosting Patterns

  • 08_workflow: Host a MAF Workflow as a durable orchestration on a standalone worker via DurableAIAgentWorker.configure_workflow. Demonstrates conditional routing and mixing AI agents with non-agent executors.
  • 09_workflow_hitl: A workflow that pauses for human approval using ctx.request_info / @response_handler, with the client discovering and answering the pending request.
  • 10_workflow_streaming: Stream a hosted workflow's events as typed WorkflowEvent objects by polling the orchestration's custom status.
  • 11_subworkflow: Compose workflows by embedding an inner Workflow as a node via WorkflowExecutor. On the durable host the inner workflow runs as its own child orchestration, and a single configure_workflow call registers both.
  • 12_subworkflow_hitl: A human-in-the-loop pause that lives inside a sub-workflow. The nested request surfaces to the client with a qualified request id ({executor}~{ordinal}~{requestId}) behind a single top-level addressing surface.

History and Retention

  • 13_conversation_compaction shows durable history with compaction and independent eager-pruning and pressure-budget settings.
  • 14_external_history_redis keeps Redis as the primary history store, separate from durable response delivery and local retention.

Azure Functions Hosting

These samples host workflows and agents on Azure Durable Functions (func start) instead of the worker-client model above. Each has its own setup steps in its README, and shared environment setup lives in azure_functions/README.md.

Retention Defaults

The retention default is retention="keep_all". Standalone DurableTaskSchedulerWorker hosts use a 1 MiB pressure budget when max_state_bytes is omitted. Explicit None opts out. Generic workers and Azure Functions remain disabled by default. Compaction does not itself delete stored messages unless follow_compaction is enabled. Pressure eviction independently triggers at the 0.85 high watermark toward 0.70, subject to protected state. The whole-entity ASCII-escaped JSON estimate is not a backend acceptance guarantee. "backend_limit" resolves to 1 MiB only with DurableTaskSchedulerWorker. Azure Functions rejects it. Samples that explicitly pass max_state_bytes=None continue to disable pressure eviction.

Completion and ingestion receipts, live results and session/control state survive transcript eviction. An unreachable protected floor raises StateCapacityError. There is no bounded receipt cleanup, and idle response expiry needs application-owned maintenance. Retention metrics describe staged changes, never confirmed commits. Per-agent and workflow budget overrides use INHERIT to inherit and None to disable pressure eviction. See the package's retention contract and metric semantics.

Running the Samples

These samples are designed to be run locally in a cloned repository.

Prerequisites

The following prerequisites are required for the standalone samples. For Functions, use the Functions prerequisites.

Configuring RBAC Permissions for Azure OpenAI

These samples are configured to use the Azure OpenAI service with RBAC permissions to access the model. You'll need to configure the RBAC permissions for the Azure OpenAI service to allow the Python app to access the model.

Below is an example of how to configure the RBAC permissions for the Azure OpenAI service to allow the current user to access the model.

Bash (Linux/macOS/WSL):

az role assignment create \
  --assignee "[email protected]" \
  --role "Cognitive Services OpenAI User" \
  --scope /subscriptions/<your-subscription-id>/resourceGroups/<your-resource-group-name>/providers/Microsoft.CognitiveServices/accounts/<your-openai-resource-name>

PowerShell:

az role assignment create `
  --assignee "[email protected]" `
  --role "Cognitive Services OpenAI User" `
  --scope /subscriptions/<your-subscription-id>/resourceGroups/<your-resource-group-name>/providers/Microsoft.CognitiveServices/accounts/<your-openai-resource-name>

More information on how to configure RBAC permissions for Azure OpenAI can be found in the Azure OpenAI documentation.

Start Durable Task Scheduler

The standalone samples use the Durable Task Scheduler (DTS) to support hosted agents and durable orchestrations. DTS also provides a dashboard for their state. The Azure Functions samples ship with the default Azure Storage backend, using Azurite locally. A DTS connection string alone does not change that backend. See the optional Functions DTS setup.

To run the Durable Task Scheduler locally, you can use the following docker command:

docker run -d --name dts-emulator -p 8080:8080 -p 8082:8082 -e DTS_USE_DYNAMIC_TASK_HUBS=true mcr.microsoft.com/dts/dts-emulator:latest

Dynamic task hubs allow the emulator to create the fresh named hubs used below, matching the CI setup. This does not verify isolation. The DTS dashboard will be available at http://localhost:8082.

Environment Configuration

Required isolated-v2 acknowledgement

Choose a new, unique alphanumeric hub name starting with a letter. The examples use durablesamplev2UNIQUE as a placeholder. Replace UNIQUE with your own unique alphanumeric suffix and use the resulting name consistently. Verify the hub is empty and reserved for this sample deployment. Provision the hub first when using an Azure-hosted scheduler. Do not reuse default or a hub containing old state, even if another sample guide or template uses it.

Upgrade all clients that will access the new hub to match this branch's runtime. Keep old workers and clients off the new hub and start new workflow instances. If old runs must finish, retain their original deployment. Setting the flag, retaining protocol 2, or rewrapping an old start input does not migrate history. Do not hard-code deployment_mode in sample workers or add an automatic fallback to bypass this deployment decision.

Standalone samples

Set these variables in both the worker and client terminals, using the same chosen hub name and endpoint. For combined samples, set them in the terminal running the sample. The endpoint below is for the local emulator.

Standalone workers and clients reject a missing, blank, or case-insensitive default TASKHUB value before they construct a scheduler connection. This keeps a sample from silently attaching to a shared live hub when the environment is incomplete.

POSIX shell (Linux/macOS/WSL):

export FOUNDRY_PROJECT_ENDPOINT="https://your-project.services.ai.azure.com/api/projects/your-project"
export FOUNDRY_MODEL="your-deployment-name"
export ENDPOINT="http://localhost:8080"
export TASKHUB="durablesamplev2UNIQUE"
export DURABLE_AGENTS_DEPLOYMENT_MODE="isolated_v2"

PowerShell:

$env:FOUNDRY_PROJECT_ENDPOINT="https://your-project.services.ai.azure.com/api/projects/your-project"
$env:FOUNDRY_MODEL="your-deployment-name"
$env:ENDPOINT="http://localhost:8080"
$env:TASKHUB="durablesamplev2UNIQUE"
$env:DURABLE_AGENTS_DEPLOYMENT_MODE="isolated_v2"

For host-generated workflows, use the upgraded DurableWorkflowClient.start_workflow with the application input and workflow name (or a constructor default). It supplies the v2 start envelope. Azure Functions generated workflow start routes do the same. Application-owned native orchestrators keep their original raw input contracts. Do not wrap their payloads.

Azure Functions samples

Copy the sample's local-settings template as described in azure_functions/README.md, then merge these entries into its Values object before func start. Keep the existing storage, model, and other sample settings. Replace every durablesamplev2UNIQUE with the same new, empty hub name chosen for that function app. These settings supersede older instructions to leave the hub as default.

{
  "Values": {
    "DURABLE_AGENTS_DEPLOYMENT_MODE": "isolated_v2",
    "TASKHUB_NAME": "durablesamplev2UNIQUE",
    "AzureFunctionsJobHost__extensions__durableTask__hubName": "durablesamplev2UNIQUE"
  }
}

The host setting explicitly selects the hub even for samples without a TASKHUB_NAME binding. Keep it and TASKHUB_NAME identical. As shipped, Functions uses Azure Storage through AzureWebJobsStorage, so verify the new hub is isolated in that storage account or local Azurite instance. Setting DURABLE_TASK_SCHEDULER_CONNECTION_STRING does not select DTS. To opt in on a new deployment, configure storageProvider.type="azureManaged", a supporting host extension, and a connection string whose TaskHub matches the host hub. Follow the optional Functions DTS setup. Do not switch an existing hub's backend as a migration. See also the Azure Functions host configuration override guidance.

Installing Dependencies

Navigate to the sample directory and install dependencies. For example:

cd samples/01_single_agent
pip install -r requirements.txt

If you're using uv for package management:

uv pip install -r requirements.txt

Starting Workers and Clients

Each sample follows a worker-client architecture. Most samples provide separate worker.py and client.py files, though some include a combined sample.py for convenience.

Running with separate worker and client:

In one terminal, start the worker:

python worker.py

In another terminal, run the client:

python client.py

Running with combined sample:

python sample.py

Viewing the Sample Output

The sample output is displayed directly in the terminal where you ran the Python script. Agent responses are printed to stdout with log formatting for better readability.

For standalone samples or Functions deployments explicitly using DTS, you can also see the state of agents and orchestrations in its dashboard at http://localhost:8082. Functions deployments using the default Azure Storage backend do not appear there.