Skip to content

Commit cec8bd3

Browse files
.NET: Improve unit test coverage for Microsoft.Agents.AI.Anthropic (#3382)
* Initial plan * Add unit tests to improve coverage for Microsoft.Agents.AI.Anthropic Co-authored-by: rogerbarreto <19890735+rogerbarreto@users.noreply.github.com> * Update instruction verification tests to check agent.Instructions property Co-authored-by: rogerbarreto <19890735+rogerbarreto@users.noreply.github.com> * Update unit tests with proper assertions for agent scenarios Co-authored-by: rogerbarreto <19890735+rogerbarreto@users.noreply.github.com> * Add assertions for tools and maxTokens in Anthropic extension tests * Add proper assertions for tools and maxTokens in Anthropic tests --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: rogerbarreto <19890735+rogerbarreto@users.noreply.github.com>
1 parent 12f7e71 commit cec8bd3

File tree

2 files changed

+398
-0
lines changed

2 files changed

+398
-0
lines changed

dotnet/tests/Microsoft.Agents.AI.Anthropic.UnitTests/Extensions/AnthropicBetaServiceExtensionsTests.cs

Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,205 @@ public void CreateAIAgent_WithNullOptions_ThrowsArgumentNullException()
188188
Assert.Equal("options", exception.ParamName);
189189
}
190190

191+
/// <summary>
192+
/// Verify that CreateAIAgent with tools correctly assigns tools to ChatOptions.
193+
/// </summary>
194+
[Fact]
195+
public void CreateAIAgent_WithTools_AssignsToolsCorrectly()
196+
{
197+
// Arrange
198+
var chatClient = new TestAnthropicChatClient();
199+
IList<AITool> tools = [AIFunctionFactory.Create(() => "test result", "TestFunction", "A test function")];
200+
201+
// Act
202+
var agent = chatClient.Beta.AsAIAgent(
203+
model: "test-model",
204+
name: "Test Agent",
205+
tools: tools);
206+
207+
// Assert
208+
Assert.NotNull(agent);
209+
Assert.Equal("Test Agent", agent.Name);
210+
// When tools are provided, ChatOptions is created but instructions remain null
211+
Assert.Null(agent.Instructions);
212+
213+
// Verify that tools are registered in the FunctionInvokingChatClient
214+
var functionInvokingClient = agent.GetService<FunctionInvokingChatClient>();
215+
Assert.NotNull(functionInvokingClient);
216+
Assert.NotNull(functionInvokingClient.AdditionalTools);
217+
Assert.Contains(functionInvokingClient.AdditionalTools, t => t is AIFunction func && func.Name == "TestFunction");
218+
}
219+
220+
/// <summary>
221+
/// Verify that CreateAIAgent with explicit defaultMaxTokens uses the provided value.
222+
/// </summary>
223+
[Fact]
224+
public async Task CreateAIAgent_WithExplicitMaxTokens_UsesProvidedValueAsync()
225+
{
226+
// Arrange
227+
int capturedMaxTokens = 0;
228+
var handler = new CapturingHttpHandler(request =>
229+
{
230+
// Parse the request body to capture max_tokens
231+
var content = request.Content?.ReadAsStringAsync().GetAwaiter().GetResult();
232+
if (content is not null)
233+
{
234+
var json = System.Text.Json.JsonDocument.Parse(content);
235+
if (json.RootElement.TryGetProperty("max_tokens", out var maxTokens))
236+
{
237+
capturedMaxTokens = maxTokens.GetInt32();
238+
}
239+
}
240+
});
241+
242+
var client = new AnthropicClient
243+
{
244+
HttpClient = new HttpClient(handler) { BaseAddress = new Uri("http://localhost") },
245+
APIKey = "test-key"
246+
};
247+
248+
// Act
249+
var agent = client.Beta.AsAIAgent(
250+
model: "claude-haiku-4-5",
251+
name: "Test Agent",
252+
defaultMaxTokens: 8192);
253+
254+
// Invoke the agent to trigger the request
255+
var thread = await agent.GetNewThreadAsync();
256+
try
257+
{
258+
await agent.RunAsync("Test message", thread);
259+
}
260+
catch
261+
{
262+
// Expected to fail since we're using a test handler
263+
}
264+
265+
// Assert
266+
Assert.Equal(8192, capturedMaxTokens);
267+
}
268+
269+
/// <summary>
270+
/// HTTP handler that captures requests for verification.
271+
/// </summary>
272+
private sealed class CapturingHttpHandler : HttpMessageHandler
273+
{
274+
private readonly Action<HttpRequestMessage> _captureRequest;
275+
276+
public CapturingHttpHandler(Action<HttpRequestMessage> captureRequest)
277+
{
278+
this._captureRequest = captureRequest;
279+
}
280+
281+
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
282+
{
283+
this._captureRequest(request);
284+
return Task.FromResult(new HttpResponseMessage(System.Net.HttpStatusCode.BadRequest)
285+
{
286+
Content = new StringContent("{\"error\": \"test\"}")
287+
});
288+
}
289+
}
290+
291+
/// <summary>
292+
/// Verify that CreateAIAgent with tools and instructions correctly assigns both.
293+
/// </summary>
294+
[Fact]
295+
public void CreateAIAgent_WithToolsAndInstructions_AssignsBothCorrectly()
296+
{
297+
// Arrange
298+
var chatClient = new TestAnthropicChatClient();
299+
IList<AITool> tools = [AIFunctionFactory.Create(() => "test result", "TestFunction", "A test function")];
300+
301+
// Act
302+
var agent = chatClient.Beta.AsAIAgent(
303+
model: "test-model",
304+
name: "Test Agent",
305+
instructions: "Test instructions",
306+
tools: tools);
307+
308+
// Assert
309+
Assert.NotNull(agent);
310+
Assert.Equal("Test Agent", agent.Name);
311+
Assert.Equal("Test instructions", agent.Instructions);
312+
313+
// Verify that tools are registered in the FunctionInvokingChatClient
314+
var functionInvokingClient = agent.GetService<FunctionInvokingChatClient>();
315+
Assert.NotNull(functionInvokingClient);
316+
Assert.NotNull(functionInvokingClient.AdditionalTools);
317+
Assert.Contains(functionInvokingClient.AdditionalTools, t => t is AIFunction func && func.Name == "TestFunction");
318+
}
319+
320+
/// <summary>
321+
/// Verify that CreateAIAgent with empty tools list does not assign tools.
322+
/// </summary>
323+
[Fact]
324+
public void CreateAIAgent_WithEmptyTools_DoesNotAssignTools()
325+
{
326+
// Arrange
327+
var chatClient = new TestAnthropicChatClient();
328+
IList<AITool> tools = [];
329+
330+
// Act
331+
var agent = chatClient.Beta.AsAIAgent(
332+
model: "test-model",
333+
name: "Test Agent",
334+
tools: tools);
335+
336+
// Assert
337+
Assert.NotNull(agent);
338+
Assert.Equal("Test Agent", agent.Name);
339+
// With empty tools and no instructions, agent instructions remain null
340+
Assert.Null(agent.Instructions);
341+
342+
// Verify that FunctionInvokingChatClient has no additional tools assigned
343+
var functionInvokingClient = agent.GetService<FunctionInvokingChatClient>();
344+
Assert.NotNull(functionInvokingClient);
345+
Assert.True(functionInvokingClient.AdditionalTools is null or { Count: 0 });
346+
}
347+
348+
/// <summary>
349+
/// Verify that CreateAIAgent with null instructions does not set instructions.
350+
/// </summary>
351+
[Fact]
352+
public void CreateAIAgent_WithNullInstructions_DoesNotSetInstructions()
353+
{
354+
// Arrange
355+
var chatClient = new TestAnthropicChatClient();
356+
357+
// Act
358+
var agent = chatClient.Beta.AsAIAgent(
359+
model: "test-model",
360+
name: "Test Agent",
361+
instructions: null);
362+
363+
// Assert
364+
Assert.NotNull(agent);
365+
Assert.Equal("Test Agent", agent.Name);
366+
Assert.Null(agent.Instructions);
367+
}
368+
369+
/// <summary>
370+
/// Verify that CreateAIAgent with whitespace instructions does not set instructions.
371+
/// </summary>
372+
[Fact]
373+
public void CreateAIAgent_WithWhitespaceInstructions_DoesNotSetInstructions()
374+
{
375+
// Arrange
376+
var chatClient = new TestAnthropicChatClient();
377+
378+
// Act
379+
var agent = chatClient.Beta.AsAIAgent(
380+
model: "test-model",
381+
name: "Test Agent",
382+
instructions: " ");
383+
384+
// Assert
385+
Assert.NotNull(agent);
386+
Assert.Equal("Test Agent", agent.Name);
387+
Assert.Null(agent.Instructions);
388+
}
389+
191390
/// <summary>
192391
/// Test custom chat client that can be used to verify clientFactory functionality.
193392
/// </summary>

0 commit comments

Comments
 (0)