diff --git a/dotnet/agent-framework-dotnet.slnx b/dotnet/agent-framework-dotnet.slnx index e06568004b..abe2992f7b 100644 --- a/dotnet/agent-framework-dotnet.slnx +++ b/dotnet/agent-framework-dotnet.slnx @@ -44,24 +44,21 @@ - - + + - - - - - - - - - - + + + + + + + @@ -81,7 +78,6 @@ - diff --git a/dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/Agent_Step01_Basics/Agent_Step01_Basics.csproj b/dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step01.1_Basics/AzureAIAgents_Step01.1_Basics.csproj similarity index 100% rename from dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/Agent_Step01_Basics/Agent_Step01_Basics.csproj rename to dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step01.1_Basics/AzureAIAgents_Step01.1_Basics.csproj diff --git a/dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/Agent_Step01_Basics/Program.cs b/dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step01.1_Basics/Program.cs similarity index 100% rename from dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/Agent_Step01_Basics/Program.cs rename to dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step01.1_Basics/Program.cs diff --git a/dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/Agent_Step01_Basics/README.md b/dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step01.1_Basics/README.md similarity index 100% rename from dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/Agent_Step01_Basics/README.md rename to dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step01.1_Basics/README.md diff --git a/dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step01_Running/AzureAIAgents_Step01_Running.csproj b/dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step01.2_Running/AzureAIAgents_Step01.2_Running.csproj similarity index 100% rename from dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step01_Running/AzureAIAgents_Step01_Running.csproj rename to dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step01.2_Running/AzureAIAgents_Step01.2_Running.csproj diff --git a/dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step01_Running/Program.cs b/dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step01.2_Running/Program.cs similarity index 100% rename from dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step01_Running/Program.cs rename to dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step01.2_Running/Program.cs diff --git a/dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step05_StructuredOutput/AzureAIAgents_Step05_StructuredOutput.csproj b/dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step05_StructuredOutput/AzureAIAgents_Step05_StructuredOutput.csproj index 3fb7e0be8f..84e9571502 100644 --- a/dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step05_StructuredOutput/AzureAIAgents_Step05_StructuredOutput.csproj +++ b/dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step05_StructuredOutput/AzureAIAgents_Step05_StructuredOutput.csproj @@ -15,6 +15,7 @@ + diff --git a/dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step07_3rdPartyThreadStorage/AzureAIAgents_Step07_3rdPartyThreadStorage.csproj b/dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step07_3rdPartyThreadStorage/AzureAIAgents_Step07_3rdPartyThreadStorage.csproj deleted file mode 100644 index ca60ab65c6..0000000000 --- a/dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step07_3rdPartyThreadStorage/AzureAIAgents_Step07_3rdPartyThreadStorage.csproj +++ /dev/null @@ -1,24 +0,0 @@ - - - - Exe - net9.0 - - enable - enable - $(NoWarn);CA1812 - - - - - - - - - - - - - - - diff --git a/dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step07_3rdPartyThreadStorage/Program.cs b/dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step07_3rdPartyThreadStorage/Program.cs deleted file mode 100644 index 801c3c2978..0000000000 --- a/dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step07_3rdPartyThreadStorage/Program.cs +++ /dev/null @@ -1,156 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -#pragma warning disable CA1869 // Cache and reuse 'JsonSerializerOptions' instances - -// This sample shows how to create and use a simple AI agent with a conversation that can be persisted to a 3rd party storage. - -using System.Text.Json; -using Azure.AI.Agents; -using Azure.Identity; -using Microsoft.Agents.AI; -using Microsoft.Extensions.AI; -using Microsoft.Extensions.VectorData; -using Microsoft.SemanticKernel.Connectors.InMemory; -using SampleApp; - -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 vector store to store the chat messages in. -// Replace this with a vector store implementation of your choice if you want to persist the chat history to disk. -VectorStore vectorStore = new InMemoryVectorStore(); - -// 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( - deploymentName, - new ChatClientAgentOptions - { - Instructions = JokerInstructions, - Name = JokerName, - ChatMessageStoreFactory = ctx => - { - // Create a new chat message store for this agent that stores the messages in a vector store. - // Each thread must get its own copy of the VectorChatMessageStore, since the store - // also contains the id that the thread is stored under. - return new VectorChatMessageStore(vectorStore, ctx.SerializedState, ctx.JsonSerializerOptions); - } - }); - -// Start a new thread for the agent conversation. -AgentThread thread = agent.GetNewThread(); - -// Run the agent with the thread that stores conversation history in the vector store. -Console.WriteLine(await agent.RunAsync("Tell me a joke about a pirate.", thread)); - -// Serialize the thread state, so it can be stored for later use. -// Since the chat history is stored in the vector store, the serialized thread -// only contains the guid that the messages are stored under in the vector store. -JsonElement serializedThread = thread.Serialize(); - -Console.WriteLine("\n--- Serialized thread ---\n"); -Console.WriteLine(JsonSerializer.Serialize(serializedThread, new JsonSerializerOptions { WriteIndented = true })); - -// The serialized thread can now be saved to a database, file, or any other storage mechanism -// and loaded again later. - -// Deserialize the thread state after loading from storage. -AgentThread resumedThread = agent.DeserializeThread(serializedThread); - -// Run the agent with the thread that stores conversation history in the vector store a second time. -Console.WriteLine(await agent.RunAsync("Now tell the same joke in the voice of a pirate, and add some emojis to the joke.", resumedThread)); - -// We can access the VectorChatMessageStore via the thread's GetService method if we need to read the key under which threads are stored. -var messageStore = resumedThread.GetService()!; -Console.WriteLine($"\nThread is stored in vector store under key: {messageStore.ThreadDbKey}"); - -// Cleanup by agent name removes the agent version created. -agentsClient.DeleteAgent(agent.Name); - -namespace SampleApp -{ - /// - /// A sample implementation of that stores chat messages in a vector store. - /// - internal sealed class VectorChatMessageStore : ChatMessageStore - { - private readonly VectorStore _vectorStore; - - public VectorChatMessageStore(VectorStore vectorStore, JsonElement serializedStoreState, JsonSerializerOptions? jsonSerializerOptions = null) - { - this._vectorStore = vectorStore ?? throw new ArgumentNullException(nameof(vectorStore)); - - if (serializedStoreState.ValueKind is JsonValueKind.String) - { - // Here we can deserialize the thread id so that we can access the same messages as before the suspension. - this.ThreadDbKey = serializedStoreState.Deserialize(); - } - } - - public string? ThreadDbKey { get; private set; } - - public override async Task AddMessagesAsync(IEnumerable messages, CancellationToken cancellationToken = default) - { - this.ThreadDbKey ??= Guid.NewGuid().ToString("N"); - - var collection = this._vectorStore.GetCollection("ChatHistory"); - await collection.EnsureCollectionExistsAsync(cancellationToken); - - await collection.UpsertAsync(messages.Select(x => new ChatHistoryItem() - { - Key = this.ThreadDbKey + x.MessageId, - Timestamp = DateTimeOffset.UtcNow, - ThreadId = this.ThreadDbKey, - SerializedMessage = JsonSerializer.Serialize(x), - MessageText = x.Text - }), cancellationToken); - } - - public override async Task> GetMessagesAsync(CancellationToken cancellationToken = default) - { - var collection = this._vectorStore.GetCollection("ChatHistory"); - await collection.EnsureCollectionExistsAsync(cancellationToken); - - var records = await collection - .GetAsync( - x => x.ThreadId == this.ThreadDbKey, 10, - new() { OrderBy = x => x.Descending(y => y.Timestamp) }, - cancellationToken) - .ToListAsync(cancellationToken); - - var messages = records.ConvertAll(x => JsonSerializer.Deserialize(x.SerializedMessage!)!) -; - messages.Reverse(); - return messages; - } - - public override JsonElement Serialize(JsonSerializerOptions? jsonSerializerOptions = null) => - // We have to serialize the thread id, so that on deserialization we can retrieve the messages using the same thread id. - JsonSerializer.SerializeToElement(this.ThreadDbKey); - - /// - /// The data structure used to store chat history items in the vector store. - /// - private sealed class ChatHistoryItem - { - [VectorStoreKey] - public string? Key { get; set; } - - [VectorStoreData] - public string? ThreadId { get; set; } - - [VectorStoreData] - public DateTimeOffset? Timestamp { get; set; } - - [VectorStoreData] - public string? SerializedMessage { get; set; } - - [VectorStoreData] - public string? MessageText { get; set; } - } - } -} diff --git a/dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step08_Observability/AzureAIAgents_Step08_Observability.csproj b/dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step07_Observability/AzureAIAgents_Step07_Observability.csproj similarity index 100% rename from dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step08_Observability/AzureAIAgents_Step08_Observability.csproj rename to dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step07_Observability/AzureAIAgents_Step07_Observability.csproj diff --git a/dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step08_Observability/Program.cs b/dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step07_Observability/Program.cs similarity index 84% rename from dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step08_Observability/Program.cs rename to dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step07_Observability/Program.cs index 532582f2b0..a1676b7471 100644 --- a/dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step08_Observability/Program.cs +++ b/dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step07_Observability/Program.cs @@ -32,13 +32,7 @@ using var tracerProvider = tracerProviderBuilder.Build(); 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 agent = agentsClient.GetAIAgent(agentVersion) +AIAgent agent = agentsClient.CreateAIAgent(name: JokerName, model: deploymentName, instructions: JokerInstructions) .AsBuilder() .UseOpenTelemetry(sourceName: sourceName) .Build(); diff --git a/dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step09_DependencyInjection/AzureAIAgents_Step09_DependencyInjection.csproj b/dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step08_DependencyInjection/AzureAIAgents_Step08_DependencyInjection.csproj similarity index 100% rename from dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step09_DependencyInjection/AzureAIAgents_Step09_DependencyInjection.csproj rename to dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step08_DependencyInjection/AzureAIAgents_Step08_DependencyInjection.csproj diff --git a/dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step09_DependencyInjection/Program.cs b/dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step08_DependencyInjection/Program.cs similarity index 85% rename from dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step09_DependencyInjection/Program.cs rename to dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step08_DependencyInjection/Program.cs index 672b99b4ae..af754f49f9 100644 --- a/dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step09_DependencyInjection/Program.cs +++ b/dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step08_DependencyInjection/Program.cs @@ -20,16 +20,12 @@ const string JokerName = "JokerAgent"; HostApplicationBuilder builder = Host.CreateApplicationBuilder(args); // Add the agents client to the service collection. -builder.Services.AddSingleton((sp) => new AgentsClient(new Uri(endpoint), new AzureCliCredential())); +builder.Services.AddSingleton((sp) => new AgentsClient(new Uri(endpoint), new AzureCliCredential())); // Add the AI agent to the service collection. -builder.Services.AddSingleton((sp) => -{ - var agentsClient = sp.GetRequiredService(); - var agentDefinition = new PromptAgentDefinition(model: deploymentName) { Instructions = JokerInstructions }; - var agentVersion = agentsClient.CreateAgentVersion(agentName: JokerName, definition: agentDefinition); - return agentsClient.GetAIAgent(agentVersion); -}); +builder.Services.AddSingleton((sp) + => sp.GetRequiredService() + .CreateAIAgent(name: JokerName, model: deploymentName, instructions: JokerInstructions)); // Add a sample service that will use the agent to respond to user input. builder.Services.AddHostedService(); diff --git a/dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step10_AsMcpTool/AzureAIAgents_Step10_AsMcpTool.csproj b/dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step09_AsMcpTool/AzureAIAgents_Step09_AsMcpTool.csproj similarity index 92% rename from dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step10_AsMcpTool/AzureAIAgents_Step10_AsMcpTool.csproj rename to dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step09_AsMcpTool/AzureAIAgents_Step09_AsMcpTool.csproj index 1c98fe266b..172882a71f 100644 --- a/dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step10_AsMcpTool/AzureAIAgents_Step10_AsMcpTool.csproj +++ b/dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step09_AsMcpTool/AzureAIAgents_Step09_AsMcpTool.csproj @@ -18,7 +18,7 @@ - + diff --git a/dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step10_AsMcpTool/Program.cs b/dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step09_AsMcpTool/Program.cs similarity index 60% rename from dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step10_AsMcpTool/Program.cs rename to dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step09_AsMcpTool/Program.cs index 16bc3cd51e..eca09b4563 100644 --- a/dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step10_AsMcpTool/Program.cs +++ b/dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step09_AsMcpTool/Program.cs @@ -2,7 +2,7 @@ // This sample shows how to expose an AI agent as an MCP tool. -using Azure.AI.Agents.Persistent; +using Azure.AI.Agents; using Azure.Identity; using Microsoft.Agents.AI; using Microsoft.Extensions.DependencyInjection; @@ -12,17 +12,19 @@ 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"; -var persistentAgentsClient = new PersistentAgentsClient(endpoint, new AzureCliCredential()); +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."; -// Create a server side persistent agent -var agentMetadata = await persistentAgentsClient.Administration.CreateAgentAsync( +// 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: "You are good at telling jokes, and you always start each joke with 'Aye aye, captain!'.", - name: "Joker", - description: "An agent that tells jokes."); - -// Retrieve the server side persistent agent as an AIAgent. -AIAgent agent = await persistentAgentsClient.GetAIAgentAsync(agentMetadata.Value.Id); + 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. @@ -35,4 +37,6 @@ builder.Services .WithStdioServerTransport() .WithTools([tool]); +Console.WriteLine("Starting MCP Tool server. Press Ctrl+C to exit."); + await builder.Build().RunAsync(); diff --git a/dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step10_AsMcpTool/README.md b/dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step09_AsMcpTool/README.md similarity index 100% rename from dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step10_AsMcpTool/README.md rename to dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step09_AsMcpTool/README.md diff --git a/dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step11_UsingImages/AzureAIAgents_Step11_UsingImages.csproj b/dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step10_UsingImages/AzureAIAgents_Step10_UsingImages.csproj similarity index 100% rename from dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step11_UsingImages/AzureAIAgents_Step11_UsingImages.csproj rename to dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step10_UsingImages/AzureAIAgents_Step10_UsingImages.csproj diff --git a/dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step11_UsingImages/Program.cs b/dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step10_UsingImages/Program.cs similarity index 77% rename from dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step11_UsingImages/Program.cs rename to dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step10_UsingImages/Program.cs index 13621fc52c..fcaca003a0 100644 --- a/dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step11_UsingImages/Program.cs +++ b/dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step10_UsingImages/Program.cs @@ -17,13 +17,7 @@ const string VisionName = "VisionAgent"; 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 = VisionInstructions }; - -// Create a server side agent version with the Azure.AI.Agents SDK client. -var agentVersion = agentsClient.CreateAgentVersion(agentName: VisionName, definition: agentDefinition); - -// Retrieve an AIAgent for the created server side agent version. -AIAgent agent = agentsClient.GetAIAgent(agentVersion); +AIAgent agent = agentsClient.CreateAIAgent(name: VisionName, model: deploymentName, instructions: VisionInstructions); ChatMessage message = new(ChatRole.User, [ new TextContent("What do you see in this image?"), diff --git a/dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step11_UsingImages/README.md b/dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step10_UsingImages/README.md similarity index 100% rename from dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step11_UsingImages/README.md rename to dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step10_UsingImages/README.md diff --git a/dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step12_AsFunctionTool/AzureAIAgents_Step12_AsFunctionTool.csproj b/dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step11_AsFunctionTool/AzureAIAgents_Step11_AsFunctionTool.csproj similarity index 100% rename from dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step12_AsFunctionTool/AzureAIAgents_Step12_AsFunctionTool.csproj rename to dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step11_AsFunctionTool/AzureAIAgents_Step11_AsFunctionTool.csproj diff --git a/dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step12_AsFunctionTool/Program.cs b/dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step11_AsFunctionTool/Program.cs similarity index 66% rename from dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step12_AsFunctionTool/Program.cs rename to dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step11_AsFunctionTool/Program.cs index 8c8c502f36..a0c62d775b 100644 --- a/dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step12_AsFunctionTool/Program.cs +++ b/dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step11_AsFunctionTool/Program.cs @@ -7,7 +7,6 @@ using Azure.AI.Agents; using Azure.Identity; using Microsoft.Agents.AI; using Microsoft.Extensions.AI; -using OpenAI.Responses; 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"; @@ -25,24 +24,19 @@ static string GetWeather([Description("The location to get the weather for.")] s var agentsClient = new AgentsClient(new Uri(endpoint), new AzureCliCredential()); // Create the weather agent with function tools. -var weatherAgentDefinition = new PromptAgentDefinition(model: deploymentName) -{ - Instructions = WeatherInstructions -}; var weatherTool = AIFunctionFactory.Create(GetWeather); -weatherAgentDefinition.Tools.Add(weatherTool.GetService() ?? weatherTool.AsOpenAIResponseTool()!); -var weatherAgentVersion = agentsClient.CreateAgentVersion(agentName: WeatherName, definition: weatherAgentDefinition); -AIAgent weatherAgent = agentsClient.GetAIAgent(weatherAgentVersion); +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. -var mainAgentDefinition = new PromptAgentDefinition(model: deploymentName) -{ - Instructions = MainInstructions -}; -var agentTool = weatherAgent.AsAIFunction(); -mainAgentDefinition.Tools.Add(agentTool.GetService() ?? agentTool.AsOpenAIResponseTool()!); -var mainAgentVersion = agentsClient.CreateAgentVersion(agentName: MainName, definition: mainAgentDefinition); -AIAgent agent = agentsClient.GetAIAgent(mainAgentVersion); +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(); diff --git a/dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step14_Middleware/AzureAIAgents_Step14_Middleware.csproj b/dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step12_Middleware/AzureAIAgents_Step12_Middleware.csproj similarity index 100% rename from dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step14_Middleware/AzureAIAgents_Step14_Middleware.csproj rename to dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step12_Middleware/AzureAIAgents_Step12_Middleware.csproj diff --git a/dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step14_Middleware/Program.cs b/dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step12_Middleware/Program.cs similarity index 79% rename from dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step14_Middleware/Program.cs rename to dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step12_Middleware/Program.cs index 0f45d6df72..257a1e97d8 100644 --- a/dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step14_Middleware/Program.cs +++ b/dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step12_Middleware/Program.cs @@ -11,7 +11,6 @@ using Azure.AI.Agents; using Azure.Identity; using Microsoft.Agents.AI; using Microsoft.Extensions.AI; -using OpenAI.Responses; // 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."); @@ -31,19 +30,15 @@ static string GetWeather([Description("The location to get the weather for.")] s static string GetDateTime() => DateTimeOffset.Now.ToString(); -// Define the agent with tools -var agentDefinition = new PromptAgentDefinition(model: deploymentName) -{ - Instructions = AssistantInstructions -}; var dateTimeTool = AIFunctionFactory.Create(GetDateTime, name: nameof(GetDateTime)); -agentDefinition.Tools.Add(dateTimeTool.GetService() ?? dateTimeTool.AsOpenAIResponseTool()!); +var getWeatherTool = AIFunctionFactory.Create(GetWeather, name: nameof(GetWeather)); -// Create a server side agent version with the Azure.AI.Agents SDK client. -var agentVersion = agentsClient.CreateAgentVersion(agentName: AssistantName, definition: agentDefinition); - -// Retrieve an AIAgent for the created server side agent version. -var originalAgent = agentsClient.GetAIAgent(agentVersion); +// 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 @@ -68,33 +63,28 @@ 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. -// Add Per-request tools -var options = new ChatClientAgentRunOptions(new() -{ - Tools = [AIFunctionFactory.Create(GetWeather, name: nameof(GetWeather))] -}); - -var functionCallResponse = await middlewareEnabledAgent.RunAsync("What's the current time and the weather in Seattle?", thread, options); +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: Per-request middleware with human in the loop function approval ==="); +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.", -var optionsWithApproval = new ChatClientAgentRunOptions(new() -{ // Adding a function with approval required - Tools = [new ApprovalRequiredAIFunction(AIFunctionFactory.Create(GetWeather, name: nameof(GetWeather)))], -}); + tools: [new ApprovalRequiredAIFunction(AIFunctionFactory.Create(GetWeather, name: nameof(GetWeather)))]); -// var response = middlewareAgent // Using per-request middleware pipeline in addition to existing agent-level middleware -var response = await originalAgent // Using per-request middleware pipeline without existing agent-level middleware +// Using the ConsolePromptingApprovalMiddleware for a specific request to handle user approval during function calls. +var response = await humamInTheLoopAgent .AsBuilder() - .Use(PerRequestFunctionCallingMiddleware) .Use(ConsolePromptingApprovalMiddleware, null) .Build() - .RunAsync("What's the current time and the weather in Seattle?", thread, optionsWithApproval); + .RunAsync("What's the current time and the weather in Seattle?"); -Console.WriteLine($"Per-request middleware response: {response}"); +Console.WriteLine($"HumamInTheLoopAgent agent middleware response: {response}"); // Function invocation middleware that logs before and after function calls. async ValueTask FunctionCallMiddleware(AIAgent agent, FunctionInvocationContext context, Func> next, CancellationToken cancellationToken) @@ -122,17 +112,6 @@ async ValueTask FunctionCallOverrideWeather(AIAgent agent, FunctionInvo return result; } -// There's no difference per-request middleware, except it's added to the agent and used for a single agent run. -// This middleware logs function names before and after they are invoked. -async ValueTask PerRequestFunctionCallingMiddleware(AIAgent agent, FunctionInvocationContext context, Func> next, CancellationToken cancellationToken) -{ - Console.WriteLine($"Agent Id: {agent.Id}"); - Console.WriteLine($"Function Name: {context!.Function.Name} - Per-Request Pre-Invoke"); - var result = await next(context, cancellationToken); - Console.WriteLine($"Function Name: {context!.Function.Name} - Per-Request Post-Invoke"); - return result; -} - // This middleware redacts PII information from input and output messages. async Task PIIMiddleware(IEnumerable messages, AgentThread? thread, AgentRunOptions? options, AIAgent innerAgent, CancellationToken cancellationToken) { diff --git a/dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step14_Middleware/README.md b/dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step12_Middleware/README.md similarity index 100% rename from dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step14_Middleware/README.md rename to dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step12_Middleware/README.md diff --git a/dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step13_Memory/AzureAIAgents_Step13_Memory.csproj b/dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step13_Memory/AzureAIAgents_Step13_Memory.csproj deleted file mode 100644 index a8f0446c0e..0000000000 --- a/dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step13_Memory/AzureAIAgents_Step13_Memory.csproj +++ /dev/null @@ -1,22 +0,0 @@ - - - - Exe - net9.0 - - enable - enable - $(NoWarn);CA1812 - - - - - - - - - - - - - diff --git a/dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step13_Memory/Program.cs b/dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step13_Memory/Program.cs deleted file mode 100644 index 6ab5e69e93..0000000000 --- a/dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step13_Memory/Program.cs +++ /dev/null @@ -1,156 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -// This sample shows how to add a basic custom memory component to an agent. -// The memory component subscribes to all messages added to the conversation and -// extracts the user's name and age if provided. -// The component adds a prompt to ask for this information if it is not already known -// and provides it to the model before each invocation if known. - -using System.Text; -using System.Text.Json; -using Azure.AI.Agents; -using Azure.Identity; -using Microsoft.Agents.AI; -using Microsoft.Extensions.AI; -using SampleApp; - -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 friendly assistant. Always address the user by their name."; -const string AssistantName = "FriendlyAssistant"; - -// 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 = AssistantInstructions }; - -// Create a server side agent version with the Azure.AI.Agents SDK client. -var agentVersion = agentsClient.CreateAgentVersion(agentName: AssistantName, definition: agentDefinition); - -// Retrieve an AIAgent for the created server side agent version. -AIAgent agent = agentsClient.GetAIAgent(agentVersion); - -// Create a new thread for the conversation. -AgentThread thread = agent.GetNewThread(); - -Console.WriteLine(">> Use thread with blank memory\n"); - -// Invoke the agent and output the text result. -Console.WriteLine(await agent.RunAsync("Hello, what is the square root of 9?", thread)); -Console.WriteLine(await agent.RunAsync("My name is Ruaidhrí", thread)); -Console.WriteLine(await agent.RunAsync("I am 20 years old", thread)); - -// We can serialize the thread. The serialized state will include the state of the memory component. -var threadElement = thread.Serialize(); - -Console.WriteLine("\n>> Use deserialized thread with previously created memories\n"); - -// Later we can deserialize the thread and continue the conversation with the previous memory component state. -var deserializedThread = agent.DeserializeThread(threadElement); -Console.WriteLine(await agent.RunAsync("What is my name and age?", deserializedThread)); - -Console.WriteLine("\n>> Read memories from memory component\n"); - -// It's possible to access the memory component via the thread's GetService method. -var userInfo = deserializedThread.GetService()?.UserInfo; - -// Output the user info that was captured by the memory component. -Console.WriteLine($"MEMORY - User Name: {userInfo?.UserName}"); -Console.WriteLine($"MEMORY - User Age: {userInfo?.UserAge}"); - -Console.WriteLine("\n>> Use new thread with previously created memories\n"); - -// It is also possible to set the memories in a memory component on an individual thread. -// This is useful if we want to start a new thread, but have it share the same memories as a previous thread. -var newThread = agent.GetNewThread(); -if (userInfo is not null && newThread.GetService() is UserInfoMemory newThreadMemory) -{ - newThreadMemory.UserInfo = userInfo; -} - -// Invoke the agent and output the text result. -// This time the agent should remember the user's name and use it in the response. -Console.WriteLine(await agent.RunAsync("What is my name and age?", newThread)); - -// Cleanup by agent name removes the agent version created. -agentsClient.DeleteAgent(agent.Name); - -namespace SampleApp -{ - /// - /// Sample memory component that can remember a user's name and age. - /// - internal sealed class UserInfoMemory : AIContextProvider - { - private readonly IChatClient _chatClient; - - public UserInfoMemory(IChatClient chatClient, UserInfo? userInfo = null) - { - this._chatClient = chatClient; - this.UserInfo = userInfo ?? new UserInfo(); - } - - public UserInfoMemory(IChatClient chatClient, JsonElement serializedState, JsonSerializerOptions? jsonSerializerOptions = null) - { - this._chatClient = chatClient; - - this.UserInfo = serializedState.ValueKind == JsonValueKind.Object ? - serializedState.Deserialize(jsonSerializerOptions)! : - new UserInfo(); - } - - public UserInfo UserInfo { get; set; } - - public override async ValueTask InvokedAsync(InvokedContext context, CancellationToken cancellationToken = default) - { - // Try and extract the user name and age from the message if we don't have it already and it's a user message. - if ((this.UserInfo.UserName is null || this.UserInfo.UserAge is null) && context.RequestMessages.Any(x => x.Role == ChatRole.User)) - { - var result = await this._chatClient.GetResponseAsync( - context.RequestMessages, - new ChatOptions() - { - Instructions = "Extract the user's name and age from the message if present. If not present return nulls." - }, - cancellationToken: cancellationToken); - - this.UserInfo.UserName ??= result.Result.UserName; - this.UserInfo.UserAge ??= result.Result.UserAge; - } - } - - public override ValueTask InvokingAsync(InvokingContext context, CancellationToken cancellationToken = default) - { - StringBuilder instructions = new(); - - // If we don't already know the user's name and age, add instructions to ask for them, otherwise just provide what we have to the context. - instructions - .AppendLine( - this.UserInfo.UserName is null ? - "Ask the user for their name and politely decline to answer any questions until they provide it." : - $"The user's name is {this.UserInfo.UserName}.") - .AppendLine( - this.UserInfo.UserAge is null ? - "Ask the user for their age and politely decline to answer any questions until they provide it." : - $"The user's age is {this.UserInfo.UserAge}."); - - return new ValueTask(new AIContext - { - Instructions = instructions.ToString() - }); - } - - public override JsonElement Serialize(JsonSerializerOptions? jsonSerializerOptions = null) - { - return JsonSerializer.SerializeToElement(this.UserInfo, jsonSerializerOptions); - } - } - - internal sealed class UserInfo - { - public string? UserName { get; set; } - public int? UserAge { get; set; } - } -} diff --git a/dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step15_Plugins/AzureAIAgents_Step15_Plugins.csproj b/dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step13_Plugins/AzureAIAgents_Step13_Plugins.csproj similarity index 100% rename from dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step15_Plugins/AzureAIAgents_Step15_Plugins.csproj rename to dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step13_Plugins/AzureAIAgents_Step13_Plugins.csproj diff --git a/dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step15_Plugins/Program.cs b/dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step13_Plugins/Program.cs similarity index 89% rename from dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step15_Plugins/Program.cs rename to dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step13_Plugins/Program.cs index 449fa6d0a6..2b3a6d71fb 100644 --- a/dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step15_Plugins/Program.cs +++ b/dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step13_Plugins/Program.cs @@ -14,7 +14,6 @@ using Azure.Identity; using Microsoft.Agents.AI; using Microsoft.Extensions.AI; using Microsoft.Extensions.DependencyInjection; -using OpenAI.Responses; 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"; @@ -34,20 +33,13 @@ IServiceProvider serviceProvider = services.BuildServiceProvider(); var agentsClient = new AgentsClient(new Uri(endpoint), new AzureCliCredential()); // Define the agent with plugin tools -var agentDefinition = new PromptAgentDefinition(model: deploymentName) -{ - Instructions = AssistantInstructions -}; -foreach (var tool in serviceProvider.GetRequiredService().AsAITools()) -{ - agentDefinition.Tools.Add(tool.GetService() ?? tool.AsOpenAIResponseTool()!); -} - -// Create a server side agent version with the Azure.AI.Agents SDK client. -var agentVersion = agentsClient.CreateAgentVersion(agentName: AssistantName, definition: agentDefinition); - -// Retrieve an AIAgent for the created server side agent version. -AIAgent agent = agentsClient.GetAIAgent(agentVersion); +// 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().AsAITools().ToList(), + services: serviceProvider); // Invoke the agent and output the text result. AgentThread thread = agent.GetNewThread(); diff --git a/dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step16_ChatReduction/Program.cs b/dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step16_ChatReduction/Program.cs index 0b522e6033..33c65c8e5a 100644 --- a/dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step16_ChatReduction/Program.cs +++ b/dotnet/samples/GettingStarted/AgentProviders/Agent_With_AzureAIAgent/AzureAIAgents_Step16_ChatReduction/Program.cs @@ -18,13 +18,7 @@ const string JokerName = "JokerAgent"; 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 agent = agentsClient.GetAIAgent(agentVersion); +AIAgent agent = agentsClient.CreateAIAgent(name: JokerName, model: deploymentName, instructions: JokerInstructions); AgentThread thread = agent.GetNewThread(); diff --git a/dotnet/src/Microsoft.Agents.AI.AzureAI/AgentsClientExtensions.cs b/dotnet/src/Microsoft.Agents.AI.AzureAI/AgentsClientExtensions.cs index af411c25dc..90b9fac4c1 100644 --- a/dotnet/src/Microsoft.Agents.AI.AzureAI/AgentsClientExtensions.cs +++ b/dotnet/src/Microsoft.Agents.AI.AzureAI/AgentsClientExtensions.cs @@ -25,6 +25,7 @@ public static class AgentsClientExtensions /// The tools to use when interacting with the agent. This is required when using prompt agent definitions with tools. /// Provides a way to customize the creation of the underlying used by the agent. /// An optional for configuring the underlying OpenAI client. + /// An optional to use for resolving services required by the instances being invoked. /// The to monitor for cancellation requests. The default is . /// A instance that can be used to perform operations based on the latest version of the named Azure AI Agent. /// Thrown when or is . @@ -37,6 +38,7 @@ public static class AgentsClientExtensions IList? tools = null, Func? clientFactory = null, OpenAIClientOptions? openAIClientOptions = null, + IServiceProvider? services = null, CancellationToken cancellationToken = default) { Throw.IfNull(agentsClient); @@ -51,6 +53,7 @@ public static class AgentsClientExtensions tools, clientFactory, openAIClientOptions, + services, cancellationToken); } @@ -62,6 +65,7 @@ public static class AgentsClientExtensions /// The tools to use when interacting with the agent. This is required when using prompt agent definitions with tools. /// Provides a way to customize the creation of the underlying used by the agent. /// An optional for configuring the underlying OpenAI client. + /// An optional to use for resolving services required by the instances being invoked. /// The to monitor for cancellation requests. The default is . /// A instance that can be used to perform operations based on the latest version of the named Azure AI Agent. /// Thrown when or is . @@ -74,6 +78,7 @@ public static class AgentsClientExtensions IList? tools = null, Func? clientFactory = null, OpenAIClientOptions? openAIClientOptions = null, + IServiceProvider? services = null, CancellationToken cancellationToken = default) { Throw.IfNull(agentsClient); @@ -88,6 +93,7 @@ public static class AgentsClientExtensions tools, clientFactory, openAIClientOptions, + services, cancellationToken); } @@ -99,6 +105,7 @@ public static class AgentsClientExtensions /// The tools to use when interacting with the agent. This is required when using prompt agent definitions with tools. /// Provides a way to customize the creation of the underlying used by the agent. /// An optional for configuring the underlying OpenAI client. + /// An optional to use for resolving services required by the instances being invoked. /// The to monitor for cancellation requests. The default is . /// A instance that can be used to perform operations based on the latest version of the Azure AI Agent. /// When using prompt agent definitions with tools the parameter needs to be provided. @@ -108,6 +115,7 @@ public static class AgentsClientExtensions IList? tools = null, Func? clientFactory = null, OpenAIClientOptions? openAIClientOptions = null, + IServiceProvider? services = null, CancellationToken cancellationToken = default) { Throw.IfNull(agentsClient); @@ -119,7 +127,7 @@ public static class AgentsClientExtensions tools, clientFactory, openAIClientOptions, - requireInvocableTools: true, + services, cancellationToken); } @@ -131,10 +139,7 @@ public static class AgentsClientExtensions /// The tools to use when interacting with the agent. This is required when using prompt agent definitions with tools. /// Provides a way to customize the creation of the underlying used by the agent. /// An optional for configuring the underlying OpenAI client. - /// - /// This defaults to and indicates whether to enforce the presence of invocable tools when the AIAgent is created with an agent definition that uses them. - /// Setting this to will require manual handling of in-proc tool invocations by the caller. - /// + /// An optional to use for resolving services required by the instances being invoked. /// The to monitor for cancellation requests. The default is . /// A instance that can be used to perform operations based on the provided version of the Azure AI Agent. /// Thrown when or is . @@ -145,7 +150,7 @@ public static class AgentsClientExtensions IList? tools = null, Func? clientFactory = null, OpenAIClientOptions? openAIClientOptions = null, - bool requireInvocableTools = true, + IServiceProvider? services = null, CancellationToken cancellationToken = default) { Throw.IfNull(agentsClient); @@ -159,7 +164,8 @@ public static class AgentsClientExtensions tools, clientFactory, openAIClientOptions, - requireInvocableTools); + requireInvocableTools: true, + services); } /// @@ -169,6 +175,7 @@ public static class AgentsClientExtensions /// The options for creating the agent. Cannot be . /// A factory function to customize the creation of the chat client used by the agent. /// An optional for configuring the underlying OpenAI client. + /// An optional to use for resolving services required by the instances being invoked. /// A to cancel the operation if needed. /// A instance that can be used to perform operations on the newly created agent. /// Thrown when or is . @@ -177,6 +184,7 @@ public static class AgentsClientExtensions ChatClientAgentOptions options, Func? clientFactory = null, OpenAIClientOptions? openAIClientOptions = null, + IServiceProvider? services = null, CancellationToken cancellationToken = default) { Throw.IfNull(agentsClient); @@ -200,7 +208,8 @@ public static class AgentsClientExtensions agentOptions, clientFactory, openAIClientOptions, - requireInvocableTools: true); + requireInvocableTools: true, + services); } /// @@ -210,6 +219,7 @@ public static class AgentsClientExtensions /// The options for creating the agent. Cannot be . /// A factory function to customize the creation of the chat client used by the agent. /// An optional for configuring the underlying OpenAI client. + /// An optional to use for resolving services required by the instances being invoked. /// A to cancel the operation if needed. /// A instance that can be used to perform operations on the newly created agent. /// Thrown when or is . @@ -218,6 +228,7 @@ public static class AgentsClientExtensions ChatClientAgentOptions options, Func? clientFactory = null, OpenAIClientOptions? openAIClientOptions = null, + IServiceProvider? services = null, CancellationToken cancellationToken = default) { Throw.IfNull(agentsClient); @@ -241,7 +252,8 @@ public static class AgentsClientExtensions agentOptions, clientFactory, openAIClientOptions, - requireInvocableTools: true); + requireInvocableTools: true, + services); } /// @@ -255,6 +267,7 @@ public static class AgentsClientExtensions /// Settings that control the creation of the agent. /// A factory function to customize the creation of the chat client used by the agent. /// An optional for configuring the underlying OpenAI client. + /// An optional to use for resolving services required by the instances being invoked. /// A token to monitor for cancellation requests. /// A instance that can be used to perform operations on the newly created agent. /// Thrown when , , or is . @@ -269,6 +282,7 @@ public static class AgentsClientExtensions AgentVersionCreationOptions? creationOptions = null, Func? clientFactory = null, OpenAIClientOptions? openAIClientOptions = null, + IServiceProvider? services = null, CancellationToken cancellationToken = default) { Throw.IfNull(agentsClient); @@ -285,6 +299,7 @@ public static class AgentsClientExtensions clientFactory, openAIClientOptions, requireInvocableTools: true, + services, cancellationToken); } @@ -299,6 +314,7 @@ public static class AgentsClientExtensions /// Settings that control the creation of the agent. /// A factory function to customize the creation of the chat client used by the agent. /// An optional for configuring the underlying OpenAI client. + /// An optional to use for resolving services required by the instances being invoked. /// A token to monitor for cancellation requests. /// A instance that can be used to perform operations on the newly created agent. /// Thrown when , , or is . @@ -313,6 +329,7 @@ public static class AgentsClientExtensions AgentVersionCreationOptions? creationOptions = null, Func? clientFactory = null, OpenAIClientOptions? openAIClientOptions = null, + IServiceProvider? services = null, CancellationToken cancellationToken = default) { Throw.IfNull(agentsClient); @@ -329,6 +346,7 @@ public static class AgentsClientExtensions clientFactory, openAIClientOptions, requireInvocableTools: true, + services, cancellationToken); } @@ -340,6 +358,7 @@ public static class AgentsClientExtensions /// The options for creating the agent. Cannot be . /// A factory function to customize the creation of the chat client used by the agent. /// An optional for configuring the underlying OpenAI client. + /// An optional to use for resolving services required by the instances being invoked. /// A to cancel the operation if needed. /// A instance that can be used to perform operations on the newly created agent. /// Thrown when or is . @@ -350,6 +369,7 @@ public static class AgentsClientExtensions ChatClientAgentOptions options, Func? clientFactory = null, OpenAIClientOptions? openAIClientOptions = null, + IServiceProvider? services = null, CancellationToken cancellationToken = default) { Throw.IfNull(agentsClient); @@ -385,7 +405,8 @@ public static class AgentsClientExtensions agentOptions, clientFactory, openAIClientOptions, - RequireInvocableTools); + RequireInvocableTools, + services); } /// @@ -396,6 +417,7 @@ public static class AgentsClientExtensions /// The options for creating the agent. Cannot be . /// A factory function to customize the creation of the chat client used by the agent. /// An optional for configuring the underlying OpenAI client. + /// An optional to use for resolving services required by the instances being invoked. /// A to cancel the operation if needed. /// A instance that can be used to perform operations on the newly created agent. /// Thrown when or is . @@ -406,6 +428,7 @@ public static class AgentsClientExtensions ChatClientAgentOptions options, Func? clientFactory = null, OpenAIClientOptions? openAIClientOptions = null, + IServiceProvider? services = null, CancellationToken cancellationToken = default) { Throw.IfNull(agentsClient); @@ -441,7 +464,8 @@ public static class AgentsClientExtensions agentOptions, clientFactory, openAIClientOptions, - RequireInvocableTools); + RequireInvocableTools, + services); } /// @@ -484,6 +508,7 @@ public static class AgentsClientExtensions clientFactory, openAIClientOptions, requireInvocableTools: false, + services: null, cancellationToken); } @@ -528,6 +553,7 @@ public static class AgentsClientExtensions clientFactory, openAIClientOptions, requireInvocableTools: false, + services: null, cancellationToken); } @@ -542,6 +568,7 @@ public static class AgentsClientExtensions Func? clientFactory, OpenAIClientOptions? openAIClientOptions, bool requireInvocableTools, + IServiceProvider? services, CancellationToken cancellationToken) { Throw.IfNull(agentsClient); @@ -560,7 +587,8 @@ public static class AgentsClientExtensions tools, clientFactory, openAIClientOptions, - requireInvocableTools); + requireInvocableTools, + services); } private static async Task CreateAIAgentAsync( @@ -572,6 +600,7 @@ public static class AgentsClientExtensions Func? clientFactory, OpenAIClientOptions? openAIClientOptions, bool requireInvocableTools, + IServiceProvider? services, CancellationToken cancellationToken) { Throw.IfNullOrWhitespace(name); @@ -590,7 +619,8 @@ public static class AgentsClientExtensions tools, clientFactory, openAIClientOptions, - requireInvocableTools); + requireInvocableTools, + services); } /// This method creates an with the specified ChatClientAgentOptions. @@ -600,7 +630,8 @@ public static class AgentsClientExtensions ChatClientAgentOptions agentOptions, Func? clientFactory, OpenAIClientOptions? openAIClientOptions, - bool requireInvocableTools) + bool requireInvocableTools, + IServiceProvider? services) { IChatClient chatClient = new AzureAIAgentChatClient(agentsClient, agentVersion, agentOptions.ChatOptions, openAIClientOptions); @@ -609,7 +640,7 @@ public static class AgentsClientExtensions chatClient = clientFactory(chatClient); } - return new ChatClientAgent(chatClient, agentOptions); + return new ChatClientAgent(chatClient, agentOptions, services: services); } /// This method creates an with a auto-generated ChatClientAgentOptions from the specified configuration parameters. @@ -619,14 +650,16 @@ public static class AgentsClientExtensions IList? tools, Func? clientFactory, OpenAIClientOptions? openAIClientOptions, - bool requireInvocableTools) + bool requireInvocableTools, + IServiceProvider? services) => CreateChatClientAgent( agentsClient, agentVersion, CreateChatClientAgentOptions(agentVersion, new ChatOptions() { Tools = tools }, requireInvocableTools), clientFactory, openAIClientOptions, - requireInvocableTools); + requireInvocableTools, + services); /// /// This method creates for the specified and the provided tools. diff --git a/dotnet/src/Microsoft.Agents.AI.AzureAI/AzureAIAgentChatClient.cs b/dotnet/src/Microsoft.Agents.AI.AzureAI/AzureAIAgentChatClient.cs index c7e11cf4f9..9b1162b81d 100644 --- a/dotnet/src/Microsoft.Agents.AI.AzureAI/AzureAIAgentChatClient.cs +++ b/dotnet/src/Microsoft.Agents.AI.AzureAI/AzureAIAgentChatClient.cs @@ -102,6 +102,7 @@ internal sealed class AzureAIAgentChatClient : DelegatingChatClient // Ignore per-request all options that can't be overriden. conversationChatOptions.Instructions = null; + conversationChatOptions.Tools = null; // Preserve the original RawRepresentationFactory var originalFactory = chatOptions?.RawRepresentationFactory; diff --git a/dotnet/tests/Microsoft.Agents.AI.AzureAI.UnitTests/AgentsClientExtensionsTests.cs b/dotnet/tests/Microsoft.Agents.AI.AzureAI.UnitTests/AgentsClientExtensionsTests.cs index 497340b298..f09a909460 100644 --- a/dotnet/tests/Microsoft.Agents.AI.AzureAI.UnitTests/AgentsClientExtensionsTests.cs +++ b/dotnet/tests/Microsoft.Agents.AI.AzureAI.UnitTests/AgentsClientExtensionsTests.cs @@ -191,25 +191,7 @@ public sealed class AgentsClientExtensionsTests }; // Act - var agent = client.GetAIAgent(agentVersion, tools: tools, requireInvocableTools: true); - - // Assert - Assert.NotNull(agent); - Assert.IsType(agent); - } - - /// - /// Verify that GetAIAgent with requireInvocableTools=false allows declarative functions. - /// - [Fact] - public void GetAIAgent_WithAgentVersion_WithRequireInvocableToolsFalse_AllowsDeclarativeFunctions() - { - // Arrange - AgentsClient client = this.CreateTestAgentsClient(); - AgentVersion agentVersion = this.CreateTestAgentVersion(); - - // Act - should not throw even without tools when requireInvocableTools is false - var agent = client.GetAIAgent(agentVersion, requireInvocableTools: false); + var agent = client.GetAIAgent(agentVersion, tools: tools); // Assert Assert.NotNull(agent);