Skip to content

Commit 855e83c

Browse files
DeepAQJiaming Liangmarkwallace-microsoftrogerbarreto
authored
.Net: Respect custom ToolChoice and ParallelToolCallsEnabled options in OpenAIResponseAgent (#13275)
### Motivation and Context <!-- Thank you for your contribution to the semantic-kernel repo! Please help reviewers and future users, providing the following information: 1. Why is this change required? 2. What problem does it solve? 3. What scenario does it contribute to? 4. If it fixes an open issue, please link to the issue here. --> Fixes #13253 by respecting custom `ToolChoice` and `ParallelToolCallsEnabled` options in `OpenAIResponseAgent`. ### Description <!-- Describe your changes, the overall approach, the underlying design. These notes will help understanding how your code works. Thanks! --> Previously, when creating `ResponseCreationOptions` for `OpenAIResponseAgent` with kernel plugins, `ToolChoice` will be set to `Auto` and `ParallelToolCallsEnabled` will be set to `true` regardless of the options provided when creating the agent. This change fixes the problem by setting the default options only when they are not provided, respecting the custom options. ### Contribution Checklist <!-- Before submitting this PR, please make sure: --> - [x] The code builds clean without any errors or warnings - [x] The PR follows the [SK Contribution Guidelines](https://github.com/microsoft/semantic-kernel/blob/main/CONTRIBUTING.md) and the [pre-submission formatting script](https://github.com/microsoft/semantic-kernel/blob/main/CONTRIBUTING.md#development-scripts) raises no violations - [x] All unit tests pass, and I have added new tests where possible - [x] I didn't break anyone 😄 --------- Co-authored-by: Jiaming Liang <[email protected]> Co-authored-by: Mark Wallace <[email protected]> Co-authored-by: Roger Barreto <[email protected]>
1 parent cd4b483 commit 855e83c

File tree

2 files changed

+65
-2
lines changed

2 files changed

+65
-2
lines changed

dotnet/src/Agents/OpenAI/Internal/ResponseCreationOptionsFactory.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,10 @@ internal static ResponseCreationOptions CreateOptions(
6060
if (responseTools is not null && responseTools.Any())
6161
{
6262
creationOptions.Tools.AddRange(responseTools);
63-
creationOptions.ToolChoice = ResponseToolChoice.CreateAutoChoice();
64-
creationOptions.ParallelToolCallsEnabled = true;
63+
if (creationOptions.ToolChoice is null)
64+
{
65+
creationOptions.ToolChoice = ResponseToolChoice.CreateAutoChoice();
66+
}
6567
}
6668

6769
return creationOptions;

dotnet/src/Agents/UnitTests/OpenAI/Internal/ResponseCreationOptionsFactoryTests.cs

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,60 @@ public void CreateOptionsWithNullAgentNameTest()
261261
Assert.Equal("UnnamedAgent", options.EndUserId); // Null name should fallback to "UnnamedAgent"
262262
}
263263

264+
/// <summary>
265+
/// Verify response options creation with kernel plugin and default response options.
266+
/// </summary>
267+
[Fact]
268+
public void CreateOptionsWithKernelPluginAndDefaultOptionsTest()
269+
{
270+
// Arrange
271+
var mockAgent = CreateMockAgent("Test Agent", "You are a helpful assistant.", storeEnabled: false);
272+
var mockThread = CreateMockAgentThread(null);
273+
mockAgent.Kernel.Plugins.AddFromObject(new TestPlugin());
274+
275+
// Act
276+
var options = ResponseCreationOptionsFactory.CreateOptions(mockAgent, mockThread.Object, null);
277+
278+
// Assert
279+
Assert.NotNull(options);
280+
Assert.Single(options.Tools);
281+
Assert.NotNull(options.ToolChoice);
282+
Assert.Equal(ResponseToolChoiceKind.Auto, options.ToolChoice.Kind);
283+
Assert.Null(options.ParallelToolCallsEnabled);
284+
}
285+
286+
/// <summary>
287+
/// Verify response options creation with kernel plugin and custom response options.
288+
/// </summary>
289+
[Fact]
290+
public void CreateOptionsWithKernelPluginAndCustomOptionsTest()
291+
{
292+
// Arrange
293+
var mockAgent = CreateMockAgent("Test Agent", "You are a helpful assistant.", storeEnabled: false);
294+
var mockThread = CreateMockAgentThread(null);
295+
mockAgent.Kernel.Plugins.AddFromObject(new TestPlugin());
296+
297+
// Custom invoke options should be respected
298+
var invokeOptions = new OpenAIResponseAgentInvokeOptions
299+
{
300+
ResponseCreationOptions = new ResponseCreationOptions
301+
{
302+
ToolChoice = ResponseToolChoice.CreateNoneChoice(),
303+
ParallelToolCallsEnabled = false
304+
}
305+
};
306+
307+
// Act
308+
var options = ResponseCreationOptionsFactory.CreateOptions(mockAgent, mockThread.Object, invokeOptions);
309+
310+
// Assert
311+
Assert.NotNull(options);
312+
Assert.Single(options.Tools);
313+
Assert.NotNull(options.ToolChoice);
314+
Assert.Equal(ResponseToolChoiceKind.None, options.ToolChoice.Kind);
315+
Assert.False(options.ParallelToolCallsEnabled);
316+
}
317+
264318
private static OpenAIResponseAgent CreateMockAgent(string? name, string? instructions, bool storeEnabled)
265319
{
266320
var mockClient = new Mock<OpenAIResponseClient>();
@@ -281,4 +335,11 @@ private static Mock<AgentThread> CreateMockAgentThread(string? threadId)
281335
mockThread.Setup(t => t.Id).Returns(threadId);
282336
return mockThread;
283337
}
338+
339+
private sealed class TestPlugin
340+
{
341+
[KernelFunction]
342+
public void TestFunction()
343+
{ }
344+
}
284345
}

0 commit comments

Comments
 (0)