From a25760305ee870faa384626281da4ca93ceff448 Mon Sep 17 00:00:00 2001 From: Ammar Date: Tue, 14 Oct 2025 18:43:48 -0500 Subject: [PATCH 1/2] =?UTF-8?q?=F0=9F=A4=96=20Fix=20Cmd+Shift+T=20keybind?= =?UTF-8?q?=20failing=20in=20new=20chats?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The toggle thinking keybind (Cmd+Shift+T) would fail in new chats because it checked message history for the current model, which is null until the first message is sent. However, users can see and select a model in the UI immediately (stored in localStorage). Root cause: State source mismatch - UI shows: selectedModel from localStorage (always available) - Keybind checked: currentModel from message history (null in new chats) Fix: Read the selected model from localStorage and fall back to message history model if not set. This matches what the user sees in the UI. Now the keybind works immediately in new chats, matching user expectations. _Generated with `cmux`_ --- src/hooks/useAIViewKeybinds.ts | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/hooks/useAIViewKeybinds.ts b/src/hooks/useAIViewKeybinds.ts index de1ebe6fe..9711f2f90 100644 --- a/src/hooks/useAIViewKeybinds.ts +++ b/src/hooks/useAIViewKeybinds.ts @@ -1,7 +1,7 @@ import { useEffect } from "react"; import type { ChatInputAPI } from "@/components/ChatInput"; import { matchesKeybind, KEYBINDS, isEditableElement } from "@/utils/ui/keybinds"; -import { getLastThinkingByModelKey } from "@/constants/storage"; +import { getLastThinkingByModelKey, getModelKey } from "@/constants/storage"; import { updatePersistedState, readPersistedState } from "@/hooks/usePersistedState"; import type { ThinkingLevel, ThinkingLevelOn } from "@/types/thinking"; import { DEFAULT_THINKING_LEVEL } from "@/types/thinking"; @@ -64,17 +64,22 @@ export function useAIViewKeybinds({ if (matchesKeybind(e, KEYBINDS.TOGGLE_THINKING)) { e.preventDefault(); - // Skip if no model set (workspace has no messages yet) - if (!currentModel) { + // Get selected model from localStorage (what user sees in UI) + // Fall back to message history model if not set + const selectedModel = readPersistedState(getModelKey(workspaceId), null); + const modelToUse = selectedModel ?? currentModel; + + // Skip if no model set at all + if (!modelToUse) { return; } // Storage key for remembering this model's last-used active thinking level - const lastThinkingKey = getLastThinkingByModelKey(currentModel); + const lastThinkingKey = getLastThinkingByModelKey(modelToUse); // Special-case: if model has single-option policy (e.g., gpt-5-pro only supports HIGH), // the toggle is a no-op to avoid confusing state transitions. - const allowed = getThinkingPolicyForModel(currentModel); + const allowed = getThinkingPolicyForModel(modelToUse); if (allowed.length === 1) { return; // No toggle for single-option policies } From 00d13c8d3392c77f70e01ddadaae681cbe574192 Mon Sep 17 00:00:00 2001 From: Ammar Date: Tue, 14 Oct 2025 19:26:40 -0500 Subject: [PATCH 2/2] =?UTF-8?q?=F0=9F=A4=96=20Use=20defaultModel=20fallbac?= =?UTF-8?q?k=20to=20match=20UI=20behavior?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The review bot correctly identified that with empty localStorage (brand new workspace or cleared storage), both selectedModel and currentModel would be null, causing the keybind to still fail. Now uses the same fallback logic as useSendMessageOptions: selectedModel ?? currentModel ?? defaultModel This ensures the keybind always has a model to work with, matching what the UI displays (which also defaults to claude-sonnet-4-5). _Generated with `cmux`_ --- src/hooks/useAIViewKeybinds.ts | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/hooks/useAIViewKeybinds.ts b/src/hooks/useAIViewKeybinds.ts index 9711f2f90..ba1c16e2e 100644 --- a/src/hooks/useAIViewKeybinds.ts +++ b/src/hooks/useAIViewKeybinds.ts @@ -6,6 +6,7 @@ import { updatePersistedState, readPersistedState } from "@/hooks/usePersistedSt import type { ThinkingLevel, ThinkingLevelOn } from "@/types/thinking"; import { DEFAULT_THINKING_LEVEL } from "@/types/thinking"; import { getThinkingPolicyForModel } from "@/utils/thinking/policy"; +import { defaultModel } from "@/utils/ai/models"; interface UseAIViewKeybindsParams { workspaceId: string; @@ -65,14 +66,10 @@ export function useAIViewKeybinds({ e.preventDefault(); // Get selected model from localStorage (what user sees in UI) - // Fall back to message history model if not set + // Fall back to message history model, then to default model + // This matches the same logic as useSendMessageOptions const selectedModel = readPersistedState(getModelKey(workspaceId), null); - const modelToUse = selectedModel ?? currentModel; - - // Skip if no model set at all - if (!modelToUse) { - return; - } + const modelToUse = selectedModel ?? currentModel ?? defaultModel; // Storage key for remembering this model's last-used active thinking level const lastThinkingKey = getLastThinkingByModelKey(modelToUse);