From e620a0be35ed1ff1a58e665a7e67bfba28085e07 Mon Sep 17 00:00:00 2001 From: Ammar Date: Fri, 16 Jan 2026 11:27:35 -0600 Subject: [PATCH 1/7] fix: allow gpt-5.2 preview suffix in thinking policy --- src/common/utils/thinking/policy.test.ts | 9 +++++++++ src/common/utils/thinking/policy.ts | 9 ++++++--- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/common/utils/thinking/policy.test.ts b/src/common/utils/thinking/policy.test.ts index af8d430dcd..1639766f9d 100644 --- a/src/common/utils/thinking/policy.test.ts +++ b/src/common/utils/thinking/policy.test.ts @@ -64,6 +64,15 @@ describe("getThinkingPolicyForModel", () => { ]); }); + test("returns 5 levels including xhigh for gpt-5.2-codex preview suffix", () => { + expect(getThinkingPolicyForModel("openai:gpt-5.2-codex-2025-12-11-preview")).toEqual([ + "off", + "low", + "medium", + "high", + "xhigh", + ]); + }); test("returns 5 levels including xhigh for gpt-5.2-codex", () => { expect(getThinkingPolicyForModel("openai:gpt-5.2-codex")).toEqual([ "off", diff --git a/src/common/utils/thinking/policy.ts b/src/common/utils/thinking/policy.ts index ac76a20840..861326f83d 100644 --- a/src/common/utils/thinking/policy.ts +++ b/src/common/utils/thinking/policy.ts @@ -53,17 +53,20 @@ export function getThinkingPolicyForModel(modelString: string): ThinkingPolicy { } // GPT-5.2-Codex supports 5 reasoning levels including xhigh (Extra High) - if (/^gpt-5\.2-codex(?!-[a-z])/.test(withoutProviderNamespace)) { + // Allow version suffixes like -2025-12-11-preview, but exclude mini variants. + if (/^gpt-5\.2-codex(?!-mini\b)/.test(withoutProviderNamespace)) { return ["off", "low", "medium", "high", "xhigh"]; } // gpt-5.2-pro supports medium, high, xhigh reasoning levels - if (/^gpt-5\.2-pro(?!-[a-z])/.test(withoutProviderNamespace)) { + // Allow version suffixes like -2025-12-11-preview, but exclude mini variants. + if (/^gpt-5\.2-pro(?!-mini\b)/.test(withoutProviderNamespace)) { return ["medium", "high", "xhigh"]; } // gpt-5.2 supports 5 reasoning levels including xhigh (Extra High) - if (/^gpt-5\.2(?!-[a-z])/.test(withoutProviderNamespace)) { + // Allow version suffixes like -2025-12-11-preview, but exclude mini variants. + if (/^gpt-5\.2(?!-mini\b)/.test(withoutProviderNamespace)) { return ["off", "low", "medium", "high", "xhigh"]; } From f7b4f6824deefc73864ef213fa75cf289e19ed41 Mon Sep 17 00:00:00 2001 From: Ammar Date: Fri, 16 Jan 2026 11:32:44 -0600 Subject: [PATCH 2/7] fix: align thinking toggle model source --- src/browser/contexts/ThinkingContext.tsx | 34 ++++++++++++------------ 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/browser/contexts/ThinkingContext.tsx b/src/browser/contexts/ThinkingContext.tsx index 2a55d452ac..e62abc2920 100644 --- a/src/browser/contexts/ThinkingContext.tsx +++ b/src/browser/contexts/ThinkingContext.tsx @@ -38,17 +38,20 @@ function getScopeId(workspaceId: string | undefined, projectPath: string | undef return workspaceId ?? (projectPath ? getProjectScopeId(projectPath) : GLOBAL_SCOPE_ID); } -function getCanonicalModelForScope(scopeId: string, fallbackModel: string): string { - const rawModel = readPersistedState(getModelKey(scopeId), fallbackModel); - return migrateGatewayModel(rawModel || fallbackModel); -} - export const ThinkingProvider: React.FC = (props) => { const { api } = useAPI(); const defaultModel = getDefaultModel(); const scopeId = getScopeId(props.workspaceId, props.projectPath); const thinkingKey = getThinkingLevelKey(scopeId); + const [rawModel] = usePersistedState(getModelKey(scopeId), defaultModel, { + listener: true, + }); + const canonicalModel = useMemo( + () => migrateGatewayModel(rawModel || defaultModel), + [rawModel, defaultModel] + ); + // Workspace-scoped thinking. (No longer per-model.) const [thinkingLevel, setThinkingLevelInternal] = usePersistedState( thinkingKey, @@ -63,21 +66,19 @@ export const ThinkingProvider: React.FC = (props) => { return; } - const model = getCanonicalModelForScope(scopeId, defaultModel); - const legacyKey = getThinkingLevelByModelKey(model); + const legacyKey = getThinkingLevelByModelKey(canonicalModel); const legacy = readPersistedState(legacyKey, undefined); if (legacy === undefined) { return; } - const effective = enforceThinkingPolicy(model, legacy); + const effective = enforceThinkingPolicy(canonicalModel, legacy); updatePersistedState(thinkingKey, effective); - }, [defaultModel, scopeId, thinkingKey]); + }, [canonicalModel, thinkingKey]); const setThinkingLevel = useCallback( (level: ThinkingLevel) => { - const model = getCanonicalModelForScope(scopeId, defaultModel); - const effective = enforceThinkingPolicy(model, level); + const effective = enforceThinkingPolicy(canonicalModel, level); setThinkingLevelInternal(effective); @@ -99,7 +100,7 @@ export const ThinkingProvider: React.FC = (props) => { prev && typeof prev === "object" ? prev : {}; return { ...record, - [agentId]: { model, thinkingLevel: effective }, + [agentId]: { model: canonicalModel, thinkingLevel: effective }, }; }, {} @@ -115,13 +116,13 @@ export const ThinkingProvider: React.FC = (props) => { .updateModeAISettings({ workspaceId: props.workspaceId, mode: agentId, - aiSettings: { model, thinkingLevel: effective }, + aiSettings: { model: canonicalModel, thinkingLevel: effective }, }) .catch(() => { // Best-effort only. If offline or backend is old, the next sendMessage will persist. }); }, - [api, defaultModel, props.workspaceId, scopeId, setThinkingLevelInternal] + [api, canonicalModel, props.workspaceId, scopeId, setThinkingLevelInternal] ); // Global keybind: cycle thinking level (Ctrl/Cmd+Shift+T). @@ -135,8 +136,7 @@ export const ThinkingProvider: React.FC = (props) => { e.preventDefault(); - const model = getCanonicalModelForScope(scopeId, defaultModel); - const allowed = getThinkingPolicyForModel(model); + const allowed = getThinkingPolicyForModel(canonicalModel); if (allowed.length <= 1) { return; } @@ -148,7 +148,7 @@ export const ThinkingProvider: React.FC = (props) => { window.addEventListener("keydown", handleKeyDown); return () => window.removeEventListener("keydown", handleKeyDown); - }, [defaultModel, scopeId, thinkingLevel, setThinkingLevel]); + }, [canonicalModel, thinkingLevel, setThinkingLevel]); // Memoize context value to prevent unnecessary re-renders of consumers. const contextValue = useMemo( From a0900fd7246f005e12a31c2d857a88730c73987d Mon Sep 17 00:00:00 2001 From: Ammar Date: Fri, 16 Jan 2026 11:37:49 -0600 Subject: [PATCH 3/7] fix: sync thinking slider with toggle --- src/browser/components/ChatInput/index.tsx | 2 +- src/browser/components/ThinkingSlider.tsx | 8 +++----- src/browser/contexts/ThinkingContext.tsx | 8 ++++++-- src/common/utils/thinking/policy.test.ts | 18 ++++++++++++++++++ src/common/utils/thinking/policy.ts | 4 ++-- 5 files changed, 30 insertions(+), 10 deletions(-) diff --git a/src/browser/components/ChatInput/index.tsx b/src/browser/components/ChatInput/index.tsx index 9caddbfae1..bb208b7094 100644 --- a/src/browser/components/ChatInput/index.tsx +++ b/src/browser/components/ChatInput/index.tsx @@ -2268,7 +2268,7 @@ const ChatInputInner: React.FC = (props) => { className="flex items-center [&_.thinking-slider]:[@container(max-width:550px)]:hidden" data-component="ThinkingSliderGroup" > - +
diff --git a/src/browser/components/ThinkingSlider.tsx b/src/browser/components/ThinkingSlider.tsx index 792c28538c..05c96e5d14 100644 --- a/src/browser/components/ThinkingSlider.tsx +++ b/src/browser/components/ThinkingSlider.tsx @@ -1,5 +1,6 @@ import React, { useEffect, useId } from "react"; import type { ThinkingLevel } from "@/common/types/thinking"; +import { useThinkingModel } from "@/browser/contexts/ThinkingContext"; import { useThinkingLevel } from "@/browser/hooks/useThinkingLevel"; import { Tooltip, TooltipTrigger, TooltipContent } from "./ui/tooltip"; import { formatKeybind, KEYBINDS } from "@/browser/utils/ui/keybinds"; @@ -59,12 +60,9 @@ const getSliderStyles = (value: number, isHover = false) => { }; }; -interface ThinkingControlProps { - modelString: string; -} - -export const ThinkingSliderComponent: React.FC = ({ modelString }) => { +export const ThinkingSliderComponent: React.FC = () => { const [thinkingLevel, setThinkingLevel] = useThinkingLevel(); + const modelString = useThinkingModel(); const [isHovering, setIsHovering] = React.useState(false); const sliderId = useId(); const allowed = getThinkingPolicyForModel(modelString); diff --git a/src/browser/contexts/ThinkingContext.tsx b/src/browser/contexts/ThinkingContext.tsx index e62abc2920..bfe0559404 100644 --- a/src/browser/contexts/ThinkingContext.tsx +++ b/src/browser/contexts/ThinkingContext.tsx @@ -22,6 +22,7 @@ import { useAPI } from "@/browser/contexts/API"; import { KEYBINDS, matchesKeybind } from "@/browser/utils/ui/keybinds"; interface ThinkingContextType { + model: string; thinkingLevel: ThinkingLevel; setThinkingLevel: (level: ThinkingLevel) => void; } @@ -152,13 +153,16 @@ export const ThinkingProvider: React.FC = (props) => { // Memoize context value to prevent unnecessary re-renders of consumers. const contextValue = useMemo( - () => ({ thinkingLevel, setThinkingLevel }), - [thinkingLevel, setThinkingLevel] + () => ({ model: canonicalModel, thinkingLevel, setThinkingLevel }), + [canonicalModel, thinkingLevel, setThinkingLevel] ); return {props.children}; }; +export const useThinkingModel = () => { + return useThinking().model; +}; export const useThinking = () => { const context = useContext(ThinkingContext); if (!context) { diff --git a/src/common/utils/thinking/policy.test.ts b/src/common/utils/thinking/policy.test.ts index 1639766f9d..44b5f8a70c 100644 --- a/src/common/utils/thinking/policy.test.ts +++ b/src/common/utils/thinking/policy.test.ts @@ -122,6 +122,24 @@ describe("getThinkingPolicyForModel", () => { "xhigh", ]); }); + + test("returns default levels for gpt-5.2-pro-mini", () => { + expect(getThinkingPolicyForModel("openai:gpt-5.2-pro-mini")).toEqual([ + "off", + "low", + "medium", + "high", + ]); + }); + + test("returns default levels for gpt-5.2-codex-mini", () => { + expect(getThinkingPolicyForModel("openai:gpt-5.2-codex-mini")).toEqual([ + "off", + "low", + "medium", + "high", + ]); + }); test("returns medium/high/xhigh for gpt-5.2-pro with version suffix", () => { expect(getThinkingPolicyForModel("openai:gpt-5.2-pro-2025-12-11")).toEqual([ "medium", diff --git a/src/common/utils/thinking/policy.ts b/src/common/utils/thinking/policy.ts index 861326f83d..bb467495e2 100644 --- a/src/common/utils/thinking/policy.ts +++ b/src/common/utils/thinking/policy.ts @@ -65,8 +65,8 @@ export function getThinkingPolicyForModel(modelString: string): ThinkingPolicy { } // gpt-5.2 supports 5 reasoning levels including xhigh (Extra High) - // Allow version suffixes like -2025-12-11-preview, but exclude mini variants. - if (/^gpt-5\.2(?!-mini\b)/.test(withoutProviderNamespace)) { + // Allow version suffixes like -2025-12-11-preview, but exclude any mini variants. + if (/^gpt-5\.2(?!.*-mini\b)/.test(withoutProviderNamespace)) { return ["off", "low", "medium", "high", "xhigh"]; } From 1b77284a3d075f6cab1e1d6f5ea499ffa00e3976 Mon Sep 17 00:00:00 2001 From: Ammar Date: Fri, 16 Jan 2026 11:55:30 -0600 Subject: [PATCH 4/7] =?UTF-8?q?=F0=9F=A4=96=20fix:=20ignore=20repeat=20key?= =?UTF-8?q?down=20for=20thinking?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/browser/contexts/ThinkingContext.tsx | 4 ++ tests/ui/thinkingKeybind.integration.test.ts | 74 ++++++++++++++++++++ 2 files changed, 78 insertions(+) create mode 100644 tests/ui/thinkingKeybind.integration.test.ts diff --git a/src/browser/contexts/ThinkingContext.tsx b/src/browser/contexts/ThinkingContext.tsx index bfe0559404..2d3f6671ad 100644 --- a/src/browser/contexts/ThinkingContext.tsx +++ b/src/browser/contexts/ThinkingContext.tsx @@ -135,6 +135,10 @@ export const ThinkingProvider: React.FC = (props) => { return; } + if (e.repeat) { + return; + } + e.preventDefault(); const allowed = getThinkingPolicyForModel(canonicalModel); diff --git a/tests/ui/thinkingKeybind.integration.test.ts b/tests/ui/thinkingKeybind.integration.test.ts new file mode 100644 index 0000000000..0ecb64d1fc --- /dev/null +++ b/tests/ui/thinkingKeybind.integration.test.ts @@ -0,0 +1,74 @@ +import { act, waitFor } from "@testing-library/react"; + +import { updatePersistedState } from "@/browser/hooks/usePersistedState"; +import { getModelKey, getThinkingLevelKey } from "@/common/constants/storage"; + +import { createAppHarness } from "./harness"; + +describe("Thinking keybind (UI)", () => { + test("cycles to xhigh for gpt-5.2-codex", async () => { + const app = await createAppHarness({ branchPrefix: "thinking-keybind" }); + + try { + const model = "openai:gpt-5.2-codex-2025-12-11-preview"; + + act(() => { + updatePersistedState(getModelKey(app.workspaceId), model); + updatePersistedState(getThinkingLevelKey(app.workspaceId), "high"); + }); + + await waitFor(() => { + const slider = app.view.getByLabelText("Thinking level") as HTMLInputElement | null; + if (!slider) { + throw new Error("Thinking slider not found"); + } + if (slider.getAttribute("aria-valuetext") !== "high") { + throw new Error("Thinking level has not updated to high"); + } + }); + + act(() => { + window.dispatchEvent( + new window.KeyboardEvent("keydown", { + key: "T", + ctrlKey: true, + shiftKey: true, + }) + ); + }); + + await waitFor(() => { + const slider = app.view.getByLabelText("Thinking level") as HTMLInputElement | null; + if (!slider) { + throw new Error("Thinking slider not found"); + } + if (slider.getAttribute("aria-valuetext") !== "xhigh") { + throw new Error("Thinking level did not advance to xhigh"); + } + }); + + act(() => { + window.dispatchEvent( + new window.KeyboardEvent("keydown", { + key: "T", + ctrlKey: true, + shiftKey: true, + repeat: true, + }) + ); + }); + + await waitFor(() => { + const slider = app.view.getByLabelText("Thinking level") as HTMLInputElement | null; + if (!slider) { + throw new Error("Thinking slider not found"); + } + if (slider.getAttribute("aria-valuetext") !== "xhigh") { + throw new Error("Thinking level should ignore repeated keydown"); + } + }); + } finally { + await app.dispose(); + } + }); +}); From 2c87171c4a56ed90a2ebaa97bb479c815e69ad4d Mon Sep 17 00:00:00 2001 From: Ammar Date: Fri, 16 Jan 2026 12:19:27 -0600 Subject: [PATCH 5/7] =?UTF-8?q?=F0=9F=A4=96=20tests:=20use=20/model=20code?= =?UTF-8?q?x=20in=20thinking=20keybind=20UI=20test?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/ui/thinkingKeybind.integration.test.ts | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/tests/ui/thinkingKeybind.integration.test.ts b/tests/ui/thinkingKeybind.integration.test.ts index 0ecb64d1fc..5a8c31c92d 100644 --- a/tests/ui/thinkingKeybind.integration.test.ts +++ b/tests/ui/thinkingKeybind.integration.test.ts @@ -1,19 +1,24 @@ import { act, waitFor } from "@testing-library/react"; -import { updatePersistedState } from "@/browser/hooks/usePersistedState"; +import { readPersistedState, updatePersistedState } from "@/browser/hooks/usePersistedState"; import { getModelKey, getThinkingLevelKey } from "@/common/constants/storage"; import { createAppHarness } from "./harness"; describe("Thinking keybind (UI)", () => { - test("cycles to xhigh for gpt-5.2-codex", async () => { + test("cycles to xhigh for gpt-5.2-codex (selected via /model)", async () => { const app = await createAppHarness({ branchPrefix: "thinking-keybind" }); try { - const model = "openai:gpt-5.2-codex-2025-12-11-preview"; + await app.chat.send("/model codex"); + await waitFor(() => { + const model = readPersistedState(getModelKey(app.workspaceId), ""); + expect(model).toBe("openai:gpt-5.2-codex"); + }); + + // Start from a deterministic thinking level so we can assert the next step. act(() => { - updatePersistedState(getModelKey(app.workspaceId), model); updatePersistedState(getThinkingLevelKey(app.workspaceId), "high"); }); @@ -25,6 +30,9 @@ describe("Thinking keybind (UI)", () => { if (slider.getAttribute("aria-valuetext") !== "high") { throw new Error("Thinking level has not updated to high"); } + + // 5 allowed levels means max index 4. + expect(slider.getAttribute("aria-valuemax")).toBe("4"); }); act(() => { From 920e3f926cf9ec8d4fc2825321fe2918726d943a Mon Sep 17 00:00:00 2001 From: Ammar Date: Fri, 16 Jan 2026 12:35:33 -0600 Subject: [PATCH 6/7] =?UTF-8?q?=F0=9F=A4=96=20fix:=20normalize=20model=20d?= =?UTF-8?q?efaults=20for=20thinking=20policy?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/WorkspaceModeAISync.tsx | 10 ++- tests/ui/thinkingKeybind.integration.test.ts | 77 +++++++++++++++---- 2 files changed, 71 insertions(+), 16 deletions(-) diff --git a/src/browser/components/WorkspaceModeAISync.tsx b/src/browser/components/WorkspaceModeAISync.tsx index 41de181521..2c5afafe06 100644 --- a/src/browser/components/WorkspaceModeAISync.tsx +++ b/src/browser/components/WorkspaceModeAISync.tsx @@ -14,6 +14,8 @@ import { MODE_AI_DEFAULTS_KEY, } from "@/common/constants/storage"; import { getDefaultModel } from "@/browser/hooks/useModelsFromSettings"; +import { migrateGatewayModel } from "@/browser/hooks/useGatewayModels"; +import { resolveModelAlias } from "@/common/utils/ai/models"; import { enforceThinkingPolicy } from "@/common/utils/thinking/policy"; import { coerceThinkingLevel, type ThinkingLevel } from "@/common/types/thinking"; import type { ModeAiDefaults } from "@/common/types/modeAiDefaults"; @@ -75,6 +77,8 @@ export function WorkspaceModeAISync(props: { workspaceId: string }): null { typeof candidateModel === "string" && candidateModel.trim().length > 0 ? candidateModel : fallbackModel; + const canonicalModel = migrateGatewayModel(resolveModelAlias(resolvedModel.trim())); + const effectiveModel = canonicalModel.trim().length > 0 ? canonicalModel : fallbackModel; const existingThinking = readPersistedState(thinkingKey, "off"); const candidateThinking = @@ -86,10 +90,10 @@ export function WorkspaceModeAISync(props: { workspaceId: string }): null { "off"; const resolvedThinking = coerceThinkingLevel(candidateThinking) ?? "off"; - const effectiveThinking = enforceThinkingPolicy(resolvedModel, resolvedThinking); + const effectiveThinking = enforceThinkingPolicy(effectiveModel, resolvedThinking); - if (existingModel !== resolvedModel) { - updatePersistedState(modelKey, resolvedModel); + if (existingModel !== effectiveModel) { + updatePersistedState(modelKey, effectiveModel); } if (existingThinking !== effectiveThinking) { diff --git a/tests/ui/thinkingKeybind.integration.test.ts b/tests/ui/thinkingKeybind.integration.test.ts index 5a8c31c92d..f3e0d09654 100644 --- a/tests/ui/thinkingKeybind.integration.test.ts +++ b/tests/ui/thinkingKeybind.integration.test.ts @@ -1,11 +1,71 @@ import { act, waitFor } from "@testing-library/react"; import { readPersistedState, updatePersistedState } from "@/browser/hooks/usePersistedState"; -import { getModelKey, getThinkingLevelKey } from "@/common/constants/storage"; +import { getModelKey, getThinkingLevelKey, MODE_AI_DEFAULTS_KEY } from "@/common/constants/storage"; +import type { ModeAiDefaults } from "@/common/types/modeAiDefaults"; + +const getActiveThinkingSlider = (container: HTMLElement): HTMLInputElement => { + const sliders = Array.from( + container.querySelectorAll('input[aria-label="Thinking level"]') + ) as HTMLInputElement[]; + + if (sliders.length === 0) { + throw new Error("Thinking slider not found"); + } + + return sliders[sliders.length - 1]; +}; import { createAppHarness } from "./harness"; describe("Thinking keybind (UI)", () => { + test("normalizes codex alias in mode defaults", async () => { + const app = await createAppHarness({ branchPrefix: "thinking-keybind-defaults" }); + + try { + act(() => { + updatePersistedState(MODE_AI_DEFAULTS_KEY, { + exec: { modelString: "codex", thinkingLevel: "high" }, + }); + }); + + await waitFor(() => { + const model = readPersistedState(getModelKey(app.workspaceId), ""); + expect(model).toBe("openai:gpt-5.2-codex"); + }); + + await waitFor(() => { + const slider = getActiveThinkingSlider(app.view.container); + if (slider.getAttribute("aria-valuetext") !== "high") { + throw new Error("Thinking level has not updated to high"); + } + expect(slider.getAttribute("aria-valuemax")).toBe("4"); + }); + + act(() => { + window.dispatchEvent( + new window.KeyboardEvent("keydown", { + key: "T", + ctrlKey: true, + shiftKey: true, + }) + ); + }); + + await waitFor(() => { + const slider = getActiveThinkingSlider(app.view.container); + if (slider.getAttribute("aria-valuetext") !== "xhigh") { + throw new Error("Thinking level did not advance to xhigh"); + } + }); + } finally { + act(() => { + updatePersistedState(MODE_AI_DEFAULTS_KEY, {}); + }); + await app.dispose(); + } + }); + test("cycles to xhigh for gpt-5.2-codex (selected via /model)", async () => { const app = await createAppHarness({ branchPrefix: "thinking-keybind" }); @@ -23,10 +83,7 @@ describe("Thinking keybind (UI)", () => { }); await waitFor(() => { - const slider = app.view.getByLabelText("Thinking level") as HTMLInputElement | null; - if (!slider) { - throw new Error("Thinking slider not found"); - } + const slider = getActiveThinkingSlider(app.view.container); if (slider.getAttribute("aria-valuetext") !== "high") { throw new Error("Thinking level has not updated to high"); } @@ -46,10 +103,7 @@ describe("Thinking keybind (UI)", () => { }); await waitFor(() => { - const slider = app.view.getByLabelText("Thinking level") as HTMLInputElement | null; - if (!slider) { - throw new Error("Thinking slider not found"); - } + const slider = getActiveThinkingSlider(app.view.container); if (slider.getAttribute("aria-valuetext") !== "xhigh") { throw new Error("Thinking level did not advance to xhigh"); } @@ -67,10 +121,7 @@ describe("Thinking keybind (UI)", () => { }); await waitFor(() => { - const slider = app.view.getByLabelText("Thinking level") as HTMLInputElement | null; - if (!slider) { - throw new Error("Thinking slider not found"); - } + const slider = getActiveThinkingSlider(app.view.container); if (slider.getAttribute("aria-valuetext") !== "xhigh") { throw new Error("Thinking level should ignore repeated keydown"); } From 660cf2862b5ae40ad8e57e9813f46a7777dc2144 Mon Sep 17 00:00:00 2001 From: Ammar Date: Fri, 16 Jan 2026 12:44:33 -0600 Subject: [PATCH 7/7] =?UTF-8?q?=F0=9F=A4=96=20refactor:=20simplify=20model?= =?UTF-8?q?=20normalization=20in=20workspace=20sync?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/browser/components/WorkspaceModeAISync.tsx | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/browser/components/WorkspaceModeAISync.tsx b/src/browser/components/WorkspaceModeAISync.tsx index 2c5afafe06..bb06ea4ed5 100644 --- a/src/browser/components/WorkspaceModeAISync.tsx +++ b/src/browser/components/WorkspaceModeAISync.tsx @@ -21,6 +21,16 @@ import { coerceThinkingLevel, type ThinkingLevel } from "@/common/types/thinking import type { ModeAiDefaults } from "@/common/types/modeAiDefaults"; import type { AgentAiDefaults } from "@/common/types/agentAiDefaults"; +const normalizeModelString = (model: string, fallback: string): string => { + const trimmed = model.trim(); + if (!trimmed) { + return fallback; + } + + const canonical = migrateGatewayModel(resolveModelAlias(trimmed)).trim(); + return canonical.length > 0 ? canonical : fallback; +}; + type WorkspaceAISettingsCache = Partial< Record >; @@ -77,8 +87,7 @@ export function WorkspaceModeAISync(props: { workspaceId: string }): null { typeof candidateModel === "string" && candidateModel.trim().length > 0 ? candidateModel : fallbackModel; - const canonicalModel = migrateGatewayModel(resolveModelAlias(resolvedModel.trim())); - const effectiveModel = canonicalModel.trim().length > 0 ? canonicalModel : fallbackModel; + const effectiveModel = normalizeModelString(resolvedModel, fallbackModel); const existingThinking = readPersistedState(thinkingKey, "off"); const candidateThinking =