From c43a5a8e359835b4133f98ef82929f80227991bd Mon Sep 17 00:00:00 2001 From: Roo Code Date: Tue, 10 Mar 2026 11:16:54 +0000 Subject: [PATCH] fix: auto-enable R1 format for models with preserveReasoning in preset picker When selecting a model preset with preserveReasoning (e.g. Kimi K2.5, Kimi K2 thinking), the R1 format setting is now automatically enabled so reasoning/thinking blocks work correctly via OpenAI Compatible endpoints. Also adds visual indicator showing applied capability flags after selecting a preset, and new tests covering the auto-enable behavior. --- .../settings/providers/OpenAICompatible.tsx | 28 +++++++++++++ .../__tests__/OpenAICompatible.spec.tsx | 41 +++++++++++++++++++ webview-ui/src/i18n/locales/en/settings.json | 9 +++- 3 files changed, 77 insertions(+), 1 deletion(-) diff --git a/webview-ui/src/components/settings/providers/OpenAICompatible.tsx b/webview-ui/src/components/settings/providers/OpenAICompatible.tsx index 9a50aace57..8609652a9d 100644 --- a/webview-ui/src/components/settings/providers/OpenAICompatible.tsx +++ b/webview-ui/src/components/settings/providers/OpenAICompatible.tsx @@ -64,6 +64,22 @@ export const OpenAICompatible = ({ const [openAiModels, setOpenAiModels] = useState | null>(null) + // Compute applied capability flags for the selected preset + const appliedCapabilityFlags = useMemo(() => { + if (!selectedPresetId) return null + const preset = modelCapabilityPresets.find((p) => `${p.provider}/${p.modelId}` === selectedPresetId) + if (!preset) return null + const flags: string[] = [] + if (preset.info.preserveReasoning) + flags.push(t("settings:providers.customModel.capabilityPreset.flags.reasoning")) + if (preset.info.supportsImages) flags.push(t("settings:providers.customModel.capabilityPreset.flags.images")) + if (preset.info.supportsPromptCache) + flags.push(t("settings:providers.customModel.capabilityPreset.flags.promptCache")) + if (preset.info.supportsTemperature) + flags.push(t("settings:providers.customModel.capabilityPreset.flags.temperature")) + return flags.length > 0 ? flags : null + }, [selectedPresetId, t]) + // Group presets by provider for organized display const groupedPresets = useMemo(() => { const groups: Record = {} @@ -81,11 +97,17 @@ export const OpenAICompatible = ({ if (presetKey === "custom") { setSelectedPresetId(null) setApiConfigurationField("openAiCustomModelInfo", openAiModelInfoSaneDefaults) + setApiConfigurationField("openAiR1FormatEnabled", false) } else { const preset = modelCapabilityPresets.find((p) => `${p.provider}/${p.modelId}` === presetKey) if (preset) { setSelectedPresetId(presetKey) setApiConfigurationField("openAiCustomModelInfo", { ...preset.info }) + + // Auto-enable R1 format for models that use reasoning/thinking blocks + if (preset.info.preserveReasoning) { + setApiConfigurationField("openAiR1FormatEnabled", true) + } } } setPresetPickerOpen(false) @@ -398,6 +420,12 @@ export const OpenAICompatible = ({ + {appliedCapabilityFlags && ( +
+ {t("settings:providers.customModel.capabilityPreset.appliedFlags")}:{" "} + {appliedCapabilityFlags.join(", ")} +
+ )}
diff --git a/webview-ui/src/components/settings/providers/__tests__/OpenAICompatible.spec.tsx b/webview-ui/src/components/settings/providers/__tests__/OpenAICompatible.spec.tsx index 7422cbd3c0..e69b8233d9 100644 --- a/webview-ui/src/components/settings/providers/__tests__/OpenAICompatible.spec.tsx +++ b/webview-ui/src/components/settings/providers/__tests__/OpenAICompatible.spec.tsx @@ -430,4 +430,45 @@ describe("OpenAICompatible Component - Model Capability Presets", () => { }), ) }) + + it("should reset openAiR1FormatEnabled when selecting custom preset", () => { + const apiConfiguration: Partial = {} + + render( + , + ) + + const customItem = screen.getByTestId("command-item-custom") + fireEvent.click(customItem) + + expect(mockSetApiConfigurationField).toHaveBeenCalledWith("openAiR1FormatEnabled", false) + }) + + it("should auto-enable openAiR1FormatEnabled when selecting a model with preserveReasoning", () => { + const apiConfiguration: Partial = {} + + render( + , + ) + + // Click on a Kimi K2.5 model which has preserveReasoning: true + const kimiItem = screen.getByTestId("command-item-Moonshot (Kimi)/kimi-k2.5") + fireEvent.click(kimiItem) + + expect(mockSetApiConfigurationField).toHaveBeenCalledWith("openAiR1FormatEnabled", true) + expect(mockSetApiConfigurationField).toHaveBeenCalledWith( + "openAiCustomModelInfo", + expect.objectContaining({ + preserveReasoning: true, + }), + ) + }) }) diff --git a/webview-ui/src/i18n/locales/en/settings.json b/webview-ui/src/i18n/locales/en/settings.json index a0dcc1a9ce..066a0dd46a 100644 --- a/webview-ui/src/i18n/locales/en/settings.json +++ b/webview-ui/src/i18n/locales/en/settings.json @@ -549,7 +549,14 @@ "custom": "Custom (configure manually)", "searchPlaceholder": "Search models...", "noResults": "No matching models found.", - "applied": "Applied capabilities from {{model}}" + "applied": "Applied capabilities from {{model}}", + "appliedFlags": "Applied capabilities", + "flags": { + "reasoning": "Reasoning/Thinking", + "images": "Image Support", + "promptCache": "Prompt Cache", + "temperature": "Temperature Control" + } }, "capabilities": "Configure the capabilities and pricing for your custom OpenAI-compatible model. Be careful when specifying the model capabilities, as they can affect how Roo Code performs.", "maxTokens": {