From c0821ab7d4d471859c1fb689faa4e88169c0a58d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 22 Jan 2026 00:03:05 +0000 Subject: [PATCH 1/6] Initial plan From 993d3b15021fb3580c62f2801b5fdbccc34e52ee Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 22 Jan 2026 00:13:19 +0000 Subject: [PATCH 2/6] Add unit tests for Microsoft.Agents.AI.OpenAI to improve code coverage Co-authored-by: rogerbarreto <19890735+rogerbarreto@users.noreply.github.com> --- .../Microsoft.Agents.AI.OpenAI.csproj | 4 + ...atCompletionUpdateCollectionResultTests.cs | 110 +++++ ...mingResponseUpdateCollectionResultTests.cs | 191 +++++++++ .../StreamingUpdatePipelineResponseTests.cs | 154 +++++++ .../AIAgentWithOpenAIExtensionsTests.cs | 167 ++++++++ .../AgentResponseExtensionsTests.cs | 145 +++++++ .../OpenAIAssistantClientExtensionsTests.cs | 382 ++++++++++++++++++ 7 files changed, 1153 insertions(+) create mode 100644 dotnet/tests/Microsoft.Agents.AI.OpenAI.UnitTests/ChatClient/AsyncStreamingChatCompletionUpdateCollectionResultTests.cs create mode 100644 dotnet/tests/Microsoft.Agents.AI.OpenAI.UnitTests/ChatClient/AsyncStreamingResponseUpdateCollectionResultTests.cs create mode 100644 dotnet/tests/Microsoft.Agents.AI.OpenAI.UnitTests/ChatClient/StreamingUpdatePipelineResponseTests.cs create mode 100644 dotnet/tests/Microsoft.Agents.AI.OpenAI.UnitTests/Extensions/AgentResponseExtensionsTests.cs diff --git a/dotnet/src/Microsoft.Agents.AI.OpenAI/Microsoft.Agents.AI.OpenAI.csproj b/dotnet/src/Microsoft.Agents.AI.OpenAI/Microsoft.Agents.AI.OpenAI.csproj index bfcf6e5263..3de68137ba 100644 --- a/dotnet/src/Microsoft.Agents.AI.OpenAI/Microsoft.Agents.AI.OpenAI.csproj +++ b/dotnet/src/Microsoft.Agents.AI.OpenAI/Microsoft.Agents.AI.OpenAI.csproj @@ -17,6 +17,10 @@ + + + + Microsoft Agent Framework OpenAI diff --git a/dotnet/tests/Microsoft.Agents.AI.OpenAI.UnitTests/ChatClient/AsyncStreamingChatCompletionUpdateCollectionResultTests.cs b/dotnet/tests/Microsoft.Agents.AI.OpenAI.UnitTests/ChatClient/AsyncStreamingChatCompletionUpdateCollectionResultTests.cs new file mode 100644 index 0000000000..d682d7e53b --- /dev/null +++ b/dotnet/tests/Microsoft.Agents.AI.OpenAI.UnitTests/ChatClient/AsyncStreamingChatCompletionUpdateCollectionResultTests.cs @@ -0,0 +1,110 @@ +// Copyright (c) Microsoft. All rights reserved. + +using System.ClientModel; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.Extensions.AI; +using OpenAI.Chat; + +namespace Microsoft.Agents.AI.OpenAI.UnitTests.ChatClient; + +/// +/// Unit tests for the class. +/// +public sealed class AsyncStreamingChatCompletionUpdateCollectionResultTests +{ + /// + /// Verify that GetContinuationToken returns null. + /// + [Fact] + public void GetContinuationToken_ReturnsNull() + { + // Arrange + IAsyncEnumerable updates = CreateTestUpdatesAsync(); + AsyncCollectionResult collectionResult = new AsyncStreamingChatCompletionUpdateCollectionResult(updates); + + // Act + ContinuationToken? token = collectionResult.GetContinuationToken(null!); + + // Assert + Assert.Null(token); + } + + /// + /// Verify that GetRawPagesAsync returns a single page. + /// + [Fact] + public async Task GetRawPagesAsync_ReturnsSinglePageAsync() + { + // Arrange + IAsyncEnumerable updates = CreateTestUpdatesAsync(); + AsyncCollectionResult collectionResult = new AsyncStreamingChatCompletionUpdateCollectionResult(updates); + + // Act + List pages = []; + await foreach (ClientResult page in collectionResult.GetRawPagesAsync()) + { + pages.Add(page); + } + + // Assert + Assert.Single(pages); + } + + /// + /// Verify that iterating through the collection yields streaming updates. + /// + [Fact] + public async Task IterateCollection_YieldsUpdatesAsync() + { + // Arrange + IAsyncEnumerable updates = CreateTestUpdatesAsync(); + AsyncCollectionResult collectionResult = new AsyncStreamingChatCompletionUpdateCollectionResult(updates); + + // Act + List results = []; + await foreach (StreamingChatCompletionUpdate update in collectionResult) + { + results.Add(update); + } + + // Assert + Assert.Single(results); + } + + /// + /// Verify that iterating through the collection with multiple updates yields all updates. + /// + [Fact] + public async Task IterateCollection_WithMultipleUpdates_YieldsAllUpdatesAsync() + { + // Arrange + IAsyncEnumerable updates = CreateMultipleTestUpdatesAsync(); + AsyncCollectionResult collectionResult = new AsyncStreamingChatCompletionUpdateCollectionResult(updates); + + // Act + List results = []; + await foreach (StreamingChatCompletionUpdate update in collectionResult) + { + results.Add(update); + } + + // Assert + Assert.Equal(3, results.Count); + } + + private static async IAsyncEnumerable CreateTestUpdatesAsync() + { + yield return new AgentResponseUpdate(ChatRole.Assistant, "test"); + await Task.CompletedTask; + } + + private static async IAsyncEnumerable CreateMultipleTestUpdatesAsync() + { + yield return new AgentResponseUpdate(ChatRole.Assistant, "first"); + yield return new AgentResponseUpdate(ChatRole.Assistant, "second"); + yield return new AgentResponseUpdate(ChatRole.Assistant, "third"); + await Task.CompletedTask; + } +} diff --git a/dotnet/tests/Microsoft.Agents.AI.OpenAI.UnitTests/ChatClient/AsyncStreamingResponseUpdateCollectionResultTests.cs b/dotnet/tests/Microsoft.Agents.AI.OpenAI.UnitTests/ChatClient/AsyncStreamingResponseUpdateCollectionResultTests.cs new file mode 100644 index 0000000000..6cb6216f5d --- /dev/null +++ b/dotnet/tests/Microsoft.Agents.AI.OpenAI.UnitTests/ChatClient/AsyncStreamingResponseUpdateCollectionResultTests.cs @@ -0,0 +1,191 @@ +// Copyright (c) Microsoft. All rights reserved. + +using System; +using System.ClientModel; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.Extensions.AI; +using OpenAI.Responses; + +namespace Microsoft.Agents.AI.OpenAI.UnitTests.ChatClient; + +/// +/// Unit tests for the class. +/// +public sealed class AsyncStreamingResponseUpdateCollectionResultTests +{ + /// + /// Verify that GetContinuationToken returns null. + /// + [Fact] + public void GetContinuationToken_ReturnsNull() + { + // Arrange + IAsyncEnumerable updates = CreateTestUpdatesAsync(); + AsyncCollectionResult collectionResult = new AsyncStreamingResponseUpdateCollectionResult(updates); + + // Act + ContinuationToken? token = collectionResult.GetContinuationToken(null!); + + // Assert + Assert.Null(token); + } + + /// + /// Verify that GetRawPagesAsync returns a single page. + /// + [Fact] + public async Task GetRawPagesAsync_ReturnsSinglePageAsync() + { + // Arrange + IAsyncEnumerable updates = CreateTestUpdatesAsync(); + AsyncCollectionResult collectionResult = new AsyncStreamingResponseUpdateCollectionResult(updates); + + // Act + List pages = []; + await foreach (ClientResult page in collectionResult.GetRawPagesAsync()) + { + pages.Add(page); + } + + // Assert + Assert.Single(pages); + } + + /// + /// Verify that iterating through the collection yields streaming updates when RawRepresentation is a StreamingResponseUpdate. + /// + [Fact] + public async Task IterateCollection_WithStreamingResponseUpdateRawRepresentation_YieldsUpdatesAsync() + { + // Arrange + StreamingResponseUpdate rawUpdate = CreateStreamingResponseUpdate(); + IAsyncEnumerable updates = CreateTestUpdatesWithRawRepresentationAsync(rawUpdate); + AsyncCollectionResult collectionResult = new AsyncStreamingResponseUpdateCollectionResult(updates); + + // Act + List results = []; + await foreach (StreamingResponseUpdate update in collectionResult) + { + results.Add(update); + } + + // Assert + Assert.Single(results); + Assert.Same(rawUpdate, results[0]); + } + + /// + /// Verify that iterating through the collection yields updates when RawRepresentation is a ChatResponseUpdate containing a StreamingResponseUpdate. + /// + [Fact] + public async Task IterateCollection_WithChatResponseUpdateContainingStreamingResponseUpdate_YieldsUpdatesAsync() + { + // Arrange + StreamingResponseUpdate rawUpdate = CreateStreamingResponseUpdate(); + ChatResponseUpdate chatResponseUpdate = new() { RawRepresentation = rawUpdate }; + IAsyncEnumerable updates = CreateTestUpdatesWithChatResponseUpdateAsync(chatResponseUpdate); + AsyncCollectionResult collectionResult = new AsyncStreamingResponseUpdateCollectionResult(updates); + + // Act + List results = []; + await foreach (StreamingResponseUpdate update in collectionResult) + { + results.Add(update); + } + + // Assert + Assert.Single(results); + Assert.Same(rawUpdate, results[0]); + } + + /// + /// Verify that iterating through the collection skips updates when RawRepresentation is not a StreamingResponseUpdate. + /// + [Fact] + public async Task IterateCollection_WithNonStreamingResponseUpdateRawRepresentation_SkipsUpdateAsync() + { + // Arrange + IAsyncEnumerable updates = CreateTestUpdatesAsync(); + AsyncCollectionResult collectionResult = new AsyncStreamingResponseUpdateCollectionResult(updates); + + // Act + List results = []; + await foreach (StreamingResponseUpdate update in collectionResult) + { + results.Add(update); + } + + // Assert - should be empty since updates don't have StreamingResponseUpdate as RawRepresentation + Assert.Empty(results); + } + + /// + /// Verify that iterating through the collection skips updates when RawRepresentation is a ChatResponseUpdate without StreamingResponseUpdate. + /// + [Fact] + public async Task IterateCollection_WithChatResponseUpdateWithoutStreamingResponseUpdate_SkipsUpdateAsync() + { + // Arrange + ChatResponseUpdate chatResponseUpdate = new() { RawRepresentation = "not a streaming update" }; + IAsyncEnumerable updates = CreateTestUpdatesWithChatResponseUpdateAsync(chatResponseUpdate); + AsyncCollectionResult collectionResult = new AsyncStreamingResponseUpdateCollectionResult(updates); + + // Act + List results = []; + await foreach (StreamingResponseUpdate update in collectionResult) + { + results.Add(update); + } + + // Assert - should be empty since the ChatResponseUpdate doesn't have StreamingResponseUpdate as RawRepresentation + Assert.Empty(results); + } + + private static async IAsyncEnumerable CreateTestUpdatesAsync() + { + yield return new AgentResponseUpdate(ChatRole.Assistant, "test"); + await Task.CompletedTask; + } + + private static async IAsyncEnumerable CreateTestUpdatesWithRawRepresentationAsync(object rawRepresentation) + { + AgentResponseUpdate update = new(ChatRole.Assistant, "test") + { + RawRepresentation = rawRepresentation + }; + yield return update; + await Task.CompletedTask; + } + + private static async IAsyncEnumerable CreateTestUpdatesWithChatResponseUpdateAsync(ChatResponseUpdate chatResponseUpdate) + { + AgentResponseUpdate update = new(ChatRole.Assistant, "test") + { + RawRepresentation = chatResponseUpdate + }; + yield return update; + await Task.CompletedTask; + } + + private static StreamingResponseUpdate CreateStreamingResponseUpdate() + { + const string Json = """ + { + "type": "response.output_item.added", + "sequence_number": 1, + "output_index": 0, + "item": { + "id": "item_abc123", + "type": "message", + "status": "in_progress", + "role": "assistant", + "content": [] + } + } + """; + + return System.ClientModel.Primitives.ModelReaderWriter.Read(BinaryData.FromString(Json))!; + } +} diff --git a/dotnet/tests/Microsoft.Agents.AI.OpenAI.UnitTests/ChatClient/StreamingUpdatePipelineResponseTests.cs b/dotnet/tests/Microsoft.Agents.AI.OpenAI.UnitTests/ChatClient/StreamingUpdatePipelineResponseTests.cs new file mode 100644 index 0000000000..19fb034bbd --- /dev/null +++ b/dotnet/tests/Microsoft.Agents.AI.OpenAI.UnitTests/ChatClient/StreamingUpdatePipelineResponseTests.cs @@ -0,0 +1,154 @@ +// Copyright (c) Microsoft. All rights reserved. + +using System; +using System.ClientModel.Primitives; +using System.Collections.Generic; +using System.Threading; + +namespace Microsoft.Agents.AI.OpenAI.UnitTests.ChatClient; + +/// +/// Unit tests for the class. +/// +public sealed class StreamingUpdatePipelineResponseTests +{ + /// + /// Verify that Status property returns 200. + /// + [Fact] + public void Status_ReturnsOkStatus() + { + // Arrange + IAsyncEnumerable updates = CreateTestUpdatesAsync(); + PipelineResponse response = new StreamingUpdatePipelineResponse(updates); + + // Act + int status = response.Status; + + // Assert + Assert.Equal(200, status); + } + + /// + /// Verify that ReasonPhrase property returns "OK". + /// + [Fact] + public void ReasonPhrase_ReturnsOk() + { + // Arrange + IAsyncEnumerable updates = CreateTestUpdatesAsync(); + PipelineResponse response = new StreamingUpdatePipelineResponse(updates); + + // Act + string reasonPhrase = response.ReasonPhrase; + + // Assert + Assert.Equal("OK", reasonPhrase); + } + + /// + /// Verify that ContentStream getter returns null. + /// + [Fact] + public void ContentStream_Get_ReturnsNull() + { + // Arrange + IAsyncEnumerable updates = CreateTestUpdatesAsync(); + PipelineResponse response = new StreamingUpdatePipelineResponse(updates); + + // Act + System.IO.Stream? contentStream = response.ContentStream; + + // Assert + Assert.Null(contentStream); + } + + /// + /// Verify that ContentStream setter is a no-op. + /// + [Fact] + public void ContentStream_Set_IsNoOp() + { + // Arrange + IAsyncEnumerable updates = CreateTestUpdatesAsync(); + PipelineResponse response = new StreamingUpdatePipelineResponse(updates); + var testStream = new System.IO.MemoryStream(); + + // Act + response.ContentStream = testStream; + + // Assert - should remain null + Assert.Null(response.ContentStream); + + testStream.Dispose(); + } + + /// + /// Verify that Content property returns empty BinaryData. + /// + [Fact] + public void Content_ReturnsEmptyBinaryData() + { + // Arrange + IAsyncEnumerable updates = CreateTestUpdatesAsync(); + PipelineResponse response = new StreamingUpdatePipelineResponse(updates); + + // Act + BinaryData content = response.Content; + + // Assert + Assert.NotNull(content); + Assert.Equal(string.Empty, content.ToString()); + } + + /// + /// Verify that BufferContent throws NotSupportedException. + /// + [Fact] + public void BufferContent_ThrowsNotSupportedException() + { + // Arrange + IAsyncEnumerable updates = CreateTestUpdatesAsync(); + PipelineResponse response = new StreamingUpdatePipelineResponse(updates); + + // Act & Assert + var exception = Assert.Throws(() => response.BufferContent()); + Assert.Contains("Buffering content is not supported", exception.Message); + } + + /// + /// Verify that BufferContentAsync throws NotSupportedException. + /// + [Fact] + public async System.Threading.Tasks.Task BufferContentAsync_ThrowsNotSupportedExceptionAsync() + { + // Arrange + IAsyncEnumerable updates = CreateTestUpdatesAsync(); + PipelineResponse response = new StreamingUpdatePipelineResponse(updates); + + // Act & Assert + var exception = await Assert.ThrowsAsync( + async () => await response.BufferContentAsync()); + Assert.Contains("Buffering content asynchronously is not supported", exception.Message); + } + + /// + /// Verify that Dispose does not throw. + /// + [Fact] + public void Dispose_DoesNotThrow() + { + // Arrange + IAsyncEnumerable updates = CreateTestUpdatesAsync(); + PipelineResponse response = new StreamingUpdatePipelineResponse(updates); + + // Act & Assert - should not throw + response.Dispose(); + } + + private static async IAsyncEnumerable CreateTestUpdatesAsync() + { + yield return new AgentResponseUpdate(Microsoft.Extensions.AI.ChatRole.Assistant, "test"); + await System.Threading.Tasks.Task.CompletedTask; + } +} diff --git a/dotnet/tests/Microsoft.Agents.AI.OpenAI.UnitTests/Extensions/AIAgentWithOpenAIExtensionsTests.cs b/dotnet/tests/Microsoft.Agents.AI.OpenAI.UnitTests/Extensions/AIAgentWithOpenAIExtensionsTests.cs index d29535eddb..a3cd7cd541 100644 --- a/dotnet/tests/Microsoft.Agents.AI.OpenAI.UnitTests/Extensions/AIAgentWithOpenAIExtensionsTests.cs +++ b/dotnet/tests/Microsoft.Agents.AI.OpenAI.UnitTests/Extensions/AIAgentWithOpenAIExtensionsTests.cs @@ -7,6 +7,7 @@ using System.Threading.Tasks; using Moq; using Moq.Protected; +using OpenAI.Responses; using ChatMessage = Microsoft.Extensions.AI.ChatMessage; using ChatRole = Microsoft.Extensions.AI.ChatRole; using OpenAIChatMessage = OpenAI.Chat.ChatMessage; @@ -208,4 +209,170 @@ private static async IAsyncEnumerable ToAsyncEnumerableAsyn yield return await Task.FromResult(update); } } + + #region ResponseItem overload tests + + /// + /// Verify that RunAsync with ResponseItem throws ArgumentNullException when agent is null. + /// + [Fact] + public async Task RunAsync_ResponseItem_WithNullAgent_ThrowsArgumentNullExceptionAsync() + { + // Arrange + AIAgent? agent = null; + IEnumerable messages = [ResponseItem.CreateUserMessageItem("Test message")]; + + // Act & Assert + var exception = await Assert.ThrowsAsync( + () => agent!.RunAsync(messages)); + + Assert.Equal("agent", exception.ParamName); + } + + /// + /// Verify that RunAsync with ResponseItem throws ArgumentNullException when messages is null. + /// + [Fact] + public async Task RunAsync_ResponseItem_WithNullMessages_ThrowsArgumentNullExceptionAsync() + { + // Arrange + var mockAgent = new Mock(); + IEnumerable? messages = null; + + // Act & Assert + var exception = await Assert.ThrowsAsync( + () => mockAgent.Object.RunAsync(messages!)); + + Assert.Equal("messages", exception.ParamName); + } + + /// + /// Verify that the RunAsync with ResponseItem extension method calls the underlying agent's RunAsync with converted messages and parameters. + /// + [Fact] + public async Task RunAsync_ResponseItem_CallsUnderlyingAgentAsync() + { + // Arrange + var mockAgent = new Mock(); + var mockThread = new Mock(); + var options = new AgentRunOptions(); + var cancellationToken = new CancellationToken(false); + const string TestMessageText = "Hello, assistant!"; + const string ResponseText = "This is the assistant's response."; + IEnumerable responseItemMessages = [ResponseItem.CreateUserMessageItem(TestMessageText)]; + + var responseMessage = new ChatMessage(ChatRole.Assistant, [new TextContent(ResponseText)]); + + mockAgent + .Protected() + .Setup>("RunCoreAsync", + ItExpr.IsAny>(), + ItExpr.IsAny(), + ItExpr.IsAny(), + ItExpr.IsAny()) + .ReturnsAsync(new AgentResponse([responseMessage])); + + // Act + ResponseResult result = await mockAgent.Object.RunAsync(responseItemMessages, mockThread.Object, options, cancellationToken); + + // Assert + mockAgent.Protected() + .Verify("RunCoreAsync", + Times.Once(), + ItExpr.IsAny>(), + mockThread.Object, + options, + cancellationToken + ); + + Assert.NotNull(result); + } + + /// + /// Verify that RunStreamingAsync with ResponseItem throws ArgumentNullException when agent is null. + /// + [Fact] + public void RunStreamingAsync_ResponseItem_WithNullAgent_ThrowsArgumentNullException() + { + // Arrange + AIAgent? agent = null; + IEnumerable messages = [ResponseItem.CreateUserMessageItem("Test message")]; + + // Act & Assert + Assert.Throws( + "agent", + () => agent!.RunStreamingAsync(messages)); + } + + /// + /// Verify that RunStreamingAsync with ResponseItem throws ArgumentNullException when messages is null. + /// + [Fact] + public void RunStreamingAsync_ResponseItem_WithNullMessages_ThrowsArgumentNullException() + { + // Arrange + var mockAgent = new Mock(); + IEnumerable? messages = null; + + // Act & Assert + var exception = Assert.Throws( + () => mockAgent.Object.RunStreamingAsync(messages!)); + + Assert.Equal("messages", exception.ParamName); + } + + /// + /// Verify that the RunStreamingAsync with ResponseItem extension method calls the underlying agent's RunStreamingAsync with converted messages and parameters. + /// + [Fact] + public async Task RunStreamingAsync_ResponseItem_CallsUnderlyingAgentAsync() + { + // Arrange + var mockAgent = new Mock(); + var mockThread = new Mock(); + var options = new AgentRunOptions(); + var cancellationToken = new CancellationToken(false); + const string TestMessageText = "Hello, assistant!"; + const string ResponseText1 = "This is "; + const string ResponseText2 = "the assistant's response."; + IEnumerable responseItemMessages = [ResponseItem.CreateUserMessageItem(TestMessageText)]; + + var responseUpdates = new List + { + new(ChatRole.Assistant, ResponseText1), + new(ChatRole.Assistant, ResponseText2) + }; + + mockAgent + .Protected() + .Setup>("RunCoreStreamingAsync", + ItExpr.IsAny>(), + ItExpr.IsAny(), + ItExpr.IsAny(), + ItExpr.IsAny()) + .Returns(ToAsyncEnumerableAsync(responseUpdates)); + + // Act + var result = mockAgent.Object.RunStreamingAsync(responseItemMessages, mockThread.Object, options, cancellationToken); + var updateCount = 0; + await foreach (var update in result) + { + updateCount++; + } + + // Assert + mockAgent.Protected() + .Verify("RunCoreStreamingAsync", + Times.Once(), + ItExpr.IsAny>(), + mockThread.Object, + options, + cancellationToken + ); + + // The updates are filtered based on raw representation, so we just need to verify the method was called + Assert.True(true, "Method was called successfully"); + } + + #endregion } diff --git a/dotnet/tests/Microsoft.Agents.AI.OpenAI.UnitTests/Extensions/AgentResponseExtensionsTests.cs b/dotnet/tests/Microsoft.Agents.AI.OpenAI.UnitTests/Extensions/AgentResponseExtensionsTests.cs new file mode 100644 index 0000000000..1cc16b95fc --- /dev/null +++ b/dotnet/tests/Microsoft.Agents.AI.OpenAI.UnitTests/Extensions/AgentResponseExtensionsTests.cs @@ -0,0 +1,145 @@ +// Copyright (c) Microsoft. All rights reserved. + +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Microsoft.Extensions.AI; +using OpenAI.Chat; +using ChatMessage = Microsoft.Extensions.AI.ChatMessage; +using ChatRole = Microsoft.Extensions.AI.ChatRole; +using TextContent = Microsoft.Extensions.AI.TextContent; + +namespace Microsoft.Agents.AI.OpenAI.UnitTests.Extensions; + +/// +/// Unit tests for the AgentResponseExtensions class that provides OpenAI extension methods. +/// +public sealed class AgentResponseExtensionsTests +{ + /// + /// Verify that AsOpenAIChatCompletion throws ArgumentNullException when response is null. + /// + [Fact] + public void AsOpenAIChatCompletion_WithNullResponse_ThrowsArgumentNullException() + { + // Arrange + AgentResponse? response = null; + + // Act & Assert + var exception = Assert.Throws( + () => response!.AsOpenAIChatCompletion()); + + Assert.Equal("response", exception.ParamName); + } + + /// + /// Verify that AsOpenAIChatCompletion returns the RawRepresentation when it is a ChatCompletion. + /// + [Fact] + public void AsOpenAIChatCompletion_WithChatCompletionRawRepresentation_ReturnsChatCompletion() + { + // Arrange + ChatCompletion chatCompletion = ModelReaderWriterHelper.CreateChatCompletion("assistant_id", "Hello"); + var responseMessage = new ChatMessage(ChatRole.Assistant, [new TextContent("Hello")]); + var agentResponse = new AgentResponse([responseMessage]) + { + RawRepresentation = chatCompletion + }; + + // Act + ChatCompletion result = agentResponse.AsOpenAIChatCompletion(); + + // Assert + Assert.NotNull(result); + Assert.Same(chatCompletion, result); + } + + /// + /// Verify that AsOpenAIChatCompletion converts a ChatResponse when RawRepresentation is not a ChatCompletion. + /// + [Fact] + public void AsOpenAIChatCompletion_WithNonChatCompletionRawRepresentation_ConvertsChatResponse() + { + // Arrange + const string ResponseText = "This is a test response."; + var responseMessage = new ChatMessage(ChatRole.Assistant, [new TextContent(ResponseText)]); + var agentResponse = new AgentResponse([responseMessage]); + + // Act + ChatCompletion result = agentResponse.AsOpenAIChatCompletion(); + + // Assert + Assert.NotNull(result); + Assert.Single(result.Content); + Assert.Equal(ResponseText, result.Content[0].Text); + } + + /// + /// Verify that AsOpenAIResponse throws ArgumentNullException when response is null. + /// + [Fact] + public void AsOpenAIResponse_WithNullResponse_ThrowsArgumentNullException() + { + // Arrange + AgentResponse? response = null; + + // Act & Assert + var exception = Assert.Throws( + () => response!.AsOpenAIResponse()); + + Assert.Equal("response", exception.ParamName); + } + + /// + /// Verify that AsOpenAIResponse converts a ChatResponse when RawRepresentation is not a ResponseResult. + /// + [Fact] + public void AsOpenAIResponse_WithNonResponseResultRawRepresentation_ConvertsChatResponse() + { + // Arrange + const string ResponseText = "This is a test response."; + var responseMessage = new ChatMessage(ChatRole.Assistant, [new TextContent(ResponseText)]); + var agentResponse = new AgentResponse([responseMessage]); + + // Act + var result = agentResponse.AsOpenAIResponse(); + + // Assert + Assert.NotNull(result); + } +} + +/// +/// Helper class for creating OpenAI model objects using ModelReaderWriter. +/// +internal static class ModelReaderWriterHelper +{ + public static ChatCompletion CreateChatCompletion(string id, string contentText) + { + string json = $$""" + { + "id": "{{id}}", + "object": "chat.completion", + "created": 1700000000, + "model": "gpt-4", + "choices": [ + { + "index": 0, + "message": { + "role": "assistant", + "content": "{{contentText}}" + }, + "finish_reason": "stop" + } + ], + "usage": { + "prompt_tokens": 10, + "completion_tokens": 10, + "total_tokens": 20 + } + } + """; + + return System.ClientModel.Primitives.ModelReaderWriter.Read(BinaryData.FromString(json))!; + } +} diff --git a/dotnet/tests/Microsoft.Agents.AI.OpenAI.UnitTests/Extensions/OpenAIAssistantClientExtensionsTests.cs b/dotnet/tests/Microsoft.Agents.AI.OpenAI.UnitTests/Extensions/OpenAIAssistantClientExtensionsTests.cs index 2401790dd0..17eb6c94de 100644 --- a/dotnet/tests/Microsoft.Agents.AI.OpenAI.UnitTests/Extensions/OpenAIAssistantClientExtensionsTests.cs +++ b/dotnet/tests/Microsoft.Agents.AI.OpenAI.UnitTests/Extensions/OpenAIAssistantClientExtensionsTests.cs @@ -569,6 +569,388 @@ public async Task CreateAIAgentAsync_WithClientFactoryAndServices_AppliesBothCor return property?.GetValue(client) as IServiceProvider; } + /// + /// Verify that CreateAIAgentAsync with HostedCodeInterpreterTool properly adds CodeInterpreter tool definition. + /// + [Fact] + public async Task CreateAIAgentAsync_WithHostedCodeInterpreterTool_CreatesAgentWithToolAsync() + { + // Arrange + var assistantClient = new TestAssistantClient(); + const string ModelId = "test-model"; + var options = new ChatClientAgentOptions + { + Name = "Test Agent", + ChatOptions = new ChatOptions + { + Instructions = "Test instructions", + Tools = [new HostedCodeInterpreterTool()] + } + }; + + // Act + var agent = await assistantClient.CreateAIAgentAsync(ModelId, options); + + // Assert + Assert.NotNull(agent); + Assert.Equal("Test Agent", agent.Name); + } + + /// + /// Verify that CreateAIAgentAsync with HostedCodeInterpreterTool with HostedFileContent input properly creates agent. + /// + [Fact] + public async Task CreateAIAgentAsync_WithHostedCodeInterpreterToolAndHostedFileContent_CreatesAgentWithToolResourcesAsync() + { + // Arrange + var assistantClient = new TestAssistantClient(); + const string ModelId = "test-model"; + var codeInterpreterTool = new HostedCodeInterpreterTool + { + Inputs = [new HostedFileContent("test-file-id")] + }; + var options = new ChatClientAgentOptions + { + Name = "Test Agent", + ChatOptions = new ChatOptions + { + Instructions = "Test instructions", + Tools = [codeInterpreterTool] + } + }; + + // Act + var agent = await assistantClient.CreateAIAgentAsync(ModelId, options); + + // Assert + Assert.NotNull(agent); + Assert.Equal("Test Agent", agent.Name); + } + + /// + /// Verify that CreateAIAgentAsync with HostedFileSearchTool properly adds FileSearch tool definition. + /// + [Fact] + public async Task CreateAIAgentAsync_WithHostedFileSearchTool_CreatesAgentWithToolAsync() + { + // Arrange + var assistantClient = new TestAssistantClient(); + const string ModelId = "test-model"; + var options = new ChatClientAgentOptions + { + Name = "Test Agent", + ChatOptions = new ChatOptions + { + Instructions = "Test instructions", + Tools = [new HostedFileSearchTool()] + } + }; + + // Act + var agent = await assistantClient.CreateAIAgentAsync(ModelId, options); + + // Assert + Assert.NotNull(agent); + Assert.Equal("Test Agent", agent.Name); + } + + /// + /// Verify that CreateAIAgentAsync with HostedFileSearchTool with HostedVectorStoreContent input properly creates agent. + /// + [Fact] + public async Task CreateAIAgentAsync_WithHostedFileSearchToolAndHostedVectorStoreContent_CreatesAgentWithToolResourcesAsync() + { + // Arrange + var assistantClient = new TestAssistantClient(); + const string ModelId = "test-model"; + var fileSearchTool = new HostedFileSearchTool + { + MaximumResultCount = 10, + Inputs = [new HostedVectorStoreContent("test-vector-store-id")] + }; + var options = new ChatClientAgentOptions + { + Name = "Test Agent", + ChatOptions = new ChatOptions + { + Instructions = "Test instructions", + Tools = [fileSearchTool] + } + }; + + // Act + var agent = await assistantClient.CreateAIAgentAsync(ModelId, options); + + // Assert + Assert.NotNull(agent); + Assert.Equal("Test Agent", agent.Name); + } + + /// + /// Verify that CreateAIAgentAsync with multiple tools including functions properly creates agent. + /// + [Fact] + public async Task CreateAIAgentAsync_WithMixedTools_CreatesAgentWithAllToolsAsync() + { + // Arrange + var assistantClient = new TestAssistantClient(); + const string ModelId = "test-model"; + var testFunction = AIFunctionFactory.Create(() => "test", "TestFunction", "A test function"); + var options = new ChatClientAgentOptions + { + Name = "Test Agent", + ChatOptions = new ChatOptions + { + Instructions = "Test instructions", + Tools = [new HostedCodeInterpreterTool(), new HostedFileSearchTool(), testFunction] + } + }; + + // Act + var agent = await assistantClient.CreateAIAgentAsync(ModelId, options); + + // Assert + Assert.NotNull(agent); + Assert.Equal("Test Agent", agent.Name); + } + + /// + /// Verify that CreateAIAgentAsync with function tools properly categorizes them as other tools. + /// + [Fact] + public async Task CreateAIAgentAsync_WithFunctionTools_CategorizesAsOtherToolsAsync() + { + // Arrange + var assistantClient = new TestAssistantClient(); + const string ModelId = "test-model"; + var testFunction = AIFunctionFactory.Create(() => "test", "TestFunction", "A test function"); + var options = new ChatClientAgentOptions + { + Name = "Test Agent", + ChatOptions = new ChatOptions + { + Instructions = "Test instructions", + Tools = [testFunction] + } + }; + + // Act + var agent = await assistantClient.CreateAIAgentAsync(ModelId, options); + + // Assert + Assert.NotNull(agent); + Assert.Equal("Test Agent", agent.Name); + } + + /// + /// Verify that AsAIAgent with legacy overload works correctly when assistant instructions are set. + /// + [Fact] + public void AsAIAgent_LegacyOverload_WithAssistantInstructions_SetsInstructions() + { + // Arrange + var assistantClient = new TestAssistantClient(); + var assistant = ModelReaderWriter.Read(BinaryData.FromString("""{"id": "asst_abc123", "name": "Test Agent", "instructions": "Original Instructions"}"""))!; + + // Act + var agent = assistantClient.AsAIAgent(assistant); + + // Assert + Assert.NotNull(agent); + Assert.Equal("Test Agent", agent.Name); + Assert.Equal("Original Instructions", agent.Instructions); + } + + /// + /// Verify that AsAIAgent with legacy overload works correctly when chatOptions with instructions is provided. + /// + [Fact] + public void AsAIAgent_LegacyOverload_WithChatOptionsInstructions_UsesChatOptionsInstructions() + { + // Arrange + var assistantClient = new TestAssistantClient(); + var assistant = ModelReaderWriter.Read(BinaryData.FromString("""{"id": "asst_abc123", "name": "Test Agent", "instructions": "Original Instructions"}"""))!; + var chatOptions = new ChatOptions { Instructions = "Override Instructions" }; + + // Act + var agent = assistantClient.AsAIAgent(assistant, chatOptions); + + // Assert + Assert.NotNull(agent); + Assert.Equal("Test Agent", agent.Name); + // The override instructions should be used + Assert.Equal("Override Instructions", agent.Instructions); + } + + /// + /// Verify that AsAIAgent with legacy overload and ClientResult works correctly. + /// + [Fact] + public void AsAIAgent_LegacyOverload_WithClientResult_WorksCorrectly() + { + // Arrange + var assistantClient = new TestAssistantClient(); + var assistant = ModelReaderWriter.Read(BinaryData.FromString("""{"id": "asst_abc123", "name": "Test Agent", "instructions": "Original Instructions"}"""))!; + var clientResult = ClientResult.FromValue(assistant, new FakePipelineResponse()); + + // Act + var agent = assistantClient.AsAIAgent(clientResult); + + // Assert + Assert.NotNull(agent); + Assert.Equal("Test Agent", agent.Name); + } + + /// + /// Verify that AsAIAgent with legacy overload throws ArgumentNullException when assistant client is null. + /// + [Fact] + public void AsAIAgent_LegacyOverload_WithNullAssistantClient_ThrowsArgumentNullException() + { + // Arrange + AssistantClient? assistantClient = null; + var assistant = ModelReaderWriter.Read(BinaryData.FromString("""{"id": "asst_abc123"}"""))!; + + // Act & Assert + var exception = Assert.Throws(() => + assistantClient!.AsAIAgent(assistant)); + + Assert.Equal("assistantClient", exception.ParamName); + } + + /// + /// Verify that AsAIAgent with legacy overload throws ArgumentNullException when assistantMetadata is null. + /// + [Fact] + public void AsAIAgent_LegacyOverload_WithNullAssistantMetadata_ThrowsArgumentNullException() + { + // Arrange + var assistantClient = new TestAssistantClient(); + + // Act & Assert + var exception = Assert.Throws(() => + assistantClient.AsAIAgent((Assistant)null!)); + + Assert.Equal("assistantMetadata", exception.ParamName); + } + + /// + /// Verify that AsAIAgent with legacy overload throws ArgumentNullException when clientResult is null. + /// + [Fact] + public void AsAIAgent_LegacyOverload_WithNullClientResult_ThrowsArgumentNullException() + { + // Arrange + var assistantClient = new TestAssistantClient(); + + // Act & Assert + var exception = Assert.Throws(() => + assistantClient.AsAIAgent((ClientResult)null!)); + + Assert.Equal("assistantClientResult", exception.ParamName); + } + + /// + /// Verify that GetAIAgentAsync with legacy overload works correctly. + /// + [Fact] + public async Task GetAIAgentAsync_LegacyOverload_WorksCorrectlyAsync() + { + // Arrange + var assistantClient = new TestAssistantClient(); + const string AgentId = "asst_abc123"; + + // Act + var agent = await assistantClient.GetAIAgentAsync(AgentId); + + // Assert + Assert.NotNull(agent); + Assert.Equal("Original Name", agent.Name); + } + + /// + /// Verify that GetAIAgentAsync with legacy overload throws ArgumentNullException when assistantClient is null. + /// + [Fact] + public async Task GetAIAgentAsync_LegacyOverload_WithNullAssistantClient_ThrowsArgumentNullExceptionAsync() + { + // Arrange + AssistantClient? assistantClient = null; + + // Act & Assert + var exception = await Assert.ThrowsAsync(() => + assistantClient!.GetAIAgentAsync("asst_abc123")); + + Assert.Equal("assistantClient", exception.ParamName); + } + + /// + /// Verify that GetAIAgentAsync with legacy overload throws ArgumentException when agentId is empty. + /// + [Fact] + public async Task GetAIAgentAsync_LegacyOverload_WithEmptyAgentId_ThrowsArgumentExceptionAsync() + { + // Arrange + var assistantClient = new TestAssistantClient(); + + // Act & Assert + var exception = await Assert.ThrowsAsync(() => + assistantClient.GetAIAgentAsync(string.Empty)); + + Assert.Equal("agentId", exception.ParamName); + } + + /// + /// Verify that GetAIAgentAsync with options throws ArgumentNullException when assistantClient is null. + /// + [Fact] + public async Task GetAIAgentAsync_WithOptions_WithNullAssistantClient_ThrowsArgumentNullExceptionAsync() + { + // Arrange + AssistantClient? assistantClient = null; + var options = new ChatClientAgentOptions(); + + // Act & Assert + var exception = await Assert.ThrowsAsync(() => + assistantClient!.GetAIAgentAsync("asst_abc123", options)); + + Assert.Equal("assistantClient", exception.ParamName); + } + + /// + /// Verify that GetAIAgentAsync with options throws ArgumentNullException when options is null. + /// + [Fact] + public async Task GetAIAgentAsync_WithOptions_WithNullOptions_ThrowsArgumentNullExceptionAsync() + { + // Arrange + var assistantClient = new TestAssistantClient(); + + // Act & Assert + var exception = await Assert.ThrowsAsync(() => + assistantClient.GetAIAgentAsync("asst_abc123", (ChatClientAgentOptions)null!)); + + Assert.Equal("options", exception.ParamName); + } + + /// + /// Verify that AsAIAgent with options throws ArgumentNullException when assistantClient is null. + /// + [Fact] + public void AsAIAgent_WithOptions_WithNullAssistantClient_ThrowsArgumentNullException() + { + // Arrange + AssistantClient? assistantClient = null; + var assistant = ModelReaderWriter.Read(BinaryData.FromString("""{"id": "asst_abc123"}"""))!; + var options = new ChatClientAgentOptions(); + + // Act & Assert + var exception = Assert.Throws(() => + assistantClient!.AsAIAgent(assistant, options)); + + Assert.Equal("assistantClient", exception.ParamName); + } + /// /// Creates a test AssistantClient implementation for testing. /// From 4f9cad225280db33561eb32209892a3df482cf87 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 22 Jan 2026 00:18:38 +0000 Subject: [PATCH 3/6] Address code review feedback: remove unused using directives Co-authored-by: rogerbarreto <19890735+rogerbarreto@users.noreply.github.com> --- .../ChatClient/StreamingUpdatePipelineResponseTests.cs | 5 +++-- .../Extensions/AgentResponseExtensionsTests.cs | 2 -- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/dotnet/tests/Microsoft.Agents.AI.OpenAI.UnitTests/ChatClient/StreamingUpdatePipelineResponseTests.cs b/dotnet/tests/Microsoft.Agents.AI.OpenAI.UnitTests/ChatClient/StreamingUpdatePipelineResponseTests.cs index 19fb034bbd..aac2a5466f 100644 --- a/dotnet/tests/Microsoft.Agents.AI.OpenAI.UnitTests/ChatClient/StreamingUpdatePipelineResponseTests.cs +++ b/dotnet/tests/Microsoft.Agents.AI.OpenAI.UnitTests/ChatClient/StreamingUpdatePipelineResponseTests.cs @@ -4,6 +4,7 @@ using System.ClientModel.Primitives; using System.Collections.Generic; using System.Threading; +using System.Threading.Tasks; namespace Microsoft.Agents.AI.OpenAI.UnitTests.ChatClient; @@ -120,7 +121,7 @@ public void BufferContent_ThrowsNotSupportedException() /// Verify that BufferContentAsync throws NotSupportedException. /// [Fact] - public async System.Threading.Tasks.Task BufferContentAsync_ThrowsNotSupportedExceptionAsync() + public async Task BufferContentAsync_ThrowsNotSupportedExceptionAsync() { // Arrange IAsyncEnumerable updates = CreateTestUpdatesAsync(); @@ -149,6 +150,6 @@ public void Dispose_DoesNotThrow() private static async IAsyncEnumerable CreateTestUpdatesAsync() { yield return new AgentResponseUpdate(Microsoft.Extensions.AI.ChatRole.Assistant, "test"); - await System.Threading.Tasks.Task.CompletedTask; + await Task.CompletedTask; } } diff --git a/dotnet/tests/Microsoft.Agents.AI.OpenAI.UnitTests/Extensions/AgentResponseExtensionsTests.cs b/dotnet/tests/Microsoft.Agents.AI.OpenAI.UnitTests/Extensions/AgentResponseExtensionsTests.cs index 1cc16b95fc..e026d56104 100644 --- a/dotnet/tests/Microsoft.Agents.AI.OpenAI.UnitTests/Extensions/AgentResponseExtensionsTests.cs +++ b/dotnet/tests/Microsoft.Agents.AI.OpenAI.UnitTests/Extensions/AgentResponseExtensionsTests.cs @@ -1,8 +1,6 @@ // Copyright (c) Microsoft. All rights reserved. using System; -using System.Collections.Generic; -using System.Threading.Tasks; using Microsoft.Extensions.AI; using OpenAI.Chat; using ChatMessage = Microsoft.Extensions.AI.ChatMessage; From 4d4160c7dd63e9817cdcf80be4775f5a0fc489cd Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 22 Jan 2026 00:26:31 +0000 Subject: [PATCH 4/6] Fix format issues: file encoding and remove unused using directives Co-authored-by: rogerbarreto <19890735+rogerbarreto@users.noreply.github.com> --- .../AsyncStreamingChatCompletionUpdateCollectionResultTests.cs | 3 +-- .../AsyncStreamingResponseUpdateCollectionResultTests.cs | 3 +-- .../ChatClient/StreamingUpdatePipelineResponseTests.cs | 3 +-- .../Extensions/AgentResponseExtensionsTests.cs | 3 +-- .../Extensions/OpenAIAssistantClientExtensionsTests.cs | 2 +- 5 files changed, 5 insertions(+), 9 deletions(-) diff --git a/dotnet/tests/Microsoft.Agents.AI.OpenAI.UnitTests/ChatClient/AsyncStreamingChatCompletionUpdateCollectionResultTests.cs b/dotnet/tests/Microsoft.Agents.AI.OpenAI.UnitTests/ChatClient/AsyncStreamingChatCompletionUpdateCollectionResultTests.cs index d682d7e53b..899d329d5b 100644 --- a/dotnet/tests/Microsoft.Agents.AI.OpenAI.UnitTests/ChatClient/AsyncStreamingChatCompletionUpdateCollectionResultTests.cs +++ b/dotnet/tests/Microsoft.Agents.AI.OpenAI.UnitTests/ChatClient/AsyncStreamingChatCompletionUpdateCollectionResultTests.cs @@ -1,8 +1,7 @@ -// Copyright (c) Microsoft. All rights reserved. +// Copyright (c) Microsoft. All rights reserved. using System.ClientModel; using System.Collections.Generic; -using System.Linq; using System.Threading.Tasks; using Microsoft.Extensions.AI; using OpenAI.Chat; diff --git a/dotnet/tests/Microsoft.Agents.AI.OpenAI.UnitTests/ChatClient/AsyncStreamingResponseUpdateCollectionResultTests.cs b/dotnet/tests/Microsoft.Agents.AI.OpenAI.UnitTests/ChatClient/AsyncStreamingResponseUpdateCollectionResultTests.cs index 6cb6216f5d..1ef28ad041 100644 --- a/dotnet/tests/Microsoft.Agents.AI.OpenAI.UnitTests/ChatClient/AsyncStreamingResponseUpdateCollectionResultTests.cs +++ b/dotnet/tests/Microsoft.Agents.AI.OpenAI.UnitTests/ChatClient/AsyncStreamingResponseUpdateCollectionResultTests.cs @@ -1,9 +1,8 @@ -// Copyright (c) Microsoft. All rights reserved. +// Copyright (c) Microsoft. All rights reserved. using System; using System.ClientModel; using System.Collections.Generic; -using System.Linq; using System.Threading.Tasks; using Microsoft.Extensions.AI; using OpenAI.Responses; diff --git a/dotnet/tests/Microsoft.Agents.AI.OpenAI.UnitTests/ChatClient/StreamingUpdatePipelineResponseTests.cs b/dotnet/tests/Microsoft.Agents.AI.OpenAI.UnitTests/ChatClient/StreamingUpdatePipelineResponseTests.cs index aac2a5466f..893255f8d3 100644 --- a/dotnet/tests/Microsoft.Agents.AI.OpenAI.UnitTests/ChatClient/StreamingUpdatePipelineResponseTests.cs +++ b/dotnet/tests/Microsoft.Agents.AI.OpenAI.UnitTests/ChatClient/StreamingUpdatePipelineResponseTests.cs @@ -1,9 +1,8 @@ -// Copyright (c) Microsoft. All rights reserved. +// Copyright (c) Microsoft. All rights reserved. using System; using System.ClientModel.Primitives; using System.Collections.Generic; -using System.Threading; using System.Threading.Tasks; namespace Microsoft.Agents.AI.OpenAI.UnitTests.ChatClient; diff --git a/dotnet/tests/Microsoft.Agents.AI.OpenAI.UnitTests/Extensions/AgentResponseExtensionsTests.cs b/dotnet/tests/Microsoft.Agents.AI.OpenAI.UnitTests/Extensions/AgentResponseExtensionsTests.cs index e026d56104..b2b0a99002 100644 --- a/dotnet/tests/Microsoft.Agents.AI.OpenAI.UnitTests/Extensions/AgentResponseExtensionsTests.cs +++ b/dotnet/tests/Microsoft.Agents.AI.OpenAI.UnitTests/Extensions/AgentResponseExtensionsTests.cs @@ -1,7 +1,6 @@ -// Copyright (c) Microsoft. All rights reserved. +// Copyright (c) Microsoft. All rights reserved. using System; -using Microsoft.Extensions.AI; using OpenAI.Chat; using ChatMessage = Microsoft.Extensions.AI.ChatMessage; using ChatRole = Microsoft.Extensions.AI.ChatRole; diff --git a/dotnet/tests/Microsoft.Agents.AI.OpenAI.UnitTests/Extensions/OpenAIAssistantClientExtensionsTests.cs b/dotnet/tests/Microsoft.Agents.AI.OpenAI.UnitTests/Extensions/OpenAIAssistantClientExtensionsTests.cs index 17eb6c94de..5f92fef13a 100644 --- a/dotnet/tests/Microsoft.Agents.AI.OpenAI.UnitTests/Extensions/OpenAIAssistantClientExtensionsTests.cs +++ b/dotnet/tests/Microsoft.Agents.AI.OpenAI.UnitTests/Extensions/OpenAIAssistantClientExtensionsTests.cs @@ -845,7 +845,7 @@ public void AsAIAgent_LegacyOverload_WithNullClientResult_ThrowsArgumentNullExce // Act & Assert var exception = Assert.Throws(() => - assistantClient.AsAIAgent((ClientResult)null!)); + assistantClient.AsAIAgent(null!)); Assert.Equal("assistantClientResult", exception.ParamName); } From 31fb3abc05b9e3f4f3b24800e6ab613f59334b20 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 22 Jan 2026 00:33:13 +0000 Subject: [PATCH 5/6] Fix redundant cast error by using named parameter Co-authored-by: rogerbarreto <19890735+rogerbarreto@users.noreply.github.com> --- .../Extensions/OpenAIAssistantClientExtensionsTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dotnet/tests/Microsoft.Agents.AI.OpenAI.UnitTests/Extensions/OpenAIAssistantClientExtensionsTests.cs b/dotnet/tests/Microsoft.Agents.AI.OpenAI.UnitTests/Extensions/OpenAIAssistantClientExtensionsTests.cs index 5f92fef13a..31f4369405 100644 --- a/dotnet/tests/Microsoft.Agents.AI.OpenAI.UnitTests/Extensions/OpenAIAssistantClientExtensionsTests.cs +++ b/dotnet/tests/Microsoft.Agents.AI.OpenAI.UnitTests/Extensions/OpenAIAssistantClientExtensionsTests.cs @@ -845,7 +845,7 @@ public void AsAIAgent_LegacyOverload_WithNullClientResult_ThrowsArgumentNullExce // Act & Assert var exception = Assert.Throws(() => - assistantClient.AsAIAgent(null!)); + assistantClient.AsAIAgent(null!, chatOptions: null)); Assert.Equal("assistantClientResult", exception.ParamName); } From 3038575aae8a2189926efec919e9d784c2309607 Mon Sep 17 00:00:00 2001 From: Roger Barreto <19890735+RogerBarreto@users.noreply.github.com> Date: Thu, 22 Jan 2026 16:10:32 +0000 Subject: [PATCH 6/6] Remove excessive inline comments per PR review feedback --- .../AsyncStreamingResponseUpdateCollectionResultTests.cs | 4 ++-- .../ChatClient/StreamingUpdatePipelineResponseTests.cs | 4 ++-- .../Extensions/AIAgentWithOpenAIExtensionsTests.cs | 3 --- .../Extensions/OpenAIAssistantClientExtensionsTests.cs | 1 - 4 files changed, 4 insertions(+), 8 deletions(-) diff --git a/dotnet/tests/Microsoft.Agents.AI.OpenAI.UnitTests/ChatClient/AsyncStreamingResponseUpdateCollectionResultTests.cs b/dotnet/tests/Microsoft.Agents.AI.OpenAI.UnitTests/ChatClient/AsyncStreamingResponseUpdateCollectionResultTests.cs index 1ef28ad041..d6bb87596c 100644 --- a/dotnet/tests/Microsoft.Agents.AI.OpenAI.UnitTests/ChatClient/AsyncStreamingResponseUpdateCollectionResultTests.cs +++ b/dotnet/tests/Microsoft.Agents.AI.OpenAI.UnitTests/ChatClient/AsyncStreamingResponseUpdateCollectionResultTests.cs @@ -116,7 +116,7 @@ public async Task IterateCollection_WithNonStreamingResponseUpdateRawRepresentat results.Add(update); } - // Assert - should be empty since updates don't have StreamingResponseUpdate as RawRepresentation + // Assert Assert.Empty(results); } @@ -138,7 +138,7 @@ public async Task IterateCollection_WithChatResponseUpdateWithoutStreamingRespon results.Add(update); } - // Assert - should be empty since the ChatResponseUpdate doesn't have StreamingResponseUpdate as RawRepresentation + // Assert Assert.Empty(results); } diff --git a/dotnet/tests/Microsoft.Agents.AI.OpenAI.UnitTests/ChatClient/StreamingUpdatePipelineResponseTests.cs b/dotnet/tests/Microsoft.Agents.AI.OpenAI.UnitTests/ChatClient/StreamingUpdatePipelineResponseTests.cs index 893255f8d3..866bba5700 100644 --- a/dotnet/tests/Microsoft.Agents.AI.OpenAI.UnitTests/ChatClient/StreamingUpdatePipelineResponseTests.cs +++ b/dotnet/tests/Microsoft.Agents.AI.OpenAI.UnitTests/ChatClient/StreamingUpdatePipelineResponseTests.cs @@ -77,7 +77,7 @@ public void ContentStream_Set_IsNoOp() // Act response.ContentStream = testStream; - // Assert - should remain null + // Assert Assert.Null(response.ContentStream); testStream.Dispose(); @@ -142,7 +142,7 @@ public void Dispose_DoesNotThrow() IAsyncEnumerable updates = CreateTestUpdatesAsync(); PipelineResponse response = new StreamingUpdatePipelineResponse(updates); - // Act & Assert - should not throw + // Act & Assert response.Dispose(); } diff --git a/dotnet/tests/Microsoft.Agents.AI.OpenAI.UnitTests/Extensions/AIAgentWithOpenAIExtensionsTests.cs b/dotnet/tests/Microsoft.Agents.AI.OpenAI.UnitTests/Extensions/AIAgentWithOpenAIExtensionsTests.cs index a3cd7cd541..db22ab090b 100644 --- a/dotnet/tests/Microsoft.Agents.AI.OpenAI.UnitTests/Extensions/AIAgentWithOpenAIExtensionsTests.cs +++ b/dotnet/tests/Microsoft.Agents.AI.OpenAI.UnitTests/Extensions/AIAgentWithOpenAIExtensionsTests.cs @@ -369,9 +369,6 @@ public async Task RunStreamingAsync_ResponseItem_CallsUnderlyingAgentAsync() options, cancellationToken ); - - // The updates are filtered based on raw representation, so we just need to verify the method was called - Assert.True(true, "Method was called successfully"); } #endregion diff --git a/dotnet/tests/Microsoft.Agents.AI.OpenAI.UnitTests/Extensions/OpenAIAssistantClientExtensionsTests.cs b/dotnet/tests/Microsoft.Agents.AI.OpenAI.UnitTests/Extensions/OpenAIAssistantClientExtensionsTests.cs index 31f4369405..44a4b73b52 100644 --- a/dotnet/tests/Microsoft.Agents.AI.OpenAI.UnitTests/Extensions/OpenAIAssistantClientExtensionsTests.cs +++ b/dotnet/tests/Microsoft.Agents.AI.OpenAI.UnitTests/Extensions/OpenAIAssistantClientExtensionsTests.cs @@ -778,7 +778,6 @@ public void AsAIAgent_LegacyOverload_WithChatOptionsInstructions_UsesChatOptions // Assert Assert.NotNull(agent); Assert.Equal("Test Agent", agent.Name); - // The override instructions should be used Assert.Equal("Override Instructions", agent.Instructions); }