From 930ac5f2457ef9fe25bc19fe2e70347fd23fce6b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 22 Jan 2026 18:03:14 +0000 Subject: [PATCH 1/3] Initial plan From 7c22df1ab9f616ef090f7423e76d3f6642f84b30 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 22 Jan 2026 18:11:09 +0000 Subject: [PATCH 2/3] Add unit tests to improve coverage for Microsoft.Agents.AI.AzureAI.Persistent Co-authored-by: rogerbarreto <19890735+rogerbarreto@users.noreply.github.com> --- .../PersistentAgentsClientExtensionsTests.cs | 586 ++++++++++++++++++ 1 file changed, 586 insertions(+) diff --git a/dotnet/tests/Microsoft.Agents.AI.AzureAI.Persistent.UnitTests/Extensions/PersistentAgentsClientExtensionsTests.cs b/dotnet/tests/Microsoft.Agents.AI.AzureAI.Persistent.UnitTests/Extensions/PersistentAgentsClientExtensionsTests.cs index 51de9ac64e..b81692df03 100644 --- a/dotnet/tests/Microsoft.Agents.AI.AzureAI.Persistent.UnitTests/Extensions/PersistentAgentsClientExtensionsTests.cs +++ b/dotnet/tests/Microsoft.Agents.AI.AzureAI.Persistent.UnitTests/Extensions/PersistentAgentsClientExtensionsTests.cs @@ -570,6 +570,592 @@ public async Task CreateAIAgentAsync_WithClientFactoryAndServices_AppliesBothCor Assert.Same(serviceProvider, GetFunctionInvocationServices(functionInvokingClient)); } + /// + /// Verify that AsAIAgent with Response and ChatOptions throws ArgumentNullException when response is null. + /// + [Fact] + public void AsAIAgent_WithNullResponseAndChatOptions_ThrowsArgumentNullException() + { + // Arrange + PersistentAgentsClient client = CreateFakePersistentAgentsClient(); + + // Act & Assert + var exception = Assert.Throws(() => + client.AsAIAgent((Response)null!, chatOptions: new ChatOptions())); + + Assert.Equal("persistentAgentResponse", exception.ParamName); + } + + /// + /// Verify that AsAIAgent with PersistentAgent and ChatOptions throws ArgumentNullException when client is null. + /// + [Fact] + public void AsAIAgent_WithNullClientAndChatOptions_ThrowsArgumentNullException() + { + // Arrange + PersistentAgent persistentAgent = ModelReaderWriter.Read(BinaryData.FromString("""{"id": "agent_abc123"}"""))!; + + // Act & Assert + var exception = Assert.Throws(() => + ((PersistentAgentsClient)null!).AsAIAgent(persistentAgent, chatOptions: new ChatOptions())); + + Assert.Equal("persistentAgentsClient", exception.ParamName); + } + + /// + /// Verify that AsAIAgent with PersistentAgent and ChatOptions throws ArgumentNullException when persistentAgent is null. + /// + [Fact] + public void AsAIAgent_WithNullPersistentAgentAndChatOptions_ThrowsArgumentNullException() + { + // Arrange + PersistentAgentsClient client = CreateFakePersistentAgentsClient(); + + // Act & Assert + var exception = Assert.Throws(() => + client.AsAIAgent((PersistentAgent)null!, chatOptions: new ChatOptions())); + + Assert.Equal("persistentAgentMetadata", exception.ParamName); + } + + /// + /// Verify that AsAIAgent with Response and ChatOptions propagates instructions from agent metadata when chatOptions is null. + /// + [Fact] + public void AsAIAgent_WithResponseAndNullChatOptions_UsesAgentInstructions() + { + // Arrange + PersistentAgentsClient client = CreateFakePersistentAgentsClient(); + PersistentAgent persistentAgent = ModelReaderWriter.Read(BinaryData.FromString("""{"id": "agent_abc123", "name": "Test Agent", "instructions": "Agent Instructions"}"""))!; + Response response = Response.FromValue(persistentAgent, new FakeResponse()); + + // Act + ChatClientAgent agent = client.AsAIAgent(response, chatOptions: null); + + // Assert + Assert.NotNull(agent); + Assert.Equal("Agent Instructions", agent.Instructions); + } + + /// + /// Verify that AsAIAgent with Response and ChatOptions uses agent instructions when chatOptions.Instructions is null. + /// + [Fact] + public void AsAIAgent_WithResponseAndChatOptionsWithNullInstructions_UsesAgentInstructions() + { + // Arrange + PersistentAgentsClient client = CreateFakePersistentAgentsClient(); + PersistentAgent persistentAgent = ModelReaderWriter.Read(BinaryData.FromString("""{"id": "agent_abc123", "name": "Test Agent", "instructions": "Agent Instructions"}"""))!; + Response response = Response.FromValue(persistentAgent, new FakeResponse()); + var chatOptions = new ChatOptions { Instructions = null }; + + // Act + ChatClientAgent agent = client.AsAIAgent(response, chatOptions); + + // Assert + Assert.NotNull(agent); + Assert.Equal("Agent Instructions", agent.Instructions); + } + + /// + /// Verify that AsAIAgent with Response and ChatOptions does not override chatOptions instructions when set. + /// + [Fact] + public void AsAIAgent_WithResponseAndChatOptionsWithInstructions_UsesChatOptionsInstructions() + { + // Arrange + PersistentAgentsClient client = CreateFakePersistentAgentsClient(); + PersistentAgent persistentAgent = ModelReaderWriter.Read(BinaryData.FromString("""{"id": "agent_abc123", "name": "Test Agent", "instructions": "Agent Instructions"}"""))!; + Response response = Response.FromValue(persistentAgent, new FakeResponse()); + var chatOptions = new ChatOptions { Instructions = "ChatOptions Instructions" }; + + // Act + ChatClientAgent agent = client.AsAIAgent(response, chatOptions); + + // Assert + Assert.NotNull(agent); + Assert.Equal("ChatOptions Instructions", agent.Instructions); + } + + /// + /// Verify that AsAIAgent with PersistentAgent and ChatOptions applies clientFactory correctly. + /// + [Fact] + public void AsAIAgent_WithPersistentAgentChatOptionsAndClientFactory_AppliesFactoryCorrectly() + { + // Arrange + PersistentAgentsClient client = CreateFakePersistentAgentsClient(); + PersistentAgent persistentAgent = ModelReaderWriter.Read(BinaryData.FromString("""{"id": "agent_abc123", "name": "Test Agent"}"""))!; + TestChatClient? testChatClient = null; + + // Act + ChatClientAgent agent = client.AsAIAgent( + persistentAgent, + chatOptions: null, + clientFactory: (innerClient) => testChatClient = new TestChatClient(innerClient)); + + // Assert + Assert.NotNull(agent); + TestChatClient? retrievedTestClient = agent.GetService(); + Assert.NotNull(retrievedTestClient); + Assert.Same(testChatClient, retrievedTestClient); + } + + /// + /// Verify that GetAIAgentAsync with options throws ArgumentNullException when options is null. + /// + [Fact] + public async Task GetAIAgentAsync_WithOptionsAndNullOptions_ThrowsArgumentNullExceptionAsync() + { + // Arrange + PersistentAgentsClient client = CreateFakePersistentAgentsClient(); + + // Act & Assert + ArgumentNullException exception = await Assert.ThrowsAsync(() => + client.GetAIAgentAsync("agent_abc123", (ChatClientAgentOptions)null!)); + + Assert.Equal("options", exception.ParamName); + } + + /// + /// Verify that AsAIAgent with options uses agent instructions when options.ChatOptions.Instructions is null. + /// + [Fact] + public void AsAIAgent_WithOptionsAndNullChatOptionsInstructions_UsesAgentInstructions() + { + // Arrange + PersistentAgentsClient client = CreateFakePersistentAgentsClient(); + PersistentAgent persistentAgent = ModelReaderWriter.Read(BinaryData.FromString("""{"id": "agent_abc123", "name": "Agent Name", "instructions": "Agent Instructions"}"""))!; + var options = new ChatClientAgentOptions { ChatOptions = new ChatOptions { Instructions = null } }; + + // Act + ChatClientAgent agent = client.AsAIAgent(persistentAgent, options); + + // Assert + Assert.NotNull(agent); + Assert.Equal("Agent Instructions", agent.Instructions); + } + + /// + /// Verify that CreateAIAgentAsync with HostedCodeInterpreterTool properly creates agent. + /// + [Fact] + public async Task CreateAIAgentAsync_WithHostedCodeInterpreterTool_CreatesAgentWithToolAsync() + { + // Arrange + PersistentAgentsClient client = CreateFakePersistentAgentsClient(); + const string Model = "test-model"; + var options = new ChatClientAgentOptions + { + Name = "Test Agent", + ChatOptions = new ChatOptions + { + Instructions = "Test instructions", + Tools = [new HostedCodeInterpreterTool()] + } + }; + + // Act + ChatClientAgent agent = await client.CreateAIAgentAsync(Model, 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 + PersistentAgentsClient client = CreateFakePersistentAgentsClient(); + const string Model = "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 + ChatClientAgent agent = await client.CreateAIAgentAsync(Model, options); + + // Assert + Assert.NotNull(agent); + Assert.Equal("Test Agent", agent.Name); + } + + /// + /// Verify that CreateAIAgentAsync with HostedFileSearchTool properly creates agent. + /// + [Fact] + public async Task CreateAIAgentAsync_WithHostedFileSearchTool_CreatesAgentWithToolAsync() + { + // Arrange + PersistentAgentsClient client = CreateFakePersistentAgentsClient(); + const string Model = "test-model"; + var options = new ChatClientAgentOptions + { + Name = "Test Agent", + ChatOptions = new ChatOptions + { + Instructions = "Test instructions", + Tools = [new HostedFileSearchTool()] + } + }; + + // Act + ChatClientAgent agent = await client.CreateAIAgentAsync(Model, 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 + PersistentAgentsClient client = CreateFakePersistentAgentsClient(); + const string Model = "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 + ChatClientAgent agent = await client.CreateAIAgentAsync(Model, options); + + // Assert + Assert.NotNull(agent); + Assert.Equal("Test Agent", agent.Name); + } + + /// + /// Verify that CreateAIAgentAsync with HostedWebSearchTool with connectionId properly creates agent. + /// + [Fact] + public async Task CreateAIAgentAsync_WithHostedWebSearchToolAndConnectionId_CreatesAgentWithToolAsync() + { + // Arrange + PersistentAgentsClient client = CreateFakePersistentAgentsClient(); + const string Model = "test-model"; + var webSearchTool = new HostedWebSearchTool(new Dictionary + { + { "connectionId", "test-connection-id" } + }); + var options = new ChatClientAgentOptions + { + Name = "Test Agent", + ChatOptions = new ChatOptions + { + Instructions = "Test instructions", + Tools = [webSearchTool] + } + }; + + // Act + ChatClientAgent agent = await client.CreateAIAgentAsync(Model, options); + + // Assert + Assert.NotNull(agent); + Assert.Equal("Test Agent", agent.Name); + } + + /// + /// Verify that CreateAIAgentAsync with HostedWebSearchTool without connectionId falls to default case. + /// + [Fact] + public async Task CreateAIAgentAsync_WithHostedWebSearchToolWithoutConnectionId_FallsToDefaultCaseAsync() + { + // Arrange + PersistentAgentsClient client = CreateFakePersistentAgentsClient(); + const string Model = "test-model"; + var webSearchTool = new HostedWebSearchTool(); + var options = new ChatClientAgentOptions + { + Name = "Test Agent", + ChatOptions = new ChatOptions + { + Instructions = "Test instructions", + Tools = [webSearchTool] + } + }; + + // Act + ChatClientAgent agent = await client.CreateAIAgentAsync(Model, 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 + PersistentAgentsClient client = CreateFakePersistentAgentsClient(); + const string Model = "test-model"; + AIFunction testFunction = AIFunctionFactory.Create(() => "test", "TestFunction", "A test function"); + var options = new ChatClientAgentOptions + { + Name = "Test Agent", + ChatOptions = new ChatOptions + { + Instructions = "Test instructions", + Tools = [testFunction] + } + }; + + // Act + ChatClientAgent agent = await client.CreateAIAgentAsync(Model, 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 + PersistentAgentsClient client = CreateFakePersistentAgentsClient(); + const string Model = "test-model"; + AIFunction 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 + ChatClientAgent agent = await client.CreateAIAgentAsync(Model, options); + + // Assert + Assert.NotNull(agent); + Assert.Equal("Test Agent", agent.Name); + } + + /// + /// Verify that AsAIAgent with Response and Options throws ArgumentNullException when client is null. + /// + [Fact] + public void AsAIAgent_WithNullClientResponseAndOptions_ThrowsArgumentNullException() + { + // Arrange + PersistentAgent persistentAgent = ModelReaderWriter.Read(BinaryData.FromString("""{"id": "agent_abc123"}"""))!; + Response response = Response.FromValue(persistentAgent, new FakeResponse()); + var options = new ChatClientAgentOptions(); + + // Act & Assert + ArgumentNullException exception = Assert.Throws(() => + ((PersistentAgentsClient)null!).AsAIAgent(response, options)); + + Assert.Equal("persistentAgentsClient", exception.ParamName); + } + + /// + /// Verify that AsAIAgent with PersistentAgent and Options throws ArgumentNullException when client is null. + /// + [Fact] + public void AsAIAgent_WithNullClientPersistentAgentAndOptions_ThrowsArgumentNullException() + { + // Arrange + PersistentAgent persistentAgent = ModelReaderWriter.Read(BinaryData.FromString("""{"id": "agent_abc123"}"""))!; + var options = new ChatClientAgentOptions(); + + // Act & Assert + ArgumentNullException exception = Assert.Throws(() => + ((PersistentAgentsClient)null!).AsAIAgent(persistentAgent, options)); + + Assert.Equal("persistentAgentsClient", exception.ParamName); + } + + /// + /// Verify that AsAIAgent with PersistentAgent and Options applies clientFactory correctly. + /// + [Fact] + public void AsAIAgent_WithPersistentAgentOptionsAndClientFactory_AppliesFactoryCorrectly() + { + // Arrange + PersistentAgentsClient client = CreateFakePersistentAgentsClient(); + PersistentAgent persistentAgent = ModelReaderWriter.Read(BinaryData.FromString("""{"id": "agent_abc123", "name": "Test Agent"}"""))!; + var options = new ChatClientAgentOptions { Name = "Test Agent" }; + TestChatClient? testChatClient = null; + + // Act + ChatClientAgent agent = client.AsAIAgent( + persistentAgent, + options, + clientFactory: (innerClient) => testChatClient = new TestChatClient(innerClient)); + + // Assert + Assert.NotNull(agent); + Assert.Equal("Test Agent", agent.Name); + TestChatClient? retrievedTestClient = agent.GetService(); + Assert.NotNull(retrievedTestClient); + Assert.Same(testChatClient, retrievedTestClient); + } + + /// + /// Verify that AsAIAgent with Response and Options applies clientFactory correctly. + /// + [Fact] + public void AsAIAgent_WithResponseOptionsAndClientFactory_AppliesFactoryCorrectly() + { + // Arrange + PersistentAgentsClient client = CreateFakePersistentAgentsClient(); + PersistentAgent persistentAgent = ModelReaderWriter.Read(BinaryData.FromString("""{"id": "agent_abc123", "name": "Test Agent"}"""))!; + Response response = Response.FromValue(persistentAgent, new FakeResponse()); + var options = new ChatClientAgentOptions { Name = "Test Agent" }; + TestChatClient? testChatClient = null; + + // Act + ChatClientAgent agent = client.AsAIAgent( + response, + options, + clientFactory: (innerClient) => testChatClient = new TestChatClient(innerClient)); + + // Assert + Assert.NotNull(agent); + Assert.Equal("Test Agent", agent.Name); + TestChatClient? retrievedTestClient = agent.GetService(); + Assert.NotNull(retrievedTestClient); + Assert.Same(testChatClient, retrievedTestClient); + } + + /// + /// Verify that AsAIAgent with Response and ChatOptions applies clientFactory correctly. + /// + [Fact] + public void AsAIAgent_WithResponseChatOptionsAndClientFactory_AppliesFactoryCorrectly() + { + // Arrange + PersistentAgentsClient client = CreateFakePersistentAgentsClient(); + PersistentAgent persistentAgent = ModelReaderWriter.Read(BinaryData.FromString("""{"id": "agent_abc123", "name": "Test Agent"}"""))!; + Response response = Response.FromValue(persistentAgent, new FakeResponse()); + TestChatClient? testChatClient = null; + + // Act + ChatClientAgent agent = client.AsAIAgent( + response, + chatOptions: null, + clientFactory: (innerClient) => testChatClient = new TestChatClient(innerClient)); + + // Assert + Assert.NotNull(agent); + TestChatClient? retrievedTestClient = agent.GetService(); + Assert.NotNull(retrievedTestClient); + Assert.Same(testChatClient, retrievedTestClient); + } + + /// + /// Verify that GetAIAgentAsync with options and clientFactory applies the factory correctly. + /// + [Fact] + public async Task GetAIAgentAsync_WithOptionsAndClientFactory_AppliesFactoryCorrectlyAsync() + { + // Arrange + PersistentAgentsClient client = CreateFakePersistentAgentsClient(); + TestChatClient? testChatClient = null; + var options = new ChatClientAgentOptions { Name = "Test Agent" }; + + // Act + ChatClientAgent agent = await client.GetAIAgentAsync( + agentId: "test-agent-id", + options, + clientFactory: (innerClient) => testChatClient = new TestChatClient(innerClient)); + + // Assert + Assert.NotNull(agent); + TestChatClient? retrievedTestClient = agent.GetService(); + Assert.NotNull(retrievedTestClient); + Assert.Same(testChatClient, retrievedTestClient); + } + + /// + /// Verify that GetAIAgentAsync with options and services passes services correctly. + /// + [Fact] + public async Task GetAIAgentAsync_WithOptionsAndServices_PassesServicesToAgentAsync() + { + // Arrange + PersistentAgentsClient client = CreateFakePersistentAgentsClient(); + var serviceProvider = new TestServiceProvider(); + var options = new ChatClientAgentOptions { Name = "Test Agent" }; + + // Act + ChatClientAgent agent = await client.GetAIAgentAsync("agent_abc123", options, services: serviceProvider); + + // Assert + Assert.NotNull(agent); + + // Verify the IServiceProvider was passed through to the FunctionInvokingChatClient + IChatClient? chatClient = agent.GetService(); + Assert.NotNull(chatClient); + FunctionInvokingChatClient? functionInvokingClient = chatClient.GetService(); + Assert.NotNull(functionInvokingClient); + Assert.Same(serviceProvider, GetFunctionInvocationServices(functionInvokingClient)); + } + + /// + /// Verify that CreateAIAgentAsync with options and services passes services correctly. + /// + [Fact] + public async Task CreateAIAgentAsync_WithOptionsAndServices_PassesServicesToAgentAsync() + { + // Arrange + PersistentAgentsClient client = CreateFakePersistentAgentsClient(); + var serviceProvider = new TestServiceProvider(); + const string Model = "test-model"; + var options = new ChatClientAgentOptions { Name = "Test Agent" }; + + // Act + ChatClientAgent agent = await client.CreateAIAgentAsync(Model, options, services: serviceProvider); + + // Assert + Assert.NotNull(agent); + + // Verify the IServiceProvider was passed through to the FunctionInvokingChatClient + IChatClient? chatClient = agent.GetService(); + Assert.NotNull(chatClient); + FunctionInvokingChatClient? functionInvokingClient = chatClient.GetService(); + Assert.NotNull(functionInvokingClient); + Assert.Same(serviceProvider, GetFunctionInvocationServices(functionInvokingClient)); + } + /// /// Uses reflection to access the FunctionInvocationServices property which is not public. /// From 41240efcdffd8b6b622d6d7a08f2af14117a96c6 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 23 Jan 2026 12:26:04 +0000 Subject: [PATCH 3/3] Fix redundant cast error IDE0004 Co-authored-by: rogerbarreto <19890735+rogerbarreto@users.noreply.github.com> --- .../Extensions/PersistentAgentsClientExtensionsTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dotnet/tests/Microsoft.Agents.AI.AzureAI.Persistent.UnitTests/Extensions/PersistentAgentsClientExtensionsTests.cs b/dotnet/tests/Microsoft.Agents.AI.AzureAI.Persistent.UnitTests/Extensions/PersistentAgentsClientExtensionsTests.cs index b81692df03..0d78b9ff06 100644 --- a/dotnet/tests/Microsoft.Agents.AI.AzureAI.Persistent.UnitTests/Extensions/PersistentAgentsClientExtensionsTests.cs +++ b/dotnet/tests/Microsoft.Agents.AI.AzureAI.Persistent.UnitTests/Extensions/PersistentAgentsClientExtensionsTests.cs @@ -581,7 +581,7 @@ public void AsAIAgent_WithNullResponseAndChatOptions_ThrowsArgumentNullException // Act & Assert var exception = Assert.Throws(() => - client.AsAIAgent((Response)null!, chatOptions: new ChatOptions())); + client.AsAIAgent(persistentAgentResponse: null!, chatOptions: new ChatOptions())); Assert.Equal("persistentAgentResponse", exception.ParamName); }