Skip to content

Commit 892c177

Browse files
.NET: Fix FunctionInvocationDelegatingAgent to preserve all AgentRunOptions properties (microsoft#4179)
When converting base AgentRunOptions to ChatClientAgentRunOptions, the middleware now preserves AllowBackgroundResponses, ContinuationToken, and AdditionalProperties in addition to ResponseFormat. Added unit test verifying all properties are preserved during the conversion. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent ba45455 commit 892c177

File tree

2 files changed

+61
-1
lines changed

2 files changed

+61
-1
lines changed

dotnet/src/Microsoft.Agents.AI/FunctionInvocationDelegatingAgent.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,13 @@ protected override IAsyncEnumerable<AgentResponseUpdate> RunCoreStreamingAsync(I
3232
{
3333
if (options is null || options.GetType() == typeof(AgentRunOptions))
3434
{
35-
options = new ChatClientAgentRunOptions();
35+
options = new ChatClientAgentRunOptions()
36+
{
37+
ResponseFormat = options?.ResponseFormat,
38+
AllowBackgroundResponses = options?.AllowBackgroundResponses,
39+
ContinuationToken = options?.ContinuationToken,
40+
AdditionalProperties = options?.AdditionalProperties,
41+
};
3642
}
3743

3844
if (options is not ChatClientAgentRunOptions aco)

dotnet/tests/Microsoft.Agents.AI.UnitTests/FunctionInvocationDelegatingAgentTests.cs

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -935,6 +935,60 @@ public async Task RunAsync_MiddlewareDoesNotCallNext_FunctionNotExecutedAsync()
935935

936936
#endregion
937937

938+
#region Options Preservation Tests
939+
940+
/// <summary>
941+
/// Tests that FunctionInvocationDelegatingAgent preserves all original AgentRunOptions properties
942+
/// when converting base AgentRunOptions to ChatClientAgentRunOptions.
943+
/// </summary>
944+
[Fact]
945+
public async Task RunAsync_WithBaseAgentRunOptions_PreservesAllOriginalOptionsAsync()
946+
{
947+
// Arrange
948+
AgentRunOptions? capturedOptions = null;
949+
var responseFormat = ChatResponseFormat.Json;
950+
var additionalProperties = new AdditionalPropertiesDictionary { ["key1"] = "value1" };
951+
952+
Mock<IChatClient> mockChatClient = new();
953+
var chatClientAgent = new ChatClientAgent(mockChatClient.Object);
954+
955+
// Wrap the inner agent in a spy that captures the converted options and returns a dummy response
956+
var spyAgent = new AnonymousDelegatingAIAgent(
957+
chatClientAgent,
958+
runFunc: (messages, session, options, innerAgent, ct) =>
959+
{
960+
capturedOptions = options;
961+
return Task.FromResult(new AgentResponse(new ChatResponse(new ChatMessage(ChatRole.Assistant, "test")) { ResponseId = "test" }));
962+
},
963+
runStreamingFunc: null);
964+
965+
static ValueTask<object?> MiddlewareCallbackAsync(AIAgent agent, FunctionInvocationContext context, Func<FunctionInvocationContext, CancellationToken, ValueTask<object?>> next, CancellationToken cancellationToken)
966+
=> next(context, cancellationToken);
967+
968+
var middleware = new FunctionInvocationDelegatingAgent(spyAgent, MiddlewareCallbackAsync);
969+
970+
var originalOptions = new AgentRunOptions
971+
{
972+
ResponseFormat = responseFormat,
973+
AllowBackgroundResponses = true,
974+
ContinuationToken = ResponseContinuationToken.FromBytes(new byte[] { 1, 2, 3 }),
975+
AdditionalProperties = additionalProperties,
976+
};
977+
978+
// Act
979+
await middleware.RunAsync([new(ChatRole.User, "Test")], null, originalOptions, CancellationToken.None);
980+
981+
// Assert - All original properties were preserved on the converted options
982+
Assert.NotNull(capturedOptions);
983+
Assert.IsType<ChatClientAgentRunOptions>(capturedOptions);
984+
Assert.Same(responseFormat, capturedOptions.ResponseFormat);
985+
Assert.True(capturedOptions.AllowBackgroundResponses);
986+
Assert.Same(originalOptions.ContinuationToken, capturedOptions.ContinuationToken);
987+
Assert.Same(additionalProperties, capturedOptions.AdditionalProperties);
988+
}
989+
990+
#endregion
991+
938992
/// <summary>
939993
/// Creates a mock IChatClient with predefined responses for testing.
940994
/// </summary>

0 commit comments

Comments
 (0)