diff --git a/src/Libraries/Microsoft.Extensions.AI.OpenAI/OpenAIChatClient.cs b/src/Libraries/Microsoft.Extensions.AI.OpenAI/OpenAIChatClient.cs index d9f43069490..24387aceb62 100644 --- a/src/Libraries/Microsoft.Extensions.AI.OpenAI/OpenAIChatClient.cs +++ b/src/Libraries/Microsoft.Extensions.AI.OpenAI/OpenAIChatClient.cs @@ -582,22 +582,25 @@ private static ChatCompletionOptions ToOpenAIOptions(ChatOptions? options) } } - switch (options.ToolMode) + if (result.Tools.Count > 0) { - case NoneChatToolMode: - result.ToolChoice = ChatToolChoice.CreateNoneChoice(); - break; - - case AutoChatToolMode: - case null: - result.ToolChoice = ChatToolChoice.CreateAutoChoice(); - break; - - case RequiredChatToolMode required: - result.ToolChoice = required.RequiredFunctionName is null ? - ChatToolChoice.CreateRequiredChoice() : - ChatToolChoice.CreateFunctionChoice(required.RequiredFunctionName); - break; + switch (options.ToolMode) + { + case NoneChatToolMode: + result.ToolChoice = ChatToolChoice.CreateNoneChoice(); + break; + + case AutoChatToolMode: + case null: + result.ToolChoice = ChatToolChoice.CreateAutoChoice(); + break; + + case RequiredChatToolMode required: + result.ToolChoice = required.RequiredFunctionName is null ? + ChatToolChoice.CreateRequiredChoice() : + ChatToolChoice.CreateFunctionChoice(required.RequiredFunctionName); + break; + } } } diff --git a/test/Libraries/Microsoft.Extensions.AI.OpenAI.Tests/OpenAIChatClientTests.cs b/test/Libraries/Microsoft.Extensions.AI.OpenAI.Tests/OpenAIChatClientTests.cs index 78dc920f8cb..2d7ec89b149 100644 --- a/test/Libraries/Microsoft.Extensions.AI.OpenAI.Tests/OpenAIChatClientTests.cs +++ b/test/Libraries/Microsoft.Extensions.AI.OpenAI.Tests/OpenAIChatClientTests.cs @@ -773,6 +773,91 @@ public async Task FunctionCallContent_NonStreaming() Assert.Equal("fp_f85bea6784", response.AdditionalProperties[nameof(ChatCompletion.SystemFingerprint)]); } + [Fact] + public async Task UnavailableBuiltInFunctionCall_NonStreaming() + { + const string Input = """ + { + "messages": [ + { + "role": "user", + "content": "What day is it?" + } + ], + "model": "gpt-4o-mini" + } + """; + + const string Output = """ + { + "id": "chatcmpl-ADydKhrSKEBWJ8gy0KCIU74rN3Hmk", + "object": "chat.completion", + "created": 1727894702, + "model": "gpt-4o-mini-2024-07-18", + "choices": [ + { + "index": 0, + "message": { + "role": "assistant", + "content": "December 31, 2023", + "refusal": null + }, + "logprobs": null, + "finish_reason": "stop" + } + ], + "usage": { + "prompt_tokens": 61, + "completion_tokens": 16, + "total_tokens": 77, + "prompt_tokens_details": { + "cached_tokens": 13 + }, + "completion_tokens_details": { + "reasoning_tokens": 90 + } + }, + "system_fingerprint": "fp_f85bea6784" + } + """; + + using VerbatimHttpHandler handler = new(Input, Output); + using HttpClient httpClient = new(handler); + using IChatClient client = CreateChatClient(httpClient, "gpt-4o-mini"); + + var response = await client.GetResponseAsync("What day is it?", new() + { + Tools = [new HostedWebSearchTool()], + }); + Assert.NotNull(response); + + Assert.Equal("December 31, 2023", response.Text); + Assert.Equal("gpt-4o-mini-2024-07-18", response.ModelId); + Assert.Equal(ChatRole.Assistant, response.Messages.Single().Role); + Assert.Equal(DateTimeOffset.FromUnixTimeSeconds(1_727_894_702), response.CreatedAt); + Assert.Equal(ChatFinishReason.Stop, response.FinishReason); + Assert.NotNull(response.Usage); + Assert.Equal(61, response.Usage.InputTokenCount); + Assert.Equal(16, response.Usage.OutputTokenCount); + Assert.Equal(77, response.Usage.TotalTokenCount); + + Assert.Equal(new Dictionary + { + { "InputTokenDetails.AudioTokenCount", 0 }, + { "InputTokenDetails.CachedTokenCount", 13 }, + { "OutputTokenDetails.ReasoningTokenCount", 90 }, + { "OutputTokenDetails.AudioTokenCount", 0 }, + { "OutputTokenDetails.AcceptedPredictionTokenCount", 0 }, + { "OutputTokenDetails.RejectedPredictionTokenCount", 0 }, + }, response.Usage.AdditionalCounts); + + Assert.Single(response.Messages.Single().Contents); + TextContent fcc = Assert.IsType(response.Messages.Single().Contents[0]); + + Assert.NotNull(response.AdditionalProperties); + Assert.Equal("fp_f85bea6784", response.AdditionalProperties[nameof(ChatCompletion.SystemFingerprint)]); + } + [Fact] public async Task FunctionCallContent_Streaming() {