feat: add option to omit tool_choice param for Azure/LiteLLM compatibility

Adds openAiOmitToolChoice setting to the OpenAI provider that allows users
to optionally omit the tool_choice parameter from API requests. This
resolves 400 errors when using Azure-hosted models (like GPT-5) through
LiteLLM proxies that do not support the tool_choice parameter.

Closes: #10701
This commit is contained in:
Roo Code 2026-01-13 22:18:40 +00:00
parent 83037104c6
commit b292902bfc
4 changed files with 17 additions and 4 deletions

View file

@ -250,6 +250,7 @@ const openAiSchema = baseProviderSettingsSchema.extend({
openAiStreamingEnabled: z.boolean().optional(),
openAiHostHeader: z.string().optional(), // Keep temporarily for backward compatibility during migration.
openAiHeaders: z.record(z.string(), z.string()).optional(),
openAiOmitToolChoice: z.boolean().optional(), // Omit tool_choice param for Azure/LiteLLM compatibility.
})
const ollamaSchema = baseProviderSettingsSchema.extend({

View file

@ -161,7 +161,7 @@ export class OpenAiHandler extends BaseProvider implements SingleCompletionHandl
...(isGrokXAI ? {} : { stream_options: { include_usage: true } }),
...(reasoning && reasoning),
...(metadata?.tools && { tools: this.convertToolsForOpenAI(metadata.tools) }),
...(metadata?.tool_choice && { tool_choice: metadata.tool_choice }),
...(metadata?.tool_choice && !this.options.openAiOmitToolChoice && { tool_choice: metadata.tool_choice }),
...(metadata?.toolProtocol === "native" &&
metadata.parallelToolCalls === true && {
parallel_tool_calls: true,
@ -231,7 +231,7 @@ export class OpenAiHandler extends BaseProvider implements SingleCompletionHandl
? convertToR1Format([{ role: "user", content: systemPrompt }, ...messages])
: [systemMessage, ...convertToOpenAiMessages(messages)],
...(metadata?.tools && { tools: this.convertToolsForOpenAI(metadata.tools) }),
...(metadata?.tool_choice && { tool_choice: metadata.tool_choice }),
...(metadata?.tool_choice && !this.options.openAiOmitToolChoice && { tool_choice: metadata.tool_choice }),
...(metadata?.toolProtocol === "native" &&
metadata.parallelToolCalls === true && {
parallel_tool_calls: true,
@ -358,7 +358,7 @@ export class OpenAiHandler extends BaseProvider implements SingleCompletionHandl
reasoning_effort: modelInfo.reasoningEffort as "low" | "medium" | "high" | undefined,
temperature: undefined,
...(metadata?.tools && { tools: this.convertToolsForOpenAI(metadata.tools) }),
...(metadata?.tool_choice && { tool_choice: metadata.tool_choice }),
...(metadata?.tool_choice && !this.options.openAiOmitToolChoice && { tool_choice: metadata.tool_choice }),
...(metadata?.toolProtocol === "native" &&
metadata.parallelToolCalls === true && {
parallel_tool_calls: true,
@ -394,7 +394,7 @@ export class OpenAiHandler extends BaseProvider implements SingleCompletionHandl
reasoning_effort: modelInfo.reasoningEffort as "low" | "medium" | "high" | undefined,
temperature: undefined,
...(metadata?.tools && { tools: this.convertToolsForOpenAI(metadata.tools) }),
...(metadata?.tool_choice && { tool_choice: metadata.tool_choice }),
...(metadata?.tool_choice && !this.options.openAiOmitToolChoice && { tool_choice: metadata.tool_choice }),
...(metadata?.toolProtocol === "native" &&
metadata.parallelToolCalls === true && {
parallel_tool_calls: true,

View file

@ -173,6 +173,16 @@ export const OpenAICompatible = ({
onChange={handleInputChange("openAiUseAzure", noTransform)}>
{t("settings:modelInfo.useAzure")}
</Checkbox>
<div>
<Checkbox
checked={apiConfiguration?.openAiOmitToolChoice ?? false}
onChange={handleInputChange("openAiOmitToolChoice", noTransform)}>
{t("settings:modelInfo.omitToolChoice")}
</Checkbox>
<div className="text-sm text-vscode-descriptionForeground ml-6">
{t("settings:modelInfo.omitToolChoiceTips")}
</div>
</div>
<div>
<Checkbox
checked={azureApiVersionSelected}

View file

@ -878,6 +878,8 @@
"enableR1Format": "Enable R1 model parameters",
"enableR1FormatTips": "Must be enabled when using R1 models such as QWQ to prevent 400 errors",
"useAzure": "Use Azure",
"omitToolChoice": "Omit tool_choice parameter",
"omitToolChoiceTips": "Enable this if your Azure or LiteLLM endpoint doesn't support the tool_choice parameter",
"azureApiVersion": "Set Azure API version",
"gemini": {
"freeRequests": "* Free up to {{count}} requests per minute. After that, billing depends on prompt size.",