From 84db9f0516505e3bc625652655ddf53e99e2db75 Mon Sep 17 00:00:00 2001 From: Kang Date: Sun, 27 Sep 2026 21:12:54 +0800 Subject: [PATCH] fix(ai): preserve default reasoning efforts --- src/components/settings/AiTab.test.tsx | 23 +++++++++++++++++++++++ src/components/settings/AiTab.tsx | 9 +++++++-- src/lib/aiSettings.ts | 11 +++++++++-- 3 files changed, 39 insertions(+), 4 deletions(-) diff --git a/src/components/settings/AiTab.test.tsx b/src/components/settings/AiTab.test.tsx index accbc8b6..e625744e 100644 --- a/src/components/settings/AiTab.test.tsx +++ b/src/components/settings/AiTab.test.tsx @@ -105,6 +105,29 @@ describe("AI provider settings", () => { }); }); + it("preserves default reasoning efforts when customizing an unconfigured model", () => { + const initial = settingsWithProviders(); + delete initial.models[0].supported_reasoning_efforts; + render(); + + fireEvent.click(screen.getByRole("button", { name: "ai.editModelConfig" })); + expect(screen.getByRole("button", { name: "none" }).getAttribute("aria-pressed")).toBe("true"); + expect(screen.getByRole("button", { name: "minimal" }).getAttribute("aria-pressed")).toBe( + "false", + ); + expect(screen.getByRole("button", { name: "low" }).getAttribute("aria-pressed")).toBe("true"); + + fireEvent.click(screen.getByRole("button", { name: "minimal" })); + expect(currentSettings.models[0].supported_reasoning_efforts).toEqual([ + "none", + "minimal", + "low", + "medium", + "high", + "xhigh", + ]); + }); + it.each([ ["Ollama", "ollama"], ["OpenAI-compatible", "openai_compatible"], diff --git a/src/components/settings/AiTab.tsx b/src/components/settings/AiTab.tsx index 16c6a5b9..ad8d9cba 100644 --- a/src/components/settings/AiTab.tsx +++ b/src/components/settings/AiTab.tsx @@ -46,6 +46,7 @@ import { aiModelIdForCredential, aiModelIdForProvider, BUILTIN_PROVIDERS, + DEFAULT_MODEL_REASONING_EFFORTS, getCustomProviderBaseUrlPlaceholder, getProviderLabel, isBuiltinProvider, @@ -1409,7 +1410,9 @@ export function AiModelsTab() { }; const toggleModelReasoningEffort = (model: AIModelConfigItem, effort: AIModelReasoningEffort) => { - const selected = new Set(model.supported_reasoning_efforts ?? []); + const selected = new Set( + model.supported_reasoning_efforts ?? DEFAULT_MODEL_REASONING_EFFORTS, + ); if (selected.has(effort)) selected.delete(effort); else selected.add(effort); updateModel(model.id, { @@ -2066,7 +2069,9 @@ export function AiModelsTab() { className="mt-2 flex flex-wrap gap-2" > {MODEL_REASONING_EFFORTS.map((effort) => { - const selected = model.supported_reasoning_efforts?.includes(effort); + const selected = ( + model.supported_reasoning_efforts ?? DEFAULT_MODEL_REASONING_EFFORTS + ).includes(effort); return (