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,30 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net10.0</TargetFrameworks>
<OutputType>Exe</OutputType>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<AssemblyName>AgentOrchestration_Concurrency</AssemblyName>
<RootNamespace>AgentOrchestration_Concurrency</RootNamespace>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Azure.AI.OpenAI" />
<PackageReference Include="Azure.Identity" />
<PackageReference Include="Microsoft.DurableTask.Client.AzureManaged" />
<PackageReference Include="Microsoft.DurableTask.Worker.AzureManaged" />
<PackageReference Include="Microsoft.Extensions.Hosting" />
</ItemGroup>
<!-- Local projects that should be switched to package references when using the sample outside of this MAF repo -->
<!--
<ItemGroup>
<PackageReference Include="Microsoft.Agents.AI.DurableTask" />
<PackageReference Include="Microsoft.Agents.AI.OpenAI" />
</ItemGroup>
-->
<ItemGroup>
<ProjectReference Include="..\..\..\..\..\src\Microsoft.Agents.AI.DurableTask\Microsoft.Agents.AI.DurableTask.csproj" />
<ProjectReference Include="..\..\..\..\..\src\Microsoft.Agents.AI.OpenAI\Microsoft.Agents.AI.OpenAI.csproj" />
</ItemGroup>
</Project>
@@ -0,0 +1,6 @@
// Copyright (c) Microsoft. All rights reserved.
namespace AgentOrchestration_Concurrency;
// Response model
public sealed record TextResponse(string Text);
@@ -0,0 +1,194 @@
// Copyright (c) Microsoft. All rights reserved.
using System.Text.Json;
using AgentOrchestration_Concurrency;
using Azure;
using Azure.AI.OpenAI;
using Azure.Identity;
using Microsoft.Agents.AI;
using Microsoft.Agents.AI.DurableTask;
using Microsoft.DurableTask;
using Microsoft.DurableTask.Client;
using Microsoft.DurableTask.Client.AzureManaged;
using Microsoft.DurableTask.Worker;
using Microsoft.DurableTask.Worker.AzureManaged;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using OpenAI.Chat;
// Get the Azure OpenAI endpoint and deployment name from environment variables.
string endpoint = Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT")
?? throw new InvalidOperationException("AZURE_OPENAI_ENDPOINT is not set.");
string deploymentName = Environment.GetEnvironmentVariable("AZURE_OPENAI_DEPLOYMENT_NAME")
?? throw new InvalidOperationException("AZURE_OPENAI_DEPLOYMENT_NAME is not set.");
// Get DTS connection string from environment variable
string dtsConnectionString = Environment.GetEnvironmentVariable("DURABLE_TASK_SCHEDULER_CONNECTION_STRING")
?? "Endpoint=http://localhost:8080;TaskHub=default;Authentication=None";
// Use Azure Key Credential if provided, otherwise use Azure CLI Credential.
string? azureOpenAiKey = Environment.GetEnvironmentVariable("AZURE_OPENAI_API_KEY");
// WARNING: DefaultAzureCredential is convenient for development but requires careful consideration in production.
// In production, consider using a specific credential (e.g., ManagedIdentityCredential) to avoid
// latency issues, unintended credential probing, and potential security risks from fallback mechanisms.
AzureOpenAIClient client = !string.IsNullOrEmpty(azureOpenAiKey)
? new AzureOpenAIClient(new Uri(endpoint), new AzureKeyCredential(azureOpenAiKey))
: new AzureOpenAIClient(new Uri(endpoint), new DefaultAzureCredential());
// Two agents used by the orchestration to demonstrate concurrent execution.
const string PhysicistName = "PhysicistAgent";
const string PhysicistInstructions = "You are an expert in physics. You answer questions from a physics perspective.";
const string ChemistName = "ChemistAgent";
const string ChemistInstructions = "You are a middle school chemistry teacher. You answer questions so that middle school students can understand.";
AIAgent physicistAgent = client.GetChatClient(deploymentName).AsAIAgent(PhysicistInstructions, PhysicistName);
AIAgent chemistAgent = client.GetChatClient(deploymentName).AsAIAgent(ChemistInstructions, ChemistName);
// Orchestrator function
static async Task<object> RunOrchestratorAsync(TaskOrchestrationContext context, string prompt)
{
// Get both agents
DurableAIAgent physicist = context.GetAgent(PhysicistName);
DurableAIAgent chemist = context.GetAgent(ChemistName);
// Start both agent runs concurrently
Task<AgentResponse<TextResponse>> physicistTask = physicist.RunAsync<TextResponse>(prompt);
Task<AgentResponse<TextResponse>> chemistTask = chemist.RunAsync<TextResponse>(prompt);
// Wait for both tasks to complete using Task.WhenAll
await Task.WhenAll(physicistTask, chemistTask);
// Get the results
TextResponse physicistResponse = (await physicistTask).Result;
TextResponse chemistResponse = (await chemistTask).Result;
// Return the result as a structured, anonymous type
return new
{
physicist = physicistResponse.Text,
chemist = chemistResponse.Text,
};
}
// Configure the console app to host the AI agents.
IHost host = Host.CreateDefaultBuilder(args)
.ConfigureLogging(loggingBuilder => loggingBuilder.SetMinimumLevel(LogLevel.Warning))
.ConfigureServices(services =>
{
services.ConfigureDurableAgents(
options =>
{
options
.AddAIAgent(physicistAgent)
.AddAIAgent(chemistAgent);
},
workerBuilder: builder =>
{
builder.UseDurableTaskScheduler(dtsConnectionString);
builder.AddTasks(
registry => registry.AddOrchestratorFunc<string, object>(nameof(RunOrchestratorAsync), RunOrchestratorAsync));
},
clientBuilder: builder => builder.UseDurableTaskScheduler(dtsConnectionString));
})
.Build();
await host.StartAsync();
DurableTaskClient durableTaskClient = host.Services.GetRequiredService<DurableTaskClient>();
// Console colors for better UX
Console.ForegroundColor = ConsoleColor.Cyan;
Console.WriteLine("=== Multi-Agent Concurrent Orchestration Sample ===");
Console.ResetColor();
Console.WriteLine("Enter a question for the agents:");
Console.WriteLine();
// Read prompt from stdin
string? prompt = Console.ReadLine();
if (string.IsNullOrWhiteSpace(prompt))
{
Console.ForegroundColor = ConsoleColor.Red;
Console.Error.WriteLine("Error: Prompt is required.");
Console.ResetColor();
Environment.Exit(1);
return;
}
Console.WriteLine();
Console.ForegroundColor = ConsoleColor.Gray;
Console.WriteLine("Starting orchestration...");
Console.ResetColor();
try
{
// Start the orchestration
string instanceId = await durableTaskClient.ScheduleNewOrchestrationInstanceAsync(
orchestratorName: nameof(RunOrchestratorAsync),
input: prompt);
Console.ForegroundColor = ConsoleColor.Gray;
Console.WriteLine($"Orchestration started with instance ID: {instanceId}");
Console.WriteLine("Waiting for completion...");
Console.ResetColor();
// Wait for orchestration to complete
OrchestrationMetadata status = await durableTaskClient.WaitForInstanceCompletionAsync(
instanceId,
getInputsAndOutputs: true,
CancellationToken.None);
Console.WriteLine();
if (status.RuntimeStatus == OrchestrationRuntimeStatus.Completed)
{
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine("✓ Orchestration completed successfully!");
Console.ResetColor();
Console.WriteLine();
// Parse the output
using JsonDocument doc = JsonDocument.Parse(status.SerializedOutput!);
JsonElement output = doc.RootElement;
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine("Physicist's response:");
Console.ResetColor();
Console.WriteLine(output.GetProperty("physicist").GetString());
Console.WriteLine();
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine("Chemist's response:");
Console.ResetColor();
Console.WriteLine(output.GetProperty("chemist").GetString());
}
else if (status.RuntimeStatus == OrchestrationRuntimeStatus.Failed)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("✗ Orchestration failed!");
Console.ResetColor();
if (status.FailureDetails != null)
{
Console.WriteLine($"Error: {status.FailureDetails.ErrorMessage}");
}
Environment.Exit(1);
}
else
{
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine($"Orchestration status: {status.RuntimeStatus}");
Console.ResetColor();
}
}
catch (Exception ex)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.Error.WriteLine($"Error: {ex.Message}");
Console.ResetColor();
Environment.Exit(1);
}
finally
{
await host.StopAsync();
}
@@ -0,0 +1,68 @@
# Multi-Agent Concurrent Orchestration Sample
This sample demonstrates how to use the durable agents extension to create a console app that orchestrates concurrent execution of multiple AI agents using durable orchestration.
## Key Concepts Demonstrated
- Running multiple agents concurrently in a single orchestration
- Using `Task.WhenAll` to wait for concurrent agent executions
- Combining results from multiple agents into a single response
- Waiting for orchestration completion using `WaitForInstanceCompletionAsync`
## Environment Setup
See the [README.md](../README.md) file in the parent directory for more information on how to configure the environment, including how to install and run common sample dependencies.
## Running the Sample
With the environment setup, you can run the sample:
```bash
cd dotnet/samples/04-hosting/DurableAgents/ConsoleApps/03_AgentOrchestration_Concurrency
dotnet run --framework net10.0
```
The app will prompt you for a question:
```text
=== Multi-Agent Concurrent Orchestration Sample ===
Enter a question for the agents:
What is temperature?
```
The orchestration will run both agents concurrently and display their responses:
```text
Orchestration started with instance ID: 86313f1d45fb42eeb50b1852626bf3ff
Waiting for completion...
✓ Orchestration completed successfully!
Physicist's response:
Temperature is a measure of the average kinetic energy of particles in a system...
Chemist's response:
From a chemistry perspective, temperature is crucial for chemical reactions...
```
Both agents run in parallel, and the orchestration waits for both to complete before returning the combined results.
## Viewing Orchestration State
You can view the state of the orchestration in the Durable Task Scheduler dashboard:
1. Open your browser and navigate to `http://localhost:8082`
2. In the dashboard, you can see:
- **Orchestrations**: View the orchestration instance, including its runtime status, input, output, and execution history
- **Agents**: View the state of both the PhysicistAgent and ChemistAgent, including their individual conversation histories
The orchestration instance ID is displayed in the console output. You can use this ID to find the specific orchestration in the dashboard and inspect how the concurrent agent executions were coordinated, including the timing of when each agent started and completed.
## Scriptable Usage
You can also pipe input to the app:
```bash
echo "What is temperature?" | dotnet run
```