diff --git a/dotnet/src/Microsoft.Agents.AI/FunctionInvocationDelegatingAgent.cs b/dotnet/src/Microsoft.Agents.AI/FunctionInvocationDelegatingAgent.cs index bf34dfdeed..13f15ff1e9 100644 --- a/dotnet/src/Microsoft.Agents.AI/FunctionInvocationDelegatingAgent.cs +++ b/dotnet/src/Microsoft.Agents.AI/FunctionInvocationDelegatingAgent.cs @@ -32,7 +32,13 @@ protected override IAsyncEnumerable RunCoreStreamingAsync(I { if (options is null || options.GetType() == typeof(AgentRunOptions)) { - options = new ChatClientAgentRunOptions(); + options = new ChatClientAgentRunOptions() + { + ResponseFormat = options?.ResponseFormat, + AllowBackgroundResponses = options?.AllowBackgroundResponses, + ContinuationToken = options?.ContinuationToken, + AdditionalProperties = options?.AdditionalProperties, + }; } if (options is not ChatClientAgentRunOptions aco) diff --git a/dotnet/tests/Microsoft.Agents.AI.UnitTests/FunctionInvocationDelegatingAgentTests.cs b/dotnet/tests/Microsoft.Agents.AI.UnitTests/FunctionInvocationDelegatingAgentTests.cs index d54a0644a4..68228155a7 100644 --- a/dotnet/tests/Microsoft.Agents.AI.UnitTests/FunctionInvocationDelegatingAgentTests.cs +++ b/dotnet/tests/Microsoft.Agents.AI.UnitTests/FunctionInvocationDelegatingAgentTests.cs @@ -935,6 +935,60 @@ public async Task RunAsync_MiddlewareDoesNotCallNext_FunctionNotExecutedAsync() #endregion + #region Options Preservation Tests + + /// + /// Tests that FunctionInvocationDelegatingAgent preserves all original AgentRunOptions properties + /// when converting base AgentRunOptions to ChatClientAgentRunOptions. + /// + [Fact] + public async Task RunAsync_WithBaseAgentRunOptions_PreservesAllOriginalOptionsAsync() + { + // Arrange + AgentRunOptions? capturedOptions = null; + var responseFormat = ChatResponseFormat.Json; + var additionalProperties = new AdditionalPropertiesDictionary { ["key1"] = "value1" }; + + Mock mockChatClient = new(); + var chatClientAgent = new ChatClientAgent(mockChatClient.Object); + + // Wrap the inner agent in a spy that captures the converted options and returns a dummy response + var spyAgent = new AnonymousDelegatingAIAgent( + chatClientAgent, + runFunc: (messages, session, options, innerAgent, ct) => + { + capturedOptions = options; + return Task.FromResult(new AgentResponse(new ChatResponse(new ChatMessage(ChatRole.Assistant, "test")) { ResponseId = "test" })); + }, + runStreamingFunc: null); + + static ValueTask MiddlewareCallbackAsync(AIAgent agent, FunctionInvocationContext context, Func> next, CancellationToken cancellationToken) + => next(context, cancellationToken); + + var middleware = new FunctionInvocationDelegatingAgent(spyAgent, MiddlewareCallbackAsync); + + var originalOptions = new AgentRunOptions + { + ResponseFormat = responseFormat, + AllowBackgroundResponses = true, + ContinuationToken = ResponseContinuationToken.FromBytes(new byte[] { 1, 2, 3 }), + AdditionalProperties = additionalProperties, + }; + + // Act + await middleware.RunAsync([new(ChatRole.User, "Test")], null, originalOptions, CancellationToken.None); + + // Assert - All original properties were preserved on the converted options + Assert.NotNull(capturedOptions); + Assert.IsType(capturedOptions); + Assert.Same(responseFormat, capturedOptions.ResponseFormat); + Assert.True(capturedOptions.AllowBackgroundResponses); + Assert.Same(originalOptions.ContinuationToken, capturedOptions.ContinuationToken); + Assert.Same(additionalProperties, capturedOptions.AdditionalProperties); + } + + #endregion + /// /// Creates a mock IChatClient with predefined responses for testing. ///