Skip to content

Commit af0c117

Browse files
bmehta001Copilot
andcommitted
Align ToolChoice with official OpenAI .NET SDK patterns
- ToolDefinition.Type: non-nullable with default ToolType.Function - FunctionDefinition: Function and Name marked as required - ToolChoice: factory methods (CreateAutoChoice, CreateNoneChoice, CreateRequiredChoice, CreateFunctionChoice) instead of static properties - Update all callers in samples and tests - Update sample Directory.Packages.props WinML version Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 3fa1101 commit af0c117

5 files changed

Lines changed: 32 additions & 23 deletions

File tree

samples/cs/Directory.Packages.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
</PropertyGroup>
77
<ItemGroup>
88
<PackageVersion Include="Microsoft.AI.Foundry.Local" Version="0.9.0-dev" />
9-
<PackageVersion Include="Microsoft.AI.Foundry.Local.WinML" Version="0.9.0-dev-20260324" />
9+
<PackageVersion Include="Microsoft.AI.Foundry.Local.WinML" Version="0.9.0-dev" />
1010
<PackageVersion Include="Microsoft.Extensions.Logging" Version="9.0.10" />
1111
<PackageVersion Include="Microsoft.Extensions.Logging.Console" Version="9.0.10" />
1212
<PackageVersion Include="NAudio" Version="2.2.1" />

samples/cs/tool-calling-foundry-local-sdk/Program.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ await model.DownloadAsync(progress =>
5757

5858
// Get a chat client
5959
var chatClient = await model.GetChatClientAsync();
60-
chatClient.Settings.ToolChoice = ToolChoice.Required; // Force the model to make a tool call
60+
chatClient.Settings.ToolChoice = ToolChoice.CreateRequiredChoice(); // Force the model to make a tool call
6161

6262

6363
// Prepare messages
@@ -145,7 +145,7 @@ await model.DownloadAsync(progress =>
145145

146146
// Set tool calling back to auto so that the model can decide whether to call
147147
// the tool again or continue the conversation based on the new user prompt
148-
chatClient.Settings.ToolChoice = ToolChoice.Auto;
148+
chatClient.Settings.ToolChoice = ToolChoice.CreateAutoChoice();
149149

150150

151151
// Run the next turn of the conversation

samples/cs/tutorial-tool-calling/Program.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ await model.DownloadAsync(progress =>
134134
Console.WriteLine("Model loaded and ready.");
135135

136136
var chatClient = await model.GetChatClientAsync();
137-
chatClient.Settings.ToolChoice = ToolChoice.Auto;
137+
chatClient.Settings.ToolChoice = ToolChoice.CreateAutoChoice();
138138

139139
var messages = new List<ChatMessage>
140140
{

sdk/cs/src/OpenAI/ToolCallingTypes.cs

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,13 @@ namespace Microsoft.AI.Foundry.Local.OpenAI;
1818
/// </summary>
1919
public class ToolDefinition
2020
{
21-
/// <summary>The type of tool.</summary>
21+
/// <summary>The type of tool. Defaults to <see cref="ToolType.Function"/>.</summary>
2222
[JsonPropertyName("type")]
23-
public ToolType? Type { get; set; }
23+
public ToolType Type { get; set; } = ToolType.Function;
2424

2525
/// <summary>The function definition.</summary>
2626
[JsonPropertyName("function")]
27-
public FunctionDefinition? Function { get; set; }
27+
public required FunctionDefinition Function { get; set; }
2828
}
2929

3030
/// <summary>
@@ -34,7 +34,7 @@ public class FunctionDefinition
3434
{
3535
/// <summary>The name of the function.</summary>
3636
[JsonPropertyName("name")]
37-
public string? Name { get; set; }
37+
public required string Name { get; set; }
3838

3939
/// <summary>A description of what the function does.</summary>
4040
[JsonPropertyName("description")]
@@ -117,26 +117,35 @@ public class JsonSchema
117117

118118
/// <summary>
119119
/// Controls which tool the model should use.
120-
/// Use static properties <see cref="None"/>, <see cref="Auto"/>, or <see cref="Required"/>
121-
/// for standard choices.
120+
/// Use static methods <see cref="CreateNoneChoice"/>, <see cref="CreateAutoChoice"/>,
121+
/// <see cref="CreateRequiredChoice"/>, or <see cref="CreateFunctionChoice(string)"/>.
122122
/// </summary>
123123
[JsonConverter(typeof(ToolChoiceConverter))]
124124
public class ToolChoice
125125
{
126126
/// <summary>The tool choice type.</summary>
127-
public string? Type { get; set; }
127+
public string? Type { get; internal set; }
128128

129129
/// <summary>Specifies a particular function to call.</summary>
130-
public FunctionTool? Function { get; set; }
130+
public FunctionTool? Function { get; internal set; }
131+
132+
/// <summary>Creates a choice indicating the model will not call any tool.</summary>
133+
public static ToolChoice CreateNoneChoice() => new() { Type = "none" };
131134

132-
/// <summary>The model will not call any tool.</summary>
133-
public static ToolChoice None => new() { Type = "none" };
135+
/// <summary>Creates a choice indicating the model can choose whether to call a tool.</summary>
136+
public static ToolChoice CreateAutoChoice() => new() { Type = "auto" };
134137

135-
/// <summary>The model can choose whether to call a tool.</summary>
136-
public static ToolChoice Auto => new() { Type = "auto" };
138+
/// <summary>Creates a choice indicating the model must call one or more tools.</summary>
139+
public static ToolChoice CreateRequiredChoice() => new() { Type = "required" };
137140

138-
/// <summary>The model must call one or more tools.</summary>
139-
public static ToolChoice Required => new() { Type = "required" };
141+
/// <summary>Creates a choice indicating the model must call the specified function.</summary>
142+
/// <exception cref="ArgumentNullException"><paramref name="functionName"/> is null.</exception>
143+
/// <exception cref="ArgumentException"><paramref name="functionName"/> is empty.</exception>
144+
public static ToolChoice CreateFunctionChoice(string functionName)
145+
{
146+
ArgumentNullException.ThrowIfNullOrEmpty(functionName, nameof(functionName));
147+
return new() { Type = "function", Function = new FunctionTool { Name = functionName } };
148+
}
140149

141150
/// <summary>
142151
/// Specifies a specific function tool to call.

sdk/cs/test/FoundryLocal.Tests/ChatCompletionsTests.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// --------------------------------------------------------------------------------------------------------------------
1+
// --------------------------------------------------------------------------------------------------------------------
22
// <copyright company="Microsoft">
33
// Copyright (c) Microsoft. All rights reserved.
44
// </copyright>
@@ -136,7 +136,7 @@ public async Task DirectTool_NoStreaming_Succeeds()
136136

137137
chatClient.Settings.MaxTokens = 500;
138138
chatClient.Settings.Temperature = 0.0f; // for deterministic results
139-
chatClient.Settings.ToolChoice = ToolChoice.Required; // Force the model to make a tool call
139+
chatClient.Settings.ToolChoice = ToolChoice.CreateRequiredChoice(); // Force the model to make a tool call
140140

141141
// Prepare messages and tools
142142
List<ChatMessage> messages =
@@ -202,7 +202,7 @@ public async Task DirectTool_NoStreaming_Succeeds()
202202

203203
// Set tool calling back to auto so that the model can decide whether to call
204204
// the tool again or continue the conversation based on the new user prompt
205-
chatClient.Settings.ToolChoice = ToolChoice.Auto;
205+
chatClient.Settings.ToolChoice = ToolChoice.CreateAutoChoice();
206206

207207
// Run the next turn of the conversation
208208
response = await chatClient.CompleteChatAsync(messages, tools).ConfigureAwait(false);
@@ -220,7 +220,7 @@ public async Task DirectTool_Streaming_Succeeds()
220220

221221
chatClient.Settings.MaxTokens = 500;
222222
chatClient.Settings.Temperature = 0.0f; // for deterministic results
223-
chatClient.Settings.ToolChoice = ToolChoice.Required; // Force the model to make a tool call
223+
chatClient.Settings.ToolChoice = ToolChoice.CreateRequiredChoice(); // Force the model to make a tool call
224224

225225
// Prepare messages and tools
226226
List<ChatMessage> messages =
@@ -306,7 +306,7 @@ public async Task DirectTool_Streaming_Succeeds()
306306

307307
// Set tool calling back to auto so that the model can decide whether to call
308308
// the tool again or continue the conversation based on the new user prompt
309-
chatClient.Settings.ToolChoice = ToolChoice.Auto;
309+
chatClient.Settings.ToolChoice = ToolChoice.CreateAutoChoice();
310310

311311
// Run the next turn of the conversation
312312
updates = chatClient.CompleteChatStreamingAsync(messages, tools, CancellationToken.None).ConfigureAwait(false);

0 commit comments

Comments
 (0)