mirror of
https://github.com/microsoft/agent-framework.git
synced 2026-06-16 21:04:09 +08:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
469525d9e6 | ||
|
|
6e04c6bbbe | ||
|
|
f5d6056074 | ||
|
|
9586a3ea53 | ||
|
|
82bd9cf6b5 | ||
|
|
4cbde55243 | ||
|
|
864b1f7a91 | ||
|
|
5131f3a129 | ||
|
|
2ee34beed5 | ||
|
|
d55b15903d | ||
|
|
5a8c8fe634 | ||
|
|
b2c38ac98c | ||
|
|
1aa00e6428 | ||
|
|
f0d2dd6774 | ||
|
|
bf007f854c | ||
|
|
55a4aa2b53 | ||
|
|
95fe891369 | ||
|
|
4d1a132737 | ||
|
|
943e37836f | ||
|
|
65e1c12dfa | ||
|
|
279d91f58e | ||
|
|
51e7a2134a | ||
|
|
90226526fa | ||
|
|
7405759593 | ||
|
|
698aba5f97 | ||
|
|
7e23140ca9 | ||
|
|
904e17473f | ||
|
|
2c5cf6c67b |
@@ -7,7 +7,7 @@ name: dotnet-format
|
|||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
pull_request:
|
pull_request:
|
||||||
branches: ["main", "feature*"]
|
branches: ["main"]
|
||||||
paths:
|
paths:
|
||||||
- dotnet/**
|
- dotnet/**
|
||||||
- '.github/workflows/dotnet-format.yml'
|
- '.github/workflows/dotnet-format.yml'
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
<PackageVersion Include="Aspire.Microsoft.Azure.Cosmos" Version="$(AspireAppHostSdkVersion)" />
|
<PackageVersion Include="Aspire.Microsoft.Azure.Cosmos" Version="$(AspireAppHostSdkVersion)" />
|
||||||
<PackageVersion Include="CommunityToolkit.Aspire.OllamaSharp" Version="9.9.0" />
|
<PackageVersion Include="CommunityToolkit.Aspire.OllamaSharp" Version="9.9.0" />
|
||||||
<!-- Azure.* -->
|
<!-- Azure.* -->
|
||||||
|
<PackageVersion Include="Azure.AI.Agents" Version="2.0.0-alpha.20251104.7" />
|
||||||
<PackageVersion Include="Azure.AI.Agents.Persistent" Version="1.2.0-beta.7" />
|
<PackageVersion Include="Azure.AI.Agents.Persistent" Version="1.2.0-beta.7" />
|
||||||
<PackageVersion Include="Azure.AI.OpenAI" Version="2.5.0-beta.1" />
|
<PackageVersion Include="Azure.AI.OpenAI" Version="2.5.0-beta.1" />
|
||||||
<PackageVersion Include="Azure.Identity" Version="1.17.0" />
|
<PackageVersion Include="Azure.Identity" Version="1.17.0" />
|
||||||
@@ -151,4 +152,4 @@
|
|||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -43,6 +43,23 @@
|
|||||||
<Project Path="samples/GettingStarted/AgentProviders/Agent_With_OpenAIChatCompletion/Agent_With_OpenAIChatCompletion.csproj" />
|
<Project Path="samples/GettingStarted/AgentProviders/Agent_With_OpenAIChatCompletion/Agent_With_OpenAIChatCompletion.csproj" />
|
||||||
<Project Path="samples/GettingStarted/AgentProviders/Agent_With_OpenAIResponses/Agent_With_OpenAIResponses.csproj" />
|
<Project Path="samples/GettingStarted/AgentProviders/Agent_With_OpenAIResponses/Agent_With_OpenAIResponses.csproj" />
|
||||||
</Folder>
|
</Folder>
|
||||||
|
<Folder Name="/Samples/GettingStarted/AgentProviders/AzureAIAgents/">
|
||||||
|
<Project Path="samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step01.1_Basics/AzureAIAgents_Step01.1_Basics.csproj" />
|
||||||
|
<Project Path="samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step01.2_Running/AzureAIAgents_Step01.2_Running.csproj" />
|
||||||
|
<Project Path="samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step02_MultiturnConversation/AzureAIAgents_Step02_MultiturnConversation.csproj" />
|
||||||
|
<Project Path="samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step03.1_UsingFunctionTools/AzureAIAgents_Step03.1_UsingFunctionTools.csproj" />
|
||||||
|
<Project Path="samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step03.2_UsingFunctionTools_FromOpenAPI/AzureAIAgents_Step03.2_UsingFunctionTools_FromOpenAPI.csproj" />
|
||||||
|
<Project Path="samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step04_UsingFunctionToolsWithApprovals/AzureAIAgents_Step04_UsingFunctionToolsWithApprovals.csproj" />
|
||||||
|
<Project Path="samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step05_StructuredOutput/AzureAIAgents_Step05_StructuredOutput.csproj" />
|
||||||
|
<Project Path="samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step06_PersistedConversations/AzureAIAgents_Step06_PersistedConversations.csproj" />
|
||||||
|
<Project Path="samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step07_Observability/AzureAIAgents_Step07_Observability.csproj" />
|
||||||
|
<Project Path="samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step08_DependencyInjection/AzureAIAgents_Step08_DependencyInjection.csproj" />
|
||||||
|
<Project Path="samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step09_AsMcpTool/AzureAIAgents_Step09_AsMcpTool.csproj" />
|
||||||
|
<Project Path="samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step10_UsingImages/AzureAIAgents_Step10_UsingImages.csproj" />
|
||||||
|
<Project Path="samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step11_AsFunctionTool/AzureAIAgents_Step11_AsFunctionTool.csproj" />
|
||||||
|
<Project Path="samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step12_Middleware/AzureAIAgents_Step12_Middleware.csproj" />
|
||||||
|
<Project Path="samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step13_Plugins/AzureAIAgents_Step13_Plugins.csproj" />
|
||||||
|
</Folder>
|
||||||
<Folder Name="/Samples/GettingStarted/Agents/">
|
<Folder Name="/Samples/GettingStarted/Agents/">
|
||||||
<File Path="samples/GettingStarted/Agents/README.md" />
|
<File Path="samples/GettingStarted/Agents/README.md" />
|
||||||
<Project Path="samples/GettingStarted/Agents/Agent_Step01_Running/Agent_Step01_Running.csproj" />
|
<Project Path="samples/GettingStarted/Agents/Agent_Step01_Running/Agent_Step01_Running.csproj" />
|
||||||
@@ -61,7 +78,6 @@
|
|||||||
<Project Path="samples/GettingStarted/Agents/Agent_Step13_Memory/Agent_Step13_Memory.csproj" />
|
<Project Path="samples/GettingStarted/Agents/Agent_Step13_Memory/Agent_Step13_Memory.csproj" />
|
||||||
<Project Path="samples/GettingStarted/Agents/Agent_Step14_Middleware/Agent_Step14_Middleware.csproj" />
|
<Project Path="samples/GettingStarted/Agents/Agent_Step14_Middleware/Agent_Step14_Middleware.csproj" />
|
||||||
<Project Path="samples/GettingStarted/Agents/Agent_Step15_Plugins/Agent_Step15_Plugins.csproj" />
|
<Project Path="samples/GettingStarted/Agents/Agent_Step15_Plugins/Agent_Step15_Plugins.csproj" />
|
||||||
<Project Path="samples/GettingStarted/Agents/Agent_Step16_ChatReduction/Agent_Step16_ChatReduction.csproj" />
|
|
||||||
<Project Path="samples/GettingStarted/Agents/Agent_Step17_BackgroundResponses/Agent_Step17_BackgroundResponses.csproj" />
|
<Project Path="samples/GettingStarted/Agents/Agent_Step17_BackgroundResponses/Agent_Step17_BackgroundResponses.csproj" />
|
||||||
<Project Path="samples/GettingStarted/Agents/Agent_Step18_TextSearchRag/Agent_Step18_TextSearchRag.csproj" />
|
<Project Path="samples/GettingStarted/Agents/Agent_Step18_TextSearchRag/Agent_Step18_TextSearchRag.csproj" />
|
||||||
<Project Path="samples/GettingStarted/Agents/Agent_Step19_Mem0Provider/Agent_Step19_Mem0Provider.csproj" />
|
<Project Path="samples/GettingStarted/Agents/Agent_Step19_Mem0Provider/Agent_Step19_Mem0Provider.csproj" />
|
||||||
@@ -283,6 +299,7 @@
|
|||||||
<Project Path="src/Microsoft.Agents.AI.Abstractions/Microsoft.Agents.AI.Abstractions.csproj" />
|
<Project Path="src/Microsoft.Agents.AI.Abstractions/Microsoft.Agents.AI.Abstractions.csproj" />
|
||||||
<Project Path="src/Microsoft.Agents.AI.AGUI/Microsoft.Agents.AI.AGUI.csproj" />
|
<Project Path="src/Microsoft.Agents.AI.AGUI/Microsoft.Agents.AI.AGUI.csproj" />
|
||||||
<Project Path="src/Microsoft.Agents.AI.AzureAI.Persistent/Microsoft.Agents.AI.AzureAI.Persistent.csproj" />
|
<Project Path="src/Microsoft.Agents.AI.AzureAI.Persistent/Microsoft.Agents.AI.AzureAI.Persistent.csproj" />
|
||||||
|
<Project Path="src/Microsoft.Agents.AI.AzureAI/Microsoft.Agents.AI.AzureAI.csproj" />
|
||||||
<Project Path="src/Microsoft.Agents.AI.CopilotStudio/Microsoft.Agents.AI.CopilotStudio.csproj" />
|
<Project Path="src/Microsoft.Agents.AI.CopilotStudio/Microsoft.Agents.AI.CopilotStudio.csproj" />
|
||||||
<Project Path="src/Microsoft.Agents.AI.DevUI/Microsoft.Agents.AI.DevUI.csproj" />
|
<Project Path="src/Microsoft.Agents.AI.DevUI/Microsoft.Agents.AI.DevUI.csproj" />
|
||||||
<Project Path="src/Microsoft.Agents.AI.Hosting.A2A.AspNetCore/Microsoft.Agents.AI.Hosting.A2A.AspNetCore.csproj" />
|
<Project Path="src/Microsoft.Agents.AI.Hosting.A2A.AspNetCore/Microsoft.Agents.AI.Hosting.A2A.AspNetCore.csproj" />
|
||||||
@@ -313,6 +330,7 @@
|
|||||||
<Project Path="tests/Microsoft.Agents.AI.Abstractions.UnitTests/Microsoft.Agents.AI.Abstractions.UnitTests.csproj" />
|
<Project Path="tests/Microsoft.Agents.AI.Abstractions.UnitTests/Microsoft.Agents.AI.Abstractions.UnitTests.csproj" />
|
||||||
<Project Path="tests/Microsoft.Agents.AI.AGUI.UnitTests/Microsoft.Agents.AI.AGUI.UnitTests.csproj" />
|
<Project Path="tests/Microsoft.Agents.AI.AGUI.UnitTests/Microsoft.Agents.AI.AGUI.UnitTests.csproj" />
|
||||||
<Project Path="tests/Microsoft.Agents.AI.AzureAI.Persistent.UnitTests/Microsoft.Agents.AI.AzureAI.Persistent.UnitTests.csproj" />
|
<Project Path="tests/Microsoft.Agents.AI.AzureAI.Persistent.UnitTests/Microsoft.Agents.AI.AzureAI.Persistent.UnitTests.csproj" />
|
||||||
|
<Project Path="tests/Microsoft.Agents.AI.AzureAI.UnitTests/Microsoft.Agents.AI.AzureAI.UnitTests.csproj" />
|
||||||
<Project Path="tests/Microsoft.Agents.AI.Hosting.A2A.Tests/Microsoft.Agents.AI.Hosting.A2A.Tests.csproj" Id="2a1c544d-237d-4436-8732-ba0c447ac06b" />
|
<Project Path="tests/Microsoft.Agents.AI.Hosting.A2A.Tests/Microsoft.Agents.AI.Hosting.A2A.Tests.csproj" Id="2a1c544d-237d-4436-8732-ba0c447ac06b" />
|
||||||
<Project Path="tests/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore.UnitTests/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore.UnitTests.csproj" />
|
<Project Path="tests/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore.UnitTests/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore.UnitTests.csproj" />
|
||||||
<Project Path="tests/Microsoft.Agents.AI.Hosting.OpenAI.UnitTests/Microsoft.Agents.AI.Hosting.OpenAI.UnitTests.csproj" />
|
<Project Path="tests/Microsoft.Agents.AI.Hosting.OpenAI.UnitTests/Microsoft.Agents.AI.Hosting.OpenAI.UnitTests.csproj" />
|
||||||
|
|||||||
@@ -3,10 +3,14 @@
|
|||||||
<packageSources>
|
<packageSources>
|
||||||
<clear />
|
<clear />
|
||||||
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
|
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
|
||||||
|
<add key="azure-sdk-for-net" value="https://pkgs.dev.azure.com/azure-sdk/public/_packaging/azure-sdk-for-net/nuget/v3/index.json" />
|
||||||
</packageSources>
|
</packageSources>
|
||||||
<packageSourceMapping>
|
<packageSourceMapping>
|
||||||
<packageSource key="nuget.org">
|
<packageSource key="nuget.org">
|
||||||
<package pattern="*" />
|
<package pattern="*" />
|
||||||
</packageSource>
|
</packageSource>
|
||||||
|
<packageSource key="azure-sdk-for-net">
|
||||||
|
<package pattern="Azure.AI.Agents" />
|
||||||
|
</packageSource>
|
||||||
</packageSourceMapping>
|
</packageSourceMapping>
|
||||||
</configuration>
|
</configuration>
|
||||||
+21
@@ -0,0 +1,21 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
|
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<NoWarn>$(NoWarn);IDE0059</NoWarn>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Azure.AI.Agents" />
|
||||||
|
<PackageReference Include="Azure.Identity" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\..\..\..\src\Microsoft.Agents.AI.AzureAI\Microsoft.Agents.AI.AzureAI.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
+54
@@ -0,0 +1,54 @@
|
|||||||
|
// Copyright (c) Microsoft. All rights reserved.
|
||||||
|
|
||||||
|
// This sample shows how to create and use a AI agents with Azure Foundry Agents as the backend.
|
||||||
|
|
||||||
|
using Azure.AI.Agents;
|
||||||
|
using Azure.Identity;
|
||||||
|
using Microsoft.Agents.AI;
|
||||||
|
|
||||||
|
var endpoint = Environment.GetEnvironmentVariable("AZURE_FOUNDRY_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("AZURE_FOUNDRY_PROJECT_ENDPOINT is not set.");
|
||||||
|
var deploymentName = Environment.GetEnvironmentVariable("AZURE_FOUNDRY_PROJECT_DEPLOYMENT_NAME") ?? "gpt-4o-mini";
|
||||||
|
|
||||||
|
const string JokerInstructions = "You are good at telling jokes.";
|
||||||
|
const string JokerName = "JokerAgent";
|
||||||
|
|
||||||
|
// Get a client to create/retrieve/delete server side agents with Azure Foundry Agents.
|
||||||
|
var agentsClient = new AgentsClient(new Uri(endpoint), new AzureCliCredential());
|
||||||
|
|
||||||
|
// Define the agent you want to create. (Prompt Agent in this case)
|
||||||
|
var agentDefinition = new PromptAgentDefinition(model: deploymentName) { Instructions = JokerInstructions };
|
||||||
|
|
||||||
|
// Azure.AI.Agents SDK creates and manages agent by name and versions.
|
||||||
|
// You can create a server side agent version with the Azure.AI.Agents SDK client below.
|
||||||
|
var agentVersion = agentsClient.CreateAgentVersion(agentName: JokerName, definition: agentDefinition);
|
||||||
|
|
||||||
|
// Note:
|
||||||
|
// agentVersion.Id = "<agentName>:<versionNumber>",
|
||||||
|
// agentVersion.Version = <versionNumber>,
|
||||||
|
// agentVersion.Name = <agentName>
|
||||||
|
|
||||||
|
// You can retrieve an AIAgent for a already created server side agent version.
|
||||||
|
AIAgent jokerAgentV1 = agentsClient.GetAIAgent(agentVersion);
|
||||||
|
|
||||||
|
// You can also create another AIAgent version (V2) by providing the same name with a different definition.
|
||||||
|
AIAgent jokerAgentV2 = agentsClient.CreateAIAgent(name: JokerName, model: deploymentName, instructions: JokerInstructions + "V2");
|
||||||
|
|
||||||
|
// You can also get the AIAgent latest version just providing its name.
|
||||||
|
AIAgent jokerAgentLatest = agentsClient.GetAIAgent(name: JokerName);
|
||||||
|
var latestVersion = jokerAgentLatest.GetService<AgentVersion>()!;
|
||||||
|
|
||||||
|
// The AIAgent version can be accessed via the GetService method.
|
||||||
|
Console.WriteLine($"Latest agent version id: {latestVersion.Id}");
|
||||||
|
|
||||||
|
// Once you have the AIAgent, you can invoke it like any other AIAgent.
|
||||||
|
AgentThread thread = jokerAgentLatest.GetNewThread();
|
||||||
|
Console.WriteLine(await jokerAgentLatest.RunAsync("Tell me a joke about a pirate.", thread));
|
||||||
|
|
||||||
|
// This will use the same thread to continue the conversation.
|
||||||
|
Console.WriteLine(await jokerAgentLatest.RunAsync("Now tell me a joke about a cat and a dog using last joke as the anchor.", thread));
|
||||||
|
|
||||||
|
// Cleanup by agent name removes both agent versions created (jokerAgentV1 + jokerAgentV2).
|
||||||
|
agentsClient.DeleteAgent(jokerAgentV1.Name);
|
||||||
|
|
||||||
|
// It is also possible delete just a specific agent version by the composition (name + version number).
|
||||||
|
// agentsClient.DeleteAgentVersion(latestVersion.Name, latestVersion.Version);
|
||||||
+16
@@ -0,0 +1,16 @@
|
|||||||
|
# Prerequisites
|
||||||
|
|
||||||
|
Before you begin, ensure you have the following prerequisites:
|
||||||
|
|
||||||
|
- .NET 8.0 SDK or later
|
||||||
|
- Azure Foundry service endpoint and deployment configured
|
||||||
|
- Azure CLI installed and authenticated (for Azure credential authentication)
|
||||||
|
|
||||||
|
**Note**: This demo uses Azure CLI credentials for authentication. Make sure you're logged in with `az login` and have access to the Azure Foundry resource. For more information, see the [Azure CLI documentation](https://learn.microsoft.com/cli/azure/authenticate-azure-cli-interactively).
|
||||||
|
|
||||||
|
Set the following environment variables:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
$env:AZURE_FOUNDRY_PROJECT_ENDPOINT="https://your-foundry-service.services.ai.azure.com/api/projects/your-foundry-project" # Replace with your Azure Foundry resource endpoint
|
||||||
|
$env:AZURE_FOUNDRY_PROJECT_DEPLOYMENT_NAME="gpt-4o-mini" # Optional, defaults to gpt-4o-mini
|
||||||
|
```
|
||||||
+20
@@ -0,0 +1,20 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
|
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Azure.AI.Agents" />
|
||||||
|
<PackageReference Include="Azure.Identity" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\..\..\..\src\Microsoft.Agents.AI.AzureAI\Microsoft.Agents.AI.AzureAI.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
+40
@@ -0,0 +1,40 @@
|
|||||||
|
// Copyright (c) Microsoft. All rights reserved.
|
||||||
|
|
||||||
|
// This sample shows how to create and use a simple AI agent with Azure Foundry Agents as the backend.
|
||||||
|
|
||||||
|
using Azure.AI.Agents;
|
||||||
|
using Azure.Identity;
|
||||||
|
using Microsoft.Agents.AI;
|
||||||
|
|
||||||
|
var endpoint = Environment.GetEnvironmentVariable("AZURE_FOUNDRY_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("AZURE_FOUNDRY_PROJECT_ENDPOINT is not set.");
|
||||||
|
var deploymentName = Environment.GetEnvironmentVariable("AZURE_FOUNDRY_PROJECT_DEPLOYMENT_NAME") ?? "gpt-4o-mini";
|
||||||
|
|
||||||
|
const string JokerInstructions = "You are good at telling jokes.";
|
||||||
|
const string JokerName = "JokerAgent";
|
||||||
|
|
||||||
|
// Get a client to create/retrieve/delete server side agents with Azure Foundry Agents.
|
||||||
|
var agentsClient = new AgentsClient(new Uri(endpoint), new AzureCliCredential());
|
||||||
|
|
||||||
|
// Define the agent you want to create. (Prompt Agent in this case)
|
||||||
|
var agentDefinition = new PromptAgentDefinition(model: deploymentName) { Instructions = JokerInstructions };
|
||||||
|
|
||||||
|
// Azure.AI.Agents SDK creates and manages agent by name and versions.
|
||||||
|
// You can create a server side agent version with the Azure.AI.Agents SDK client below.
|
||||||
|
var agentVersion = agentsClient.CreateAgentVersion(agentName: JokerName, definition: agentDefinition);
|
||||||
|
|
||||||
|
// You can retrieve an AIAgent for a already created server side agent version.
|
||||||
|
AIAgent jokerAgent = agentsClient.GetAIAgent(agentVersion);
|
||||||
|
|
||||||
|
// Invoke the agent and output the text result.
|
||||||
|
AgentThread thread = jokerAgent.GetNewThread();
|
||||||
|
Console.WriteLine(await jokerAgent.RunAsync("Tell me a joke about a pirate.", thread));
|
||||||
|
|
||||||
|
// Invoke the agent with streaming support.
|
||||||
|
thread = jokerAgent.GetNewThread();
|
||||||
|
await foreach (var update in jokerAgent.RunStreamingAsync("Tell me a joke about a pirate.", thread))
|
||||||
|
{
|
||||||
|
Console.WriteLine(update);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cleanup by agent name removes the agent version created.
|
||||||
|
agentsClient.DeleteAgent(jokerAgent.Name);
|
||||||
+20
@@ -0,0 +1,20 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
|
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Azure.AI.Agents" />
|
||||||
|
<PackageReference Include="Azure.Identity" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\..\..\..\src\Microsoft.Agents.AI.AzureAI\Microsoft.Agents.AI.AzureAI.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
+44
@@ -0,0 +1,44 @@
|
|||||||
|
// Copyright (c) Microsoft. All rights reserved.
|
||||||
|
|
||||||
|
// This sample shows how to create and use a simple AI agent with a multi-turn conversation.
|
||||||
|
|
||||||
|
using Azure.AI.Agents;
|
||||||
|
using Azure.Identity;
|
||||||
|
using Microsoft.Agents.AI;
|
||||||
|
|
||||||
|
var endpoint = Environment.GetEnvironmentVariable("AZURE_FOUNDRY_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("AZURE_FOUNDRY_PROJECT_ENDPOINT is not set.");
|
||||||
|
var deploymentName = Environment.GetEnvironmentVariable("AZURE_FOUNDRY_PROJECT_DEPLOYMENT_NAME") ?? "gpt-4o-mini";
|
||||||
|
|
||||||
|
const string JokerInstructions = "You are good at telling jokes.";
|
||||||
|
const string JokerName = "JokerAgent";
|
||||||
|
|
||||||
|
// Get a client to create/retrieve/delete server side agents with Azure Foundry Agents.
|
||||||
|
var agentsClient = new AgentsClient(new Uri(endpoint), new AzureCliCredential());
|
||||||
|
|
||||||
|
// Define the agent you want to create. (Prompt Agent in this case)
|
||||||
|
var agentDefinition = new PromptAgentDefinition(model: deploymentName) { Instructions = JokerInstructions };
|
||||||
|
|
||||||
|
// Create a server side agent version with the Azure.AI.Agents SDK client.
|
||||||
|
var agentVersion = agentsClient.CreateAgentVersion(agentName: JokerName, definition: agentDefinition);
|
||||||
|
|
||||||
|
// Retrieve an AIAgent for the created server side agent version.
|
||||||
|
AIAgent jokerAgent = agentsClient.GetAIAgent(agentVersion);
|
||||||
|
|
||||||
|
// Invoke the agent with a multi-turn conversation, where the context is preserved in the thread object.
|
||||||
|
AgentThread thread = jokerAgent.GetNewThread();
|
||||||
|
Console.WriteLine(await jokerAgent.RunAsync("Tell me a joke about a pirate.", thread));
|
||||||
|
Console.WriteLine(await jokerAgent.RunAsync("Now add some emojis to the joke and tell it in the voice of a pirate's parrot.", thread));
|
||||||
|
|
||||||
|
// Invoke the agent with a multi-turn conversation and streaming, where the context is preserved in the thread object.
|
||||||
|
thread = jokerAgent.GetNewThread();
|
||||||
|
await foreach (var update in jokerAgent.RunStreamingAsync("Tell me a joke about a pirate.", thread))
|
||||||
|
{
|
||||||
|
Console.WriteLine(update);
|
||||||
|
}
|
||||||
|
await foreach (var update in jokerAgent.RunStreamingAsync("Now add some emojis to the joke and tell it in the voice of a pirate's parrot.", thread))
|
||||||
|
{
|
||||||
|
Console.WriteLine(update);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cleanup by agent name removes the agent version created.
|
||||||
|
agentsClient.DeleteAgent(jokerAgent.Name);
|
||||||
+21
@@ -0,0 +1,21 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
|
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Azure.AI.Agents" />
|
||||||
|
<PackageReference Include="Azure.Identity" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\..\..\..\src\Microsoft.Agents.AI.AzureAI\Microsoft.Agents.AI.AzureAI.csproj" />
|
||||||
|
<ProjectReference Include="..\..\..\..\..\src\Microsoft.Agents.AI\Microsoft.Agents.AI.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
+43
@@ -0,0 +1,43 @@
|
|||||||
|
// Copyright (c) Microsoft. All rights reserved.
|
||||||
|
|
||||||
|
// This sample demonstrates how to use an agent with function tools.
|
||||||
|
// It shows both non-streaming and streaming agent interactions using weather-related tools.
|
||||||
|
|
||||||
|
using System.ComponentModel;
|
||||||
|
using Azure.AI.Agents;
|
||||||
|
using Azure.Identity;
|
||||||
|
using Microsoft.Agents.AI;
|
||||||
|
using Microsoft.Extensions.AI;
|
||||||
|
|
||||||
|
var endpoint = Environment.GetEnvironmentVariable("AZURE_FOUNDRY_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("AZURE_FOUNDRY_PROJECT_ENDPOINT is not set.");
|
||||||
|
var deploymentName = Environment.GetEnvironmentVariable("AZURE_FOUNDRY_PROJECT_DEPLOYMENT_NAME") ?? "gpt-4o-mini";
|
||||||
|
|
||||||
|
[Description("Get the weather for a given location.")]
|
||||||
|
static string GetWeather([Description("The location to get the weather for.")] string location)
|
||||||
|
=> $"The weather in {location} is cloudy with a high of 15°C.";
|
||||||
|
|
||||||
|
const string AssistantInstructions = "You are a helpful assistant that can get weather information.";
|
||||||
|
const string AssistantName = "WeatherAssistant";
|
||||||
|
|
||||||
|
// Get a client to create/retrieve/delete server side agents with Azure Foundry Agents.
|
||||||
|
var agentsClient = new AgentsClient(new Uri(endpoint), new AzureCliCredential());
|
||||||
|
|
||||||
|
// Define the agent with function tools.
|
||||||
|
var tool = AIFunctionFactory.Create(GetWeather);
|
||||||
|
|
||||||
|
// Create AIAgent directly
|
||||||
|
AIAgent agent = await agentsClient.CreateAIAgentAsync(name: AssistantName, model: deploymentName, instructions: AssistantInstructions, tools: [tool]);
|
||||||
|
|
||||||
|
// Non-streaming agent interaction with function tools.
|
||||||
|
AgentThread thread = agent.GetNewThread();
|
||||||
|
Console.WriteLine(await agent.RunAsync("What is the weather like in Amsterdam?", thread));
|
||||||
|
|
||||||
|
// Streaming agent interaction with function tools.
|
||||||
|
thread = agent.GetNewThread();
|
||||||
|
await foreach (var update in agent.RunStreamingAsync("What is the weather like in Amsterdam?", thread))
|
||||||
|
{
|
||||||
|
Console.WriteLine(update);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cleanup by agent name removes the agent version created.
|
||||||
|
agentsClient.DeleteAgent(agent.Name);
|
||||||
+28
@@ -0,0 +1,28 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
|
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Azure.AI.Agents" />
|
||||||
|
<PackageReference Include="Azure.Identity" />
|
||||||
|
<PackageReference Include="Microsoft.SemanticKernel.Plugins.OpenApi" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\..\..\..\src\Microsoft.Agents.AI.AzureAI\Microsoft.Agents.AI.AzureAI.csproj" />
|
||||||
|
<ProjectReference Include="..\..\..\..\..\src\Microsoft.Agents.AI\Microsoft.Agents.AI.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<None Update="OpenAPISpec.json">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
+354
@@ -0,0 +1,354 @@
|
|||||||
|
{
|
||||||
|
"openapi": "3.0.1",
|
||||||
|
"info": {
|
||||||
|
"title": "Github Versions API",
|
||||||
|
"version": "1.0.0"
|
||||||
|
},
|
||||||
|
"servers": [
|
||||||
|
{
|
||||||
|
"url": "https://api.github.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"components": {
|
||||||
|
"schemas": {
|
||||||
|
"basic-error": {
|
||||||
|
"title": "Basic Error",
|
||||||
|
"description": "Basic Error",
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"message": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"documentation_url": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"url": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"label": {
|
||||||
|
"title": "Label",
|
||||||
|
"description": "Color-coded labels help you categorize and filter your issues (just like labels in Gmail).",
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"id": {
|
||||||
|
"description": "Unique identifier for the label.",
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int64",
|
||||||
|
"example": 208045946
|
||||||
|
},
|
||||||
|
"node_id": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "MDU6TGFiZWwyMDgwNDU5NDY="
|
||||||
|
},
|
||||||
|
"url": {
|
||||||
|
"description": "URL for the label",
|
||||||
|
"example": "https://api.github.com/repositories/42/labels/bug",
|
||||||
|
"type": "string",
|
||||||
|
"format": "uri"
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"description": "The name of the label.",
|
||||||
|
"example": "bug",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"description": {
|
||||||
|
"description": "Optional description of the label, such as its purpose.",
|
||||||
|
"type": "string",
|
||||||
|
"example": "Something isn't working",
|
||||||
|
"nullable": true
|
||||||
|
},
|
||||||
|
"color": {
|
||||||
|
"description": "6-character hex code, without the leading #, identifying the color",
|
||||||
|
"example": "FFFFFF",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"default": {
|
||||||
|
"description": "Whether this label comes by default in a new repository.",
|
||||||
|
"type": "boolean",
|
||||||
|
"example": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"id",
|
||||||
|
"node_id",
|
||||||
|
"url",
|
||||||
|
"name",
|
||||||
|
"description",
|
||||||
|
"color",
|
||||||
|
"default"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"tag": {
|
||||||
|
"title": "Tag",
|
||||||
|
"description": "Tag",
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"name": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "v0.1"
|
||||||
|
},
|
||||||
|
"commit": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"sha": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"url": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "uri"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"sha",
|
||||||
|
"url"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"zipball_url": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "uri",
|
||||||
|
"example": "https://github.com/octocat/Hello-World/zipball/v0.1"
|
||||||
|
},
|
||||||
|
"tarball_url": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "uri",
|
||||||
|
"example": "https://github.com/octocat/Hello-World/tarball/v0.1"
|
||||||
|
},
|
||||||
|
"node_id": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"name",
|
||||||
|
"node_id",
|
||||||
|
"commit",
|
||||||
|
"zipball_url",
|
||||||
|
"tarball_url"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"examples": {
|
||||||
|
"label-items": {
|
||||||
|
"value": [
|
||||||
|
{
|
||||||
|
"id": 208045946,
|
||||||
|
"node_id": "MDU6TGFiZWwyMDgwNDU5NDY=",
|
||||||
|
"url": "https://api.github.com/repos/octocat/Hello-World/labels/bug",
|
||||||
|
"name": "bug",
|
||||||
|
"description": "Something isn't working",
|
||||||
|
"color": "f29513",
|
||||||
|
"default": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 208045947,
|
||||||
|
"node_id": "MDU6TGFiZWwyMDgwNDU5NDc=",
|
||||||
|
"url": "https://api.github.com/repos/octocat/Hello-World/labels/enhancement",
|
||||||
|
"name": "enhancement",
|
||||||
|
"description": "New feature or request",
|
||||||
|
"color": "a2eeef",
|
||||||
|
"default": false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"tag-items": {
|
||||||
|
"value": [
|
||||||
|
{
|
||||||
|
"name": "v0.1",
|
||||||
|
"commit": {
|
||||||
|
"sha": "c5b97d5ae6c19d5c5df71a34c7fbeeda2479ccbc",
|
||||||
|
"url": "https://api.github.com/repos/octocat/Hello-World/commits/c5b97d5ae6c19d5c5df71a34c7fbeeda2479ccbc"
|
||||||
|
},
|
||||||
|
"zipball_url": "https://github.com/octocat/Hello-World/zipball/v0.1",
|
||||||
|
"tarball_url": "https://github.com/octocat/Hello-World/tarball/v0.1",
|
||||||
|
"node_id": "MDQ6VXNlcjE="
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"parameters": {
|
||||||
|
"owner": {
|
||||||
|
"name": "owner",
|
||||||
|
"description": "The account owner of the repository. The name is not case sensitive.",
|
||||||
|
"in": "path",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"repo": {
|
||||||
|
"name": "repo",
|
||||||
|
"description": "The name of the repository without the `.git` extension. The name is not case sensitive.",
|
||||||
|
"in": "path",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"per-page": {
|
||||||
|
"name": "per_page",
|
||||||
|
"description": "The number of results per page (max 100). For more information, see \"[Using pagination in the REST API](https://docs.github.com/rest/using-the-rest-api/using-pagination-in-the-rest-api).\"",
|
||||||
|
"in": "query",
|
||||||
|
"schema": {
|
||||||
|
"type": "integer",
|
||||||
|
"default": 30
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"page": {
|
||||||
|
"name": "page",
|
||||||
|
"description": "The page number of the results to fetch. For more information, see \"[Using pagination in the REST API](https://docs.github.com/rest/using-the-rest-api/using-pagination-in-the-rest-api).\"",
|
||||||
|
"in": "query",
|
||||||
|
"schema": {
|
||||||
|
"type": "integer",
|
||||||
|
"default": 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"responses": {
|
||||||
|
"not_found": {
|
||||||
|
"description": "Resource not found",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/basic-error"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"headers": {
|
||||||
|
"link": {
|
||||||
|
"example": "<https://api.github.com/resource?page=2>; rel=\"next\", <https://api.github.com/resource?page=5>; rel=\"last\"",
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"paths": {
|
||||||
|
"/repos/{owner}/{repo}/tags": {
|
||||||
|
"get": {
|
||||||
|
"summary": "List repository tags",
|
||||||
|
"description": "",
|
||||||
|
"tags": [
|
||||||
|
"repos"
|
||||||
|
],
|
||||||
|
"operationId": "repos/list-tags",
|
||||||
|
"externalDocs": {
|
||||||
|
"description": "API method documentation",
|
||||||
|
"url": "https://docs.github.com/rest/repos/repos#list-repository-tags"
|
||||||
|
},
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"$ref": "#/components/parameters/owner"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$ref": "#/components/parameters/repo"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$ref": "#/components/parameters/per-page"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$ref": "#/components/parameters/page"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Response",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/components/schemas/tag"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"examples": {
|
||||||
|
"default": {
|
||||||
|
"$ref": "#/components/examples/tag-items"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"headers": {
|
||||||
|
"Link": {
|
||||||
|
"$ref": "#/components/headers/link"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"x-github": {
|
||||||
|
"githubCloudOnly": false,
|
||||||
|
"enabledForGitHubApps": true,
|
||||||
|
"category": "repos",
|
||||||
|
"subcategory": "repos"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/repos/{owner}/{repo}/labels": {
|
||||||
|
"get": {
|
||||||
|
"summary": "List labels for a repository",
|
||||||
|
"description": "Lists all labels for a repository.",
|
||||||
|
"tags": [
|
||||||
|
"issues"
|
||||||
|
],
|
||||||
|
"operationId": "issues/list-labels-for-repo",
|
||||||
|
"externalDocs": {
|
||||||
|
"description": "API method documentation",
|
||||||
|
"url": "https://docs.github.com/rest/issues/labels#list-labels-for-a-repository"
|
||||||
|
},
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"$ref": "#/components/parameters/owner"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$ref": "#/components/parameters/repo"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$ref": "#/components/parameters/per-page"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$ref": "#/components/parameters/page"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Response",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/components/schemas/label"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"examples": {
|
||||||
|
"default": {
|
||||||
|
"$ref": "#/components/examples/label-items"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"headers": {
|
||||||
|
"Link": {
|
||||||
|
"$ref": "#/components/headers/link"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"404": {
|
||||||
|
"$ref": "#/components/responses/not_found"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"x-github": {
|
||||||
|
"githubCloudOnly": false,
|
||||||
|
"enabledForGitHubApps": true,
|
||||||
|
"category": "issues",
|
||||||
|
"subcategory": "labels"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+38
@@ -0,0 +1,38 @@
|
|||||||
|
// Copyright (c) Microsoft. All rights reserved.
|
||||||
|
|
||||||
|
// This sample demonstrates how to use an agent with function tools provided via an OpenAPI spec.
|
||||||
|
// It uses functionality from Semantic Kernel to parse the OpenAPI spec and create function tools to use with the Agent Framework Agent.
|
||||||
|
|
||||||
|
using Azure.AI.Agents;
|
||||||
|
using Azure.Identity;
|
||||||
|
using Microsoft.Agents.AI;
|
||||||
|
using Microsoft.Extensions.AI;
|
||||||
|
using Microsoft.SemanticKernel;
|
||||||
|
using Microsoft.SemanticKernel.Plugins.OpenApi;
|
||||||
|
|
||||||
|
var endpoint = Environment.GetEnvironmentVariable("AZURE_FOUNDRY_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("AZURE_FOUNDRY_PROJECT_ENDPOINT is not set.");
|
||||||
|
var deploymentName = Environment.GetEnvironmentVariable("AZURE_FOUNDRY_PROJECT_DEPLOYMENT_NAME") ?? "gpt-4o-mini";
|
||||||
|
|
||||||
|
// Load the OpenAPI Spec from a file.
|
||||||
|
KernelPlugin plugin = await OpenApiKernelPluginFactory.CreateFromOpenApiAsync("github", "OpenAPISpec.json");
|
||||||
|
|
||||||
|
// Convert the Semantic Kernel plugin to Agent Framework function tools.
|
||||||
|
// This requires a dummy Kernel instance, since KernelFunctions cannot execute without one.
|
||||||
|
Kernel kernel = new();
|
||||||
|
List<AITool> tools = plugin.Select(x => x.WithKernel(kernel)).Cast<AITool>().ToList();
|
||||||
|
|
||||||
|
const string AssistantInstructions = "You are a helpful assistant that can query GitHub repositories.";
|
||||||
|
const string AssistantName = "GitHubAssistant";
|
||||||
|
|
||||||
|
// Get a client to create/retrieve/delete server side agents with Azure Foundry Agents.
|
||||||
|
var agentsClient = new AgentsClient(new Uri(endpoint), new AzureCliCredential());
|
||||||
|
|
||||||
|
// Create AIAgent directly
|
||||||
|
AIAgent agent = await agentsClient.CreateAIAgentAsync(name: AssistantName, model: deploymentName, instructions: AssistantInstructions, tools: tools);
|
||||||
|
|
||||||
|
// Run the agent with the OpenAPI function tools.
|
||||||
|
AgentThread thread = agent.GetNewThread();
|
||||||
|
Console.WriteLine(await agent.RunAsync("Please list the names, colors and descriptions of all the labels available in the microsoft/agent-framework repository on github.", thread));
|
||||||
|
|
||||||
|
// Cleanup by agent name removes the agent version created.
|
||||||
|
agentsClient.DeleteAgent(agent.Name);
|
||||||
+21
@@ -0,0 +1,21 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
|
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Azure.AI.Agents" />
|
||||||
|
<PackageReference Include="Azure.Identity" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\..\..\..\src\Microsoft.Agents.AI.AzureAI\Microsoft.Agents.AI.AzureAI.csproj" />
|
||||||
|
<ProjectReference Include="..\..\..\..\..\src\Microsoft.Agents.AI\Microsoft.Agents.AI.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
+64
@@ -0,0 +1,64 @@
|
|||||||
|
// Copyright (c) Microsoft. All rights reserved.
|
||||||
|
|
||||||
|
// This sample demonstrates how to use an agent with function tools that require a human in the loop for approvals.
|
||||||
|
// It shows both non-streaming and streaming agent interactions using weather-related tools.
|
||||||
|
// If the agent is hosted in a service, with a remote user, combine this sample with the Persisted Conversations sample to persist the chat history
|
||||||
|
// while the agent is waiting for user input.
|
||||||
|
|
||||||
|
using System.ComponentModel;
|
||||||
|
using Azure.AI.Agents;
|
||||||
|
using Azure.Identity;
|
||||||
|
using Microsoft.Agents.AI;
|
||||||
|
using Microsoft.Extensions.AI;
|
||||||
|
|
||||||
|
var endpoint = Environment.GetEnvironmentVariable("AZURE_FOUNDRY_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("AZURE_FOUNDRY_PROJECT_ENDPOINT is not set.");
|
||||||
|
var deploymentName = Environment.GetEnvironmentVariable("AZURE_FOUNDRY_PROJECT_DEPLOYMENT_NAME") ?? "gpt-4o-mini";
|
||||||
|
|
||||||
|
// Create a sample function tool that the agent can use.
|
||||||
|
[Description("Get the weather for a given location.")]
|
||||||
|
static string GetWeather([Description("The location to get the weather for.")] string location)
|
||||||
|
=> $"The weather in {location} is cloudy with a high of 15°C.";
|
||||||
|
|
||||||
|
const string AssistantInstructions = "You are a helpful assistant that can get weather information.";
|
||||||
|
const string AssistantName = "WeatherAssistant";
|
||||||
|
|
||||||
|
// Get a client to create/retrieve/delete server side agents with Azure Foundry Agents.
|
||||||
|
var agentsClient = new AgentsClient(new Uri(endpoint), new AzureCliCredential());
|
||||||
|
|
||||||
|
var approvalTool = new ApprovalRequiredAIFunction(AIFunctionFactory.Create(GetWeather));
|
||||||
|
|
||||||
|
// Create AIAgent directly
|
||||||
|
AIAgent agent = await agentsClient.CreateAIAgentAsync(name: AssistantName, model: deploymentName, instructions: AssistantInstructions, tools: [approvalTool]);
|
||||||
|
|
||||||
|
// Call the agent with approval-required function tools.
|
||||||
|
// The agent will request approval before invoking the function.
|
||||||
|
AgentThread thread = agent.GetNewThread();
|
||||||
|
var response = await agent.RunAsync("What is the weather like in Amsterdam?", thread);
|
||||||
|
|
||||||
|
// Check if there are any user input requests (approvals needed).
|
||||||
|
var userInputRequests = response.UserInputRequests.ToList();
|
||||||
|
|
||||||
|
while (userInputRequests.Count > 0)
|
||||||
|
{
|
||||||
|
// Ask the user to approve each function call request.
|
||||||
|
// For simplicity, we are assuming here that only function approval requests are being made.
|
||||||
|
var userInputMessages = userInputRequests
|
||||||
|
.OfType<FunctionApprovalRequestContent>()
|
||||||
|
.Select(functionApprovalRequest =>
|
||||||
|
{
|
||||||
|
Console.WriteLine($"The agent would like to invoke the following function, please reply Y to approve: Name {functionApprovalRequest.FunctionCall.Name}");
|
||||||
|
var approved = Console.ReadLine()?.Equals("Y", StringComparison.OrdinalIgnoreCase) ?? false;
|
||||||
|
return new ChatMessage(ChatRole.User, [functionApprovalRequest.CreateResponse(approved)]);
|
||||||
|
})
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
// Pass the user input responses back to the agent for further processing.
|
||||||
|
response = await agent.RunAsync(userInputMessages, thread);
|
||||||
|
|
||||||
|
userInputRequests = response.UserInputRequests.ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.WriteLine($"\nAgent: {response}");
|
||||||
|
|
||||||
|
// Cleanup by agent name removes the agent version created.
|
||||||
|
agentsClient.DeleteAgent(agent.Name);
|
||||||
+21
@@ -0,0 +1,21 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
|
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Azure.AI.Agents" />
|
||||||
|
<PackageReference Include="Azure.Identity" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\..\..\..\src\Microsoft.Agents.AI.AzureAI\Microsoft.Agents.AI.AzureAI.csproj" />
|
||||||
|
<ProjectReference Include="..\..\..\..\..\src\Microsoft.Agents.AI.OpenAI\Microsoft.Agents.AI.OpenAI.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
+79
@@ -0,0 +1,79 @@
|
|||||||
|
// Copyright (c) Microsoft. All rights reserved.
|
||||||
|
|
||||||
|
// This sample shows how to configure an agent to produce structured output.
|
||||||
|
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Text.Json;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
using Azure.AI.Agents;
|
||||||
|
using Azure.Identity;
|
||||||
|
using Microsoft.Agents.AI;
|
||||||
|
using SampleApp;
|
||||||
|
|
||||||
|
#pragma warning disable CA5399
|
||||||
|
|
||||||
|
var endpoint = Environment.GetEnvironmentVariable("AZURE_FOUNDRY_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("AZURE_FOUNDRY_PROJECT_ENDPOINT is not set.");
|
||||||
|
var deploymentName = "gpt-5"; // Environment.GetEnvironmentVariable("AZURE_FOUNDRY_PROJECT_DEPLOYMENT_NAME") ?? "gpt-4o-mini";
|
||||||
|
|
||||||
|
const string AssistantInstructions = "You are a helpful assistant that extracts structured information about people.";
|
||||||
|
const string AssistantName = "StructuredOutputAssistant";
|
||||||
|
|
||||||
|
// Get a client to create/retrieve/delete server side agents with Azure Foundry Agents.
|
||||||
|
var agentsClient = new AgentsClient(new Uri(endpoint), new AzureCliCredential());
|
||||||
|
|
||||||
|
// Create ChatClientAgent directly
|
||||||
|
ChatClientAgent agent = await agentsClient.CreateAIAgentAsync(
|
||||||
|
model: deploymentName,
|
||||||
|
new ChatClientAgentOptions(name: AssistantName, instructions: AssistantInstructions));
|
||||||
|
|
||||||
|
// Set PersonInfo as the type parameter of RunAsync method to specify the expected structured output from the agent and invoke the agent with some unstructured input.
|
||||||
|
AgentRunResponse<PersonInfo> response = await agent.RunAsync<PersonInfo>("Please provide information about John Smith, who is a 35-year-old software engineer.");
|
||||||
|
|
||||||
|
// Access the structured output via the Result property of the agent response.
|
||||||
|
Console.WriteLine("Assistant Output:");
|
||||||
|
Console.WriteLine($"Name: {response.Result.Name}");
|
||||||
|
Console.WriteLine($"Age: {response.Result.Age}");
|
||||||
|
Console.WriteLine($"Occupation: {response.Result.Occupation}");
|
||||||
|
|
||||||
|
// Create the ChatClientAgent with the specified name, instructions, and expected structured output the agent should produce.
|
||||||
|
ChatClientAgent agentWithPersonInfo = agentsClient.CreateAIAgent(model: deploymentName, new ChatClientAgentOptions(name: AssistantName, instructions: AssistantInstructions)
|
||||||
|
{
|
||||||
|
ChatOptions = new()
|
||||||
|
{
|
||||||
|
ResponseFormat = Microsoft.Extensions.AI.ChatResponseFormat.ForJsonSchema<PersonInfo>()
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Invoke the agent with some unstructured input while streaming, to extract the structured information from.
|
||||||
|
var updates = agentWithPersonInfo.RunStreamingAsync("Please provide information about John Smith, who is a 35-year-old software engineer.");
|
||||||
|
|
||||||
|
// Assemble all the parts of the streamed output, since we can only deserialize once we have the full json,
|
||||||
|
// then deserialize the response into the PersonInfo class.
|
||||||
|
PersonInfo personInfo = (await updates.ToAgentRunResponseAsync()).Deserialize<PersonInfo>(JsonSerializerOptions.Web);
|
||||||
|
|
||||||
|
Console.WriteLine("Assistant Output:");
|
||||||
|
Console.WriteLine($"Name: {personInfo.Name}");
|
||||||
|
Console.WriteLine($"Age: {personInfo.Age}");
|
||||||
|
Console.WriteLine($"Occupation: {personInfo.Occupation}");
|
||||||
|
|
||||||
|
// Cleanup by agent name removes the agent version created.
|
||||||
|
agentsClient.DeleteAgent(agent.Name);
|
||||||
|
|
||||||
|
namespace SampleApp
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents information about a person, including their name, age, and occupation, matched to the JSON schema used in the agent.
|
||||||
|
/// </summary>
|
||||||
|
[Description("Information about a person including their name, age, and occupation")]
|
||||||
|
public class PersonInfo
|
||||||
|
{
|
||||||
|
[JsonPropertyName("name")]
|
||||||
|
public string? Name { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("age")]
|
||||||
|
public int? Age { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("occupation")]
|
||||||
|
public string? Occupation { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
+20
@@ -0,0 +1,20 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
|
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Azure.AI.Agents" />
|
||||||
|
<PackageReference Include="Azure.Identity" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\..\..\..\src\Microsoft.Agents.AI.AzureAI\Microsoft.Agents.AI.AzureAI.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
+44
@@ -0,0 +1,44 @@
|
|||||||
|
// Copyright (c) Microsoft. All rights reserved.
|
||||||
|
|
||||||
|
// This sample shows how to create and use a simple AI agent with a conversation that can be persisted to disk.
|
||||||
|
|
||||||
|
using System.Text.Json;
|
||||||
|
using Azure.AI.Agents;
|
||||||
|
using Azure.Identity;
|
||||||
|
using Microsoft.Agents.AI;
|
||||||
|
|
||||||
|
var endpoint = Environment.GetEnvironmentVariable("AZURE_FOUNDRY_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("AZURE_FOUNDRY_PROJECT_ENDPOINT is not set.");
|
||||||
|
var deploymentName = Environment.GetEnvironmentVariable("AZURE_FOUNDRY_PROJECT_DEPLOYMENT_NAME") ?? "gpt-4o-mini";
|
||||||
|
|
||||||
|
const string JokerInstructions = "You are good at telling jokes.";
|
||||||
|
const string JokerName = "JokerAgent";
|
||||||
|
|
||||||
|
// Get a client to create/retrieve/delete server side agents with Azure Foundry Agents.
|
||||||
|
var agentsClient = new AgentsClient(new Uri(endpoint), new AzureCliCredential());
|
||||||
|
|
||||||
|
AIAgent agent = await agentsClient.CreateAIAgentAsync(name: JokerName, model: deploymentName, instructions: JokerInstructions);
|
||||||
|
|
||||||
|
// Start a new thread for the agent conversation.
|
||||||
|
AgentThread thread = agent.GetNewThread();
|
||||||
|
|
||||||
|
// Run the agent with a new thread.
|
||||||
|
Console.WriteLine(await agent.RunAsync("Tell me a joke about a pirate.", thread));
|
||||||
|
|
||||||
|
// Serialize the thread state to a JsonElement, so it can be stored for later use.
|
||||||
|
JsonElement serializedThread = thread.Serialize();
|
||||||
|
|
||||||
|
// Save the serialized thread to a temporary file (for demonstration purposes).
|
||||||
|
string tempFilePath = Path.GetTempFileName();
|
||||||
|
await File.WriteAllTextAsync(tempFilePath, JsonSerializer.Serialize(serializedThread));
|
||||||
|
|
||||||
|
// Load the serialized thread from the temporary file (for demonstration purposes).
|
||||||
|
JsonElement reloadedSerializedThread = JsonSerializer.Deserialize<JsonElement>(await File.ReadAllTextAsync(tempFilePath));
|
||||||
|
|
||||||
|
// Deserialize the thread state after loading from storage.
|
||||||
|
AgentThread resumedThread = agent.DeserializeThread(reloadedSerializedThread);
|
||||||
|
|
||||||
|
// Run the agent again with the resumed thread.
|
||||||
|
Console.WriteLine(await agent.RunAsync("Now tell the same joke in the voice of a pirate, and add some emojis to the joke.", resumedThread));
|
||||||
|
|
||||||
|
// Cleanup by agent name removes the agent version created.
|
||||||
|
agentsClient.DeleteAgent(agent.Name);
|
||||||
+23
@@ -0,0 +1,23 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
|
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Azure.AI.Agents" />
|
||||||
|
<PackageReference Include="Azure.Identity" />
|
||||||
|
<PackageReference Include="Azure.Monitor.OpenTelemetry.Exporter" />
|
||||||
|
<PackageReference Include="OpenTelemetry" />
|
||||||
|
<PackageReference Include="OpenTelemetry.Exporter.Console" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\..\..\..\src\Microsoft.Agents.AI.AzureAI\Microsoft.Agents.AI.AzureAI.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
+52
@@ -0,0 +1,52 @@
|
|||||||
|
// Copyright (c) Microsoft. All rights reserved.
|
||||||
|
|
||||||
|
// This sample shows how to create and use a simple AI agent with Azure Foundry Agents as the backend that logs telemetry using OpenTelemetry.
|
||||||
|
|
||||||
|
using Azure.AI.Agents;
|
||||||
|
using Azure.Identity;
|
||||||
|
using Azure.Monitor.OpenTelemetry.Exporter;
|
||||||
|
using Microsoft.Agents.AI;
|
||||||
|
using OpenTelemetry;
|
||||||
|
using OpenTelemetry.Trace;
|
||||||
|
|
||||||
|
var endpoint = Environment.GetEnvironmentVariable("AZURE_FOUNDRY_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("AZURE_FOUNDRY_PROJECT_ENDPOINT is not set.");
|
||||||
|
var deploymentName = Environment.GetEnvironmentVariable("AZURE_FOUNDRY_PROJECT_DEPLOYMENT_NAME") ?? "gpt-4o-mini";
|
||||||
|
var applicationInsightsConnectionString = Environment.GetEnvironmentVariable("APPLICATIONINSIGHTS_CONNECTION_STRING");
|
||||||
|
|
||||||
|
const string JokerInstructions = "You are good at telling jokes.";
|
||||||
|
const string JokerName = "JokerAgent";
|
||||||
|
|
||||||
|
// Create TracerProvider with console exporter
|
||||||
|
// This will output the telemetry data to the console.
|
||||||
|
string sourceName = Guid.NewGuid().ToString("N");
|
||||||
|
var tracerProviderBuilder = Sdk.CreateTracerProviderBuilder()
|
||||||
|
.AddSource(sourceName)
|
||||||
|
.AddConsoleExporter();
|
||||||
|
if (!string.IsNullOrWhiteSpace(applicationInsightsConnectionString))
|
||||||
|
{
|
||||||
|
tracerProviderBuilder.AddAzureMonitorTraceExporter(options => options.ConnectionString = applicationInsightsConnectionString);
|
||||||
|
}
|
||||||
|
using var tracerProvider = tracerProviderBuilder.Build();
|
||||||
|
|
||||||
|
// Get a client to create/retrieve/delete server side agents with Azure Foundry Agents.
|
||||||
|
var agentsClient = new AgentsClient(new Uri(endpoint), new AzureCliCredential());
|
||||||
|
|
||||||
|
// Define the agent you want to create. (Prompt Agent in this case)
|
||||||
|
AIAgent agent = agentsClient.CreateAIAgent(name: JokerName, model: deploymentName, instructions: JokerInstructions)
|
||||||
|
.AsBuilder()
|
||||||
|
.UseOpenTelemetry(sourceName: sourceName)
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
// Invoke the agent and output the text result.
|
||||||
|
AgentThread thread = agent.GetNewThread();
|
||||||
|
Console.WriteLine(await agent.RunAsync("Tell me a joke about a pirate.", thread));
|
||||||
|
|
||||||
|
// Invoke the agent with streaming support.
|
||||||
|
thread = agent.GetNewThread();
|
||||||
|
await foreach (var update in agent.RunStreamingAsync("Tell me a joke about a pirate.", thread))
|
||||||
|
{
|
||||||
|
Console.WriteLine(update);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cleanup by agent name removes the agent version created.
|
||||||
|
agentsClient.DeleteAgent(agent.Name);
|
||||||
+21
@@ -0,0 +1,21 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
|
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Azure.AI.Agents" />
|
||||||
|
<PackageReference Include="Azure.Identity" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Hosting" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\..\..\..\src\Microsoft.Agents.AI.AzureAI\Microsoft.Agents.AI.AzureAI.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
+80
@@ -0,0 +1,80 @@
|
|||||||
|
// Copyright (c) Microsoft. All rights reserved.
|
||||||
|
|
||||||
|
#pragma warning disable CA1812
|
||||||
|
|
||||||
|
// This sample shows how to use dependency injection to register an AIAgent and use it from a hosted service with a user input chat loop.
|
||||||
|
|
||||||
|
using Azure.AI.Agents;
|
||||||
|
using Azure.Identity;
|
||||||
|
using Microsoft.Agents.AI;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.Hosting;
|
||||||
|
|
||||||
|
var endpoint = Environment.GetEnvironmentVariable("AZURE_FOUNDRY_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("AZURE_FOUNDRY_PROJECT_ENDPOINT is not set.");
|
||||||
|
var deploymentName = Environment.GetEnvironmentVariable("AZURE_FOUNDRY_PROJECT_DEPLOYMENT_NAME") ?? "gpt-4o-mini";
|
||||||
|
|
||||||
|
const string JokerInstructions = "You are good at telling jokes.";
|
||||||
|
const string JokerName = "JokerAgent";
|
||||||
|
|
||||||
|
// Create a host builder that we will register services with and then run.
|
||||||
|
HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
|
||||||
|
|
||||||
|
// Add the agents client to the service collection.
|
||||||
|
builder.Services.AddSingleton((sp) => new AgentsClient(new Uri(endpoint), new AzureCliCredential()));
|
||||||
|
|
||||||
|
// Add the AI agent to the service collection.
|
||||||
|
builder.Services.AddSingleton<AIAgent>((sp)
|
||||||
|
=> sp.GetRequiredService<AgentsClient>()
|
||||||
|
.CreateAIAgent(name: JokerName, model: deploymentName, instructions: JokerInstructions));
|
||||||
|
|
||||||
|
// Add a sample service that will use the agent to respond to user input.
|
||||||
|
builder.Services.AddHostedService<SampleService>();
|
||||||
|
|
||||||
|
// Build and run the host.
|
||||||
|
using IHost host = builder.Build();
|
||||||
|
await host.RunAsync().ConfigureAwait(false);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A sample service that uses an AI agent to respond to user input.
|
||||||
|
/// </summary>
|
||||||
|
internal sealed class SampleService(AIAgent agent, IHostApplicationLifetime appLifetime) : IHostedService
|
||||||
|
{
|
||||||
|
private AgentThread? _thread;
|
||||||
|
|
||||||
|
public async Task StartAsync(CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
// Create a thread that will be used for the entirety of the service lifetime so that the user can ask follow up questions.
|
||||||
|
this._thread = agent.GetNewThread();
|
||||||
|
_ = this.RunAsync(appLifetime.ApplicationStopping);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task RunAsync(CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
// Delay a little to allow the service to finish starting.
|
||||||
|
await Task.Delay(100, cancellationToken);
|
||||||
|
|
||||||
|
while (!cancellationToken.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
Console.WriteLine("\nAgent: Ask me to tell you a joke about a specific topic. To exit just press Ctrl+C or enter without any input.\n");
|
||||||
|
Console.Write("> ");
|
||||||
|
var input = Console.ReadLine();
|
||||||
|
|
||||||
|
// If the user enters no input, signal the application to shut down.
|
||||||
|
if (string.IsNullOrWhiteSpace(input))
|
||||||
|
{
|
||||||
|
appLifetime.StopApplication();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stream the output to the console as it is generated.
|
||||||
|
await foreach (var update in agent.RunStreamingAsync(input, this._thread, cancellationToken: cancellationToken))
|
||||||
|
{
|
||||||
|
Console.Write(update);
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.WriteLine();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
|
||||||
|
}
|
||||||
+25
@@ -0,0 +1,25 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
|
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<UserSecretsId>3afc9b74-af74-4d8e-ae96-fa1c511d11ac</UserSecretsId>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Azure.AI.Agents.Persistent" />
|
||||||
|
<PackageReference Include="Azure.Identity" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Hosting" />
|
||||||
|
<PackageReference Include="ModelContextProtocol" />
|
||||||
|
<PackageReference Include="System.Net.ServerSentEvents" VersionOverride="10.0.0-rc.2.25502.107" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\..\..\..\src\Microsoft.Agents.AI.AzureAI\Microsoft.Agents.AI.AzureAI.csproj" />
|
||||||
|
<ProjectReference Include="..\..\..\..\..\src\Microsoft.Agents.AI\Microsoft.Agents.AI.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
+42
@@ -0,0 +1,42 @@
|
|||||||
|
// Copyright (c) Microsoft. All rights reserved.
|
||||||
|
|
||||||
|
// This sample shows how to expose an AI agent as an MCP tool.
|
||||||
|
|
||||||
|
using Azure.AI.Agents;
|
||||||
|
using Azure.Identity;
|
||||||
|
using Microsoft.Agents.AI;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.Hosting;
|
||||||
|
using ModelContextProtocol.Server;
|
||||||
|
|
||||||
|
var endpoint = Environment.GetEnvironmentVariable("AZURE_FOUNDRY_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("AZURE_FOUNDRY_PROJECT_ENDPOINT is not set.");
|
||||||
|
var deploymentName = Environment.GetEnvironmentVariable("AZURE_FOUNDRY_PROJECT_DEPLOYMENT_NAME") ?? "gpt-4o-mini";
|
||||||
|
|
||||||
|
const string JokerInstructions = "You are good at telling jokes, and you always start each joke with 'Aye aye, captain!'.";
|
||||||
|
const string JokerName = "JokerAgent";
|
||||||
|
const string JokerDescription = "An agent that tells jokes.";
|
||||||
|
|
||||||
|
// Get a client to create/retrieve/delete server side agents with Azure Foundry Agents.
|
||||||
|
var agentsClient = new AgentsClient(new Uri(endpoint), new AzureCliCredential());
|
||||||
|
|
||||||
|
// Define the agent you want to create. (Prompt Agent in this case)
|
||||||
|
AIAgent agent = agentsClient.CreateAIAgent(
|
||||||
|
name: JokerName,
|
||||||
|
model: deploymentName,
|
||||||
|
instructions: JokerInstructions,
|
||||||
|
creationOptions: new() { Description = JokerDescription });
|
||||||
|
|
||||||
|
// Convert the agent to an AIFunction and then to an MCP tool.
|
||||||
|
// The agent name and description will be used as the mcp tool name and description.
|
||||||
|
McpServerTool tool = McpServerTool.Create(agent.AsAIFunction());
|
||||||
|
|
||||||
|
// Register the MCP server with StdIO transport and expose the tool via the server.
|
||||||
|
HostApplicationBuilder builder = Host.CreateEmptyApplicationBuilder(settings: null);
|
||||||
|
builder.Services
|
||||||
|
.AddMcpServer()
|
||||||
|
.WithStdioServerTransport()
|
||||||
|
.WithTools([tool]);
|
||||||
|
|
||||||
|
Console.WriteLine("Starting MCP Tool server. Press Ctrl+C to exit.");
|
||||||
|
|
||||||
|
await builder.Build().RunAsync();
|
||||||
+29
@@ -0,0 +1,29 @@
|
|||||||
|
This sample demonstrates how to expose an existing AI agent as an MCP tool.
|
||||||
|
|
||||||
|
## Run the sample
|
||||||
|
|
||||||
|
To run the sample, please use one of the following MCP clients: https://modelcontextprotocol.io/clients
|
||||||
|
|
||||||
|
Alternatively, use the QuickstartClient sample from this repository: https://github.com/modelcontextprotocol/csharp-sdk/tree/main/samples/QuickstartClient
|
||||||
|
|
||||||
|
## Run the sample using MCP Inspector
|
||||||
|
|
||||||
|
To use the [MCP Inspector](https://modelcontextprotocol.io/docs/tools/inspector), follow these steps:
|
||||||
|
|
||||||
|
1. Open a terminal in the Agent_Step10_AsMcpTool project directory.
|
||||||
|
1. Run the `npx @modelcontextprotocol/inspector dotnet run` command to start the MCP Inspector. Make sure you have [node.js](https://nodejs.org/en/download/) and npm installed.
|
||||||
|
```bash
|
||||||
|
npx @modelcontextprotocol/inspector dotnet run
|
||||||
|
```
|
||||||
|
1. When the inspector is running, it will display a URL in the terminal, like this:
|
||||||
|
```
|
||||||
|
MCP Inspector is up and running at http://127.0.0.1:6274
|
||||||
|
```
|
||||||
|
1. Open a web browser and navigate to the URL displayed in the terminal. If not opened automatically, this will open the MCP Inspector interface.
|
||||||
|
1. In the MCP Inspector interface, add the following environment variables to allow your MCP server to access Azure AI Foundry Project to create and run the agent:
|
||||||
|
- AZURE_FOUNDRY_PROJECT_ENDPOINT = https://your-resource.openai.azure.com/ # Replace with your Azure AI Foundry Project endpoint
|
||||||
|
- AZURE_FOUNDRY_PROJECT_DEPLOYMENT_NAME = gpt-4o-mini # Replace with your model deployment name
|
||||||
|
1. Find and click the `Connect` button in the MCP Inspector interface to connect to the MCP server.
|
||||||
|
1. As soon as the connection is established, open the `Tools` tab in the MCP Inspector interface and select the `Joker` tool from the list.
|
||||||
|
1. Specify your prompt as a value for the `query` argument, for example: `Tell me a joke about a pirate` and click the `Run Tool` button to run the tool.
|
||||||
|
1. The agent will process the request and return a response in accordance with the provided instructions that instruct it to always start each joke with 'Aye aye, captain!'.
|
||||||
+20
@@ -0,0 +1,20 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
|
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Azure.AI.Agents" />
|
||||||
|
<PackageReference Include="Azure.Identity" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\..\..\..\src\Microsoft.Agents.AI.AzureAI\Microsoft.Agents.AI.AzureAI.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
+35
@@ -0,0 +1,35 @@
|
|||||||
|
// Copyright (c) Microsoft. All rights reserved.
|
||||||
|
|
||||||
|
// This sample shows how to use Image Multi-Modality with an AI agent.
|
||||||
|
|
||||||
|
using Azure.AI.Agents;
|
||||||
|
using Azure.Identity;
|
||||||
|
using Microsoft.Agents.AI;
|
||||||
|
using Microsoft.Extensions.AI;
|
||||||
|
|
||||||
|
var endpoint = Environment.GetEnvironmentVariable("AZURE_FOUNDRY_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("AZURE_FOUNDRY_PROJECT_ENDPOINT is not set.");
|
||||||
|
var deploymentName = System.Environment.GetEnvironmentVariable("AZURE_FOUNDRY_PROJECT_DEPLOYMENT_NAME") ?? "gpt-4o";
|
||||||
|
|
||||||
|
const string VisionInstructions = "You are a helpful agent that can analyze images";
|
||||||
|
const string VisionName = "VisionAgent";
|
||||||
|
|
||||||
|
// Get a client to create/retrieve/delete server side agents with Azure Foundry Agents.
|
||||||
|
var agentsClient = new AgentsClient(new Uri(endpoint), new AzureCliCredential());
|
||||||
|
|
||||||
|
// Define the agent you want to create. (Prompt Agent in this case)
|
||||||
|
AIAgent agent = agentsClient.CreateAIAgent(name: VisionName, model: deploymentName, instructions: VisionInstructions);
|
||||||
|
|
||||||
|
ChatMessage message = new(ChatRole.User, [
|
||||||
|
new TextContent("What do you see in this image?"),
|
||||||
|
new UriContent("https://upload.wikimedia.org/wikipedia/commons/thumb/d/dd/Gfp-wisconsin-madison-the-nature-boardwalk.jpg/2560px-Gfp-wisconsin-madison-the-nature-boardwalk.jpg", "image/jpeg")
|
||||||
|
]);
|
||||||
|
|
||||||
|
var thread = agent.GetNewThread();
|
||||||
|
|
||||||
|
await foreach (var update in agent.RunStreamingAsync(message, thread))
|
||||||
|
{
|
||||||
|
Console.WriteLine(update);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cleanup by agent name removes the agent version created.
|
||||||
|
agentsClient.DeleteAgent(agent.Name);
|
||||||
+52
@@ -0,0 +1,52 @@
|
|||||||
|
# Using Images with AI Agents
|
||||||
|
|
||||||
|
This sample demonstrates how to use image multi-modality with an AI agent. It shows how to create a vision-enabled agent that can analyze and describe images using Azure OpenAI.
|
||||||
|
|
||||||
|
## What this sample demonstrates
|
||||||
|
|
||||||
|
- Creating a persistent AI agent with vision capabilities
|
||||||
|
- Sending both text and image content to an agent in a single message
|
||||||
|
- Using `UriContent` to Uri referenced images
|
||||||
|
- Processing multimodal input (text + image) with an AI agent
|
||||||
|
|
||||||
|
## Key features
|
||||||
|
|
||||||
|
- **Vision Agent**: Creates an agent specifically instructed to analyze images
|
||||||
|
- **Multimodal Input**: Combines text questions with image uri in a single message
|
||||||
|
- **Azure OpenAI Integration**: Uses AzureOpenAI LLM agents
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
Before running this sample, ensure you have:
|
||||||
|
|
||||||
|
1. An Azure OpenAI project set up
|
||||||
|
2. A compatible model deployment (e.g., gpt-4o)
|
||||||
|
3. Azure CLI installed and authenticated
|
||||||
|
|
||||||
|
## Environment Variables
|
||||||
|
|
||||||
|
Set the following environment variables:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
$env:AZURE_OPENAI_ENDPOINT="https://your-resource.openai.azure.com/" # Replace with your Azure OpenAI endpoint
|
||||||
|
$env:AZURE_OPENAI_DEPLOYMENT_NAME="gpt-4o" # Replace with your model deployment name (optional, defaults to gpt-4o)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Run the sample
|
||||||
|
|
||||||
|
Navigate to the sample directory and run:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
cd Agent_Step11_UsingImages
|
||||||
|
dotnet run
|
||||||
|
```
|
||||||
|
|
||||||
|
## Expected behavior
|
||||||
|
|
||||||
|
The sample will:
|
||||||
|
|
||||||
|
1. Create a vision-enabled agent named "VisionAgent"
|
||||||
|
2. Send a message containing both text ("What do you see in this image?") and a Uri image of a green walk
|
||||||
|
3. The agent will analyze the image and provide a description
|
||||||
|
4. Clean up resources by deleting the thread and agent
|
||||||
|
|
||||||
+22
@@ -0,0 +1,22 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
|
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<UserSecretsId>3afc9b74-af74-4d8e-ae96-fa1c511d11ac</UserSecretsId>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Azure.AI.Agents" />
|
||||||
|
<PackageReference Include="Azure.Identity" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\..\..\..\src\Microsoft.Agents.AI.AzureAI\Microsoft.Agents.AI.AzureAI.csproj" />
|
||||||
|
<ProjectReference Include="..\..\..\..\..\src\Microsoft.Agents.AI\Microsoft.Agents.AI.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
+47
@@ -0,0 +1,47 @@
|
|||||||
|
// Copyright (c) Microsoft. All rights reserved.
|
||||||
|
|
||||||
|
// This sample shows how to create and use an Azure Foundry Agents AI agent as a function tool.
|
||||||
|
|
||||||
|
using System.ComponentModel;
|
||||||
|
using Azure.AI.Agents;
|
||||||
|
using Azure.Identity;
|
||||||
|
using Microsoft.Agents.AI;
|
||||||
|
using Microsoft.Extensions.AI;
|
||||||
|
|
||||||
|
var endpoint = Environment.GetEnvironmentVariable("AZURE_FOUNDRY_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("AZURE_FOUNDRY_PROJECT_ENDPOINT is not set.");
|
||||||
|
var deploymentName = Environment.GetEnvironmentVariable("AZURE_FOUNDRY_PROJECT_DEPLOYMENT_NAME") ?? "gpt-4o-mini";
|
||||||
|
|
||||||
|
const string WeatherInstructions = "You answer questions about the weather.";
|
||||||
|
const string WeatherName = "WeatherAgent";
|
||||||
|
const string MainInstructions = "You are a helpful assistant who responds in French.";
|
||||||
|
const string MainName = "MainAgent";
|
||||||
|
|
||||||
|
[Description("Get the weather for a given location.")]
|
||||||
|
static string GetWeather([Description("The location to get the weather for.")] string location)
|
||||||
|
=> $"The weather in {location} is cloudy with a high of 15°C.";
|
||||||
|
|
||||||
|
// Get a client to create/retrieve/delete server side agents with Azure Foundry Agents.
|
||||||
|
var agentsClient = new AgentsClient(new Uri(endpoint), new AzureCliCredential());
|
||||||
|
|
||||||
|
// Create the weather agent with function tools.
|
||||||
|
var weatherTool = AIFunctionFactory.Create(GetWeather);
|
||||||
|
AIAgent weatherAgent = agentsClient.CreateAIAgent(
|
||||||
|
name: WeatherName,
|
||||||
|
model: deploymentName,
|
||||||
|
instructions: WeatherInstructions,
|
||||||
|
tools: [weatherTool]);
|
||||||
|
|
||||||
|
// Create the main agent, and provide the weather agent as a function tool.
|
||||||
|
AIAgent agent = agentsClient.CreateAIAgent(
|
||||||
|
name: MainName,
|
||||||
|
model: deploymentName,
|
||||||
|
instructions: MainInstructions,
|
||||||
|
tools: [weatherAgent.AsAIFunction()]);
|
||||||
|
|
||||||
|
// Invoke the agent and output the text result.
|
||||||
|
AgentThread thread = agent.GetNewThread();
|
||||||
|
Console.WriteLine(await agent.RunAsync("What is the weather like in Amsterdam?", thread));
|
||||||
|
|
||||||
|
// Cleanup by agent name removes the agent versions created.
|
||||||
|
agentsClient.DeleteAgent(agent.Name);
|
||||||
|
agentsClient.DeleteAgent(weatherAgent.Name);
|
||||||
+22
@@ -0,0 +1,22 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
|
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Logging.Console" />
|
||||||
|
<PackageReference Include="Azure.Identity" />
|
||||||
|
<PackageReference Include="Azure.AI.Agents" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\..\..\..\src\Microsoft.Agents.AI.AzureAI\Microsoft.Agents.AI.AzureAI.csproj" />
|
||||||
|
<ProjectReference Include="..\..\..\..\..\src\Microsoft.Agents.AI\Microsoft.Agents.AI.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
+222
@@ -0,0 +1,222 @@
|
|||||||
|
// Copyright (c) Microsoft. All rights reserved.
|
||||||
|
|
||||||
|
// This sample shows multiple middleware layers working together with Azure Foundry Agents:
|
||||||
|
// agent run (PII filtering and guardrails),
|
||||||
|
// function invocation (logging and result overrides), and human-in-the-loop
|
||||||
|
// approval workflows for sensitive function calls.
|
||||||
|
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using Azure.AI.Agents;
|
||||||
|
using Azure.Identity;
|
||||||
|
using Microsoft.Agents.AI;
|
||||||
|
using Microsoft.Extensions.AI;
|
||||||
|
|
||||||
|
// Get Azure AI Foundry configuration from environment variables
|
||||||
|
var endpoint = Environment.GetEnvironmentVariable("AZURE_FOUNDRY_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("AZURE_FOUNDRY_PROJECT_ENDPOINT is not set.");
|
||||||
|
var deploymentName = System.Environment.GetEnvironmentVariable("AZURE_FOUNDRY_PROJECT_DEPLOYMENT_NAME") ?? "gpt-4o";
|
||||||
|
|
||||||
|
const string AssistantInstructions = "You are an AI assistant that helps people find information.";
|
||||||
|
const string AssistantName = "InformationAssistant";
|
||||||
|
|
||||||
|
// Get a client to create/retrieve/delete server side agents with Azure Foundry Agents.
|
||||||
|
var agentsClient = new AgentsClient(new Uri(endpoint), new AzureCliCredential());
|
||||||
|
|
||||||
|
[Description("Get the weather for a given location.")]
|
||||||
|
static string GetWeather([Description("The location to get the weather for.")] string location)
|
||||||
|
=> $"The weather in {location} is cloudy with a high of 15°C.";
|
||||||
|
|
||||||
|
[Description("The current datetime offset.")]
|
||||||
|
static string GetDateTime()
|
||||||
|
=> DateTimeOffset.Now.ToString();
|
||||||
|
|
||||||
|
var dateTimeTool = AIFunctionFactory.Create(GetDateTime, name: nameof(GetDateTime));
|
||||||
|
var getWeatherTool = AIFunctionFactory.Create(GetWeather, name: nameof(GetWeather));
|
||||||
|
|
||||||
|
// Define the agent you want to create. (Prompt Agent in this case)
|
||||||
|
AIAgent originalAgent = agentsClient.CreateAIAgent(
|
||||||
|
name: AssistantName,
|
||||||
|
model: deploymentName,
|
||||||
|
instructions: AssistantInstructions,
|
||||||
|
tools: [getWeatherTool, dateTimeTool]);
|
||||||
|
|
||||||
|
// Adding middleware to the agent level
|
||||||
|
var middlewareEnabledAgent = originalAgent
|
||||||
|
.AsBuilder()
|
||||||
|
.Use(FunctionCallMiddleware)
|
||||||
|
.Use(FunctionCallOverrideWeather)
|
||||||
|
.Use(PIIMiddleware, null)
|
||||||
|
.Use(GuardrailMiddleware, null)
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
var thread = middlewareEnabledAgent.GetNewThread();
|
||||||
|
|
||||||
|
Console.WriteLine("\n\n=== Example 1: Wording Guardrail ===");
|
||||||
|
var guardRailedResponse = await middlewareEnabledAgent.RunAsync("Tell me something harmful.");
|
||||||
|
Console.WriteLine($"Guard railed response: {guardRailedResponse}");
|
||||||
|
|
||||||
|
Console.WriteLine("\n\n=== Example 2: PII detection ===");
|
||||||
|
var piiResponse = await middlewareEnabledAgent.RunAsync("My name is John Doe, call me at 123-456-7890 or email me at john@something.com");
|
||||||
|
Console.WriteLine($"Pii filtered response: {piiResponse}");
|
||||||
|
|
||||||
|
Console.WriteLine("\n\n=== Example 3: Agent function middleware ===");
|
||||||
|
|
||||||
|
// Agent function middleware support is limited to agents that wraps a upstream ChatClientAgent or derived from it.
|
||||||
|
|
||||||
|
var functionCallResponse = await middlewareEnabledAgent.RunAsync("What's the current time and the weather in Seattle?", thread);
|
||||||
|
Console.WriteLine($"Function calling response: {functionCallResponse}");
|
||||||
|
|
||||||
|
// Special per-request middleware agent.
|
||||||
|
Console.WriteLine("\n\n=== Example 4: Middleware with human in the loop function approval ===");
|
||||||
|
|
||||||
|
AIAgent humamInTheLoopAgent = agentsClient.CreateAIAgent(
|
||||||
|
name: "HumanInTheLoopAgent",
|
||||||
|
model: deploymentName,
|
||||||
|
instructions: "You are an Human in the loop testing AI assistant that helps people find information.",
|
||||||
|
|
||||||
|
// Adding a function with approval required
|
||||||
|
tools: [new ApprovalRequiredAIFunction(AIFunctionFactory.Create(GetWeather, name: nameof(GetWeather)))]);
|
||||||
|
|
||||||
|
// Using the ConsolePromptingApprovalMiddleware for a specific request to handle user approval during function calls.
|
||||||
|
var response = await humamInTheLoopAgent
|
||||||
|
.AsBuilder()
|
||||||
|
.Use(ConsolePromptingApprovalMiddleware, null)
|
||||||
|
.Build()
|
||||||
|
.RunAsync("What's the current time and the weather in Seattle?");
|
||||||
|
|
||||||
|
Console.WriteLine($"HumamInTheLoopAgent agent middleware response: {response}");
|
||||||
|
|
||||||
|
// Function invocation middleware that logs before and after function calls.
|
||||||
|
async ValueTask<object?> FunctionCallMiddleware(AIAgent agent, FunctionInvocationContext context, Func<FunctionInvocationContext, CancellationToken, ValueTask<object?>> next, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"Function Name: {context!.Function.Name} - Middleware 1 Pre-Invoke");
|
||||||
|
var result = await next(context, cancellationToken);
|
||||||
|
Console.WriteLine($"Function Name: {context!.Function.Name} - Middleware 1 Post-Invoke");
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function invocation middleware that overrides the result of the GetWeather function.
|
||||||
|
async ValueTask<object?> FunctionCallOverrideWeather(AIAgent agent, FunctionInvocationContext context, Func<FunctionInvocationContext, CancellationToken, ValueTask<object?>> next, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"Function Name: {context!.Function.Name} - Middleware 2 Pre-Invoke");
|
||||||
|
|
||||||
|
var result = await next(context, cancellationToken);
|
||||||
|
|
||||||
|
if (context.Function.Name == nameof(GetWeather))
|
||||||
|
{
|
||||||
|
// Override the result of the GetWeather function
|
||||||
|
result = "The weather is sunny with a high of 25°C.";
|
||||||
|
}
|
||||||
|
Console.WriteLine($"Function Name: {context!.Function.Name} - Middleware 2 Post-Invoke");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This middleware redacts PII information from input and output messages.
|
||||||
|
async Task<AgentRunResponse> PIIMiddleware(IEnumerable<ChatMessage> messages, AgentThread? thread, AgentRunOptions? options, AIAgent innerAgent, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
// Redact PII information from input messages
|
||||||
|
var filteredMessages = FilterMessages(messages);
|
||||||
|
Console.WriteLine("Pii Middleware - Filtered Messages Pre-Run");
|
||||||
|
|
||||||
|
var response = await innerAgent.RunAsync(filteredMessages, thread, options, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
|
// Redact PII information from output messages
|
||||||
|
response.Messages = FilterMessages(response.Messages);
|
||||||
|
|
||||||
|
Console.WriteLine("Pii Middleware - Filtered Messages Post-Run");
|
||||||
|
|
||||||
|
return response;
|
||||||
|
|
||||||
|
static IList<ChatMessage> FilterMessages(IEnumerable<ChatMessage> messages)
|
||||||
|
{
|
||||||
|
return messages.Select(m => new ChatMessage(m.Role, FilterPii(m.Text))).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
static string FilterPii(string content)
|
||||||
|
{
|
||||||
|
// Regex patterns for PII detection (simplified for demonstration)
|
||||||
|
Regex[] piiPatterns = [
|
||||||
|
new(@"\b\d{3}-\d{3}-\d{4}\b", RegexOptions.Compiled), // Phone number (e.g., 123-456-7890)
|
||||||
|
new(@"\b[\w\.-]+@[\w\.-]+\.\w+\b", RegexOptions.Compiled), // Email address
|
||||||
|
new(@"\b[A-Z][a-z]+\s[A-Z][a-z]+\b", RegexOptions.Compiled) // Full name (e.g., John Doe)
|
||||||
|
];
|
||||||
|
|
||||||
|
foreach (var pattern in piiPatterns)
|
||||||
|
{
|
||||||
|
content = pattern.Replace(content, "[REDACTED: PII]");
|
||||||
|
}
|
||||||
|
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This middleware enforces guardrails by redacting certain keywords from input and output messages.
|
||||||
|
async Task<AgentRunResponse> GuardrailMiddleware(IEnumerable<ChatMessage> messages, AgentThread? thread, AgentRunOptions? options, AIAgent innerAgent, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
// Redact keywords from input messages
|
||||||
|
var filteredMessages = FilterMessages(messages);
|
||||||
|
|
||||||
|
Console.WriteLine("Guardrail Middleware - Filtered messages Pre-Run");
|
||||||
|
|
||||||
|
// Proceed with the agent run
|
||||||
|
var response = await innerAgent.RunAsync(filteredMessages, thread, options, cancellationToken);
|
||||||
|
|
||||||
|
// Redact keywords from output messages
|
||||||
|
response.Messages = FilterMessages(response.Messages);
|
||||||
|
|
||||||
|
Console.WriteLine("Guardrail Middleware - Filtered messages Post-Run");
|
||||||
|
|
||||||
|
return response;
|
||||||
|
|
||||||
|
List<ChatMessage> FilterMessages(IEnumerable<ChatMessage> messages)
|
||||||
|
{
|
||||||
|
return messages.Select(m => new ChatMessage(m.Role, FilterContent(m.Text))).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
static string FilterContent(string content)
|
||||||
|
{
|
||||||
|
foreach (var keyword in new[] { "harmful", "illegal", "violence" })
|
||||||
|
{
|
||||||
|
if (content.Contains(keyword, StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
return "[REDACTED: Forbidden content]";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This middleware handles Human in the loop console interaction for any user approval required during function calling.
|
||||||
|
async Task<AgentRunResponse> ConsolePromptingApprovalMiddleware(IEnumerable<ChatMessage> messages, AgentThread? thread, AgentRunOptions? options, AIAgent innerAgent, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
var response = await innerAgent.RunAsync(messages, thread, options, cancellationToken);
|
||||||
|
|
||||||
|
var userInputRequests = response.UserInputRequests.ToList();
|
||||||
|
|
||||||
|
while (userInputRequests.Count > 0)
|
||||||
|
{
|
||||||
|
// Ask the user to approve each function call request.
|
||||||
|
// For simplicity, we are assuming here that only function approval requests are being made.
|
||||||
|
|
||||||
|
// Pass the user input responses back to the agent for further processing.
|
||||||
|
response.Messages = userInputRequests
|
||||||
|
.OfType<FunctionApprovalRequestContent>()
|
||||||
|
.Select(functionApprovalRequest =>
|
||||||
|
{
|
||||||
|
Console.WriteLine($"The agent would like to invoke the following function, please reply Y to approve: Name {functionApprovalRequest.FunctionCall.Name}");
|
||||||
|
return new ChatMessage(ChatRole.User, [functionApprovalRequest.CreateResponse(Console.ReadLine()?.Equals("Y", StringComparison.OrdinalIgnoreCase) ?? false)]);
|
||||||
|
})
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
response = await innerAgent.RunAsync(response.Messages, thread, options, cancellationToken);
|
||||||
|
|
||||||
|
userInputRequests = response.UserInputRequests.ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cleanup by agent name removes the agent version created.
|
||||||
|
agentsClient.DeleteAgent(middlewareEnabledAgent.Name);
|
||||||
+41
@@ -0,0 +1,41 @@
|
|||||||
|
# Agent Middleware
|
||||||
|
|
||||||
|
This sample demonstrates how to add middleware to intercept:
|
||||||
|
- Chat client calls (global and per‑request)
|
||||||
|
- Agent runs (guardrails and PII filtering)
|
||||||
|
- Function calling (logging/override)
|
||||||
|
|
||||||
|
## What This Sample Shows
|
||||||
|
|
||||||
|
1. Azure OpenAI integration via `AzureOpenAIClient` and `AzureCliCredential`
|
||||||
|
2. Chat client middleware using `ChatClientBuilder.Use(...)`
|
||||||
|
3. Agent run middleware (PII redaction and wording guardrails)
|
||||||
|
4. Function invocation middleware (logging and overriding a tool result)
|
||||||
|
5. Per‑request chat client middleware
|
||||||
|
6. Per‑request function pipeline with approval
|
||||||
|
7. Combining agent‑level and per‑request middleware
|
||||||
|
|
||||||
|
## Function Invocation Middleware
|
||||||
|
|
||||||
|
Not all agents support function invocation middleware.
|
||||||
|
|
||||||
|
Attempting to use function middleware on agents that do not wrap a ChatClientAgent or derives from it will throw an InvalidOperationException.
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
1. Environment variables:
|
||||||
|
- `AZURE_OPENAI_ENDPOINT`: Your Azure OpenAI endpoint
|
||||||
|
- `AZURE_OPENAI_DEPLOYMENT_NAME`: Chat deployment name (optional; defaults to `gpt-4o`)
|
||||||
|
2. Sign in with Azure CLI (PowerShell):
|
||||||
|
```powershell
|
||||||
|
az login
|
||||||
|
```
|
||||||
|
|
||||||
|
## Running the Sample
|
||||||
|
|
||||||
|
Use PowerShell:
|
||||||
|
```powershell
|
||||||
|
cd dotnet/samples/GettingStarted/Agents/Agent_Step14_Middleware
|
||||||
|
dotnet run
|
||||||
|
```
|
||||||
|
|
||||||
+24
@@ -0,0 +1,24 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
|
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<NoWarn>$(NoWarn);CA1812</NoWarn>
|
||||||
|
<RootNamespace>Agent_Step15_Plugins</RootNamespace>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Logging.Console" />
|
||||||
|
<PackageReference Include="Azure.Identity" />
|
||||||
|
<PackageReference Include="Azure.AI.Agents" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\..\..\..\src\Microsoft.Agents.AI.AzureAI\Microsoft.Agents.AI.AzureAI.csproj" />
|
||||||
|
<ProjectReference Include="..\..\..\..\..\src\Microsoft.Agents.AI\Microsoft.Agents.AI.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
+139
@@ -0,0 +1,139 @@
|
|||||||
|
// Copyright (c) Microsoft. All rights reserved.
|
||||||
|
|
||||||
|
// This sample shows how to use plugins with an AI agent. Plugin classes can
|
||||||
|
// depend on other services that need to be injected. In this sample, the
|
||||||
|
// AgentPlugin class uses the WeatherProvider and CurrentTimeProvider classes
|
||||||
|
// to get weather and current time information. Both services are registered
|
||||||
|
// in the service collection and injected into the plugin.
|
||||||
|
// Plugin classes may have many methods, but only some are intended to be used
|
||||||
|
// as AI functions. The AsAITools method of the plugin class shows how to specify
|
||||||
|
// which methods should be exposed to the AI agent.
|
||||||
|
|
||||||
|
using Azure.AI.Agents;
|
||||||
|
using Azure.Identity;
|
||||||
|
using Microsoft.Agents.AI;
|
||||||
|
using Microsoft.Extensions.AI;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
|
var endpoint = Environment.GetEnvironmentVariable("AZURE_FOUNDRY_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("AZURE_FOUNDRY_PROJECT_ENDPOINT is not set.");
|
||||||
|
var deploymentName = Environment.GetEnvironmentVariable("AZURE_FOUNDRY_PROJECT_DEPLOYMENT_NAME") ?? "gpt-4o-mini";
|
||||||
|
|
||||||
|
const string AssistantInstructions = "You are a helpful assistant that helps people find information.";
|
||||||
|
const string AssistantName = "PluginAssistant";
|
||||||
|
|
||||||
|
// Create a service collection to hold the agent plugin and its dependencies.
|
||||||
|
ServiceCollection services = new();
|
||||||
|
services.AddSingleton<WeatherProvider>();
|
||||||
|
services.AddSingleton<CurrentTimeProvider>();
|
||||||
|
services.AddSingleton<AgentPlugin>(); // The plugin depends on WeatherProvider and CurrentTimeProvider registered above.
|
||||||
|
|
||||||
|
IServiceProvider serviceProvider = services.BuildServiceProvider();
|
||||||
|
|
||||||
|
// Get a client to create/retrieve/delete server side agents with Azure Foundry Agents.
|
||||||
|
var agentsClient = new AgentsClient(new Uri(endpoint), new AzureCliCredential());
|
||||||
|
|
||||||
|
// Define the agent with plugin tools
|
||||||
|
// Define the agent you want to create. (Prompt Agent in this case)
|
||||||
|
AIAgent agent = agentsClient.CreateAIAgent(
|
||||||
|
name: AssistantName,
|
||||||
|
model: deploymentName,
|
||||||
|
instructions: AssistantInstructions,
|
||||||
|
tools: serviceProvider.GetRequiredService<AgentPlugin>().AsAITools().ToList(),
|
||||||
|
services: serviceProvider);
|
||||||
|
|
||||||
|
// Invoke the agent and output the text result.
|
||||||
|
AgentThread thread = agent.GetNewThread();
|
||||||
|
Console.WriteLine(await agent.RunAsync("Tell me current time and weather in Seattle.", thread));
|
||||||
|
|
||||||
|
// Cleanup by agent name removes the agent version created.
|
||||||
|
agentsClient.DeleteAgent(agent.Name);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The agent plugin that provides weather and current time information.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="weatherProvider">The weather provider to get weather information.</param>
|
||||||
|
internal sealed class AgentPlugin(WeatherProvider weatherProvider)
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the weather information for the specified location.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// This method demonstrates how to use the dependency that was injected into the plugin class.
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="location">The location to get the weather for.</param>
|
||||||
|
/// <returns>The weather information for the specified location.</returns>
|
||||||
|
public string GetWeather(string location)
|
||||||
|
{
|
||||||
|
return weatherProvider.GetWeather(location);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the current date and time for the specified location.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// This method demonstrates how to resolve a dependency using the service provider passed to the method.
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="sp">The service provider to resolve the <see cref="CurrentTimeProvider"/>.</param>
|
||||||
|
/// <param name="location">The location to get the current time for.</param>
|
||||||
|
/// <returns>The current date and time as a <see cref="DateTimeOffset"/>.</returns>
|
||||||
|
public DateTimeOffset GetCurrentTime(IServiceProvider sp, string location)
|
||||||
|
{
|
||||||
|
// Resolve the CurrentTimeProvider from the service provider
|
||||||
|
var currentTimeProvider = sp.GetRequiredService<CurrentTimeProvider>();
|
||||||
|
|
||||||
|
return currentTimeProvider.GetCurrentTime(location);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the functions provided by this plugin.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// In real world scenarios, a class may have many methods and only a subset of them may be intended to be exposed as AI functions.
|
||||||
|
/// This method demonstrates how to explicitly specify which methods should be exposed to the AI agent.
|
||||||
|
/// </remarks>
|
||||||
|
/// <returns>The functions provided by this plugin.</returns>
|
||||||
|
public IEnumerable<AITool> AsAITools()
|
||||||
|
{
|
||||||
|
yield return AIFunctionFactory.Create(this.GetWeather);
|
||||||
|
yield return AIFunctionFactory.Create(this.GetCurrentTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The weather provider that returns weather information.
|
||||||
|
/// </summary>
|
||||||
|
internal sealed class WeatherProvider
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the weather information for the specified location.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// The weather information is hardcoded for demonstration purposes.
|
||||||
|
/// In a real application, this could call a weather API to get actual weather data.
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="location">The location to get the weather for.</param>
|
||||||
|
/// <returns>The weather information for the specified location.</returns>
|
||||||
|
public string GetWeather(string location)
|
||||||
|
{
|
||||||
|
return $"The weather in {location} is cloudy with a high of 15°C.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Provides the current date and time.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// This class returns the current date and time using the system's clock.
|
||||||
|
/// </remarks>
|
||||||
|
internal sealed class CurrentTimeProvider
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the current date and time.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="location">The location to get the current time for (not used in this implementation).</param>
|
||||||
|
/// <returns>The current date and time as a <see cref="DateTimeOffset"/>.</returns>
|
||||||
|
public DateTimeOffset GetCurrentTime(string location)
|
||||||
|
{
|
||||||
|
return DateTimeOffset.Now;
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFrameworks>$(ProjectsTargetFrameworks)</TargetFrameworks>
|
<TargetFrameworks>$(ProjectsTargetFrameworks)</TargetFrameworks>
|
||||||
|
|||||||
@@ -0,0 +1,831 @@
|
|||||||
|
// Copyright (c) Microsoft. All rights reserved.
|
||||||
|
|
||||||
|
using Microsoft.Agents.AI;
|
||||||
|
using Microsoft.Agents.AI.AzureAI;
|
||||||
|
using Microsoft.Extensions.AI;
|
||||||
|
using Microsoft.Shared.Diagnostics;
|
||||||
|
using OpenAI;
|
||||||
|
using OpenAI.Responses;
|
||||||
|
|
||||||
|
#pragma warning disable MEAI001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
|
||||||
|
#pragma warning disable OPENAI001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
|
||||||
|
|
||||||
|
namespace Azure.AI.Agents;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Provides extension methods for <see cref="AgentsClient"/>.
|
||||||
|
/// </summary>
|
||||||
|
public static class AgentsClientExtensions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieves an existing server side agent, wrapped as a <see cref="ChatClientAgent"/> using the provided <see cref="AgentsClient"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="agentsClient">The <see cref="AgentsClient"/> to create the <see cref="ChatClientAgent"/> with. Cannot be <see langword="null"/>.</param>
|
||||||
|
/// <param name="name">The name of the server side agent to create a <see cref="ChatClientAgent"/> for. Cannot be <see langword="null"/> or whitespace.</param>
|
||||||
|
/// <param name="tools">The tools to use when interacting with the agent. This is required when using prompt agent definitions with tools.</param>
|
||||||
|
/// <param name="clientFactory">Provides a way to customize the creation of the underlying <see cref="IChatClient"/> used by the agent.</param>
|
||||||
|
/// <param name="openAIClientOptions">An optional <see cref="OpenAIClientOptions"/> for configuring the underlying OpenAI client.</param>
|
||||||
|
/// <param name="services">An optional <see cref="IServiceProvider"/> to use for resolving services required by the <see cref="AIFunction"/> instances being invoked.</param>
|
||||||
|
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests. The default is <see cref="CancellationToken.None"/>.</param>
|
||||||
|
/// <returns>A <see cref="ChatClientAgent"/> instance that can be used to perform operations based on the latest version of the named Azure AI Agent.</returns>
|
||||||
|
/// <exception cref="ArgumentNullException">Thrown when <paramref name="agentsClient"/> or <paramref name="name"/> is <see langword="null"/>.</exception>
|
||||||
|
/// <exception cref="ArgumentException">Thrown when <paramref name="name"/> is empty or whitespace, or when the agent with the specified name was not found.</exception>
|
||||||
|
/// <exception cref="InvalidOperationException">The agent with the specified name was not found.</exception>
|
||||||
|
/// <remarks>When using prompt agent definitions with tools the parameter <paramref name="tools"/> needs to be provided.</remarks>
|
||||||
|
public static ChatClientAgent GetAIAgent(
|
||||||
|
this AgentsClient agentsClient,
|
||||||
|
string name,
|
||||||
|
IList<AITool>? tools = null,
|
||||||
|
Func<IChatClient, IChatClient>? clientFactory = null,
|
||||||
|
OpenAIClientOptions? openAIClientOptions = null,
|
||||||
|
IServiceProvider? services = null,
|
||||||
|
CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
Throw.IfNull(agentsClient);
|
||||||
|
Throw.IfNullOrWhitespace(name);
|
||||||
|
|
||||||
|
var agentRecord = agentsClient.GetAgent(name, cancellationToken).Value
|
||||||
|
?? throw new InvalidOperationException($"Agent with name '{name}' not found.");
|
||||||
|
|
||||||
|
return GetAIAgent(
|
||||||
|
agentsClient,
|
||||||
|
agentRecord,
|
||||||
|
tools,
|
||||||
|
clientFactory,
|
||||||
|
openAIClientOptions,
|
||||||
|
services,
|
||||||
|
cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asynchronously retrieves an existing server side agent, wrapped as a <see cref="ChatClientAgent"/> using the provided <see cref="AgentsClient"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="agentsClient">The <see cref="AgentsClient"/> to create the <see cref="ChatClientAgent"/> with. Cannot be <see langword="null"/>.</param>
|
||||||
|
/// <param name="name">The name of the server side agent to create a <see cref="ChatClientAgent"/> for. Cannot be <see langword="null"/> or whitespace.</param>
|
||||||
|
/// <param name="tools">The tools to use when interacting with the agent. This is required when using prompt agent definitions with tools.</param>
|
||||||
|
/// <param name="clientFactory">Provides a way to customize the creation of the underlying <see cref="IChatClient"/> used by the agent.</param>
|
||||||
|
/// <param name="openAIClientOptions">An optional <see cref="OpenAIClientOptions"/> for configuring the underlying OpenAI client.</param>
|
||||||
|
/// <param name="services">An optional <see cref="IServiceProvider"/> to use for resolving services required by the <see cref="AIFunction"/> instances being invoked.</param>
|
||||||
|
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests. The default is <see cref="CancellationToken.None"/>.</param>
|
||||||
|
/// <returns>A <see cref="ChatClientAgent"/> instance that can be used to perform operations based on the latest version of the named Azure AI Agent.</returns>
|
||||||
|
/// <exception cref="ArgumentNullException">Thrown when <paramref name="agentsClient"/> or <paramref name="name"/> is <see langword="null"/>.</exception>
|
||||||
|
/// <exception cref="ArgumentException">Thrown when <paramref name="name"/> is empty or whitespace, or when the agent with the specified name was not found.</exception>
|
||||||
|
/// <exception cref="InvalidOperationException">The agent with the specified name was not found.</exception>
|
||||||
|
/// <remarks>When using prompt agent definitions with tools the parameter <paramref name="tools"/> needs to be provided.</remarks>
|
||||||
|
public static async Task<ChatClientAgent> GetAIAgentAsync(
|
||||||
|
this AgentsClient agentsClient,
|
||||||
|
string name,
|
||||||
|
IList<AITool>? tools = null,
|
||||||
|
Func<IChatClient, IChatClient>? clientFactory = null,
|
||||||
|
OpenAIClientOptions? openAIClientOptions = null,
|
||||||
|
IServiceProvider? services = null,
|
||||||
|
CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
Throw.IfNull(agentsClient);
|
||||||
|
Throw.IfNullOrWhitespace(name);
|
||||||
|
|
||||||
|
var agentRecord = (await agentsClient.GetAgentAsync(name, cancellationToken).ConfigureAwait(false)).Value
|
||||||
|
?? throw new InvalidOperationException($"Agent with name '{name}' not found.");
|
||||||
|
|
||||||
|
return GetAIAgent(
|
||||||
|
agentsClient,
|
||||||
|
agentRecord,
|
||||||
|
tools,
|
||||||
|
clientFactory,
|
||||||
|
openAIClientOptions,
|
||||||
|
services,
|
||||||
|
cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a runnable agent instance from the provided agent record.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="agentsClient">The client used to interact with Azure AI Agents. Cannot be <see langword="null"/>.</param>
|
||||||
|
/// <param name="agentRecord">The agent record to be converted. The latest version will be used. Cannot be <see langword="null"/>.</param>
|
||||||
|
/// <param name="tools">The tools to use when interacting with the agent. This is required when using prompt agent definitions with tools.</param>
|
||||||
|
/// <param name="clientFactory">Provides a way to customize the creation of the underlying <see cref="IChatClient"/> used by the agent.</param>
|
||||||
|
/// <param name="openAIClientOptions">An optional <see cref="OpenAIClientOptions"/> for configuring the underlying OpenAI client.</param>
|
||||||
|
/// <param name="services">An optional <see cref="IServiceProvider"/> to use for resolving services required by the <see cref="AIFunction"/> instances being invoked.</param>
|
||||||
|
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests. The default is <see cref="CancellationToken.None"/>.</param>
|
||||||
|
/// <returns>A <see cref="ChatClientAgent"/> instance that can be used to perform operations based on the latest version of the Azure AI Agent.</returns>
|
||||||
|
/// <remarks>When using prompt agent definitions with tools the parameter <paramref name="tools"/> needs to be provided.</remarks>
|
||||||
|
public static ChatClientAgent GetAIAgent(
|
||||||
|
this AgentsClient agentsClient,
|
||||||
|
AgentRecord agentRecord,
|
||||||
|
IList<AITool>? tools = null,
|
||||||
|
Func<IChatClient, IChatClient>? clientFactory = null,
|
||||||
|
OpenAIClientOptions? openAIClientOptions = null,
|
||||||
|
IServiceProvider? services = null,
|
||||||
|
CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
Throw.IfNull(agentsClient);
|
||||||
|
Throw.IfNull(agentRecord);
|
||||||
|
|
||||||
|
return GetAIAgent(
|
||||||
|
agentsClient,
|
||||||
|
agentRecord.Versions.Latest,
|
||||||
|
tools,
|
||||||
|
clientFactory,
|
||||||
|
openAIClientOptions,
|
||||||
|
services,
|
||||||
|
cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a runnable agent instance from a <see cref="AgentVersion"/> containing metadata about an Azure AI Agent.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="agentsClient">The client used to interact with Azure AI Agents. Cannot be <see langword="null"/>.</param>
|
||||||
|
/// <param name="agentVersion">The agent version to be converted. Cannot be <see langword="null"/>.</param>
|
||||||
|
/// <param name="tools">The tools to use when interacting with the agent. This is required when using prompt agent definitions with tools.</param>
|
||||||
|
/// <param name="clientFactory">Provides a way to customize the creation of the underlying <see cref="IChatClient"/> used by the agent.</param>
|
||||||
|
/// <param name="openAIClientOptions">An optional <see cref="OpenAIClientOptions"/> for configuring the underlying OpenAI client.</param>
|
||||||
|
/// <param name="services">An optional <see cref="IServiceProvider"/> to use for resolving services required by the <see cref="AIFunction"/> instances being invoked.</param>
|
||||||
|
/// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests. The default is <see cref="CancellationToken.None"/>.</param>
|
||||||
|
/// <returns>A <see cref="ChatClientAgent"/> instance that can be used to perform operations based on the provided version of the Azure AI Agent.</returns>
|
||||||
|
/// <exception cref="ArgumentNullException">Thrown when <paramref name="agentsClient"/> or <paramref name="agentVersion"/> is <see langword="null"/>.</exception>
|
||||||
|
/// <remarks>When using prompt agent definitions with tools the parameter <paramref name="tools"/> needs to be provided.</remarks>
|
||||||
|
public static ChatClientAgent GetAIAgent(
|
||||||
|
this AgentsClient agentsClient,
|
||||||
|
AgentVersion agentVersion,
|
||||||
|
IList<AITool>? tools = null,
|
||||||
|
Func<IChatClient, IChatClient>? clientFactory = null,
|
||||||
|
OpenAIClientOptions? openAIClientOptions = null,
|
||||||
|
IServiceProvider? services = null,
|
||||||
|
CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
Throw.IfNull(agentsClient);
|
||||||
|
Throw.IfNull(agentVersion);
|
||||||
|
|
||||||
|
ValidateUsingToolsParameter(agentVersion, tools);
|
||||||
|
|
||||||
|
return CreateChatClientAgent(
|
||||||
|
agentsClient,
|
||||||
|
agentVersion,
|
||||||
|
tools,
|
||||||
|
clientFactory,
|
||||||
|
openAIClientOptions,
|
||||||
|
requireInvocableTools: true,
|
||||||
|
services);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new Prompt AI Agent using the provided <see cref="AgentsClient"/> and options.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="agentsClient">The client used to manage and interact with AI agents. Cannot be <see langword="null"/>.</param>
|
||||||
|
/// <param name="options">The options for creating the agent. Cannot be <see langword="null"/>.</param>
|
||||||
|
/// <param name="clientFactory">A factory function to customize the creation of the chat client used by the agent.</param>
|
||||||
|
/// <param name="openAIClientOptions">An optional <see cref="OpenAIClientOptions"/> for configuring the underlying OpenAI client.</param>
|
||||||
|
/// <param name="services">An optional <see cref="IServiceProvider"/> to use for resolving services required by the <see cref="AIFunction"/> instances being invoked.</param>
|
||||||
|
/// <param name="cancellationToken">A <see cref="CancellationToken"/> to cancel the operation if needed.</param>
|
||||||
|
/// <returns>A <see cref="ChatClientAgent"/> instance that can be used to perform operations on the newly created agent.</returns>
|
||||||
|
/// <exception cref="ArgumentNullException">Thrown when <paramref name="agentsClient"/> or <paramref name="options"/> is <see langword="null"/>.</exception>
|
||||||
|
public static ChatClientAgent GetAIAgent(
|
||||||
|
this AgentsClient agentsClient,
|
||||||
|
ChatClientAgentOptions options,
|
||||||
|
Func<IChatClient, IChatClient>? clientFactory = null,
|
||||||
|
OpenAIClientOptions? openAIClientOptions = null,
|
||||||
|
IServiceProvider? services = null,
|
||||||
|
CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
Throw.IfNull(agentsClient);
|
||||||
|
Throw.IfNull(options);
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(options.Name))
|
||||||
|
{
|
||||||
|
throw new ArgumentException("Agent name must be provided in the options.Name property", nameof(options));
|
||||||
|
}
|
||||||
|
|
||||||
|
var agentRecord = agentsClient.GetAgent(options.Name, cancellationToken).Value
|
||||||
|
?? throw new InvalidOperationException($"Agent with name '{options.Name}' not found.");
|
||||||
|
|
||||||
|
var agentVersion = agentRecord.Versions.Latest;
|
||||||
|
|
||||||
|
var agentOptions = CreateChatClientAgentOptions(agentVersion, options, requireInvocableTools: true);
|
||||||
|
|
||||||
|
return CreateChatClientAgent(
|
||||||
|
agentsClient,
|
||||||
|
agentVersion,
|
||||||
|
agentOptions,
|
||||||
|
clientFactory,
|
||||||
|
openAIClientOptions,
|
||||||
|
requireInvocableTools: true,
|
||||||
|
services);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new Prompt AI Agent using the provided <see cref="AgentsClient"/> and options.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="agentsClient">The client used to manage and interact with AI agents. Cannot be <see langword="null"/>.</param>
|
||||||
|
/// <param name="options">The options for creating the agent. Cannot be <see langword="null"/>.</param>
|
||||||
|
/// <param name="clientFactory">A factory function to customize the creation of the chat client used by the agent.</param>
|
||||||
|
/// <param name="openAIClientOptions">An optional <see cref="OpenAIClientOptions"/> for configuring the underlying OpenAI client.</param>
|
||||||
|
/// <param name="services">An optional <see cref="IServiceProvider"/> to use for resolving services required by the <see cref="AIFunction"/> instances being invoked.</param>
|
||||||
|
/// <param name="cancellationToken">A <see cref="CancellationToken"/> to cancel the operation if needed.</param>
|
||||||
|
/// <returns>A <see cref="ChatClientAgent"/> instance that can be used to perform operations on the newly created agent.</returns>
|
||||||
|
/// <exception cref="ArgumentNullException">Thrown when <paramref name="agentsClient"/> or <paramref name="options"/> is <see langword="null"/>.</exception>
|
||||||
|
public static async Task<ChatClientAgent> GetAIAgentAsync(
|
||||||
|
this AgentsClient agentsClient,
|
||||||
|
ChatClientAgentOptions options,
|
||||||
|
Func<IChatClient, IChatClient>? clientFactory = null,
|
||||||
|
OpenAIClientOptions? openAIClientOptions = null,
|
||||||
|
IServiceProvider? services = null,
|
||||||
|
CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
Throw.IfNull(agentsClient);
|
||||||
|
Throw.IfNull(options);
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(options.Name))
|
||||||
|
{
|
||||||
|
throw new ArgumentException("Agent name must be provided in the options.Name property", nameof(options));
|
||||||
|
}
|
||||||
|
|
||||||
|
var agentRecord = (await agentsClient.GetAgentAsync(options.Name, cancellationToken).ConfigureAwait(false)).Value
|
||||||
|
?? throw new InvalidOperationException($"Agent with name '{options.Name}' not found.");
|
||||||
|
|
||||||
|
var agentVersion = agentRecord.Versions.Latest;
|
||||||
|
|
||||||
|
var agentOptions = CreateChatClientAgentOptions(agentVersion, options, requireInvocableTools: true);
|
||||||
|
|
||||||
|
return CreateChatClientAgent(
|
||||||
|
agentsClient,
|
||||||
|
agentVersion,
|
||||||
|
agentOptions,
|
||||||
|
clientFactory,
|
||||||
|
openAIClientOptions,
|
||||||
|
requireInvocableTools: true,
|
||||||
|
services);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new Prompt AI agent using the specified configuration parameters.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="agentsClient">The client used to manage and interact with AI agents. Cannot be <see langword="null"/>.</param>
|
||||||
|
/// <param name="name">The name for the agent.</param>
|
||||||
|
/// <param name="model">The name of the model to use for the agent. Cannot be <see langword="null"/> or whitespace.</param>
|
||||||
|
/// <param name="instructions">The instructions that guide the agent's behavior. Cannot be <see langword="null"/> or whitespace.</param>
|
||||||
|
/// <param name="tools">The tools to use when interacting with the agent, this is required when using prompt agent definitions with tools.</param>
|
||||||
|
/// <param name="creationOptions">Settings that control the creation of the agent.</param>
|
||||||
|
/// <param name="clientFactory">A factory function to customize the creation of the chat client used by the agent.</param>
|
||||||
|
/// <param name="openAIClientOptions">An optional <see cref="OpenAIClientOptions"/> for configuring the underlying OpenAI client.</param>
|
||||||
|
/// <param name="services">An optional <see cref="IServiceProvider"/> to use for resolving services required by the <see cref="AIFunction"/> instances being invoked.</param>
|
||||||
|
/// <param name="cancellationToken">A token to monitor for cancellation requests.</param>
|
||||||
|
/// <returns>A <see cref="ChatClientAgent"/> instance that can be used to perform operations on the newly created agent.</returns>
|
||||||
|
/// <exception cref="ArgumentNullException">Thrown when <paramref name="agentsClient"/>, <paramref name="model"/>, or <paramref name="instructions"/> is <see langword="null"/>.</exception>
|
||||||
|
/// <exception cref="ArgumentException">Thrown when <paramref name="model"/> or <paramref name="instructions"/> is empty or whitespace.</exception>
|
||||||
|
/// <remarks>When using prompt agent definitions with tools the parameter <paramref name="tools"/> needs to be provided.</remarks>
|
||||||
|
public static ChatClientAgent CreateAIAgent(
|
||||||
|
this AgentsClient agentsClient,
|
||||||
|
string name,
|
||||||
|
string model,
|
||||||
|
string instructions,
|
||||||
|
IList<AITool>? tools = null,
|
||||||
|
AgentVersionCreationOptions? creationOptions = null,
|
||||||
|
Func<IChatClient, IChatClient>? clientFactory = null,
|
||||||
|
OpenAIClientOptions? openAIClientOptions = null,
|
||||||
|
IServiceProvider? services = null,
|
||||||
|
CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
Throw.IfNull(agentsClient);
|
||||||
|
Throw.IfNullOrWhitespace(name);
|
||||||
|
Throw.IfNullOrWhitespace(model);
|
||||||
|
Throw.IfNullOrWhitespace(instructions);
|
||||||
|
|
||||||
|
return CreateAIAgent(
|
||||||
|
agentsClient,
|
||||||
|
name,
|
||||||
|
tools,
|
||||||
|
new PromptAgentDefinition(model) { Instructions = instructions },
|
||||||
|
creationOptions,
|
||||||
|
clientFactory,
|
||||||
|
openAIClientOptions,
|
||||||
|
requireInvocableTools: true,
|
||||||
|
services,
|
||||||
|
cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new Prompt AI agent using the specified configuration parameters.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="agentsClient">The client used to manage and interact with AI agents. Cannot be <see langword="null"/>.</param>
|
||||||
|
/// <param name="name">The name for the agent.</param>
|
||||||
|
/// <param name="model">The name of the model to use for the agent. Cannot be <see langword="null"/> or whitespace.</param>
|
||||||
|
/// <param name="instructions">The instructions that guide the agent's behavior. Cannot be <see langword="null"/> or whitespace.</param>
|
||||||
|
/// <param name="tools">The tools to use when interacting with the agent, this is required when using prompt agent definitions with tools.</param>
|
||||||
|
/// <param name="creationOptions">Settings that control the creation of the agent.</param>
|
||||||
|
/// <param name="clientFactory">A factory function to customize the creation of the chat client used by the agent.</param>
|
||||||
|
/// <param name="openAIClientOptions">An optional <see cref="OpenAIClientOptions"/> for configuring the underlying OpenAI client.</param>
|
||||||
|
/// <param name="services">An optional <see cref="IServiceProvider"/> to use for resolving services required by the <see cref="AIFunction"/> instances being invoked.</param>
|
||||||
|
/// <param name="cancellationToken">A token to monitor for cancellation requests.</param>
|
||||||
|
/// <returns>A <see cref="ChatClientAgent"/> instance that can be used to perform operations on the newly created agent.</returns>
|
||||||
|
/// <exception cref="ArgumentNullException">Thrown when <paramref name="agentsClient"/>, <paramref name="model"/>, or <paramref name="instructions"/> is <see langword="null"/>.</exception>
|
||||||
|
/// <exception cref="ArgumentException">Thrown when <paramref name="model"/> or <paramref name="instructions"/> is empty or whitespace.</exception>
|
||||||
|
/// <remarks>When using prompt agent definitions with tools the parameter <paramref name="tools"/> needs to be provided.</remarks>
|
||||||
|
public static Task<ChatClientAgent> CreateAIAgentAsync(
|
||||||
|
this AgentsClient agentsClient,
|
||||||
|
string name,
|
||||||
|
string model,
|
||||||
|
string instructions,
|
||||||
|
IList<AITool>? tools = null,
|
||||||
|
AgentVersionCreationOptions? creationOptions = null,
|
||||||
|
Func<IChatClient, IChatClient>? clientFactory = null,
|
||||||
|
OpenAIClientOptions? openAIClientOptions = null,
|
||||||
|
IServiceProvider? services = null,
|
||||||
|
CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
Throw.IfNull(agentsClient);
|
||||||
|
Throw.IfNullOrWhitespace(name);
|
||||||
|
Throw.IfNullOrWhitespace(model);
|
||||||
|
Throw.IfNullOrWhitespace(instructions);
|
||||||
|
|
||||||
|
return CreateAIAgentAsync(
|
||||||
|
agentsClient,
|
||||||
|
name,
|
||||||
|
tools,
|
||||||
|
new PromptAgentDefinition(model) { Instructions = instructions },
|
||||||
|
creationOptions,
|
||||||
|
clientFactory,
|
||||||
|
openAIClientOptions,
|
||||||
|
requireInvocableTools: true,
|
||||||
|
services,
|
||||||
|
cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new Prompt AI Agent using the provided <see cref="AgentsClient"/> and options.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="agentsClient">The client used to manage and interact with AI agents. Cannot be <see langword="null"/>.</param>
|
||||||
|
/// <param name="model">The name of the model to use for the agent. Cannot be <see langword="null"/> or whitespace.</param>
|
||||||
|
/// <param name="options">The options for creating the agent. Cannot be <see langword="null"/>.</param>
|
||||||
|
/// <param name="clientFactory">A factory function to customize the creation of the chat client used by the agent.</param>
|
||||||
|
/// <param name="openAIClientOptions">An optional <see cref="OpenAIClientOptions"/> for configuring the underlying OpenAI client.</param>
|
||||||
|
/// <param name="services">An optional <see cref="IServiceProvider"/> to use for resolving services required by the <see cref="AIFunction"/> instances being invoked.</param>
|
||||||
|
/// <param name="cancellationToken">A <see cref="CancellationToken"/> to cancel the operation if needed.</param>
|
||||||
|
/// <returns>A <see cref="ChatClientAgent"/> instance that can be used to perform operations on the newly created agent.</returns>
|
||||||
|
/// <exception cref="ArgumentNullException">Thrown when <paramref name="agentsClient"/> or <paramref name="options"/> is <see langword="null"/>.</exception>
|
||||||
|
/// <exception cref="ArgumentException">Thrown when <paramref name="model"/> is empty or whitespace, or when the agent name is not provided in the options.</exception>
|
||||||
|
public static ChatClientAgent CreateAIAgent(
|
||||||
|
this AgentsClient agentsClient,
|
||||||
|
string model,
|
||||||
|
ChatClientAgentOptions options,
|
||||||
|
Func<IChatClient, IChatClient>? clientFactory = null,
|
||||||
|
OpenAIClientOptions? openAIClientOptions = null,
|
||||||
|
IServiceProvider? services = null,
|
||||||
|
CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
Throw.IfNull(agentsClient);
|
||||||
|
Throw.IfNull(options);
|
||||||
|
Throw.IfNullOrWhitespace(model);
|
||||||
|
const bool RequireInvocableTools = true;
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(options.Name))
|
||||||
|
{
|
||||||
|
throw new ArgumentException("Agent name must be provided in the options.Name property", nameof(options));
|
||||||
|
}
|
||||||
|
|
||||||
|
PromptAgentDefinition agentDefinition = new(model)
|
||||||
|
{
|
||||||
|
Instructions = options.Instructions,
|
||||||
|
};
|
||||||
|
|
||||||
|
ApplyToolsToAgentDefinition(agentDefinition, options.ChatOptions?.Tools, RequireInvocableTools);
|
||||||
|
|
||||||
|
AgentVersionCreationOptions? versionCreationOptions = null;
|
||||||
|
if (!string.IsNullOrWhiteSpace(options.Description))
|
||||||
|
{
|
||||||
|
(versionCreationOptions ??= new()).Description = options.Description;
|
||||||
|
}
|
||||||
|
|
||||||
|
AgentVersion agentVersion = agentsClient.CreateAgentVersion(options.Name, agentDefinition, versionCreationOptions, cancellationToken).Value;
|
||||||
|
|
||||||
|
var agentOptions = CreateChatClientAgentOptions(agentVersion, options, RequireInvocableTools);
|
||||||
|
|
||||||
|
return CreateChatClientAgent(
|
||||||
|
agentsClient,
|
||||||
|
agentVersion,
|
||||||
|
agentOptions,
|
||||||
|
clientFactory,
|
||||||
|
openAIClientOptions,
|
||||||
|
RequireInvocableTools,
|
||||||
|
services);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new Prompt AI Agent using the provided <see cref="AgentsClient"/> and options.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="agentsClient">The client used to manage and interact with AI agents. Cannot be <see langword="null"/>.</param>
|
||||||
|
/// <param name="model">The name of the model to use for the agent. Cannot be <see langword="null"/> or whitespace.</param>
|
||||||
|
/// <param name="options">The options for creating the agent. Cannot be <see langword="null"/>.</param>
|
||||||
|
/// <param name="clientFactory">A factory function to customize the creation of the chat client used by the agent.</param>
|
||||||
|
/// <param name="openAIClientOptions">An optional <see cref="OpenAIClientOptions"/> for configuring the underlying OpenAI client.</param>
|
||||||
|
/// <param name="services">An optional <see cref="IServiceProvider"/> to use for resolving services required by the <see cref="AIFunction"/> instances being invoked.</param>
|
||||||
|
/// <param name="cancellationToken">A <see cref="CancellationToken"/> to cancel the operation if needed.</param>
|
||||||
|
/// <returns>A <see cref="ChatClientAgent"/> instance that can be used to perform operations on the newly created agent.</returns>
|
||||||
|
/// <exception cref="ArgumentNullException">Thrown when <paramref name="agentsClient"/> or <paramref name="options"/> is <see langword="null"/>.</exception>
|
||||||
|
/// <exception cref="ArgumentException">Thrown when <paramref name="model"/> is empty or whitespace, or when the agent name is not provided in the options.</exception>
|
||||||
|
public static async Task<ChatClientAgent> CreateAIAgentAsync(
|
||||||
|
this AgentsClient agentsClient,
|
||||||
|
string model,
|
||||||
|
ChatClientAgentOptions options,
|
||||||
|
Func<IChatClient, IChatClient>? clientFactory = null,
|
||||||
|
OpenAIClientOptions? openAIClientOptions = null,
|
||||||
|
IServiceProvider? services = null,
|
||||||
|
CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
Throw.IfNull(agentsClient);
|
||||||
|
Throw.IfNull(options);
|
||||||
|
Throw.IfNullOrWhitespace(model);
|
||||||
|
const bool RequireInvocableTools = true;
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(options.Name))
|
||||||
|
{
|
||||||
|
throw new ArgumentException("Agent name must be provided in the options.Name property", nameof(options));
|
||||||
|
}
|
||||||
|
|
||||||
|
PromptAgentDefinition agentDefinition = new(model)
|
||||||
|
{
|
||||||
|
Instructions = options.Instructions,
|
||||||
|
};
|
||||||
|
|
||||||
|
ApplyToolsToAgentDefinition(agentDefinition, options.ChatOptions?.Tools, RequireInvocableTools);
|
||||||
|
|
||||||
|
AgentVersionCreationOptions? versionCreationOptions = null;
|
||||||
|
if (!string.IsNullOrWhiteSpace(options.Description))
|
||||||
|
{
|
||||||
|
(versionCreationOptions ??= new()).Description = options.Description;
|
||||||
|
}
|
||||||
|
|
||||||
|
AgentVersion agentVersion = await agentsClient.CreateAgentVersionAsync(options.Name, agentDefinition, versionCreationOptions, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
|
var agentOptions = CreateChatClientAgentOptions(agentVersion, options, RequireInvocableTools);
|
||||||
|
|
||||||
|
return CreateChatClientAgent(
|
||||||
|
agentsClient,
|
||||||
|
agentVersion,
|
||||||
|
agentOptions,
|
||||||
|
clientFactory,
|
||||||
|
openAIClientOptions,
|
||||||
|
RequireInvocableTools,
|
||||||
|
services);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new AI agent using the specified agent definition and optional configuration parameters.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="agentsClient">The client used to manage and interact with AI agents. Cannot be <see langword="null"/>.</param>
|
||||||
|
/// <param name="name">The name for the agent.</param>
|
||||||
|
/// <param name="agentDefinition">The definition that specifies the configuration and behavior of the agent to create. Cannot be <see langword="null"/>.</param>
|
||||||
|
/// <param name="creationOptions">Settings that control the creation of the agent.</param>
|
||||||
|
/// <param name="clientFactory">A factory function to customize the creation of the chat client used by the agent.</param>
|
||||||
|
/// <param name="openAIClientOptions">An optional <see cref="OpenAIClientOptions"/> for configuring the underlying OpenAI client.</param>
|
||||||
|
/// <param name="cancellationToken">A token to monitor for cancellation requests.</param>
|
||||||
|
/// <returns>A <see cref="ChatClientAgent"/> instance that can be used to perform operations on the newly created agent.</returns>
|
||||||
|
/// <exception cref="ArgumentNullException">Thrown when <paramref name="agentsClient"/> or <paramref name="agentDefinition"/> is <see langword="null"/>.</exception>
|
||||||
|
/// <remarks>
|
||||||
|
/// When using this extension method with a <see cref="PromptAgentDefinition"/> the tools are only declarative and not invocable.
|
||||||
|
/// Invocation of any in-process tools will need to be handled manually.
|
||||||
|
/// </remarks>
|
||||||
|
public static ChatClientAgent CreateAIAgent(
|
||||||
|
this AgentsClient agentsClient,
|
||||||
|
string name,
|
||||||
|
AgentDefinition agentDefinition,
|
||||||
|
AgentVersionCreationOptions? creationOptions = null,
|
||||||
|
Func<IChatClient, IChatClient>? clientFactory = null,
|
||||||
|
OpenAIClientOptions? openAIClientOptions = null,
|
||||||
|
CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
Throw.IfNull(agentsClient);
|
||||||
|
Throw.IfNullOrWhitespace(name);
|
||||||
|
Throw.IfNull(agentDefinition);
|
||||||
|
|
||||||
|
var tools = (agentDefinition as PromptAgentDefinition)?.Tools.Select(t => t.AsAITool()).ToList();
|
||||||
|
|
||||||
|
return CreateAIAgent(
|
||||||
|
agentsClient,
|
||||||
|
name,
|
||||||
|
tools,
|
||||||
|
agentDefinition,
|
||||||
|
creationOptions,
|
||||||
|
clientFactory,
|
||||||
|
openAIClientOptions,
|
||||||
|
requireInvocableTools: false,
|
||||||
|
services: null,
|
||||||
|
cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Asynchronously creates a new AI agent using the specified agent definition and optional configuration
|
||||||
|
/// parameters.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="agentsClient">The client used to manage and interact with AI agents. Cannot be <see langword="null"/>.</param>
|
||||||
|
/// <param name="name">The name for the agent.</param>
|
||||||
|
/// <param name="agentDefinition">The definition that specifies the configuration and behavior of the agent to create. Cannot be <see langword="null"/>.</param>
|
||||||
|
/// <param name="agentVersionCreationOptions">Settings that control the creation of the agent.</param>
|
||||||
|
/// <param name="clientFactory">A factory function to customize the creation of the chat client used by the agent.</param>
|
||||||
|
/// <param name="openAIClientOptions">An optional <see cref="OpenAIClientOptions"/> for configuring the underlying OpenAI client.</param>
|
||||||
|
/// <param name="cancellationToken">A token to monitor for cancellation requests.</param>
|
||||||
|
/// <returns>A <see cref="ChatClientAgent"/> instance that can be used to perform operations on the newly created agent.</returns>
|
||||||
|
/// <exception cref="ArgumentNullException">Thrown when <paramref name="agentsClient"/> or <paramref name="agentDefinition"/> is <see langword="null"/>.</exception>
|
||||||
|
/// <remarks>
|
||||||
|
/// When using this extension method with a <see cref="PromptAgentDefinition"/> the tools are only declarative and not invocable.
|
||||||
|
/// Invocation of any in-process tools will need to be handled manually.
|
||||||
|
/// </remarks>
|
||||||
|
public static Task<ChatClientAgent> CreateAIAgentAsync(
|
||||||
|
this AgentsClient agentsClient,
|
||||||
|
string name,
|
||||||
|
AgentDefinition agentDefinition,
|
||||||
|
AgentVersionCreationOptions? agentVersionCreationOptions = null,
|
||||||
|
Func<IChatClient, IChatClient>? clientFactory = null,
|
||||||
|
OpenAIClientOptions? openAIClientOptions = null,
|
||||||
|
CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
Throw.IfNullOrWhitespace(name);
|
||||||
|
Throw.IfNull(agentsClient);
|
||||||
|
Throw.IfNull(agentDefinition);
|
||||||
|
|
||||||
|
var tools = (agentDefinition as PromptAgentDefinition)?.Tools.Select(t => t.AsAITool()).ToList();
|
||||||
|
|
||||||
|
return CreateAIAgentAsync(
|
||||||
|
agentsClient,
|
||||||
|
name,
|
||||||
|
tools,
|
||||||
|
agentDefinition,
|
||||||
|
agentVersionCreationOptions,
|
||||||
|
clientFactory,
|
||||||
|
openAIClientOptions,
|
||||||
|
requireInvocableTools: false,
|
||||||
|
services: null,
|
||||||
|
cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Private
|
||||||
|
|
||||||
|
private static ChatClientAgent CreateAIAgent(
|
||||||
|
this AgentsClient agentsClient,
|
||||||
|
string name,
|
||||||
|
IList<AITool>? tools,
|
||||||
|
AgentDefinition agentDefinition,
|
||||||
|
AgentVersionCreationOptions? creationOptions,
|
||||||
|
Func<IChatClient, IChatClient>? clientFactory,
|
||||||
|
OpenAIClientOptions? openAIClientOptions,
|
||||||
|
bool requireInvocableTools,
|
||||||
|
IServiceProvider? services,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
Throw.IfNull(agentsClient);
|
||||||
|
Throw.IfNullOrWhitespace(name);
|
||||||
|
Throw.IfNull(agentDefinition);
|
||||||
|
|
||||||
|
tools ??= (agentDefinition as PromptAgentDefinition)?.Tools.Select(t => t.AsAITool()).ToList();
|
||||||
|
|
||||||
|
ApplyToolsToAgentDefinition(agentDefinition, tools, requireInvocableTools);
|
||||||
|
|
||||||
|
AgentVersion agentVersion = agentsClient.CreateAgentVersion(name, agentDefinition, creationOptions, cancellationToken).Value;
|
||||||
|
|
||||||
|
return CreateChatClientAgent(
|
||||||
|
agentsClient,
|
||||||
|
agentVersion,
|
||||||
|
tools,
|
||||||
|
clientFactory,
|
||||||
|
openAIClientOptions,
|
||||||
|
requireInvocableTools,
|
||||||
|
services);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static async Task<ChatClientAgent> CreateAIAgentAsync(
|
||||||
|
this AgentsClient agentsClient,
|
||||||
|
string name,
|
||||||
|
IList<AITool>? tools,
|
||||||
|
AgentDefinition agentDefinition,
|
||||||
|
AgentVersionCreationOptions? agentVersionCreationOptions,
|
||||||
|
Func<IChatClient, IChatClient>? clientFactory,
|
||||||
|
OpenAIClientOptions? openAIClientOptions,
|
||||||
|
bool requireInvocableTools,
|
||||||
|
IServiceProvider? services,
|
||||||
|
CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
Throw.IfNullOrWhitespace(name);
|
||||||
|
Throw.IfNull(agentsClient);
|
||||||
|
Throw.IfNull(agentDefinition);
|
||||||
|
|
||||||
|
tools ??= (agentDefinition as PromptAgentDefinition)?.Tools.Select(t => t.AsAITool()).ToList();
|
||||||
|
|
||||||
|
ApplyToolsToAgentDefinition(agentDefinition, tools, requireInvocableTools);
|
||||||
|
|
||||||
|
AgentVersion agentVersion = await agentsClient.CreateAgentVersionAsync(name, agentDefinition, agentVersionCreationOptions, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
|
return CreateChatClientAgent(
|
||||||
|
agentsClient,
|
||||||
|
agentVersion,
|
||||||
|
tools,
|
||||||
|
clientFactory,
|
||||||
|
openAIClientOptions,
|
||||||
|
requireInvocableTools,
|
||||||
|
services);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>This method creates an <see cref="ChatClientAgent"/> with the specified ChatClientAgentOptions.</summary>
|
||||||
|
private static ChatClientAgent CreateChatClientAgent(
|
||||||
|
AgentsClient agentsClient,
|
||||||
|
AgentVersion agentVersion,
|
||||||
|
ChatClientAgentOptions agentOptions,
|
||||||
|
Func<IChatClient, IChatClient>? clientFactory,
|
||||||
|
OpenAIClientOptions? openAIClientOptions,
|
||||||
|
bool requireInvocableTools,
|
||||||
|
IServiceProvider? services)
|
||||||
|
{
|
||||||
|
IChatClient chatClient = new AzureAIAgentChatClient(agentsClient, agentVersion, agentOptions.ChatOptions, openAIClientOptions);
|
||||||
|
|
||||||
|
if (clientFactory is not null)
|
||||||
|
{
|
||||||
|
chatClient = clientFactory(chatClient);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ChatClientAgent(chatClient, agentOptions, services: services);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>This method creates an <see cref="ChatClientAgent"/> with a auto-generated ChatClientAgentOptions from the specified configuration parameters.</summary>
|
||||||
|
private static ChatClientAgent CreateChatClientAgent(
|
||||||
|
AgentsClient agentsClient,
|
||||||
|
AgentVersion agentVersion,
|
||||||
|
IList<AITool>? tools,
|
||||||
|
Func<IChatClient, IChatClient>? clientFactory,
|
||||||
|
OpenAIClientOptions? openAIClientOptions,
|
||||||
|
bool requireInvocableTools,
|
||||||
|
IServiceProvider? services)
|
||||||
|
=> CreateChatClientAgent(
|
||||||
|
agentsClient,
|
||||||
|
agentVersion,
|
||||||
|
CreateChatClientAgentOptions(agentVersion, new ChatOptions() { Tools = tools }, requireInvocableTools),
|
||||||
|
clientFactory,
|
||||||
|
openAIClientOptions,
|
||||||
|
requireInvocableTools,
|
||||||
|
services);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This method creates <see cref="ChatClientAgentOptions"/> for the specified <see cref="AgentVersion"/> and the provided tools.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="agentVersion">The agent version.</param>
|
||||||
|
/// <param name="chatOptions">The <see cref="ChatOptions"/> to use when interacting with the agent.</param>
|
||||||
|
/// <param name="requireInvocableTools">Indicates whether to enforce the presence of invocable tools when the AIAgent is created with an agent definition that uses them.</param>
|
||||||
|
/// <returns>The created <see cref="ChatClientAgentOptions"/>.</returns>
|
||||||
|
/// <exception cref="InvalidOperationException">Thrown when the agent definition requires in-process tools but none were provided.</exception>
|
||||||
|
/// <exception cref="InvalidOperationException">Thrown when the agent definition required tools were not provided.</exception>
|
||||||
|
/// <remarks>
|
||||||
|
/// This method rebuilds the agent options from the agent definition returned by the version and combine with the in-proc tools when provided
|
||||||
|
/// this ensures that all required tools are provided and the definition of the agent options are consistent with the agent definition coming from the server.
|
||||||
|
/// </remarks>
|
||||||
|
private static ChatClientAgentOptions CreateChatClientAgentOptions(AgentVersion agentVersion, ChatOptions? chatOptions, bool requireInvocableTools)
|
||||||
|
{
|
||||||
|
var agentDefinition = agentVersion.Definition;
|
||||||
|
|
||||||
|
List<AITool>? agentTools = null;
|
||||||
|
if (agentDefinition is PromptAgentDefinition { Tools: { Count: > 0 } definitionTools })
|
||||||
|
{
|
||||||
|
// Check if no tools were provided while the agent definition requires in-proc tools.
|
||||||
|
if (requireInvocableTools && chatOptions?.Tools is null or { Count: 0 } && definitionTools.Any(t => t is FunctionTool))
|
||||||
|
{
|
||||||
|
throw new ArgumentException("The agent definition in-process tools must be provided in the extension method tools parameter.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Agregate all missing tools for a single error message.
|
||||||
|
List<string>? missingTools = null;
|
||||||
|
|
||||||
|
// Check function tools
|
||||||
|
foreach (ResponseTool responseTool in definitionTools)
|
||||||
|
{
|
||||||
|
if (responseTool is FunctionTool functionTool)
|
||||||
|
{
|
||||||
|
// Check if a tool with the same type and name exists in the provided tools.
|
||||||
|
var matchingTool = chatOptions?.Tools?.FirstOrDefault(t =>
|
||||||
|
requireInvocableTools
|
||||||
|
? t is AIFunction tf && functionTool.FunctionName == tf.Name // When invocable tools are required, match only AIFunction.
|
||||||
|
: (t is AIFunctionDeclaration tfd && functionTool.FunctionName == tfd.Name) ? true // When not required, match AIFunctionDeclaration OR
|
||||||
|
: (t.GetService<FunctionTool>() is FunctionTool ft && functionTool.FunctionName == ft.FunctionName)); // Match a FunctionTool converted AsAITool.
|
||||||
|
|
||||||
|
if (matchingTool is null)
|
||||||
|
{
|
||||||
|
(missingTools ??= []).Add($"Function tool: {functionTool.FunctionName}");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
(agentTools ??= []).Add(matchingTool!);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
(agentTools ??= []).Add(responseTool.AsAITool());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (missingTools is { Count: > 0 })
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException($"The following prompt agent definition required tools were not provided: {string.Join(", ", missingTools)}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var agentOptions = new ChatClientAgentOptions()
|
||||||
|
{
|
||||||
|
Id = agentVersion.Id,
|
||||||
|
Name = agentVersion.Name,
|
||||||
|
Description = agentVersion.Description,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (agentDefinition is PromptAgentDefinition promptAgentDefinition)
|
||||||
|
{
|
||||||
|
agentOptions.ChatOptions ??= chatOptions?.Clone() ?? new();
|
||||||
|
agentOptions.Instructions = promptAgentDefinition.Instructions;
|
||||||
|
agentOptions.ChatOptions.Temperature = promptAgentDefinition.Temperature;
|
||||||
|
agentOptions.ChatOptions.TopP = promptAgentDefinition.TopP;
|
||||||
|
agentOptions.ChatOptions.Instructions = promptAgentDefinition.Instructions;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (agentTools is { Count: > 0 })
|
||||||
|
{
|
||||||
|
agentOptions.ChatOptions ??= chatOptions?.Clone() ?? new();
|
||||||
|
agentOptions.ChatOptions.Tools = agentTools;
|
||||||
|
}
|
||||||
|
|
||||||
|
return agentOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new instance of <see cref="ChatClientAgentOptions"/> configured for the specified agent version and
|
||||||
|
/// optional base options.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="agentVersion">The agent version to use when configuring the chat client agent options.</param>
|
||||||
|
/// <param name="options">An optional <see cref="ChatClientAgentOptions"/> instance whose relevant properties will be copied to the
|
||||||
|
/// returned options. If <see langword="null"/>, only default values are used.</param>
|
||||||
|
/// <param name="requireInvocableTools">Specifies whether the returned options must include invocable tools. Set to <see langword="true"/> to require
|
||||||
|
/// invocable tools; otherwise, <see langword="false"/>.</param>
|
||||||
|
/// <returns>A <see cref="ChatClientAgentOptions"/> instance configured according to the specified parameters.</returns>
|
||||||
|
private static ChatClientAgentOptions CreateChatClientAgentOptions(AgentVersion agentVersion, ChatClientAgentOptions? options, bool requireInvocableTools)
|
||||||
|
{
|
||||||
|
var agentOptions = CreateChatClientAgentOptions(agentVersion, options?.ChatOptions, requireInvocableTools);
|
||||||
|
if (options is not null)
|
||||||
|
{
|
||||||
|
agentOptions.AIContextProviderFactory = options.AIContextProviderFactory;
|
||||||
|
agentOptions.ChatMessageStoreFactory = options.ChatMessageStoreFactory;
|
||||||
|
agentOptions.UseProvidedChatClientAsIs = options.UseProvidedChatClientAsIs;
|
||||||
|
}
|
||||||
|
|
||||||
|
return agentOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>For already created agent versions, retrieve the definition and validate the tools parameter.</summary>
|
||||||
|
/// <exception cref="ArgumentException"><see cref="PromptAgentDefinition.Tools"/> cannot be used. The <paramref name="tools"/> parameter should be used instead.</exception>
|
||||||
|
/// <remarks>
|
||||||
|
/// Because <see cref="PromptAgentDefinition.Tools"/> doesn't support in-proc tools (only declarative/definitions),
|
||||||
|
/// the <paramref name="tools"/> parameter needs to be the single source of truth for tools, and must be provided when using tools.
|
||||||
|
/// </remarks>
|
||||||
|
private static void ValidateUsingToolsParameter(AgentVersion agentVersion, IList<AITool>? tools)
|
||||||
|
{
|
||||||
|
if (agentVersion.Definition is PromptAgentDefinition { Tools.Count: > 0 } && tools is null or { Count: 0 })
|
||||||
|
{
|
||||||
|
throw new ArgumentException("When retrieving prompt agents with tools the tools parameter needs to be provided with the necessary tools.", nameof(tools));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds the specified AI tools to a prompt agent definition, ensuring that all tools are compatible and, if required, invocable.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>This method ensures that only compatible and properly constructed tools are added to the agent definition.
|
||||||
|
/// When <paramref name="requireInvocableTools"/> is <see langword="true"/>, all tools must be
|
||||||
|
/// invocable AIFunctions, which can be created using AIFunctionFactory.Create. Tools are converted to ResponseTool
|
||||||
|
/// instances before being added.</remarks>
|
||||||
|
/// <param name="agentDefinition">The agent definition to which the tools will be applied. Must be a PromptAgentDefinition to support tools.</param>
|
||||||
|
/// <param name="tools">A list of AI tools to add to the agent definition. If null or empty, no tools are added.</param>
|
||||||
|
/// <param name="requireInvocableTools">Indicates whether all provided tools must be invocable AI functions. If set to <see langword="true"/>, only
|
||||||
|
/// invocable AIFunctions are accepted.</param>
|
||||||
|
/// <exception cref="ArgumentException">Thrown if <paramref name="agentDefinition"/> is not a <see cref="PromptAgentDefinition"/>.</exception>
|
||||||
|
/// <exception cref="InvalidOperationException">Thrown if <paramref name="requireInvocableTools"/> is <see langword="true"/> and a tool is an
|
||||||
|
/// <see cref="AIFunctionDeclaration"/> that is not invocable, or if a tool cannot be converted to a <see cref="ResponseTool"/>.</exception>
|
||||||
|
private static void ApplyToolsToAgentDefinition(AgentDefinition agentDefinition, IList<AITool>? tools, bool requireInvocableTools)
|
||||||
|
{
|
||||||
|
if (tools is { Count: > 0 })
|
||||||
|
{
|
||||||
|
if (agentDefinition is not PromptAgentDefinition promptAgentDefinition)
|
||||||
|
{
|
||||||
|
throw new ArgumentException("Only prompt agent definitions support tools.", nameof(agentDefinition));
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var tool in tools)
|
||||||
|
{
|
||||||
|
// Ensure that any AIFunctions provided are In-Proc, not just the declarations.
|
||||||
|
if (requireInvocableTools && tool is not AIFunction && (
|
||||||
|
tool.GetService<FunctionTool>() is not null // Declarative FunctionTool converted as AsAITool()
|
||||||
|
|| tool is AIFunctionDeclaration)) // AIFunctionDeclaration type
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("When providing functions, they need to be invokable AIFunctions. AIFunctions can be created correctly using AIFunctionFactory.Create");
|
||||||
|
}
|
||||||
|
|
||||||
|
promptAgentDefinition.Tools.Add(
|
||||||
|
// If this is a converted ResponseTool as AITool, we can directly retrieve the ResponseTool instance from GetService.
|
||||||
|
tool.GetService<ResponseTool>()
|
||||||
|
// Otherwise we should be able to convert existing MEAI Tool abstractions into OpenAI ResponseTools
|
||||||
|
?? tool.AsOpenAIResponseTool()
|
||||||
|
?? throw new InvalidOperationException("The provided AITool could not be converted to a ResponseTool, ensure that the AITool was created using responseTool.AsAITool() extension."));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@@ -0,0 +1,148 @@
|
|||||||
|
// Copyright (c) Microsoft. All rights reserved.
|
||||||
|
|
||||||
|
using System.ClientModel.Primitives;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Text;
|
||||||
|
using Azure.AI.Agents;
|
||||||
|
using Microsoft.Extensions.AI;
|
||||||
|
using Microsoft.Shared.Diagnostics;
|
||||||
|
using OpenAI;
|
||||||
|
using OpenAI.Responses;
|
||||||
|
|
||||||
|
#pragma warning disable OPENAI001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
|
||||||
|
|
||||||
|
namespace Microsoft.Agents.AI.AzureAI;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Provides a chat client implementation that integrates with Azure AI Agents, enabling chat interactions using
|
||||||
|
/// Azure-specific agent capabilities.
|
||||||
|
/// </summary>
|
||||||
|
internal sealed class AzureAIAgentChatClient : DelegatingChatClient
|
||||||
|
{
|
||||||
|
private readonly ChatClientMetadata? _metadata;
|
||||||
|
private readonly AgentsClient _agentsClient;
|
||||||
|
private readonly AgentVersion _agentVersion;
|
||||||
|
private readonly ChatOptions? _chatOptions;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The usage of a no-op model is a necessary change to avoid OpenAIClients to throw exceptions when
|
||||||
|
/// used with Azure AI Agents as the model used is now defined at the agent creation time.
|
||||||
|
/// </summary>
|
||||||
|
private const string NoOpModel = "no-op";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="AzureAIAgentChatClient"/> class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="agentsClient">An instance of <see cref="AgentsClient"/> to interact with Azure AI Agents services.</param>
|
||||||
|
/// <param name="agentRecord">An instance of <see cref="AgentRecord"/> representing the specific agent to use.</param>
|
||||||
|
/// <param name="chatOptions">An instance of <see cref="ChatOptions"/> representing the options on how the agent was predefined</param>
|
||||||
|
/// <param name="openAIClientOptions">An optional <see cref="OpenAIClientOptions"/> for configuring the underlying OpenAI client.</param>
|
||||||
|
/// <remarks>
|
||||||
|
/// The <see cref="IChatClient"/> provided should be decorated with a <see cref="AzureAIAgentChatClient"/> for proper functionality.
|
||||||
|
/// </remarks>
|
||||||
|
internal AzureAIAgentChatClient(AgentsClient agentsClient, AgentRecord agentRecord, ChatOptions? chatOptions, OpenAIClientOptions? openAIClientOptions = null)
|
||||||
|
: this(agentsClient, Throw.IfNull(agentRecord).Versions.Latest, chatOptions, openAIClientOptions)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
internal AzureAIAgentChatClient(AgentsClient agentsClient, AgentVersion agentVersion, ChatOptions? chatOptions, OpenAIClientOptions? openAIClientOptions = null)
|
||||||
|
: base(agentsClient
|
||||||
|
.GetOpenAIClient(openAIClientOptions)
|
||||||
|
.GetOpenAIResponseClient((agentVersion.Definition as PromptAgentDefinition)?.Model ?? NoOpModel)
|
||||||
|
.AsIChatClient())
|
||||||
|
{
|
||||||
|
this._agentsClient = Throw.IfNull(agentsClient);
|
||||||
|
this._agentVersion = Throw.IfNull(agentVersion);
|
||||||
|
this._metadata = new ChatClientMetadata("azure.ai.agents");
|
||||||
|
this._chatOptions = chatOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override object? GetService(Type serviceType, object? serviceKey = null)
|
||||||
|
{
|
||||||
|
return (serviceKey is null && serviceType == typeof(ChatClientMetadata))
|
||||||
|
? this._metadata
|
||||||
|
: (serviceKey is null && serviceType == typeof(AgentsClient))
|
||||||
|
? this._agentsClient
|
||||||
|
: (serviceKey is null && serviceType == typeof(AgentVersion))
|
||||||
|
? this._agentVersion
|
||||||
|
: base.GetService(serviceType, serviceKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override async Task<ChatResponse> GetResponseAsync(IEnumerable<ChatMessage> messages, ChatOptions? options = null, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
var conversationId = await this.GetOrCreateConversationAsync(options, cancellationToken).ConfigureAwait(false);
|
||||||
|
var conversationChatOptions = this.GetConversationEnabledChatOptions(options, conversationId);
|
||||||
|
|
||||||
|
return await base.GetResponseAsync(messages, conversationChatOptions, cancellationToken).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public async override IAsyncEnumerable<ChatResponseUpdate> GetStreamingResponseAsync(IEnumerable<ChatMessage> messages, ChatOptions? options = null, [EnumeratorCancellation] CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
var conversation = await this.GetOrCreateConversationAsync(options, cancellationToken).ConfigureAwait(false);
|
||||||
|
var conversationOptions = this.GetConversationEnabledChatOptions(options, conversation);
|
||||||
|
|
||||||
|
await foreach (var chunk in base.GetStreamingResponseAsync(messages, conversationOptions, cancellationToken).ConfigureAwait(false))
|
||||||
|
{
|
||||||
|
yield return chunk;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<string> GetOrCreateConversationAsync(ChatOptions? options, CancellationToken cancellationToken)
|
||||||
|
=> string.IsNullOrWhiteSpace(options?.ConversationId)
|
||||||
|
? (await this._agentsClient.GetConversationClient().CreateConversationAsync(cancellationToken: cancellationToken).ConfigureAwait(false)).Value.Id
|
||||||
|
: options.ConversationId;
|
||||||
|
|
||||||
|
private ChatOptions GetConversationEnabledChatOptions(ChatOptions? chatOptions, string conversationId)
|
||||||
|
{
|
||||||
|
// Start with a clone of the base chat options defined for the agent, if any.
|
||||||
|
ChatOptions conversationChatOptions = this._chatOptions?.Clone() ?? new();
|
||||||
|
|
||||||
|
// Ignore per-request all options that can't be overriden.
|
||||||
|
conversationChatOptions.Instructions = null;
|
||||||
|
conversationChatOptions.Tools = null;
|
||||||
|
|
||||||
|
// Preserve the original RawRepresentationFactory
|
||||||
|
var originalFactory = chatOptions?.RawRepresentationFactory;
|
||||||
|
|
||||||
|
conversationChatOptions.RawRepresentationFactory = (client) =>
|
||||||
|
{
|
||||||
|
if (originalFactory?.Invoke(this) is not ResponseCreationOptions responseCreationOptions)
|
||||||
|
{
|
||||||
|
responseCreationOptions = new ResponseCreationOptions();
|
||||||
|
}
|
||||||
|
|
||||||
|
SetAgentReference(responseCreationOptions, this._agentVersion);
|
||||||
|
SetConversationReference(responseCreationOptions, conversationId);
|
||||||
|
|
||||||
|
return responseCreationOptions;
|
||||||
|
};
|
||||||
|
|
||||||
|
return conversationChatOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Since the SetAdditionalProperty/SetAgentReference/SetConversationReference extensions in Azure.AI.Agents does not yet support the recent updates in OpenAI 2.6.0
|
||||||
|
// The methods below are copied and adapted to the new OpenAI SDK 2.6.0 structure where the Patch property is now exposed directly on ResponseCreationOptions and
|
||||||
|
// may be removed once the Azure.AI.Agents package is updated to support OpenAI SDK 2.6+.
|
||||||
|
#pragma warning disable SCME0001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
|
||||||
|
private static void SetAdditionalProperty(ResponseCreationOptions responseCreationOptions, string key, BinaryData value)
|
||||||
|
{
|
||||||
|
responseCreationOptions.Patch.Set([.. "$."u8, .. Encoding.UTF8.GetBytes(key)], value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void SetAgentReference(ResponseCreationOptions responseCreationOptions, AgentVersion agentVersion)
|
||||||
|
{
|
||||||
|
var agentReference = new AgentReference(agentVersion.Name) { Version = agentVersion.Version };
|
||||||
|
|
||||||
|
SetAdditionalProperty(responseCreationOptions, "agent", ModelReaderWriter.Write(agentReference, new ModelReaderWriterOptions("W"), AzureAIAgentsContext.Default));
|
||||||
|
responseCreationOptions.Patch.Remove([.. "$."u8, .. Encoding.UTF8.GetBytes("model")]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void SetConversationReference(ResponseCreationOptions responseCreationOptions, string conversationId)
|
||||||
|
{
|
||||||
|
SetAdditionalProperty(responseCreationOptions, "conversation", BinaryData.FromString($"\"{conversationId}\""));
|
||||||
|
}
|
||||||
|
#pragma warning restore SCME0001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFrameworks>$(ProjectsTargetFrameworks)</TargetFrameworks>
|
||||||
|
<TargetFrameworks Condition="'$(Configuration)' == 'Debug'">$(ProjectsDebugTargetFrameworks)</TargetFrameworks>
|
||||||
|
<VersionSuffix>preview</VersionSuffix>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<InjectSharedThrow>true</InjectSharedThrow>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<Import Project="$(RepoRoot)/dotnet/nuget/nuget-package.props" />
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Azure.AI.Agents" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.AI" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.AI.OpenAI" />
|
||||||
|
<PackageReference Include="OpenAI" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\Microsoft.Agents.AI\Microsoft.Agents.AI.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<!-- NuGet Package Settings -->
|
||||||
|
<Title>Microsoft Agent Framework Azure AI Agents</Title>
|
||||||
|
<Description>Provides Microsoft Agent Framework support for Azure AI Agents.</Description>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
File diff suppressed because it is too large
Load Diff
+11
@@ -0,0 +1,11 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFrameworks>$(ProjectsTargetFrameworks)</TargetFrameworks>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\src\Microsoft.Agents.AI.AzureAI\Microsoft.Agents.AI.AzureAI.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
@@ -68,7 +68,7 @@ public class OpenAIResponseFixture(bool store) : IChatClientAgentFixture
|
|||||||
string name = "HelpfulAssistant",
|
string name = "HelpfulAssistant",
|
||||||
string instructions = "You are a helpful assistant.",
|
string instructions = "You are a helpful assistant.",
|
||||||
IList<AITool>? aiTools = null) =>
|
IList<AITool>? aiTools = null) =>
|
||||||
new ChatClientAgent(
|
new(
|
||||||
this._openAIResponseClient.AsIChatClient(),
|
this._openAIResponseClient.AsIChatClient(),
|
||||||
options: new()
|
options: new()
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user