chore: import upstream snapshot with attribution
dotnet-build-and-test / dotnet-test-functions (push) Has been cancelled
dotnet-build-and-test / paths-filter (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Debug, windows-latest, net9.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Release, ubuntu-latest, net10.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Release, ubuntu-latest, net8.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Release, windows-latest, net472) (push) Has been cancelled
dotnet-build-and-test / dotnet-test (Release, integration, true, ubuntu-latest, net10.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-test (Release, integration, true, windows-latest, net472) (push) Has been cancelled
dotnet-build-and-test / dotnet-foundry-hosted-it (push) Has been cancelled
dotnet-build-and-test / dotnet-build-and-test-check (push) Has been cancelled
dotnet-build-and-test / Integration Test Report (push) Has been cancelled
CodeQL / Analyze (csharp) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 13:39:25 +08:00
commit db620d33df
5151 changed files with 925932 additions and 0 deletions
@@ -0,0 +1,104 @@
# Multi-Agent Sample
This sample demonstrates how to use the Durable Extension for Agent Framework to create an Azure Functions app that hosts multiple AI agents and provides direct HTTP API access for interactive conversations with each agent.
## Key Concepts Demonstrated
- Using the Microsoft Agent Framework to define multiple AI agents with unique names and instructions.
- Registering multiple agents with the Function app and running them using HTTP.
- Conversation management (via session IDs) for isolated interactions per agent.
- Two different methods for registering agents: list-based initialization and incremental addition.
## Prerequisites
Complete the common environment preparation steps described in `../README.md`, including installing Azure Functions Core Tools, starting Azurite, configuring Azure OpenAI settings, and installing this sample's requirements.
## Running the Sample
With the environment setup and function app running, you can test the sample by sending HTTP requests to the different agent endpoints.
You can use the `demo.http` file to send messages to the agents, or a command line tool like `curl` as shown below:
> **Note:** Each endpoint waits for the agent response by default. To receive an immediate HTTP 202 instead, set the `x-ms-wait-for-response` header or include `"wait_for_response": false` in the request body.
### Test the Weather Agent
Bash (Linux/macOS/WSL):
Weather agent request:
```bash
curl -X POST http://localhost:7071/api/agents/WeatherAgent/run \
-H "Content-Type: application/json" \
-d '{"message": "What is the weather in Seattle?"}'
```
Expected HTTP 202 payload:
```json
{
"status": "accepted",
"response": "Agent request accepted",
"message": "What is the weather in Seattle?",
"thread_id": "<guid>",
"correlation_id": "<guid>"
}
```
Math agent request:
```bash
curl -X POST http://localhost:7071/api/agents/MathAgent/run \
-H "Content-Type: application/json" \
-d '{"message": "Calculate a 20% tip on a $50 bill"}'
```
Expected HTTP 202 payload:
```json
{
"status": "accepted",
"response": "Agent request accepted",
"message": "Calculate a 20% tip on a $50 bill",
"thread_id": "<guid>",
"correlation_id": "<guid>"
}
```
Health check (optional):
```bash
curl http://localhost:7071/api/health
```
Expected response:
```json
{
"status": "healthy",
"agents": [
{"name": "WeatherAgent", "type": "Agent"},
{"name": "MathAgent", "type": "Agent"}
],
"agent_count": 2
}
```
## Code Structure
The sample demonstrates two ways to register multiple agents:
### Option 1: Pass list of agents during initialization
```python
app = AgentFunctionApp(agents=[weather_agent, math_agent])
```
### Option 2: Add agents incrementally (commented in sample)
```python
app = AgentFunctionApp()
app.add_agent(weather_agent)
app.add_agent(math_agent)
```
Each agent automatically gets:
- `POST /api/agents/{agent_name}/run` - Send messages to the agent
@@ -0,0 +1,57 @@
### DAFx Multi-Agent Function App - HTTP Samples
### Use with the VS Code REST Client extension or any HTTP client
###
### API Structure:
### - POST /api/agents/{agentName}/run -> Send a message to an agent
### - GET /api/health -> Health check and agent metadata
### Variables
@baseUrl = http://localhost:7071
@weatherAgentName = WeatherAgent
@mathAgentName = MathAgent
@weatherAgentRoute = {{baseUrl}}/api/agents/{{weatherAgentName}}
@mathAgentRoute = {{baseUrl}}/api/agents/{{mathAgentName}}
@healthRoute = {{baseUrl}}/api/health
### Health Check
# Confirms the Azure Functions app is running and both agents are registered
# Expected response:
# {
# "status": "healthy",
# "agents": [
# {"name": "WeatherAgent", "type": "AzureOpenAIAssistantsAgent"},
# {"name": "MathAgent", "type": "AzureOpenAIAssistantsAgent"}
# ],
# "agent_count": 2
# }
GET {{healthRoute}}
###
### Weather Agent - Current Conditions
# Tests the Weather agent's tool-assisted response path
# Expected response: { "response": "The weather in Seattle...", "status": "success" }
POST {{weatherAgentRoute}}/run
Content-Type: application/json
{
"message": "What is the weather in Seattle?",
"thread_id": "weather-user-001"
}
###
### Math Agent - Tip Calculation
# Exercises the Math agent with a calculation request
# Expected response: { "response": "A 20% tip on a $50 bill is $10...", "status": "success" }
POST {{mathAgentRoute}}/run
Content-Type: application/json
{
"message": "Calculate a 20% tip on a $50 bill",
"thread_id": "math-user-001"
}
###
@@ -0,0 +1,111 @@
# Copyright (c) Microsoft. All rights reserved.
"""Host multiple Azure OpenAI-powered agents inside a single Azure Functions app.
Components used in this sample:
- OpenAIChatCompletionClient configured for Azure OpenAI.
- AgentFunctionApp to register multiple agents and expose dedicated HTTP endpoints.
- Custom tool functions to demonstrate tool invocation from different agents.
Prerequisites: set `AZURE_OPENAI_ENDPOINT`, `AZURE_OPENAI_MODEL`, and sign in with Azure CLI before starting the Functions host."""
import logging
from typing import Any
from agent_framework import Agent, tool
from agent_framework.azure import AgentFunctionApp
from agent_framework.openai import OpenAIChatCompletionClient
from azure.identity.aio import AzureCliCredential
from dotenv import load_dotenv
# Load environment variables from .env file
load_dotenv()
logger = logging.getLogger(__name__)
# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production;
# see samples/02-agents/tools/function_tool_with_approval.py
# and samples/02-agents/tools/function_tool_with_approval_and_sessions.py.
@tool(approval_mode="never_require")
def get_weather(location: str) -> dict[str, Any]:
"""Get current weather for a location."""
logger.info(f"🔧 [TOOL CALLED] get_weather(location={location})")
result = {
"location": location,
"temperature": 72,
"conditions": "Sunny",
"humidity": 45,
}
logger.info(f"✓ [TOOL RESULT] {result}")
return result
@tool(approval_mode="never_require")
def calculate_tip(bill_amount: float, tip_percentage: float = 15.0) -> dict[str, Any]:
"""Calculate tip amount and total bill."""
logger.info(f"🔧 [TOOL CALLED] calculate_tip(bill_amount={bill_amount}, tip_percentage={tip_percentage})")
tip = bill_amount * (tip_percentage / 100)
total = bill_amount + tip
result = {
"bill_amount": bill_amount,
"tip_percentage": tip_percentage,
"tip_amount": round(tip, 2),
"total": round(total, 2),
}
logger.info(f"✓ [TOOL RESULT] {result}")
return result
# 1. Create multiple agents, each with its own instruction set and tools.
client = OpenAIChatCompletionClient(
credential=AzureCliCredential(),
)
weather_agent = Agent(
client=client,
name="WeatherAgent",
instructions="You are a helpful weather assistant. Provide current weather information.",
tools=[get_weather],
)
math_agent = Agent(
client=client,
name="MathAgent",
instructions="You are a helpful math assistant. Help users with calculations like tip calculations.",
tools=[calculate_tip],
)
# 2. Register both agents with AgentFunctionApp to expose their HTTP routes and health check.
app = AgentFunctionApp(agents=[weather_agent, math_agent], enable_health_check=True, max_poll_retries=50)
# Option 2: Add agents after initialization (commented out as we're using Option 1)
# app = AgentFunctionApp(enable_health_check=True)
# app.add_agent(weather_agent)
# app.add_agent(math_agent)
"""
Expected output when invoking `POST /api/agents/WeatherAgent/run`:
HTTP/1.1 202 Accepted
{
"status": "accepted",
"response": "Agent request accepted",
"message": "What is the weather in Seattle?",
"conversation_id": "<guid>",
"correlation_id": "<guid>"
}
Expected output when invoking `POST /api/agents/MathAgent/run`:
HTTP/1.1 202 Accepted
{
"status": "accepted",
"response": "Agent request accepted",
"message": "Calculate a 20% tip on a $50 bill",
"conversation_id": "<guid>",
"correlation_id": "<guid>"
}
"""
@@ -0,0 +1,20 @@
{
"version": "2.0",
"logging": {
"applicationInsights": {
"samplingSettings": {
"isEnabled": true,
"maxTelemetryItemsPerSecond": 20
}
}
},
"extensionBundle": {
"id": "Microsoft.Azure.Functions.ExtensionBundle",
"version": "[4.*, 5.0.0)"
},
"extensions": {
"durableTask": {
"hubName": "%TASKHUB_NAME%"
}
}
}
@@ -0,0 +1,11 @@
{
"IsEncrypted": false,
"Values": {
"FUNCTIONS_WORKER_RUNTIME": "python",
"AzureWebJobsStorage": "UseDevelopmentStorage=true",
"DURABLE_TASK_SCHEDULER_CONNECTION_STRING": "Endpoint=http://localhost:8080;TaskHub=default;Authentication=None",
"TASKHUB_NAME": "default",
"FOUNDRY_PROJECT_ENDPOINT": "<FOUNDRY_PROJECT_ENDPOINT>",
"FOUNDRY_MODEL": "<FOUNDRY_MODEL>"
}
}
@@ -0,0 +1,15 @@
# Agent Framework packages
# To use the deployed version, uncomment the lines below and comment out the local installation lines
# agent-framework-foundry
# agent-framework-azurefunctions
# Local installation (for development and testing)
# Each package must be listed explicitly because pip doesn't resolve uv workspace sources.
# Without explicit entries, pip would fetch transitive dependencies from PyPI instead of local source.
-e ../../../../packages/core # Core framework - base dependency for all packages
-e ../../../../packages/foundry # Foundry support - dependency for hosted chat/agent samples
-e ../../../../packages/durabletask # Durable Task support - dependency of azurefunctions
-e ../../../../packages/azurefunctions # Azure Functions integration - the main package for this sample
# Azure authentication
azure-identity