diff --git a/dotnet/src/Agents/Orchestration/Handoff/HandoffActor.cs b/dotnet/src/Agents/Orchestration/Handoff/HandoffActor.cs index 6c1380e2c5e2..457d7fce7f12 100644 --- a/dotnet/src/Agents/Orchestration/Handoff/HandoffActor.cs +++ b/dotnet/src/Agents/Orchestration/Handoff/HandoffActor.cs @@ -5,6 +5,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.Logging; +using Microsoft.SemanticKernel; using Microsoft.SemanticKernel.Agents.Runtime; using Microsoft.SemanticKernel.Agents.Runtime.Core; using Microsoft.SemanticKernel.ChatCompletion; @@ -66,18 +67,47 @@ protected override AgentInvokeOptions CreateInvokeOptions(Func executionSettings = []; + if (this.Agent.Arguments?.ExecutionSettings is { Count: > 0 } agentExecutionSettings) + { + foreach (KeyValuePair kv in agentExecutionSettings) + { + PromptExecutionSettings cloned = kv.Value.Clone(); + cloned.FunctionChoiceBehavior = handoffFunctionChoice; + executionSettings[kv.Key] = cloned; + } + } + else + { + executionSettings[PromptExecutionSettings.DefaultServiceId] = new PromptExecutionSettings + { + FunctionChoiceBehavior = handoffFunctionChoice, + }; + } + + Dictionary parameters = []; + if (this.Agent.Arguments is { Count: > 0 } agentArguments) + { + foreach (KeyValuePair kv in agentArguments) + { + parameters[kv.Key] = kv.Value; + } + } + + KernelArguments kernelArguments = new(parameters, executionSettings); + AgentInvokeOptions options = new() { Kernel = kernel, - KernelArguments = new(new PromptExecutionSettings - { - FunctionChoiceBehavior = FunctionChoiceBehavior.Auto(options: new() - { - RetainArgumentTypes = true, - }) - }), + KernelArguments = kernelArguments, OnIntermediateMessage = messageHandler, }; diff --git a/dotnet/src/Agents/UnitTests/Orchestration/HandoffOrchestrationTests.cs b/dotnet/src/Agents/UnitTests/Orchestration/HandoffOrchestrationTests.cs index a5f27265b09a..ca43b7883176 100644 --- a/dotnet/src/Agents/UnitTests/Orchestration/HandoffOrchestrationTests.cs +++ b/dotnet/src/Agents/UnitTests/Orchestration/HandoffOrchestrationTests.cs @@ -3,12 +3,15 @@ using System; using System.Collections.Generic; using System.Net.Http; +using System.Text.Json; using System.Threading.Tasks; using Microsoft.SemanticKernel; using Microsoft.SemanticKernel.Agents; using Microsoft.SemanticKernel.Agents.Orchestration; using Microsoft.SemanticKernel.Agents.Orchestration.Handoff; using Microsoft.SemanticKernel.Agents.Runtime.InProcess; +using Microsoft.SemanticKernel.Connectors.OpenAI; +using ChatReasoningEffortLevel = global::OpenAI.Chat.ChatReasoningEffortLevel; using Xunit; namespace SemanticKernel.Agents.UnitTests.Orchestration; @@ -88,6 +91,32 @@ public async Task HandoffOrchestrationWithMultipleAgentsAsync() Assert.Equal("Final response", response); } + [Fact] + public async Task HandoffOrchestrationPreservesAgentExecutionSettingsAsync() + { + // Arrange + HttpMessageHandlerStub messageHandlerStub = new(); + ChatCompletionAgent mockAgent = + this.CreateMockAgent( + "Agent1", + "Test Agent", + Responses.Message("Final response"), + messageHandlerStub, + new KernelArguments(new OpenAIPromptExecutionSettings + { + ReasoningEffort = ChatReasoningEffortLevel.High, + })); + + // Act + string response = await ExecuteOrchestrationAsync(OrchestrationHandoffs.StartWith(mockAgent), mockAgent); + + // Assert + Assert.Equal("Final response", response); + + using JsonDocument requestBody = JsonDocument.Parse(messageHandlerStub.RequestContent!); + Assert.Equal("high", requestBody.RootElement.GetProperty("reasoning_effort").GetString()); + } + private static async Task ExecuteOrchestrationAsync(OrchestrationHandoffs handoffs, params Agent[] mockAgents) { // Arrange @@ -110,17 +139,15 @@ private static async Task ExecuteOrchestrationAsync(OrchestrationHandoff return response; } - private ChatCompletionAgent CreateMockAgent(string name, string description, string response) + private ChatCompletionAgent CreateMockAgent(string name, string description, string response, HttpMessageHandlerStub? messageHandlerStub = null, KernelArguments? arguments = null) { - HttpMessageHandlerStub messageHandlerStub = - new() - { - ResponseToReturn = new HttpResponseMessage - { - StatusCode = System.Net.HttpStatusCode.OK, - Content = new StringContent(response), - }, - }; + messageHandlerStub ??= new HttpMessageHandlerStub(); + + messageHandlerStub.ResponseToReturn = new HttpResponseMessage + { + StatusCode = System.Net.HttpStatusCode.OK, + Content = new StringContent(response), + }; HttpClient httpClient = new(messageHandlerStub, disposeHandler: false); this._disposables.Add(messageHandlerStub); @@ -136,6 +163,7 @@ private ChatCompletionAgent CreateMockAgent(string name, string description, str Name = name, Description = description, Kernel = kernel, + Arguments = arguments, }; return mockAgent1;