From d2faac50c6138e23cb96a12fec87ebd31aeceb0f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 30 Jan 2026 11:40:16 +0000 Subject: [PATCH 1/3] Initial plan From 7b01da929f8da7e2b9e040fe23e49add58c4a383 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 30 Jan 2026 11:55:39 +0000 Subject: [PATCH 2/3] Update Anthropic packages to v12.3.0 and Anthropic.Foundry to v0.4.1 Co-authored-by: rogerbarreto <19890735+rogerbarreto@users.noreply.github.com> --- dotnet/Directory.Packages.props | 6 +-- .../Agent_With_Anthropic/Program.cs | 53 ++----------------- .../Agent_Anthropic_Step01_Running/Program.cs | 2 +- .../Program.cs | 2 +- .../Program.cs | 2 +- .../05_MultiModelService/Program.cs | 2 +- .../AnthropicChatCompletionFixture.cs | 2 +- .../AnthropicBetaServiceExtensionsTests.cs | 15 +++--- .../AnthropicClientExtensionsTests.cs | 13 ++--- 9 files changed, 28 insertions(+), 69 deletions(-) diff --git a/dotnet/Directory.Packages.props b/dotnet/Directory.Packages.props index 00435037d1..98c7376aaf 100644 --- a/dotnet/Directory.Packages.props +++ b/dotnet/Directory.Packages.props @@ -11,8 +11,8 @@ - - + + @@ -42,7 +42,7 @@ - + diff --git a/dotnet/samples/GettingStarted/AgentProviders/Agent_With_Anthropic/Program.cs b/dotnet/samples/GettingStarted/AgentProviders/Agent_With_Anthropic/Program.cs index ad49c9229e..001425fe49 100644 --- a/dotnet/samples/GettingStarted/AgentProviders/Agent_With_Anthropic/Program.cs +++ b/dotnet/samples/GettingStarted/AgentProviders/Agent_With_Anthropic/Program.cs @@ -2,15 +2,12 @@ // This sample shows how to create and use an AI agent with Anthropic as the backend. -using System.Net.Http.Headers; using Anthropic; using Anthropic.Foundry; -using Azure.Core; using Azure.Identity; using Microsoft.Agents.AI; -using Sample; -var deploymentName = Environment.GetEnvironmentVariable("ANTHROPIC_DEPLOYMENT_NAME") ?? "claude-haiku-4-5"; +string deploymentName = Environment.GetEnvironmentVariable("ANTHROPIC_DEPLOYMENT_NAME") ?? "claude-haiku-4-5"; // The resource is the subdomain name / first name coming before '.services.ai.azure.com' in the endpoint Uri // ie: https://(resource name).services.ai.azure.com/anthropic/v1/chat/completions @@ -20,55 +17,13 @@ const string JokerInstructions = "You are good at telling jokes."; const string JokerName = "JokerAgent"; -AnthropicClient? client = (resource is null) - ? new AnthropicClient() { APIKey = apiKey ?? throw new InvalidOperationException("ANTHROPIC_API_KEY is required when no ANTHROPIC_RESOURCE is provided") } // If no resource is provided, use Anthropic public API +AnthropicClient client = (resource is null) + ? new AnthropicClient() { ApiKey = apiKey ?? throw new InvalidOperationException("ANTHROPIC_API_KEY is required when no ANTHROPIC_RESOURCE is provided") } // If no resource is provided, use Anthropic public API : (apiKey is not null) ? new AnthropicFoundryClient(new AnthropicFoundryApiKeyCredentials(apiKey, resource)) // If an apiKey is provided, use Foundry with ApiKey authentication - : new AnthropicFoundryClient(new AnthropicAzureTokenCredential(new AzureCliCredential(), resource)); // Otherwise, use Foundry with Azure Client authentication + : new AnthropicFoundryClient(new AnthropicFoundryIdentityTokenCredentials(new AzureCliCredential(), resource, ["https://ai.azure.com/.default"])); // Otherwise, use Foundry with Azure TokenCredential authentication AIAgent agent = client.AsAIAgent(model: deploymentName, instructions: JokerInstructions, name: JokerName); // Invoke the agent and output the text result. Console.WriteLine(await agent.RunAsync("Tell me a joke about a pirate.")); - -namespace Sample -{ - /// - /// Provides methods for invoking the Azure hosted Anthropic models using types. - /// - public sealed class AnthropicAzureTokenCredential : IAnthropicFoundryCredentials - { - private readonly TokenCredential _tokenCredential; - private readonly Lock _lock = new(); - private AccessToken? _cachedAccessToken; - - /// - public string ResourceName { get; } - - /// - /// Creates a new instance of the . - /// - /// The credential provider. Use any specialization of to get your access token in supported environments. - /// The service resource subdomain name to use in the anthropic azure endpoint - internal AnthropicAzureTokenCredential(TokenCredential tokenCredential, string resourceName) - { - this.ResourceName = resourceName ?? throw new ArgumentNullException(nameof(resourceName)); - this._tokenCredential = tokenCredential ?? throw new ArgumentNullException(nameof(tokenCredential)); - } - - /// - public void Apply(HttpRequestMessage requestMessage) - { - lock (this._lock) - { - // Add a 5-minute buffer to avoid using tokens that are about to expire - if (this._cachedAccessToken is null || this._cachedAccessToken.Value.ExpiresOn <= DateTimeOffset.Now.AddMinutes(5)) - { - this._cachedAccessToken = this._tokenCredential.GetToken(new TokenRequestContext(scopes: ["https://ai.azure.com/.default"]), CancellationToken.None); - } - } - - requestMessage.Headers.Authorization = new AuthenticationHeaderValue("bearer", this._cachedAccessToken.Value.Token); - } - } -} diff --git a/dotnet/samples/GettingStarted/AgentWithAnthropic/Agent_Anthropic_Step01_Running/Program.cs b/dotnet/samples/GettingStarted/AgentWithAnthropic/Agent_Anthropic_Step01_Running/Program.cs index 085fbfd989..7aee814c0c 100644 --- a/dotnet/samples/GettingStarted/AgentWithAnthropic/Agent_Anthropic_Step01_Running/Program.cs +++ b/dotnet/samples/GettingStarted/AgentWithAnthropic/Agent_Anthropic_Step01_Running/Program.cs @@ -10,7 +10,7 @@ var apiKey = Environment.GetEnvironmentVariable("ANTHROPIC_API_KEY") ?? throw new InvalidOperationException("ANTHROPIC_API_KEY is not set."); var model = Environment.GetEnvironmentVariable("ANTHROPIC_MODEL") ?? "claude-haiku-4-5"; -AIAgent agent = new AnthropicClient(new ClientOptions { APIKey = apiKey }) +AIAgent agent = new AnthropicClient(new ClientOptions { ApiKey = apiKey }) .AsAIAgent(model: model, instructions: "You are good at telling jokes.", name: "Joker"); // Invoke the agent and output the text result. diff --git a/dotnet/samples/GettingStarted/AgentWithAnthropic/Agent_Anthropic_Step02_Reasoning/Program.cs b/dotnet/samples/GettingStarted/AgentWithAnthropic/Agent_Anthropic_Step02_Reasoning/Program.cs index 120402ee14..78633cb7a8 100644 --- a/dotnet/samples/GettingStarted/AgentWithAnthropic/Agent_Anthropic_Step02_Reasoning/Program.cs +++ b/dotnet/samples/GettingStarted/AgentWithAnthropic/Agent_Anthropic_Step02_Reasoning/Program.cs @@ -13,7 +13,7 @@ var maxTokens = 4096; var thinkingTokens = 2048; -var agent = new AnthropicClient(new ClientOptions { APIKey = apiKey }) +var agent = new AnthropicClient(new ClientOptions { ApiKey = apiKey }) .AsAIAgent( model: model, clientFactory: (chatClient) => chatClient diff --git a/dotnet/samples/GettingStarted/AgentWithAnthropic/Agent_Anthropic_Step03_UsingFunctionTools/Program.cs b/dotnet/samples/GettingStarted/AgentWithAnthropic/Agent_Anthropic_Step03_UsingFunctionTools/Program.cs index f9634d9212..6c32741c94 100644 --- a/dotnet/samples/GettingStarted/AgentWithAnthropic/Agent_Anthropic_Step03_UsingFunctionTools/Program.cs +++ b/dotnet/samples/GettingStarted/AgentWithAnthropic/Agent_Anthropic_Step03_UsingFunctionTools/Program.cs @@ -22,7 +22,7 @@ static string GetWeather([Description("The location to get the weather for.")] s AITool tool = AIFunctionFactory.Create(GetWeather); // Get anthropic client to create agents. -AIAgent agent = new AnthropicClient { APIKey = apiKey } +AIAgent agent = new AnthropicClient { ApiKey = apiKey } .AsAIAgent(model: model, instructions: AssistantInstructions, name: AssistantName, tools: [tool]); // Non-streaming agent interaction with function tools. diff --git a/dotnet/samples/GettingStarted/Workflows/_Foundational/05_MultiModelService/Program.cs b/dotnet/samples/GettingStarted/Workflows/_Foundational/05_MultiModelService/Program.cs index 7d81d891f7..9eca1e3e4e 100644 --- a/dotnet/samples/GettingStarted/Workflows/_Foundational/05_MultiModelService/Program.cs +++ b/dotnet/samples/GettingStarted/Workflows/_Foundational/05_MultiModelService/Program.cs @@ -16,7 +16,7 @@ .AsIChatClient("amazon.nova-pro-v1:0"); IChatClient anthropic = new Anthropic.AnthropicClient( - new() { APIKey = Environment.GetEnvironmentVariable("ANTHROPIC_APIKEY") }) + new() { ApiKey = Environment.GetEnvironmentVariable("ANTHROPIC_APIKEY") }) .AsIChatClient("claude-sonnet-4-20250514"); IChatClient openai = new OpenAI.OpenAIClient( diff --git a/dotnet/tests/AnthropicChatCompletion.IntegrationTests/AnthropicChatCompletionFixture.cs b/dotnet/tests/AnthropicChatCompletion.IntegrationTests/AnthropicChatCompletionFixture.cs index 555576df9d..5f0fcbca2c 100644 --- a/dotnet/tests/AnthropicChatCompletion.IntegrationTests/AnthropicChatCompletionFixture.cs +++ b/dotnet/tests/AnthropicChatCompletion.IntegrationTests/AnthropicChatCompletionFixture.cs @@ -52,7 +52,7 @@ public Task CreateChatClientAgentAsync( string instructions = "You are a helpful assistant.", IList? aiTools = null) { - var anthropicClient = new AnthropicClient() { APIKey = s_config.ApiKey }; + var anthropicClient = new AnthropicClient() { ApiKey = s_config.ApiKey }; IChatClient? chatClient = this._useBeta ? anthropicClient diff --git a/dotnet/tests/Microsoft.Agents.AI.Anthropic.UnitTests/Extensions/AnthropicBetaServiceExtensionsTests.cs b/dotnet/tests/Microsoft.Agents.AI.Anthropic.UnitTests/Extensions/AnthropicBetaServiceExtensionsTests.cs index c26be5822c..738475da03 100644 --- a/dotnet/tests/Microsoft.Agents.AI.Anthropic.UnitTests/Extensions/AnthropicBetaServiceExtensionsTests.cs +++ b/dotnet/tests/Microsoft.Agents.AI.Anthropic.UnitTests/Extensions/AnthropicBetaServiceExtensionsTests.cs @@ -242,7 +242,7 @@ public async Task CreateAIAgent_WithExplicitMaxTokens_UsesProvidedValueAsync() var client = new AnthropicClient { HttpClient = new HttpClient(handler) { BaseAddress = new Uri("http://localhost") }, - APIKey = "test-key" + ApiKey = "test-key" }; // Act @@ -436,13 +436,15 @@ public TestAnthropicChatClient() } public HttpClient HttpClient { get => throw new NotImplementedException(); init => throw new NotImplementedException(); } - public Uri BaseUrl { get => new("http://localhost"); init => throw new NotImplementedException(); } + public string BaseUrl { get => "http://localhost"; init => throw new NotImplementedException(); } public bool ResponseValidation { get => throw new NotImplementedException(); init => throw new NotImplementedException(); } public int? MaxRetries { get => throw new NotImplementedException(); init => throw new NotImplementedException(); } public TimeSpan? Timeout { get => throw new NotImplementedException(); init => throw new NotImplementedException(); } - public string? APIKey { get => throw new NotImplementedException(); init => throw new NotImplementedException(); } + public string? ApiKey { get => throw new NotImplementedException(); init => throw new NotImplementedException(); } public string? AuthToken { get => throw new NotImplementedException(); init => throw new NotImplementedException(); } + public IAnthropicClientWithRawResponse WithRawResponse => throw new NotImplementedException(); + public IMessageService Messages => throw new NotImplementedException(); public IModelService Models => throw new NotImplementedException(); @@ -453,14 +455,13 @@ public TestAnthropicChatClient() IMessageService IAnthropicClient.Messages => new Mock().Object; - public Task Execute(HttpRequest request, CancellationToken cancellationToken = default) where T : ParamsBase + public IAnthropicClient WithOptions(Func modifier) { throw new NotImplementedException(); } - public IAnthropicClient WithOptions(Func modifier) + public void Dispose() { - throw new NotImplementedException(); } private sealed class TestBetaService : IBetaService @@ -472,6 +473,8 @@ public TestBetaService(IAnthropicClient client) this._client = client; } + public IBetaServiceWithRawResponse WithRawResponse => throw new NotImplementedException(); + public global::Anthropic.Services.Beta.IModelService Models => throw new NotImplementedException(); public global::Anthropic.Services.Beta.IFileService Files => throw new NotImplementedException(); diff --git a/dotnet/tests/Microsoft.Agents.AI.Anthropic.UnitTests/Extensions/AnthropicClientExtensionsTests.cs b/dotnet/tests/Microsoft.Agents.AI.Anthropic.UnitTests/Extensions/AnthropicClientExtensionsTests.cs index 4a61a699fc..33cd212928 100644 --- a/dotnet/tests/Microsoft.Agents.AI.Anthropic.UnitTests/Extensions/AnthropicClientExtensionsTests.cs +++ b/dotnet/tests/Microsoft.Agents.AI.Anthropic.UnitTests/Extensions/AnthropicClientExtensionsTests.cs @@ -66,27 +66,28 @@ public TestAnthropicChatClient() } public HttpClient HttpClient { get => throw new NotImplementedException(); init => throw new NotImplementedException(); } - public Uri BaseUrl { get => new("http://localhost"); init => throw new NotImplementedException(); } + public string BaseUrl { get => "http://localhost"; init => throw new NotImplementedException(); } public bool ResponseValidation { get => throw new NotImplementedException(); init => throw new NotImplementedException(); } public int? MaxRetries { get => throw new NotImplementedException(); init => throw new NotImplementedException(); } public TimeSpan? Timeout { get => throw new NotImplementedException(); init => throw new NotImplementedException(); } - public string? APIKey { get => throw new NotImplementedException(); init => throw new NotImplementedException(); } + public string? ApiKey { get => throw new NotImplementedException(); init => throw new NotImplementedException(); } public string? AuthToken { get => throw new NotImplementedException(); init => throw new NotImplementedException(); } + public IAnthropicClientWithRawResponse WithRawResponse => throw new NotImplementedException(); + public IMessageService Messages => throw new NotImplementedException(); public IModelService Models => throw new NotImplementedException(); public IBetaService Beta => throw new NotImplementedException(); - public Task Execute(HttpRequest request, CancellationToken cancellationToken = default) where T : ParamsBase + public IAnthropicClient WithOptions(Func modifier) { throw new NotImplementedException(); } - public IAnthropicClient WithOptions(Func modifier) + public void Dispose() { - throw new NotImplementedException(); } } @@ -309,7 +310,7 @@ public async Task CreateAIAgent_WithExplicitMaxTokens_UsesProvidedValueAsync() var client = new AnthropicClient { HttpClient = new HttpClient(handler) { BaseAddress = new Uri("http://localhost") }, - APIKey = "test-key" + ApiKey = "test-key" }; // Act From 110c4205366a4ff072b92b74a560e4bfe39685ec Mon Sep 17 00:00:00 2001 From: Roger Barreto <19890735+rogerbarreto@users.noreply.github.com> Date: Fri, 30 Jan 2026 13:41:01 +0000 Subject: [PATCH 3/3] Fix AnthropicClient not being disposed in sample --- .../AgentProviders/Agent_With_Anthropic/Program.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dotnet/samples/GettingStarted/AgentProviders/Agent_With_Anthropic/Program.cs b/dotnet/samples/GettingStarted/AgentProviders/Agent_With_Anthropic/Program.cs index 001425fe49..b281274051 100644 --- a/dotnet/samples/GettingStarted/AgentProviders/Agent_With_Anthropic/Program.cs +++ b/dotnet/samples/GettingStarted/AgentProviders/Agent_With_Anthropic/Program.cs @@ -17,7 +17,7 @@ const string JokerInstructions = "You are good at telling jokes."; const string JokerName = "JokerAgent"; -AnthropicClient client = (resource is null) +using AnthropicClient client = (resource is null) ? new AnthropicClient() { ApiKey = apiKey ?? throw new InvalidOperationException("ANTHROPIC_API_KEY is required when no ANTHROPIC_RESOURCE is provided") } // If no resource is provided, use Anthropic public API : (apiKey is not null) ? new AnthropicFoundryClient(new AnthropicFoundryApiKeyCredentials(apiKey, resource)) // If an apiKey is provided, use Foundry with ApiKey authentication