diff --git a/dotnet/agent-framework-dotnet.slnx b/dotnet/agent-framework-dotnet.slnx index 75888768fa..86f87b40e1 100644 --- a/dotnet/agent-framework-dotnet.slnx +++ b/dotnet/agent-framework-dotnet.slnx @@ -284,8 +284,11 @@ + + + diff --git a/dotnet/samples/05-end-to-end/HostedAgents/AgentThreadAndHITL/AgentThreadAndHITL.csproj b/dotnet/samples/05-end-to-end/HostedAgents/AgentThreadAndHITL/AgentThreadAndHITL.csproj index 17b90fd6e2..1398a60228 100644 --- a/dotnet/samples/05-end-to-end/HostedAgents/AgentThreadAndHITL/AgentThreadAndHITL.csproj +++ b/dotnet/samples/05-end-to-end/HostedAgents/AgentThreadAndHITL/AgentThreadAndHITL.csproj @@ -1,4 +1,4 @@ - + Exe @@ -36,11 +36,10 @@ - + - - + diff --git a/dotnet/samples/05-end-to-end/HostedAgents/AgentThreadAndHITL/Program.cs b/dotnet/samples/05-end-to-end/HostedAgents/AgentThreadAndHITL/Program.cs index 305b9835ed..c816b018e9 100644 --- a/dotnet/samples/05-end-to-end/HostedAgents/AgentThreadAndHITL/Program.cs +++ b/dotnet/samples/05-end-to-end/HostedAgents/AgentThreadAndHITL/Program.cs @@ -11,9 +11,10 @@ using Azure.Identity; using Microsoft.Agents.AI; using Microsoft.Extensions.AI; +using OpenAI.Chat; -var endpoint = Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT") ?? throw new InvalidOperationException("AZURE_OPENAI_ENDPOINT is not set."); -var deploymentName = Environment.GetEnvironmentVariable("AZURE_OPENAI_DEPLOYMENT_NAME") ?? "gpt-4o-mini"; +string endpoint = Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT") ?? throw new InvalidOperationException("AZURE_OPENAI_ENDPOINT is not set."); +string deploymentName = Environment.GetEnvironmentVariable("AZURE_OPENAI_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) @@ -22,17 +23,19 @@ static string GetWeather([Description("The location to get the weather for.")] s // Create the chat client and agent. // Note: ApprovalRequiredAIFunction wraps the tool to require user approval before invocation. // User should reply with 'approve' or 'reject' when prompted. +// WARNING: DefaultAzureCredential is convenient for development but requires careful consideration in production. +// In production, consider using a specific credential (e.g., ManagedIdentityCredential) to avoid +// latency issues, unintended credential probing, and potential security risks from fallback mechanisms. #pragma warning disable MEAI001 // Type is for evaluation purposes only AIAgent agent = new AzureOpenAIClient( new Uri(endpoint), - new AzureCliCredential()) + new DefaultAzureCredential()) .GetChatClient(deploymentName) - .AsIChatClient() - .CreateAIAgent( + .AsAIAgent( instructions: "You are a helpful assistant", tools: [new ApprovalRequiredAIFunction(AIFunctionFactory.Create(GetWeather))] ); #pragma warning restore MEAI001 -var threadRepository = new InMemoryAgentThreadRepository(agent); +InMemoryAgentThreadRepository threadRepository = new(agent); await agent.RunAIAgentAsync(telemetrySourceName: "Agents", threadRepository: threadRepository); diff --git a/dotnet/samples/05-end-to-end/HostedAgents/AgentWithHostedMCP/AgentWithHostedMCP.csproj b/dotnet/samples/05-end-to-end/HostedAgents/AgentWithHostedMCP/AgentWithHostedMCP.csproj index 361848c27d..e854cfcd40 100644 --- a/dotnet/samples/05-end-to-end/HostedAgents/AgentWithHostedMCP/AgentWithHostedMCP.csproj +++ b/dotnet/samples/05-end-to-end/HostedAgents/AgentWithHostedMCP/AgentWithHostedMCP.csproj @@ -35,10 +35,10 @@ - + - + diff --git a/dotnet/samples/05-end-to-end/HostedAgents/AgentWithHostedMCP/Program.cs b/dotnet/samples/05-end-to-end/HostedAgents/AgentWithHostedMCP/Program.cs index 0898bc0252..972205cfe2 100644 --- a/dotnet/samples/05-end-to-end/HostedAgents/AgentWithHostedMCP/Program.cs +++ b/dotnet/samples/05-end-to-end/HostedAgents/AgentWithHostedMCP/Program.cs @@ -9,9 +9,10 @@ using Azure.Identity; using Microsoft.Agents.AI; using Microsoft.Extensions.AI; +using OpenAI.Responses; -var endpoint = Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT") ?? throw new InvalidOperationException("AZURE_OPENAI_ENDPOINT is not set."); -var deploymentName = Environment.GetEnvironmentVariable("AZURE_OPENAI_DEPLOYMENT_NAME") ?? "gpt-4o-mini"; +string endpoint = Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT") ?? throw new InvalidOperationException("AZURE_OPENAI_ENDPOINT is not set."); +string deploymentName = Environment.GetEnvironmentVariable("AZURE_OPENAI_DEPLOYMENT_NAME") ?? "gpt-4o-mini"; // Create an MCP tool that can be called without approval. AITool mcpTool = new HostedMcpServerTool(serverName: "microsoft_learn", serverAddress: "https://learn.microsoft.com/api/mcp") @@ -28,8 +29,7 @@ new Uri(endpoint), new DefaultAzureCredential()) .GetResponsesClient(deploymentName) - .AsIChatClient() - .CreateAIAgent( + .AsAIAgent( instructions: "You answer questions by searching the Microsoft Learn content only.", name: "MicrosoftLearnAgent", tools: [mcpTool]); diff --git a/dotnet/samples/05-end-to-end/HostedAgents/AgentWithHostedMCP/README.md b/dotnet/samples/05-end-to-end/HostedAgents/AgentWithHostedMCP/README.md index 8d8ddba330..106e08e720 100644 --- a/dotnet/samples/05-end-to-end/HostedAgents/AgentWithHostedMCP/README.md +++ b/dotnet/samples/05-end-to-end/HostedAgents/AgentWithHostedMCP/README.md @@ -18,7 +18,7 @@ Before running this sample, ensure you have: 2. A deployment of a chat model (e.g., gpt-4o-mini) 3. Azure CLI installed and authenticated -**Note**: This sample uses Azure CLI credentials for authentication. Make sure you're logged in with `az login` and have access to the Azure OpenAI resource. +**Note**: This sample uses `DefaultAzureCredential` for authentication, which probes multiple sources automatically. For local development, make sure you're logged in with `az login` and have access to the Azure OpenAI resource. ## Environment Variables diff --git a/dotnet/samples/05-end-to-end/HostedAgents/AgentWithLocalTools/AgentWithLocalTools.csproj b/dotnet/samples/05-end-to-end/HostedAgents/AgentWithLocalTools/AgentWithLocalTools.csproj index 43cdbfb025..975333e584 100644 --- a/dotnet/samples/05-end-to-end/HostedAgents/AgentWithLocalTools/AgentWithLocalTools.csproj +++ b/dotnet/samples/05-end-to-end/HostedAgents/AgentWithLocalTools/AgentWithLocalTools.csproj @@ -36,11 +36,11 @@ - + - + diff --git a/dotnet/samples/05-end-to-end/HostedAgents/AgentWithLocalTools/Program.cs b/dotnet/samples/05-end-to-end/HostedAgents/AgentWithLocalTools/Program.cs index 72eb938047..78a0aa62e9 100644 --- a/dotnet/samples/05-end-to-end/HostedAgents/AgentWithLocalTools/Program.cs +++ b/dotnet/samples/05-end-to-end/HostedAgents/AgentWithLocalTools/Program.cs @@ -15,21 +15,21 @@ using Microsoft.Agents.AI; using Microsoft.Extensions.AI; -var endpoint = Environment.GetEnvironmentVariable("AZURE_AI_PROJECT_ENDPOINT") +string endpoint = Environment.GetEnvironmentVariable("AZURE_AI_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("AZURE_AI_PROJECT_ENDPOINT is not set."); -var deploymentName = Environment.GetEnvironmentVariable("MODEL_DEPLOYMENT_NAME") ?? "gpt-4o-mini"; +string deploymentName = Environment.GetEnvironmentVariable("MODEL_DEPLOYMENT_NAME") ?? "gpt-4o-mini"; Console.WriteLine($"Project Endpoint: {endpoint}"); Console.WriteLine($"Model Deployment: {deploymentName}"); -var seattleHotels = new[] -{ +Hotel[] seattleHotels = +[ new Hotel("Contoso Suites", 189, 4.5, "Downtown"), new Hotel("Fabrikam Residences", 159, 4.2, "Pike Place Market"), new Hotel("Alpine Ski House", 249, 4.7, "Seattle Center"), new Hotel("Margie's Travel Lodge", 219, 4.4, "Waterfront"), new Hotel("Northwind Inn", 139, 4.0, "Capitol Hill"), new Hotel("Relecloud Hotel", 99, 3.8, "University District"), -}; +]; [Description("Get available hotels in Seattle for the specified dates. This simulates a call to a hotel availability API.")] string GetAvailableHotels( @@ -54,21 +54,21 @@ string GetAvailableHotels( return "Error: Check-out date must be after check-in date."; } - var nights = (checkOut - checkIn).Days; - var availableHotels = seattleHotels.Where(h => h.PricePerNight <= maxPrice).ToList(); + int nights = (checkOut - checkIn).Days; + List availableHotels = seattleHotels.Where(h => h.PricePerNight <= maxPrice).ToList(); if (availableHotels.Count == 0) { return $"No hotels found in Seattle within your budget of ${maxPrice}/night."; } - var result = new StringBuilder(); + StringBuilder result = new(); result.AppendLine($"Available hotels in Seattle from {checkInDate} to {checkOutDate} ({nights} nights):"); result.AppendLine(); - foreach (var hotel in availableHotels) + foreach (Hotel hotel in availableHotels) { - var totalCost = hotel.PricePerNight * nights; + int totalCost = hotel.PricePerNight * nights; result.AppendLine($"**{hotel.Name}**"); result.AppendLine($" Location: {hotel.Location}"); result.AppendLine($" Rating: {hotel.Rating}/5"); @@ -84,7 +84,10 @@ string GetAvailableHotels( } } -var credential = new AzureCliCredential(); +// WARNING: DefaultAzureCredential is convenient for development but requires careful consideration in production. +// In production, consider using a specific credential (e.g., ManagedIdentityCredential) to avoid +// latency issues, unintended credential probing, and potential security risks from fallback mechanisms. +DefaultAzureCredential credential = new(); AIProjectClient projectClient = new(new Uri(endpoint), credential); ClientConnection connection = projectClient.GetConnection(typeof(AzureOpenAIClient).FullName!); @@ -96,14 +99,14 @@ string GetAvailableHotels( openAiEndpoint = new Uri($"https://{openAiEndpoint.Host}"); Console.WriteLine($"OpenAI Endpoint: {openAiEndpoint}"); -var chatClient = new AzureOpenAIClient(openAiEndpoint, credential) +IChatClient chatClient = new AzureOpenAIClient(openAiEndpoint, credential) .GetChatClient(deploymentName) .AsIChatClient() .AsBuilder() .UseOpenTelemetry(sourceName: "Agents", configure: cfg => cfg.EnableSensitiveData = false) .Build(); -var agent = new ChatClientAgent(chatClient, +AIAgent agent = chatClient.AsAIAgent( name: "SeattleHotelAgent", instructions: """ You are a helpful travel assistant specializing in finding hotels in Seattle, Washington. diff --git a/dotnet/samples/05-end-to-end/HostedAgents/AgentWithTextSearchRag/AgentWithTextSearchRag.csproj b/dotnet/samples/05-end-to-end/HostedAgents/AgentWithTextSearchRag/AgentWithTextSearchRag.csproj index 03ffaf1824..32e00f832b 100644 --- a/dotnet/samples/05-end-to-end/HostedAgents/AgentWithTextSearchRag/AgentWithTextSearchRag.csproj +++ b/dotnet/samples/05-end-to-end/HostedAgents/AgentWithTextSearchRag/AgentWithTextSearchRag.csproj @@ -35,11 +35,10 @@ - + - - + diff --git a/dotnet/samples/05-end-to-end/HostedAgents/AgentWithTextSearchRag/Program.cs b/dotnet/samples/05-end-to-end/HostedAgents/AgentWithTextSearchRag/Program.cs index ae94a52f67..bb28fc0d9b 100644 --- a/dotnet/samples/05-end-to-end/HostedAgents/AgentWithTextSearchRag/Program.cs +++ b/dotnet/samples/05-end-to-end/HostedAgents/AgentWithTextSearchRag/Program.cs @@ -11,8 +11,8 @@ using Microsoft.Extensions.AI; using OpenAI.Chat; -var endpoint = Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT") ?? throw new InvalidOperationException("AZURE_OPENAI_ENDPOINT is not set."); -var deploymentName = Environment.GetEnvironmentVariable("AZURE_OPENAI_DEPLOYMENT_NAME") ?? "gpt-4o-mini"; +string endpoint = Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT") ?? throw new InvalidOperationException("AZURE_OPENAI_ENDPOINT is not set."); +string deploymentName = Environment.GetEnvironmentVariable("AZURE_OPENAI_DEPLOYMENT_NAME") ?? "gpt-4o-mini"; TextSearchProviderOptions textSearchOptions = new() { @@ -28,13 +28,13 @@ new Uri(endpoint), new DefaultAzureCredential()) .GetChatClient(deploymentName) - .CreateAIAgent(new ChatClientAgentOptions + .AsAIAgent(new ChatClientAgentOptions { ChatOptions = new ChatOptions { Instructions = "You are a helpful support specialist for Contoso Outdoors. Answer questions using the provided context and cite the source document when available.", }, - AIContextProviderFactory = ctx => new TextSearchProvider(MockSearchAsync, ctx.SerializedState, ctx.JsonSerializerOptions, textSearchOptions) + AIContextProviders = [new TextSearchProvider(MockSearchAsync, textSearchOptions)] }); await agent.RunAIAgentAsync(); diff --git a/dotnet/samples/05-end-to-end/HostedAgents/AgentWithTools/AgentWithTools.csproj b/dotnet/samples/05-end-to-end/HostedAgents/AgentWithTools/AgentWithTools.csproj index ce8a739757..959cca1db5 100644 --- a/dotnet/samples/05-end-to-end/HostedAgents/AgentWithTools/AgentWithTools.csproj +++ b/dotnet/samples/05-end-to-end/HostedAgents/AgentWithTools/AgentWithTools.csproj @@ -35,11 +35,10 @@ - + - - + diff --git a/dotnet/samples/05-end-to-end/HostedAgents/AgentWithTools/Program.cs b/dotnet/samples/05-end-to-end/HostedAgents/AgentWithTools/Program.cs index 3bb68d6e31..f564a0d8d3 100644 --- a/dotnet/samples/05-end-to-end/HostedAgents/AgentWithTools/Program.cs +++ b/dotnet/samples/05-end-to-end/HostedAgents/AgentWithTools/Program.cs @@ -9,13 +9,16 @@ using Microsoft.Agents.AI; using Microsoft.Extensions.AI; -var openAiEndpoint = Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT") ?? throw new InvalidOperationException("AZURE_OPENAI_ENDPOINT is not set."); -var deploymentName = Environment.GetEnvironmentVariable("AZURE_OPENAI_DEPLOYMENT_NAME") ?? "gpt-4o-mini"; -var toolConnectionId = Environment.GetEnvironmentVariable("MCP_TOOL_CONNECTION_ID") ?? throw new InvalidOperationException("MCP_TOOL_CONNECTION_ID is not set."); +string openAiEndpoint = Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT") ?? throw new InvalidOperationException("AZURE_OPENAI_ENDPOINT is not set."); +string deploymentName = Environment.GetEnvironmentVariable("AZURE_OPENAI_DEPLOYMENT_NAME") ?? "gpt-4o-mini"; +string toolConnectionId = Environment.GetEnvironmentVariable("MCP_TOOL_CONNECTION_ID") ?? throw new InvalidOperationException("MCP_TOOL_CONNECTION_ID is not set."); -var credential = new AzureCliCredential(); +// WARNING: DefaultAzureCredential is convenient for development but requires careful consideration in production. +// In production, consider using a specific credential (e.g., ManagedIdentityCredential) to avoid +// latency issues, unintended credential probing, and potential security risks from fallback mechanisms. +DefaultAzureCredential credential = new(); -var chatClient = new AzureOpenAIClient(new Uri(openAiEndpoint), credential) +IChatClient chatClient = new AzureOpenAIClient(new Uri(openAiEndpoint), credential) .GetChatClient(deploymentName) .AsIChatClient() .AsBuilder() @@ -23,7 +26,7 @@ .UseOpenTelemetry(sourceName: "Agents", configure: (cfg) => cfg.EnableSensitiveData = true) .Build(); -var agent = new ChatClientAgent(chatClient, +AIAgent agent = chatClient.AsAIAgent( name: "AgentWithTools", instructions: @"You are a helpful assistant with access to tools for fetching Microsoft documentation. diff --git a/dotnet/samples/05-end-to-end/HostedAgents/AgentWithTools/README.md b/dotnet/samples/05-end-to-end/HostedAgents/AgentWithTools/README.md index 5a80ecda9f..55333f9940 100644 --- a/dotnet/samples/05-end-to-end/HostedAgents/AgentWithTools/README.md +++ b/dotnet/samples/05-end-to-end/HostedAgents/AgentWithTools/README.md @@ -6,7 +6,7 @@ Key features: - Configuring Foundry tools using `UseFoundryTools` with MCP and code interpreter - Connecting to an external MCP tool via a Foundry project connection -- Using `AzureCliCredential` for Azure authentication +- Using `DefaultAzureCredential` for Azure authentication - OpenTelemetry instrumentation for both the chat client and agent > For common prerequisites and setup instructions, see the [Hosted Agent Samples README](../README.md). @@ -36,7 +36,7 @@ $env:MCP_TOOL_CONNECTION_ID="SampleMCPTool" ## How It Works -1. An `AzureOpenAIClient` is created with `AzureCliCredential` and used to get a chat client +1. An `AzureOpenAIClient` is created with `DefaultAzureCredential` and used to get a chat client 2. The chat client is wrapped with `UseFoundryTools` which registers two Foundry tool types: - **MCP connection**: Connects to an external MCP server (Microsoft Learn) via the project connection name, providing documentation fetch and search capabilities - **Code interpreter**: Allows the agent to execute code snippets when needed diff --git a/dotnet/samples/05-end-to-end/HostedAgents/AgentsInWorkflows/AgentsInWorkflows.csproj b/dotnet/samples/05-end-to-end/HostedAgents/AgentsInWorkflows/AgentsInWorkflows.csproj index a434e07d33..56a55a428d 100644 --- a/dotnet/samples/05-end-to-end/HostedAgents/AgentsInWorkflows/AgentsInWorkflows.csproj +++ b/dotnet/samples/05-end-to-end/HostedAgents/AgentsInWorkflows/AgentsInWorkflows.csproj @@ -1,4 +1,4 @@ - + Exe @@ -35,11 +35,10 @@ - + - - + diff --git a/dotnet/samples/05-end-to-end/HostedAgents/AgentsInWorkflows/Program.cs b/dotnet/samples/05-end-to-end/HostedAgents/AgentsInWorkflows/Program.cs index bd37a8311f..f5ea72e7f7 100644 --- a/dotnet/samples/05-end-to-end/HostedAgents/AgentsInWorkflows/Program.cs +++ b/dotnet/samples/05-end-to-end/HostedAgents/AgentsInWorkflows/Program.cs @@ -12,8 +12,8 @@ using Microsoft.Extensions.AI; // Set up the Azure OpenAI client -var endpoint = Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT") ?? throw new InvalidOperationException("AZURE_OPENAI_ENDPOINT is not set."); -var deploymentName = Environment.GetEnvironmentVariable("AZURE_OPENAI_DEPLOYMENT_NAME") ?? "gpt-4o-mini"; +string endpoint = Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT") ?? throw new InvalidOperationException("AZURE_OPENAI_ENDPOINT is not set."); +string deploymentName = Environment.GetEnvironmentVariable("AZURE_OPENAI_DEPLOYMENT_NAME") ?? "gpt-4o-mini"; // WARNING: DefaultAzureCredential is convenient for development but requires careful consideration in production. // In production, consider using a specific credential (e.g., ManagedIdentityCredential) to avoid @@ -32,9 +32,9 @@ .AddEdge(frenchAgent, spanishAgent) .AddEdge(spanishAgent, englishAgent) .Build() - .AsAgent(); + .AsAIAgent(); await agent.RunAIAgentAsync(); -static ChatClientAgent GetTranslationAgent(string targetLanguage, IChatClient chatClient) => - new(chatClient, $"You are a translation assistant that translates the provided text to {targetLanguage}."); +static AIAgent GetTranslationAgent(string targetLanguage, IChatClient chatClient) => + chatClient.AsAIAgent($"You are a translation assistant that translates the provided text to {targetLanguage}."); diff --git a/dotnet/samples/05-end-to-end/HostedAgents/AgentsInWorkflows/README.md b/dotnet/samples/05-end-to-end/HostedAgents/AgentsInWorkflows/README.md index 72019bbf22..0f2f188f1b 100644 --- a/dotnet/samples/05-end-to-end/HostedAgents/AgentsInWorkflows/README.md +++ b/dotnet/samples/05-end-to-end/HostedAgents/AgentsInWorkflows/README.md @@ -19,7 +19,7 @@ Before you begin, ensure you have the following prerequisites: - Azure OpenAI 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 OpenAI resource. For more information, see the [Azure CLI documentation](https://learn.microsoft.com/cli/azure/authenticate-azure-cli-interactively). +**Note**: This demo uses `DefaultAzureCredential` for authentication, which probes multiple sources automatically. For local development, make sure you're logged in with `az login` and have access to the Azure OpenAI resource. For more information, see the [Azure CLI documentation](https://learn.microsoft.com/cli/azure/authenticate-azure-cli-interactively). Set the following environment variables: diff --git a/dotnet/samples/05-end-to-end/HostedAgents/README.md b/dotnet/samples/05-end-to-end/HostedAgents/README.md index f2d32f3c4d..a36a9bddd1 100644 --- a/dotnet/samples/05-end-to-end/HostedAgents/README.md +++ b/dotnet/samples/05-end-to-end/HostedAgents/README.md @@ -25,7 +25,7 @@ Before running any sample, ensure you have: ### Authenticate with Azure CLI -All samples use `AzureCliCredential` for authentication. Make sure you're logged in: +All samples use `DefaultAzureCredential` for authentication, which automatically probes multiple credential sources (environment variables, managed identity, Azure CLI, etc.). For local development, the simplest approach is to authenticate via Azure CLI: ```powershell az login