From 2aa1dcdc5c50aa4a1698193a074fb7a8ba3f25c7 Mon Sep 17 00:00:00 2001 From: seeones Date: Mon, 12 Oct 2026 21:58:16 +0800 Subject: [PATCH 01/12] feat(chat): compact model picker in chat input bar reusing settings ModelPicker --- .../src/components/chat/ChatModelSelector.tsx | 111 ++++++++++ .../src/components/chat/ChatTextArea.tsx | 6 + .../chat/__tests__/ChatModelSelector.spec.tsx | 161 ++++++++++++++ .../chat/hooks/useChatModelSelector.ts | 155 +++++++++++++ .../src/components/settings/ModelPicker.tsx | 204 ++++++++++++------ 5 files changed, 576 insertions(+), 61 deletions(-) create mode 100644 webview-ui/src/components/chat/ChatModelSelector.tsx create mode 100644 webview-ui/src/components/chat/__tests__/ChatModelSelector.spec.tsx create mode 100644 webview-ui/src/components/chat/hooks/useChatModelSelector.ts diff --git a/webview-ui/src/components/chat/ChatModelSelector.tsx b/webview-ui/src/components/chat/ChatModelSelector.tsx new file mode 100644 index 0000000000..1dec3051dd --- /dev/null +++ b/webview-ui/src/components/chat/ChatModelSelector.tsx @@ -0,0 +1,111 @@ +import { useCallback, useMemo } from "react" + +import type { ProviderName } from "@roo-code/types" + +import { cn } from "@/lib/utils" +import { useRooPortal } from "@/components/ui/hooks/useRooPortal" +import { vscode } from "@/utils/vscode" +import { useExtensionState } from "@/context/ExtensionStateContext" +import { ModelPicker } from "@/components/settings/ModelPicker" + +import { useChatModelSelector } from "./hooks/useChatModelSelector" + +interface ChatModelSelectorProps { + disabled?: boolean + title: string + triggerClassName?: string +} + +/** + * Compact model picker for the chat input bar. + * + * It reuses the settings page {@link ModelPicker} in `compact` mode (search, + * filtering, custom-model escape hatch and org-policy filtering all live there) + * and adds a chat-specific trigger plus a persistence adapter: the settings + * picker writes to the local settings buffer via `setApiConfigurationField`, + * while the chat bar persists the selection to the active API configuration + * profile via `upsertApiConfiguration`. + */ +export const ChatModelSelector = ({ disabled = false, title, triggerClassName = "" }: ChatModelSelectorProps) => { + const { apiConfiguration, organizationAllowList, currentApiConfigName } = useExtensionState() + const { provider, models, modelIdKey, defaultModelId, isLoading, valueTransform, displayTransform } = + useChatModelSelector() + + const portalContainer = useRooPortal("roo-portal") + + // Persist the selection to the active profile. The picker applies + // `valueTransform` before calling back, so the adapter stores the received + // value directly under the provider's model field. + const persistModel = useCallback( + (value: unknown) => { + if (!modelIdKey || !apiConfiguration || !currentApiConfigName) { + return + } + + vscode.postMessage({ + type: "upsertApiConfiguration", + text: currentApiConfigName, + apiConfiguration: { ...apiConfiguration, apiProvider: provider, [modelIdKey]: value }, + }) + }, + [provider, modelIdKey, apiConfiguration, currentApiConfigName], + ) + + const setApiConfigurationField = useCallback( + (_field: K, value: (typeof apiConfiguration)[K]) => { + persistModel(value) + }, + [persistModel], + ) + + // Free-form model ids are only offered when the provider is unrestricted. + const hideCustomModel = useMemo(() => { + if (!organizationAllowList || organizationAllowList.allowAll) return false + const providerConfig = provider ? organizationAllowList.providers?.[provider] : undefined + return !providerConfig?.allowAll + }, [organizationAllowList, provider]) + + const isDisabled = disabled || !modelIdKey || !currentApiConfigName + + return ( + ( + + )} + /> + ) +} diff --git a/webview-ui/src/components/chat/ChatTextArea.tsx b/webview-ui/src/components/chat/ChatTextArea.tsx index a78f3f0f8e..a6f47af6d7 100644 --- a/webview-ui/src/components/chat/ChatTextArea.tsx +++ b/webview-ui/src/components/chat/ChatTextArea.tsx @@ -27,6 +27,7 @@ import { StandardTooltip } from "@src/components/ui" import Thumbnails from "../common/Thumbnails" import { ModeSelector } from "./ModeSelector" import { ApiConfigSelector } from "./ApiConfigSelector" +import { ChatModelSelector } from "./ChatModelSelector" import { AutoApproveDropdown } from "./AutoApproveDropdown" import { MAX_IMAGES_PER_MESSAGE } from "./constants" import ContextMenu from "./ContextMenu" @@ -1319,6 +1320,11 @@ export const ChatTextArea = forwardRef( lockApiConfigAcrossModes={!!lockApiConfigAcrossModes} onToggleLockApiConfig={handleToggleLockApiConfig} /> +
diff --git a/webview-ui/src/components/chat/__tests__/ChatModelSelector.spec.tsx b/webview-ui/src/components/chat/__tests__/ChatModelSelector.spec.tsx new file mode 100644 index 0000000000..52db6185bb --- /dev/null +++ b/webview-ui/src/components/chat/__tests__/ChatModelSelector.spec.tsx @@ -0,0 +1,161 @@ +// npx vitest src/components/chat/__tests__/ChatModelSelector.spec.tsx + +import { screen, fireEvent, renderWithExtensionState } from "@/utils/test-utils" +import { act, type ReactNode } from "react" +import { QueryClient } from "@tanstack/react-query" +import { type Mock } from "vitest" + +import { type ModelInfo, type ProviderSettings, getProviderDefaultModelId, providerIdentifiers } from "@roo-code/types" + +import { useRouterModels } from "@/components/ui/hooks/useRouterModels" +import { useOllamaModels } from "@/components/ui/hooks/useOllamaModels" +import { useLmStudioModels } from "@/components/ui/hooks/useLmStudioModels" +import { useExtensionState } from "@src/context/ExtensionStateContext" +import { vscode } from "@/utils/vscode" + +import { ChatModelSelector } from "../ChatModelSelector" + +vi.mock("@/utils/vscode", () => ({ + vscode: { + postMessage: vi.fn(), + }, +})) + +vi.mock("@src/context/ExtensionStateContext", () => ({ + ExtensionStateContextProvider: ({ children }: { children: ReactNode }) => children, + useExtensionState: vi.fn(), +})) + +vi.mock("@/components/ui/hooks/useRouterModels") +vi.mock("@/components/ui/hooks/useOllamaModels") +vi.mock("@/components/ui/hooks/useLmStudioModels") +vi.mock("@/components/ui/hooks/useRooPortal", () => ({ useRooPortal: () => document.body })) + +const mockUseRouterModels = useRouterModels as Mock +const mockUseOllamaModels = useOllamaModels as Mock +const mockUseLmStudioModels = useLmStudioModels as Mock +const mockUseExtensionState = useExtensionState as Mock +const mockPostMessage = vscode.postMessage as Mock + +Element.prototype.scrollIntoView = vi.fn() + +type Story = Pick< + ReturnType, + "apiConfiguration" | "organizationAllowList" | "currentApiConfigName" | "routerModels" +> + +describe("ChatModelSelector", () => { + const modelInfo: ModelInfo = { + maxTokens: 8192, + contextWindow: 200_000, + supportsImages: true, + supportsPromptCache: true, + } + + const routerModels = { + openrouter: { + "model-a": { name: "Model A", ...modelInfo }, + "model-b": { name: "Model B", ...modelInfo }, + }, + } + + const queryClient = new QueryClient() + + const setState = (story: Partial) => { + mockUseExtensionState.mockReturnValue({ + apiConfiguration: { apiProvider: providerIdentifiers.openrouter } as ProviderSettings, + organizationAllowList: { allowAll: true, providers: {} }, + currentApiConfigName: "Default", + ...story, + } as unknown as ReturnType) + } + + const renderSelector = () => renderWithExtensionState(, { queryClient }) + + beforeEach(() => { + vi.clearAllMocks() + mockUseRouterModels.mockReturnValue({ + data: routerModels, + isLoading: false, + isError: false, + } as unknown as ReturnType) + mockUseOllamaModels.mockReturnValue({ + data: undefined, + isLoading: false, + } as unknown as ReturnType) + mockUseLmStudioModels.mockReturnValue({ + data: undefined, + isLoading: false, + } as unknown as ReturnType) + setState({}) + }) + + it("renders the default model id when no model is selected", () => { + renderSelector() + + const trigger = screen.getByTestId("chat-model-selector-trigger") + expect(trigger).toBeInTheDocument() + expect(trigger).toHaveTextContent(getProviderDefaultModelId(providerIdentifiers.openrouter)) + }) + + it("renders the selected model id from the active configuration", () => { + setState({ + apiConfiguration: { apiProvider: providerIdentifiers.anthropic, apiModelId: "claude-3-opus-20240229" }, + }) + + renderSelector() + + expect(screen.getByTestId("chat-model-selector-trigger")).toHaveTextContent("claude-3-opus-20240229") + }) + + it("persists the selection to the active profile via upsertApiConfiguration", async () => { + renderSelector() + + await act(async () => { + fireEvent.click(screen.getByTestId("chat-model-selector-trigger")) + }) + + await act(async () => { + fireEvent.click(screen.getByTestId("model-option-model-a")) + }) + + expect(mockPostMessage).toHaveBeenCalledWith({ + type: "upsertApiConfiguration", + text: "Default", + apiConfiguration: expect.objectContaining({ + apiProvider: providerIdentifiers.openrouter, + openRouterModelId: "model-a", + }), + }) + }) + + it("is disabled and does not persist when there is no active profile", async () => { + setState({ currentApiConfigName: undefined }) + + renderSelector() + + expect(screen.getByTestId("chat-model-selector-trigger")).toBeDisabled() + expect(mockPostMessage).not.toHaveBeenCalled() + }) + + it("hides the custom-model escape hatch for a restricted provider", async () => { + setState({ + organizationAllowList: { + allowAll: false, + providers: { [providerIdentifiers.openrouter]: { allowAll: false } }, + }, + }) + + renderSelector() + + await act(async () => { + fireEvent.click(screen.getByTestId("chat-model-selector-trigger")) + }) + + await act(async () => { + fireEvent.change(screen.getByTestId("model-input"), { target: { value: "my-custom-model" } }) + }) + + expect(screen.queryByTestId("use-custom-model")).not.toBeInTheDocument() + }) +}) diff --git a/webview-ui/src/components/chat/hooks/useChatModelSelector.ts b/webview-ui/src/components/chat/hooks/useChatModelSelector.ts new file mode 100644 index 0000000000..8434f0bd5c --- /dev/null +++ b/webview-ui/src/components/chat/hooks/useChatModelSelector.ts @@ -0,0 +1,155 @@ +import { useMemo } from "react" + +import { + type ModelInfo, + type ModelRecord, + type ProviderName, + type ProviderSettings, + getProviderDefaultModelId, + isRetiredProvider, + providerIdentifiers, +} from "@roo-code/types" + +import { useRouterModels } from "@/components/ui/hooks/useRouterModels" +import { useOllamaModels } from "@/components/ui/hooks/useOllamaModels" +import { useLmStudioModels } from "@/components/ui/hooks/useLmStudioModels" +import { getStaticModelsForProvider } from "@/components/settings/utils/providerModelConfig" +import { MODELS_BY_PROVIDER } from "@/components/settings/constants" +import { useExtensionState } from "@/context/ExtensionStateContext" + +type ModelIdKey = keyof Pick< + ProviderSettings, + | "openRouterModelId" + | "requestyModelId" + | "unboundModelId" + | "openAiModelId" + | "litellmModelId" + | "vercelAiGatewayModelId" + | "zooGatewayModelId" + | "opencodeGoModelId" + | "kenariModelId" + | "nanoGptModelId" + | "apiModelId" + | "ollamaModelId" + | "lmStudioModelId" + | "vsCodeLmModelSelector" +> + +// Router providers resolve their list through `useRouterModels` (or the +// backend-broadcast cache for litellm/poe). The map holds the config field each +// provider stores its selection under. +const ROUTER_PROVIDERS: Partial> = { + [providerIdentifiers.openrouter]: { modelIdKey: "openRouterModelId" }, + [providerIdentifiers.requesty]: { modelIdKey: "requestyModelId" }, + [providerIdentifiers.unbound]: { modelIdKey: "unboundModelId" }, + [providerIdentifiers.litellm]: { modelIdKey: "litellmModelId", fromState: true }, + [providerIdentifiers.vercelAiGateway]: { modelIdKey: "vercelAiGatewayModelId" }, + [providerIdentifiers.zooGateway]: { modelIdKey: "zooGatewayModelId" }, + [providerIdentifiers.opencodeGo]: { modelIdKey: "opencodeGoModelId" }, + [providerIdentifiers.kenari]: { modelIdKey: "kenariModelId" }, + [providerIdentifiers.nanogpt]: { modelIdKey: "nanoGptModelId" }, + [providerIdentifiers.kimiCode]: { modelIdKey: "apiModelId" }, + [providerIdentifiers.poe]: { modelIdKey: "apiModelId", fromState: true }, +} + +export interface ChatModelSelectorData { + provider: ProviderName | undefined + models: Record | null + modelIdKey: ModelIdKey | undefined + defaultModelId: string + isLoading: boolean + valueTransform?: (modelId: string) => unknown + displayTransform?: (value: unknown) => string +} + +/** + * Resolves the model list, storage key and transforms for the active provider + * so the chat input bar can render a compact model picker that mirrors the + * settings page sources. + * + * It composes the same webview data hooks the settings providers use (router + * models, Ollama, LM Studio) and the shared static provider tables, so it needs + * no chat-specific backend protocol. + */ +export const useChatModelSelector = (): ChatModelSelectorData => { + const { apiConfiguration, routerModels: stateRouterModels } = useExtensionState() + + const provider = (apiConfiguration?.apiProvider || providerIdentifiers.openrouter) as ProviderName + const activeProvider = isRetiredProvider(provider) ? undefined : provider + const routerConfig = activeProvider ? ROUTER_PROVIDERS[activeProvider] : undefined + + const routerModels = useRouterModels({ + provider: routerConfig && !routerConfig.fromState ? activeProvider : undefined, + enabled: !!routerConfig && !routerConfig.fromState, + }) + + // The list hooks only fire when a model id is provided; pass a sentinel so + // the picker can populate its options before a model is configured. + const ollamaModels = useOllamaModels( + activeProvider === providerIdentifiers.ollama ? apiConfiguration?.ollamaModelId || "ollama" : undefined, + ) + const lmStudioModels = useLmStudioModels( + activeProvider === providerIdentifiers.lmstudio ? apiConfiguration?.lmStudioModelId || "lmstudio" : undefined, + ) + + return useMemo(() => { + let models: Record | null = null + let modelIdKey: ModelIdKey | undefined = undefined + let valueTransform: ((modelId: string) => unknown) | undefined + let displayTransform: ((value: unknown) => string) | undefined + let isLoading = false + + const defaultModelId = activeProvider + ? getProviderDefaultModelId(activeProvider, { + isChina: + activeProvider === providerIdentifiers.zai && apiConfiguration?.zaiApiLine === "china_coding", + }) + : "" + + if (activeProvider) { + if (routerConfig) { + const source = (routerConfig.fromState ? stateRouterModels : routerModels.data) as + | Partial> + | undefined + models = source?.[activeProvider] ?? null + modelIdKey = routerConfig.modelIdKey + isLoading = !routerConfig.fromState && routerModels.isLoading + } else if (activeProvider === providerIdentifiers.ollama) { + models = ollamaModels.data ?? null + modelIdKey = "ollamaModelId" + isLoading = ollamaModels.isLoading + } else if (activeProvider === providerIdentifiers.lmstudio) { + models = lmStudioModels.data ?? null + modelIdKey = "lmStudioModelId" + isLoading = lmStudioModels.isLoading + } else if (activeProvider === providerIdentifiers.vscodeLm) { + // VSCode LM exposes compound `{ vendor, family }` selections. + modelIdKey = "vsCodeLmModelSelector" + valueTransform = (modelId) => { + const [vendor, family] = modelId.split("/") + return { vendor, family } + } + displayTransform = (value) => { + if (!value) return "" + const selector = value as { vendor?: string; family?: string } + return selector.vendor && selector.family ? `${selector.vendor}/${selector.family}` : "" + } + } else { + models = MODELS_BY_PROVIDER[activeProvider] + ? getStaticModelsForProvider(activeProvider, undefined, apiConfiguration) + : null + modelIdKey = "apiModelId" + } + } + + return { + provider: activeProvider, + models, + modelIdKey, + defaultModelId, + isLoading, + valueTransform, + displayTransform, + } + }, [activeProvider, routerConfig, apiConfiguration, routerModels, stateRouterModels, ollamaModels, lmStudioModels]) +} diff --git a/webview-ui/src/components/settings/ModelPicker.tsx b/webview-ui/src/components/settings/ModelPicker.tsx index aa49528f5e..d0d5b01de7 100644 --- a/webview-ui/src/components/settings/ModelPicker.tsx +++ b/webview-ui/src/components/settings/ModelPicker.tsx @@ -1,9 +1,10 @@ -import { useMemo, useState, useCallback, useEffect, useRef } from "react" +import { useMemo, useState, useCallback, useEffect, useRef, type ReactNode } from "react" import { VSCodeLink } from "@vscode/webview-ui-toolkit/react" import { Trans } from "react-i18next" import { ChevronsUpDown, Check, X, Info } from "lucide-react" import { + type ProviderName, type ProviderSettings, type ModelInfo, type OrganizationAllowList, @@ -25,6 +26,7 @@ import { Popover, PopoverContent, PopoverTrigger, + StandardTooltip, Button, } from "@src/components/ui" import { useEscapeKey } from "@src/hooks/useEscapeKey" @@ -75,6 +77,37 @@ interface ModelPickerProps { displayTransform?: (value: unknown) => string /** Callback when model changes - useful for side effects like clearing related fields */ onModelChange?: (modelId: string) => void + /** + * Compact mode for the chat input bar: renders `renderTrigger` instead of + * the labelled combobox button, hides the model info/pricing block, and + * never auto-initializes a default model (the chat selector only reflects + * the active profile and persists explicit selections). + */ + compact?: boolean + /** Tooltip content shown above the trigger (compact mode). */ + tooltip?: string + /** Disable the trigger (compact mode). */ + disabled?: boolean + /** Whether the model list is still loading (compact mode). */ + isLoading?: boolean + /** Hide the custom-model escape hatch even when free-form ids are allowed. */ + hideCustomModel?: boolean + /** Custom trigger renderer (compact mode). */ + renderTrigger?: (state: { + displayValue: string | undefined + placeholder: string + isLoading: boolean + disabled: boolean + }) => ReactNode + /** Extra classes for the popover content (compact mode). */ + contentClassName?: string + /** Portal container for the popover content (compact mode). */ + portalContainer?: HTMLElement + /** + * Provider used to filter the model list. Defaults to the provider on + * `apiConfiguration`; the chat selector overrides it for an unset provider. + */ + activeProviderOverride?: ProviderName } export const ModelPicker = ({ @@ -93,6 +126,15 @@ export const ModelPicker = ({ valueTransform, displayTransform, onModelChange, + compact = false, + tooltip, + disabled = false, + isLoading = false, + hideCustomModel = false, + renderTrigger, + contentClassName, + portalContainer, + activeProviderOverride, }: ModelPickerProps) => { const { t } = useAppTranslation() @@ -116,9 +158,10 @@ export const ModelPicker = ({ }, [displayTransform, apiConfiguration, modelIdKey, selectedModelId]) const activeProvider = - apiConfiguration.apiProvider && isRetiredProvider(apiConfiguration.apiProvider) + activeProviderOverride ?? + (apiConfiguration.apiProvider && isRetiredProvider(apiConfiguration.apiProvider) ? undefined - : apiConfiguration.apiProvider + : apiConfiguration.apiProvider) const modelIds = useMemo(() => { const filteredModels = filterModels(models, activeProvider, organizationAllowList) @@ -192,13 +235,19 @@ export const ModelPicker = ({ }, []) useEffect(() => { + // The compact (chat) picker must never auto-write configuration on mount. + if (compact) { + isInitialized.current = true + return + } + if (!selectedModelId && !isInitialized.current) { const initialValue = modelIds.includes(selectedModelId) ? selectedModelId : defaultModelId setApiConfigurationField(modelIdKey, initialValue, false) // false = automatic initialization } isInitialized.current = true - }, [modelIds, setApiConfigurationField, modelIdKey, selectedModelId, defaultModelId]) + }, [modelIds, setApiConfigurationField, modelIdKey, selectedModelId, defaultModelId, compact]) // Cleanup timeouts on unmount to prevent test flakiness useEffect(() => { @@ -215,6 +264,95 @@ export const ModelPicker = ({ // Use the shared ESC key handler hook useEscapeKey(open, () => setOpen(false)) + // Popover body shared by the settings picker and the compact chat picker. + const popoverContent = ( + + +
+ + {searchValue.length > 0 && ( +
+ +
+ )} +
+ + + {searchValue && ( +
{t("settings:modelPicker.noMatchFound")}
+ )} +
+ + {modelIds.map((model) => ( + + + {model} + + + + ))} + +
+ {!hideCustomModel && searchValue && !modelIds.includes(searchValue) && ( +
+ + {t("settings:modelPicker.useCustomModel", { modelId: searchValue })} + +
+ )} +
+
+ ) + + if (compact) { + const trigger = renderTrigger?.({ + displayValue, + placeholder: t("settings:common.select"), + isLoading, + disabled, + }) + + return ( + + {tooltip ? ( + + + {trigger} + + + ) : ( + + {trigger} + + )} + {popoverContent} + + ) + } + return ( <>
@@ -231,63 +369,7 @@ export const ModelPicker = ({ - - -
- - {searchValue.length > 0 && ( -
- -
- )} -
- - - {searchValue && ( -
- {t("settings:modelPicker.noMatchFound")} -
- )} -
- - {modelIds.map((model) => ( - - - {model} - - - - ))} - -
- {searchValue && !modelIds.includes(searchValue) && ( -
- - {t("settings:modelPicker.useCustomModel", { modelId: searchValue })} - -
- )} -
-
+ {popoverContent}
{errorMessage && } From d6c65beacc24b44bd54ef7e841c97be88c1674e7 Mon Sep 17 00:00:00 2001 From: seeones Date: Mon, 12 Oct 2026 22:24:22 +0800 Subject: [PATCH 02/12] fix(chat): preserve stored provider and load VS Code LM models in chat selector --- .../src/components/chat/ChatModelSelector.tsx | 4 +- .../chat/__tests__/ChatModelSelector.spec.tsx | 47 +++++++++++++++++++ .../chat/hooks/useChatModelSelector.ts | 31 +++++++++++- .../components/ui/hooks/useVsCodeLmModels.ts | 37 +++++++++++++++ 4 files changed, 115 insertions(+), 4 deletions(-) create mode 100644 webview-ui/src/components/ui/hooks/useVsCodeLmModels.ts diff --git a/webview-ui/src/components/chat/ChatModelSelector.tsx b/webview-ui/src/components/chat/ChatModelSelector.tsx index 1dec3051dd..b1c04183e7 100644 --- a/webview-ui/src/components/chat/ChatModelSelector.tsx +++ b/webview-ui/src/components/chat/ChatModelSelector.tsx @@ -45,10 +45,10 @@ export const ChatModelSelector = ({ disabled = false, title, triggerClassName = vscode.postMessage({ type: "upsertApiConfiguration", text: currentApiConfigName, - apiConfiguration: { ...apiConfiguration, apiProvider: provider, [modelIdKey]: value }, + apiConfiguration: { ...apiConfiguration, [modelIdKey]: value }, }) }, - [provider, modelIdKey, apiConfiguration, currentApiConfigName], + [modelIdKey, apiConfiguration, currentApiConfigName], ) const setApiConfigurationField = useCallback( diff --git a/webview-ui/src/components/chat/__tests__/ChatModelSelector.spec.tsx b/webview-ui/src/components/chat/__tests__/ChatModelSelector.spec.tsx index 52db6185bb..d7219f4937 100644 --- a/webview-ui/src/components/chat/__tests__/ChatModelSelector.spec.tsx +++ b/webview-ui/src/components/chat/__tests__/ChatModelSelector.spec.tsx @@ -10,6 +10,7 @@ import { type ModelInfo, type ProviderSettings, getProviderDefaultModelId, provi import { useRouterModels } from "@/components/ui/hooks/useRouterModels" import { useOllamaModels } from "@/components/ui/hooks/useOllamaModels" import { useLmStudioModels } from "@/components/ui/hooks/useLmStudioModels" +import { useVsCodeLmModels } from "@/components/ui/hooks/useVsCodeLmModels" import { useExtensionState } from "@src/context/ExtensionStateContext" import { vscode } from "@/utils/vscode" @@ -29,11 +30,13 @@ vi.mock("@src/context/ExtensionStateContext", () => ({ vi.mock("@/components/ui/hooks/useRouterModels") vi.mock("@/components/ui/hooks/useOllamaModels") vi.mock("@/components/ui/hooks/useLmStudioModels") +vi.mock("@/components/ui/hooks/useVsCodeLmModels") vi.mock("@/components/ui/hooks/useRooPortal", () => ({ useRooPortal: () => document.body })) const mockUseRouterModels = useRouterModels as Mock const mockUseOllamaModels = useOllamaModels as Mock const mockUseLmStudioModels = useLmStudioModels as Mock +const mockUseVsCodeLmModels = useVsCodeLmModels as Mock const mockUseExtensionState = useExtensionState as Mock const mockPostMessage = vscode.postMessage as Mock @@ -87,6 +90,10 @@ describe("ChatModelSelector", () => { data: undefined, isLoading: false, } as unknown as ReturnType) + mockUseVsCodeLmModels.mockReturnValue({ + data: [], + isLoading: false, + } as unknown as ReturnType) setState({}) }) @@ -129,6 +136,46 @@ describe("ChatModelSelector", () => { }) }) + it("preserves the stored provider without injecting a provider override", async () => { + // No apiProvider is stored; the adapter must not write one back. + setState({ apiConfiguration: {} }) + + renderSelector() + + await act(async () => { + fireEvent.click(screen.getByTestId("chat-model-selector-trigger")) + }) + + await act(async () => { + fireEvent.click(screen.getByTestId("model-option-model-a")) + }) + + const payload = mockPostMessage.mock.calls.find(([msg]) => msg.type === "upsertApiConfiguration")?.[0] + expect(payload?.apiConfiguration).not.toHaveProperty("apiProvider") + }) + + it("lists VS Code LM models keyed as vendor/family even when custom models are restricted", async () => { + setState({ + apiConfiguration: { apiProvider: providerIdentifiers.vscodeLm }, + organizationAllowList: { + allowAll: false, + providers: { [providerIdentifiers.vscodeLm]: { allowAll: false, models: ["copilot/gpt-4o"] } }, + }, + }) + mockUseVsCodeLmModels.mockReturnValue({ + data: [{ vendor: "copilot", family: "gpt-4o" }], + isLoading: false, + } as unknown as ReturnType) + + renderSelector() + + await act(async () => { + fireEvent.click(screen.getByTestId("chat-model-selector-trigger")) + }) + + expect(screen.getByTestId("model-option-copilot/gpt-4o")).toBeInTheDocument() + }) + it("is disabled and does not persist when there is no active profile", async () => { setState({ currentApiConfigName: undefined }) diff --git a/webview-ui/src/components/chat/hooks/useChatModelSelector.ts b/webview-ui/src/components/chat/hooks/useChatModelSelector.ts index 8434f0bd5c..1f314dae6c 100644 --- a/webview-ui/src/components/chat/hooks/useChatModelSelector.ts +++ b/webview-ui/src/components/chat/hooks/useChatModelSelector.ts @@ -13,6 +13,7 @@ import { import { useRouterModels } from "@/components/ui/hooks/useRouterModels" import { useOllamaModels } from "@/components/ui/hooks/useOllamaModels" import { useLmStudioModels } from "@/components/ui/hooks/useLmStudioModels" +import { useVsCodeLmModels } from "@/components/ui/hooks/useVsCodeLmModels" import { getStaticModelsForProvider } from "@/components/settings/utils/providerModelConfig" import { MODELS_BY_PROVIDER } from "@/components/settings/constants" import { useExtensionState } from "@/context/ExtensionStateContext" @@ -91,6 +92,7 @@ export const useChatModelSelector = (): ChatModelSelectorData => { const lmStudioModels = useLmStudioModels( activeProvider === providerIdentifiers.lmstudio ? apiConfiguration?.lmStudioModelId || "lmstudio" : undefined, ) + const vsCodeLmModels = useVsCodeLmModels(activeProvider === providerIdentifiers.vscodeLm) return useMemo(() => { let models: Record | null = null @@ -123,8 +125,24 @@ export const useChatModelSelector = (): ChatModelSelectorData => { modelIdKey = "lmStudioModelId" isLoading = lmStudioModels.isLoading } else if (activeProvider === providerIdentifiers.vscodeLm) { - // VSCode LM exposes compound `{ vendor, family }` selections. + // VSCode LM exposes compound `{ vendor, family }` selections. Key the + // options as `vendor/family` (mirrors the settings provider) so they + // stay selectable even when free-form model ids are restricted. modelIdKey = "vsCodeLmModelSelector" + models = (vsCodeLmModels.data ?? []).reduce( + (acc, model) => { + const modelId = `${model.vendor}/${model.family}` + acc[modelId] = { + maxTokens: 0, + contextWindow: 0, + supportsPromptCache: false, + description: `${model.vendor} - ${model.family}`, + } + return acc + }, + {} as Record, + ) + isLoading = vsCodeLmModels.isLoading valueTransform = (modelId) => { const [vendor, family] = modelId.split("/") return { vendor, family } @@ -151,5 +169,14 @@ export const useChatModelSelector = (): ChatModelSelectorData => { valueTransform, displayTransform, } - }, [activeProvider, routerConfig, apiConfiguration, routerModels, stateRouterModels, ollamaModels, lmStudioModels]) + }, [ + activeProvider, + routerConfig, + apiConfiguration, + routerModels, + stateRouterModels, + ollamaModels, + lmStudioModels, + vsCodeLmModels, + ]) } diff --git a/webview-ui/src/components/ui/hooks/useVsCodeLmModels.ts b/webview-ui/src/components/ui/hooks/useVsCodeLmModels.ts new file mode 100644 index 0000000000..2005870d74 --- /dev/null +++ b/webview-ui/src/components/ui/hooks/useVsCodeLmModels.ts @@ -0,0 +1,37 @@ +import { useQuery } from "@tanstack/react-query" +import { type LanguageModelChatSelector } from "vscode" + +import { type ExtensionMessage, VsCodeLmModelsMessageType } from "@roo-code/types" + +import { vscode } from "@src/utils/vscode" + +const getVsCodeLmModels = async () => + new Promise((resolve, reject) => { + const cleanup = () => { + window.removeEventListener("message", handler) + } + + const timeout = setTimeout(() => { + cleanup() + reject(new Error("VS Code LM models request timed out")) + }, 10000) + + const handler = (event: MessageEvent) => { + const message: ExtensionMessage = event.data + + if (message.type === VsCodeLmModelsMessageType.vsCodeLmModels) { + clearTimeout(timeout) + cleanup() + resolve(message.vsCodeLmModels ?? []) + } + } + + window.addEventListener("message", handler) + vscode.postMessage({ type: VsCodeLmModelsMessageType.requestVsCodeLmModels }) + }) + +export const useVsCodeLmModels = (enabled: boolean) => + useQuery({ + queryKey: ["vsCodeLmModels"], + queryFn: () => (enabled ? getVsCodeLmModels() : []), + }) From f430bacac2dbe05efc9c73f045646c614cfebe9f Mon Sep 17 00:00:00 2001 From: seeones Date: Mon, 12 Oct 2026 23:12:32 +0800 Subject: [PATCH 03/12] test(chat): update chat composer resting visual baselines for model selector --- .../chat-composer-resting-dark.png | Bin 9162 -> 9945 bytes ...t-composer-resting-high-contrast-light.png | Bin 9606 -> 10270 bytes .../chat-composer-resting-high-contrast.png | Bin 9624 -> 10477 bytes .../chat-composer-resting-light.png | Bin 9326 -> 9973 bytes 4 files changed, 0 insertions(+), 0 deletions(-) diff --git a/webview-ui/src/components/chat/__tests__/__screenshots__/chat-composer-resting-dark.png b/webview-ui/src/components/chat/__tests__/__screenshots__/chat-composer-resting-dark.png index fad9aa30b923ada5cbd0e6c1f1a5df83319b1d39..6c90b6f6102d1593f3dd15421757624b6cc94313 100644 GIT binary patch literal 9945 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 CivmCZ diff --git a/webview-ui/src/components/chat/__tests__/__screenshots__/chat-composer-resting-high-contrast-light.png b/webview-ui/src/components/chat/__tests__/__screenshots__/chat-composer-resting-high-contrast-light.png index f5c759fad8546da967cdbb07f93b034d78d293be..8e9c01c7fef69c4a6aa08b4c796493338c671b8d 100644 GIT binary patch literal 10270 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 literal 9606 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 G2L3Of2;d|D diff --git a/webview-ui/src/components/chat/__tests__/__screenshots__/chat-composer-resting-high-contrast.png b/webview-ui/src/components/chat/__tests__/__screenshots__/chat-composer-resting-high-contrast.png index 465ffc0263d816e953f37275f9ceb514223f33bf..8d232cb2ab90a08f637f54576ea195ada3ad1802 100644 GIT binary patch literal 10477 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�T)Xjeo%zI=0Jw}Nu$swu0L3TL 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 L@}d>O`houi$=aJZ diff --git a/webview-ui/src/components/chat/__tests__/__screenshots__/chat-composer-resting-light.png b/webview-ui/src/components/chat/__tests__/__screenshots__/chat-composer-resting-light.png index 1f238a4619657763f15f05e20656ec0f08a03eb9..b6976d6cff55dab62a17382b98838d18e49ba732 100644 GIT binary patch literal 9973 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

b3tsdW2#AyUx(s?ztAX#V`YOaQpN7 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 From c5bda2771f217b3c0a8b30866a656db0c72b990a Mon Sep 17 00:00:00 2001 From: seeones Date: Tue, 13 Oct 2026 00:07:30 +0800 Subject: [PATCH 04/12] test(chat): widen visual Tab loop and update electron dark sidebar baseline for model selector The compact chat model picker added one more focusable trigger between the ApiConfigSelector and AutoApproveDropdown, which pushed the textarea just past the visual test's fixed 10-Tab loop. Widen to 15 iterations so the Tab-driven focus walk reliably lands on the editor before the focus screenshot is taken. Also refresh the electron extension-host sidebar baseline so it reflects the new model selector button in the chat composer. --- .../electron-chat-dark-sidebar.png | Bin 30321 -> 30026 bytes .../chat/__tests__/ChatTextArea.visual.tsx | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/vscode-e2e/src/visual/__screenshots__/electron-chat-dark-sidebar.png b/apps/vscode-e2e/src/visual/__screenshots__/electron-chat-dark-sidebar.png index e8497070ef3440fe4a3bbb3ef49f9a1de9d4c4d9..3c03cbac035d27aa3820b5de342f0cf07ad05074 100644 GIT binary patch delta 10520 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 (document.activeElement as HTMLElement | null)?.blur()) for ( let index = 0; - index < 10 && !(await editor.evaluate((element) => element === document.activeElement)); + index < 15 && !(await editor.evaluate((element) => element === document.activeElement)); index++ ) { await page.keyboard.press("Tab") From 94d8eb289a768d3108484380036d30a063e381f0 Mon Sep 17 00:00:00 2001 From: seeones Date: Tue, 13 Oct 2026 11:23:05 +0800 Subject: [PATCH 05/12] test(chat): refresh chat composer focus baselines for model selector --- .../chat-composer-focus-dark.png | Bin 9166 -> 9949 bytes ...hat-composer-focus-high-contrast-light.png | Bin 9606 -> 10267 bytes .../chat-composer-focus-high-contrast.png | Bin 9624 -> 10477 bytes .../chat-composer-focus-light.png | Bin 9326 -> 9975 bytes 4 files changed, 0 insertions(+), 0 deletions(-) diff --git a/webview-ui/src/components/chat/__tests__/__screenshots__/chat-composer-focus-dark.png b/webview-ui/src/components/chat/__tests__/__screenshots__/chat-composer-focus-dark.png index 4de566f736bcf2ebeb288f4d8eaea9b509255c29..9bab7a3a7e705ad8db2ee66651c50392994f2613 100644 GIT binary patch literal 9949 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 literal 9166 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 diff --git a/webview-ui/src/components/chat/__tests__/__screenshots__/chat-composer-focus-high-contrast-light.png b/webview-ui/src/components/chat/__tests__/__screenshots__/chat-composer-focus-high-contrast-light.png index f5c759fad8546da967cdbb07f93b034d78d293be..f1641a0f3a7107e13c4244b0da66c142b7fe0018 100644 GIT binary patch literal 10267 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 KRHejM|Nj9?jRkW6 literal 9606 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 G2L3Of2;d|D diff --git a/webview-ui/src/components/chat/__tests__/__screenshots__/chat-composer-focus-high-contrast.png b/webview-ui/src/components/chat/__tests__/__screenshots__/chat-composer-focus-high-contrast.png index 465ffc0263d816e953f37275f9ceb514223f33bf..8d232cb2ab90a08f637f54576ea195ada3ad1802 100644 GIT binary patch literal 10477 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�T)Xjeo%zI=0Jw}Nu$swu0L3TL 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 L@}d>O`houi$=aJZ diff --git a/webview-ui/src/components/chat/__tests__/__screenshots__/chat-composer-focus-light.png b/webview-ui/src/components/chat/__tests__/__screenshots__/chat-composer-focus-light.png index 1f238a4619657763f15f05e20656ec0f08a03eb9..0ad288489415ba32e03c73b429be97d143298ad4 100644 GIT binary patch literal 9975 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 From d2048cfea305455cbc73fbea2c2578234c1eec83 Mon Sep 17 00:00:00 2001 From: seeones Date: Tue, 13 Oct 2026 11:37:45 +0800 Subject: [PATCH 06/12] chore: trigger fresh visual regression run From 795bc9d8f93d7b2ca268cbd8c1444f1a4e14fc78 Mon Sep 17 00:00:00 2001 From: seeones Date: Tue, 13 Oct 2026 16:06:05 +0800 Subject: [PATCH 07/12] fix(chat): abort vscode-lm request on unmount and guard provider-less profiles - useVsCodeLmModels: wire React Query's AbortSignal through to the request helper so unmounting or switching away from the VS Code LM provider removes the window message listener and clears the 10s timeout instead of leaking them. - Add a focused useVsCodeLmModels spec covering the disabled path, matching response resolution, unrelated-message filtering, the missing-array fallback, and listener cleanup. - ChatModelSelector.persistModel: refuse to post upsertApiConfiguration when apiConfiguration.apiProvider is unset. The profile schema strips provider-specific fields from provider-less profiles, so writing openRouterModelId (the hook's default) would silently disappear on reload. - Refresh ChatModelSelector tests: assert the guard rejects writes for provider-less profiles, and verify the stored provider is preserved. --- .../src/components/chat/ChatModelSelector.tsx | 68 ++--- .../chat/__tests__/ChatModelSelector.spec.tsx | 32 +- .../src/components/settings/ModelPicker.tsx | 283 ++---------------- .../__tests__/useVsCodeLmModels.spec.tsx | 106 +++++++ .../components/ui/hooks/useVsCodeLmModels.ts | 31 +- .../ui/model-select/ModelSelect.tsx | 222 ++++++++++++++ 6 files changed, 441 insertions(+), 301 deletions(-) create mode 100644 webview-ui/src/components/ui/hooks/__tests__/useVsCodeLmModels.spec.tsx create mode 100644 webview-ui/src/components/ui/model-select/ModelSelect.tsx diff --git a/webview-ui/src/components/chat/ChatModelSelector.tsx b/webview-ui/src/components/chat/ChatModelSelector.tsx index b1c04183e7..7b88c9f5ae 100644 --- a/webview-ui/src/components/chat/ChatModelSelector.tsx +++ b/webview-ui/src/components/chat/ChatModelSelector.tsx @@ -1,12 +1,10 @@ import { useCallback, useMemo } from "react" -import type { ProviderName } from "@roo-code/types" - import { cn } from "@/lib/utils" import { useRooPortal } from "@/components/ui/hooks/useRooPortal" import { vscode } from "@/utils/vscode" import { useExtensionState } from "@/context/ExtensionStateContext" -import { ModelPicker } from "@/components/settings/ModelPicker" +import { ModelSelect } from "@/components/ui/model-select/ModelSelect" import { useChatModelSelector } from "./hooks/useChatModelSelector" @@ -19,12 +17,9 @@ interface ChatModelSelectorProps { /** * Compact model picker for the chat input bar. * - * It reuses the settings page {@link ModelPicker} in `compact` mode (search, - * filtering, custom-model escape hatch and org-policy filtering all live there) - * and adds a chat-specific trigger plus a persistence adapter: the settings - * picker writes to the local settings buffer via `setApiConfigurationField`, - * while the chat bar persists the selection to the active API configuration - * profile via `upsertApiConfiguration`. + * Wraps the shared {@link ModelSelect} with a chat-specific trigger and a + * persistence adapter: selections are written to the active API configuration + * profile via `upsertApiConfiguration` rather than the settings buffer. */ export const ChatModelSelector = ({ disabled = false, title, triggerClassName = "" }: ChatModelSelectorProps) => { const { apiConfiguration, organizationAllowList, currentApiConfigName } = useExtensionState() @@ -33,29 +28,33 @@ export const ChatModelSelector = ({ disabled = false, title, triggerClassName = const portalContainer = useRooPortal("roo-portal") - // Persist the selection to the active profile. The picker applies - // `valueTransform` before calling back, so the adapter stores the received - // value directly under the provider's model field. - const persistModel = useCallback( - (value: unknown) => { - if (!modelIdKey || !apiConfiguration || !currentApiConfigName) { + // Compute the display string for the currently stored selection. + const displayValue = useMemo(() => { + if (!modelIdKey) return "" + const stored = apiConfiguration?.[modelIdKey] + if (!stored) return "" + return displayTransform ? displayTransform(stored) : String(stored) + }, [apiConfiguration, modelIdKey, displayTransform]) + + // Persist the selection to the active profile. ModelSelect delivers the + // raw model id, so apply valueTransform before writing. + const persistSelection = useCallback( + (modelId: string) => { + // Refuse to write until the user has actually picked a provider — + // the profile schema strips provider-specific fields from + // provider-less profiles, so the selection would be dropped on reload. + if (!modelIdKey || !apiConfiguration || !currentApiConfigName || !apiConfiguration.apiProvider) { return } + const value = valueTransform ? valueTransform(modelId) : modelId vscode.postMessage({ type: "upsertApiConfiguration", text: currentApiConfigName, apiConfiguration: { ...apiConfiguration, [modelIdKey]: value }, }) }, - [modelIdKey, apiConfiguration, currentApiConfigName], - ) - - const setApiConfigurationField = useCallback( - (_field: K, value: (typeof apiConfiguration)[K]) => { - persistModel(value) - }, - [persistModel], + [modelIdKey, apiConfiguration, currentApiConfigName, valueTransform], ) // Free-form model ids are only offered when the provider is unrestricted. @@ -68,26 +67,19 @@ export const ChatModelSelector = ({ disabled = false, title, triggerClassName = const isDisabled = disabled || !modelIdKey || !currentApiConfigName return ( - ( + tooltip={title} + renderTrigger={({ displayValue: value, isLoading: loading, placeholder }) => ( )} diff --git a/webview-ui/src/components/chat/__tests__/ChatModelSelector.spec.tsx b/webview-ui/src/components/chat/__tests__/ChatModelSelector.spec.tsx index d7219f4937..3b5f8c7e1b 100644 --- a/webview-ui/src/components/chat/__tests__/ChatModelSelector.spec.tsx +++ b/webview-ui/src/components/chat/__tests__/ChatModelSelector.spec.tsx @@ -136,8 +136,10 @@ describe("ChatModelSelector", () => { }) }) - it("preserves the stored provider without injecting a provider override", async () => { - // No apiProvider is stored; the adapter must not write one back. + it("does not persist when no apiProvider is stored on the active profile", async () => { + // Profiles without apiProvider get their provider-specific fields stripped + // by the schema validator, so the adapter must refuse to write rather + // than silently lose the selection on reload. setState({ apiConfiguration: {} }) renderSelector() @@ -150,8 +152,32 @@ describe("ChatModelSelector", () => { fireEvent.click(screen.getByTestId("model-option-model-a")) }) + expect(mockPostMessage).not.toHaveBeenCalledWith(expect.objectContaining({ type: "upsertApiConfiguration" })) + }) + + it("preserves the stored provider without injecting a provider override", async () => { + setState({ + apiConfiguration: { + apiProvider: providerIdentifiers.openrouter, + openRouterModelId: "model-a", + }, + }) + + renderSelector() + + await act(async () => { + fireEvent.click(screen.getByTestId("chat-model-selector-trigger")) + }) + + await act(async () => { + fireEvent.click(screen.getByTestId("model-option-model-b")) + }) + const payload = mockPostMessage.mock.calls.find(([msg]) => msg.type === "upsertApiConfiguration")?.[0] - expect(payload?.apiConfiguration).not.toHaveProperty("apiProvider") + expect(payload?.apiConfiguration).toBeDefined() + // The adapter must not rewrite apiProvider even though the hook defaults + // to OpenRouter when no provider is set. + expect(payload?.apiConfiguration).toHaveProperty("apiProvider", providerIdentifiers.openrouter) }) it("lists VS Code LM models keyed as vendor/family even when custom models are restricted", async () => { diff --git a/webview-ui/src/components/settings/ModelPicker.tsx b/webview-ui/src/components/settings/ModelPicker.tsx index d0d5b01de7..4176c8b023 100644 --- a/webview-ui/src/components/settings/ModelPicker.tsx +++ b/webview-ui/src/components/settings/ModelPicker.tsx @@ -1,10 +1,9 @@ -import { useMemo, useState, useCallback, useEffect, useRef, type ReactNode } from "react" +import { useMemo, useState, useCallback, useEffect, useRef } from "react" import { VSCodeLink } from "@vscode/webview-ui-toolkit/react" import { Trans } from "react-i18next" -import { ChevronsUpDown, Check, X, Info } from "lucide-react" +import { ChevronsUpDown, Info } from "lucide-react" import { - type ProviderName, type ProviderSettings, type ModelInfo, type OrganizationAllowList, @@ -14,22 +13,9 @@ import { import { useAppTranslation } from "@src/i18n/TranslationContext" import { useSelectedModel } from "@/components/ui/hooks/useSelectedModel" -import { filterModels } from "./utils/organizationFilters" import { cn } from "@src/lib/utils" -import { - Command, - CommandEmpty, - CommandGroup, - CommandInput, - CommandItem, - CommandList, - Popover, - PopoverContent, - PopoverTrigger, - StandardTooltip, - Button, -} from "@src/components/ui" -import { useEscapeKey } from "@src/hooks/useEscapeKey" +import { Button } from "@src/components/ui" +import { ModelSelect } from "@/components/ui/model-select/ModelSelect" import { ModelInfoView } from "./ModelInfoView" import { ApiErrorMessage } from "./ApiErrorMessage" @@ -77,37 +63,6 @@ interface ModelPickerProps { displayTransform?: (value: unknown) => string /** Callback when model changes - useful for side effects like clearing related fields */ onModelChange?: (modelId: string) => void - /** - * Compact mode for the chat input bar: renders `renderTrigger` instead of - * the labelled combobox button, hides the model info/pricing block, and - * never auto-initializes a default model (the chat selector only reflects - * the active profile and persists explicit selections). - */ - compact?: boolean - /** Tooltip content shown above the trigger (compact mode). */ - tooltip?: string - /** Disable the trigger (compact mode). */ - disabled?: boolean - /** Whether the model list is still loading (compact mode). */ - isLoading?: boolean - /** Hide the custom-model escape hatch even when free-form ids are allowed. */ - hideCustomModel?: boolean - /** Custom trigger renderer (compact mode). */ - renderTrigger?: (state: { - displayValue: string | undefined - placeholder: string - isLoading: boolean - disabled: boolean - }) => ReactNode - /** Extra classes for the popover content (compact mode). */ - contentClassName?: string - /** Portal container for the popover content (compact mode). */ - portalContainer?: HTMLElement - /** - * Provider used to filter the model list. Defaults to the provider on - * `apiConfiguration`; the chat selector overrides it for an unset provider. - */ - activeProviderOverride?: ProviderName } export const ModelPicker = ({ @@ -126,251 +81,73 @@ export const ModelPicker = ({ valueTransform, displayTransform, onModelChange, - compact = false, - tooltip, - disabled = false, - isLoading = false, - hideCustomModel = false, - renderTrigger, - contentClassName, - portalContainer, - activeProviderOverride, }: ModelPickerProps) => { const { t } = useAppTranslation() - const [open, setOpen] = useState(false) const [isDescriptionExpanded, setIsDescriptionExpanded] = useState(false) const isInitialized = useRef(false) - const searchInputRef = useRef(null) - const selectTimeoutRef = useRef(null) - const closeTimeoutRef = useRef(null) const { id: selectedModelId, info: selectedModelInfo } = useSelectedModel(apiConfiguration) - // Get the display value for the current selection - // If displayTransform is provided, use it to convert the stored value to a display string + // Derive the display value for the current selection. If displayTransform + // is provided, convert the stored value to a display string; otherwise + // use the resolved selected model id from useSelectedModel. const displayValue = useMemo(() => { if (displayTransform) { const storedValue = apiConfiguration[modelIdKey] - return storedValue ? displayTransform(storedValue) : undefined + return storedValue ? displayTransform(storedValue) : "" } - return selectedModelId + return selectedModelId ?? "" }, [displayTransform, apiConfiguration, modelIdKey, selectedModelId]) const activeProvider = - activeProviderOverride ?? - (apiConfiguration.apiProvider && isRetiredProvider(apiConfiguration.apiProvider) + apiConfiguration.apiProvider && isRetiredProvider(apiConfiguration.apiProvider) ? undefined - : apiConfiguration.apiProvider) - - const modelIds = useMemo(() => { - const filteredModels = filterModels(models, activeProvider, organizationAllowList) - - // Include the currently selected model even if deprecated (so users can see what they have selected) - // But filter out other deprecated models from being newly selectable - const availableModels = Object.entries(filteredModels ?? {}) - .filter(([modelId, modelInfo]) => { - // Always include the currently selected model - if (modelId === selectedModelId) return true - // Filter out deprecated models that aren't currently selected - return !modelInfo.deprecated - }) - .reduce( - (acc, [modelId, modelInfo]) => { - acc[modelId] = modelInfo - return acc - }, - {} as Record, - ) - - return Object.keys(availableModels).sort((a, b) => a.localeCompare(b)) - }, [models, activeProvider, organizationAllowList, selectedModelId]) - - const [searchValue, setSearchValue] = useState("") + : apiConfiguration.apiProvider const onSelect = useCallback( (modelId: string) => { - if (!modelId) { - return - } - - setOpen(false) - - // Apply value transform if provided (e.g., for VSCodeLM selector) + if (!modelId) return const valueToStore = valueTransform ? valueTransform(modelId) : modelId setApiConfigurationField(modelIdKey, valueToStore as ProviderSettings[ModelIdKey]) - - // Call the optional change callback onModelChange?.(modelId) - - // Clear any existing timeout - if (selectTimeoutRef.current) { - clearTimeout(selectTimeoutRef.current) - } - - // Delay to ensure the popover is closed before setting the search value. - selectTimeoutRef.current = setTimeout(() => setSearchValue(""), 100) }, [modelIdKey, setApiConfigurationField, valueTransform, onModelChange], ) - const onOpenChange = useCallback((open: boolean) => { - setOpen(open) - - // Abandon the current search if the popover is closed. - if (!open) { - // Clear any existing timeout - if (closeTimeoutRef.current) { - clearTimeout(closeTimeoutRef.current) - } - - // Clear the search value when closing instead of prefilling it - closeTimeoutRef.current = setTimeout(() => setSearchValue(""), 100) - } - }, []) - - const onClearSearch = useCallback(() => { - setSearchValue("") - searchInputRef.current?.focus() - }, []) - + // Auto-initialize a default model when none is selected yet. This runs + // only once and only for the settings picker (the chat selector never + // auto-writes configuration). useEffect(() => { - // The compact (chat) picker must never auto-write configuration on mount. - if (compact) { - isInitialized.current = true - return - } - - if (!selectedModelId && !isInitialized.current) { - const initialValue = modelIds.includes(selectedModelId) ? selectedModelId : defaultModelId + if (isInitialized.current) return + if (!selectedModelId) { + const initialValue = selectedModelId === defaultModelId ? selectedModelId : defaultModelId setApiConfigurationField(modelIdKey, initialValue, false) // false = automatic initialization } - isInitialized.current = true - }, [modelIds, setApiConfigurationField, modelIdKey, selectedModelId, defaultModelId, compact]) - - // Cleanup timeouts on unmount to prevent test flakiness - useEffect(() => { - return () => { - if (selectTimeoutRef.current) { - clearTimeout(selectTimeoutRef.current) - } - if (closeTimeoutRef.current) { - clearTimeout(closeTimeoutRef.current) - } - } - }, []) - - // Use the shared ESC key handler hook - useEscapeKey(open, () => setOpen(false)) - - // Popover body shared by the settings picker and the compact chat picker. - const popoverContent = ( - - -

- - {searchValue.length > 0 && ( -
- -
- )} -
- - - {searchValue && ( -
{t("settings:modelPicker.noMatchFound")}
- )} -
- - {modelIds.map((model) => ( - - - {model} - - - - ))} - -
- {!hideCustomModel && searchValue && !modelIds.includes(searchValue) && ( -
- - {t("settings:modelPicker.useCustomModel", { modelId: searchValue })} - -
- )} - - - ) - - if (compact) { - const trigger = renderTrigger?.({ - displayValue, - placeholder: t("settings:common.select"), - isLoading, - disabled, - }) - - return ( - - {tooltip ? ( - - - {trigger} - - - ) : ( - - {trigger} - - )} - {popoverContent} - - ) - } + }, [selectedModelId, defaultModelId, modelIdKey, setApiConfigurationField]) return ( <>
- - + ( - - {popoverContent} - + )} + />
{errorMessage && } {selectedModelInfo?.deprecated && ( diff --git a/webview-ui/src/components/ui/hooks/__tests__/useVsCodeLmModels.spec.tsx b/webview-ui/src/components/ui/hooks/__tests__/useVsCodeLmModels.spec.tsx new file mode 100644 index 0000000000..e2c105d9b4 --- /dev/null +++ b/webview-ui/src/components/ui/hooks/__tests__/useVsCodeLmModels.spec.tsx @@ -0,0 +1,106 @@ +// npx vitest src/components/ui/hooks/__tests__/useVsCodeLmModels.spec.ts +import { QueryClient, QueryClientProvider } from "@tanstack/react-query" +import { renderHook, waitFor } from "@testing-library/react" +import React from "react" +import { beforeEach, describe, expect, it, vi } from "vitest" + +import { VsCodeLmModelsMessageType } from "@roo-code/types" + +vi.mock("@src/utils/vscode", () => ({ + vscode: { + postMessage: vi.fn(), + }, +})) + +import { vscode } from "@src/utils/vscode" + +import { useVsCodeLmModels } from "../useVsCodeLmModels" + +const wrapper = () => { + const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false } } }) + const Wrapper = ({ children }: { children: React.ReactNode }) => ( + {children} + ) + return { queryClient, Wrapper } +} + +const emitMessage = (data: unknown) => { + window.dispatchEvent(new MessageEvent("message", { data })) +} + +describe("useVsCodeLmModels", () => { + beforeEach(() => { + vi.clearAllMocks() + vi.useRealTimers() + }) + + it("does not post a request when disabled", async () => { + const { Wrapper } = wrapper() + renderHook(() => useVsCodeLmModels(false), { wrapper: Wrapper }) + + await waitFor(() => { + expect(vscode.postMessage).not.toHaveBeenCalled() + }) + }) + + it("posts a request when enabled and resolves with the matching response", async () => { + const { Wrapper } = wrapper() + const { result } = renderHook(() => useVsCodeLmModels(true), { wrapper: Wrapper }) + + expect(vscode.postMessage).toHaveBeenCalledWith({ + type: VsCodeLmModelsMessageType.requestVsCodeLmModels, + }) + + emitMessage({ + type: VsCodeLmModelsMessageType.vsCodeLmModels, + vsCodeLmModels: [{ vendor: "copilot", family: "gpt-4o" }], + }) + + await waitFor(() => expect(result.current.isSuccess).toBe(true)) + expect(result.current.data).toEqual([{ vendor: "copilot", family: "gpt-4o" }]) + }) + + it("ignores unrelated messages and keeps waiting for the matching response", async () => { + const { Wrapper } = wrapper() + const { result } = renderHook(() => useVsCodeLmModels(true), { wrapper: Wrapper }) + + emitMessage({ type: "someOtherMessage", payload: "nope" }) + + await waitFor(() => expect(vscode.postMessage).toHaveBeenCalled()) + expect(result.current.isSuccess).toBe(false) + + emitMessage({ + type: VsCodeLmModelsMessageType.vsCodeLmModels, + vsCodeLmModels: [{ vendor: "copilot", family: "gpt-4o-mini" }], + }) + + await waitFor(() => expect(result.current.isSuccess).toBe(true)) + expect(result.current.data).toEqual([{ vendor: "copilot", family: "gpt-4o-mini" }]) + }) + + it("defaults to an empty array when the response omits the model list", async () => { + const { Wrapper } = wrapper() + const { result } = renderHook(() => useVsCodeLmModels(true), { wrapper: Wrapper }) + + emitMessage({ type: VsCodeLmModelsMessageType.vsCodeLmModels }) + + await waitFor(() => expect(result.current.isSuccess).toBe(true)) + expect(result.current.data).toEqual([]) + }) + + it("removes the window message listener once the request resolves", async () => { + const { Wrapper } = wrapper() + const removeSpy = vi.spyOn(window, "removeEventListener") + renderHook(() => useVsCodeLmModels(true), { wrapper: Wrapper }) + + emitMessage({ + type: VsCodeLmModelsMessageType.vsCodeLmModels, + vsCodeLmModels: [], + }) + + await waitFor(() => { + expect(removeSpy).toHaveBeenCalledWith("message", expect.any(Function)) + }) + removeSpy.mockRestore() + }) +}) diff --git a/webview-ui/src/components/ui/hooks/useVsCodeLmModels.ts b/webview-ui/src/components/ui/hooks/useVsCodeLmModels.ts index 2005870d74..6d99bed610 100644 --- a/webview-ui/src/components/ui/hooks/useVsCodeLmModels.ts +++ b/webview-ui/src/components/ui/hooks/useVsCodeLmModels.ts @@ -5,27 +5,44 @@ import { type ExtensionMessage, VsCodeLmModelsMessageType } from "@roo-code/type import { vscode } from "@src/utils/vscode" -const getVsCodeLmModels = async () => +const getVsCodeLmModels = async (signal?: AbortSignal) => new Promise((resolve, reject) => { + let settled = false const cleanup = () => { window.removeEventListener("message", handler) + clearTimeout(timeout) } - const timeout = setTimeout(() => { + const finish = (fn: () => void) => { + if (settled || signal?.aborted) { + return + } + settled = true cleanup() - reject(new Error("VS Code LM models request timed out")) + fn() + } + + const timeout = setTimeout(() => { + finish(() => reject(new Error("VS Code LM models request timed out"))) }, 10000) const handler = (event: MessageEvent) => { const message: ExtensionMessage = event.data if (message.type === VsCodeLmModelsMessageType.vsCodeLmModels) { - clearTimeout(timeout) - cleanup() - resolve(message.vsCodeLmModels ?? []) + finish(() => resolve(message.vsCodeLmModels ?? [])) } } + signal?.addEventListener("abort", () => { + if (settled) { + return + } + settled = true + cleanup() + reject(new DOMException("Aborted", "AbortError")) + }) + window.addEventListener("message", handler) vscode.postMessage({ type: VsCodeLmModelsMessageType.requestVsCodeLmModels }) }) @@ -33,5 +50,5 @@ const getVsCodeLmModels = async () => export const useVsCodeLmModels = (enabled: boolean) => useQuery({ queryKey: ["vsCodeLmModels"], - queryFn: () => (enabled ? getVsCodeLmModels() : []), + queryFn: ({ signal }) => (enabled ? getVsCodeLmModels(signal) : []), }) diff --git a/webview-ui/src/components/ui/model-select/ModelSelect.tsx b/webview-ui/src/components/ui/model-select/ModelSelect.tsx new file mode 100644 index 0000000000..635a8cdd95 --- /dev/null +++ b/webview-ui/src/components/ui/model-select/ModelSelect.tsx @@ -0,0 +1,222 @@ +import { useCallback, useEffect, useMemo, useRef, useState, type ReactNode } from "react" +import { Check, X } from "lucide-react" + +import { type ModelInfo, type OrganizationAllowList, type ProviderName } from "@roo-code/types" + +import { useAppTranslation } from "@src/i18n/TranslationContext" +import { cn } from "@src/lib/utils" +import { + Command, + CommandEmpty, + CommandGroup, + CommandInput, + CommandItem, + CommandList, + Popover, + PopoverContent, + PopoverTrigger, + StandardTooltip, +} from "@src/components/ui" +import { useEscapeKey } from "@src/hooks/useEscapeKey" + +import { filterModels } from "@/components/settings/utils/organizationFilters" + +export interface ModelSelectProps { + models: Record | null + value: string + onChange: (modelId: string) => void + placeholder?: string + disabled?: boolean + isLoading?: boolean + hideCustomModel?: boolean + /** Provider used to apply organization allow-list filtering. */ + activeProvider?: ProviderName + organizationAllowList?: OrganizationAllowList + /** Extra classes for the popover content. */ + contentClassName?: string + /** Portal container for the popover content. */ + portalContainer?: HTMLElement + /** Optional tooltip shown above the trigger (wraps PopoverTrigger). */ + tooltip?: string + /** Custom trigger renderer. */ + renderTrigger?: (args: { + displayValue: string + isLoading: boolean + placeholder: string + disabled: boolean + }) => ReactNode +} + +/** + * Core model selection logic shared by the settings page and the chat input + * bar: a Popover with a searchable Command list, ESC to close, search-state + * cleanup, and an optional custom-model escape hatch. + * + * This component intentionally does **not** auto-initialize a default model, + * nor does it write to configuration directly — callers own persistence. + */ +export const ModelSelect = ({ + models, + value, + onChange, + placeholder, + disabled = false, + isLoading = false, + hideCustomModel = false, + activeProvider, + organizationAllowList, + contentClassName, + portalContainer, + tooltip, + renderTrigger, +}: ModelSelectProps) => { + const { t } = useAppTranslation() + + const [open, setOpen] = useState(false) + const searchInputRef = useRef(null) + const selectTimeoutRef = useRef(null) + const closeTimeoutRef = useRef(null) + const [searchValue, setSearchValue] = useState("") + + const displayValue = value ?? "" + + const modelIds = useMemo(() => { + const filtered = filterModels(models, activeProvider, organizationAllowList) + + // Always include the currently selected model even if deprecated, but + // filter out other deprecated models from being newly selectable. + const available = Object.entries(filtered ?? {}).filter(([modelId, info]) => + modelId === displayValue ? true : !info.deprecated, + ) + + return available.map(([id]) => id).sort((a, b) => a.localeCompare(b)) + }, [models, activeProvider, organizationAllowList, displayValue]) + + const onSelect = useCallback( + (modelId: string) => { + if (!modelId) return + + setOpen(false) + onChange(modelId) + + if (selectTimeoutRef.current) clearTimeout(selectTimeoutRef.current) + // Delay to ensure the popover is closed before clearing search. + selectTimeoutRef.current = setTimeout(() => setSearchValue(""), 100) + }, + [onChange], + ) + + const onOpenChange = useCallback((nextOpen: boolean) => { + setOpen(nextOpen) + // Abandon the current search when the popover closes. + if (!nextOpen) { + if (closeTimeoutRef.current) clearTimeout(closeTimeoutRef.current) + closeTimeoutRef.current = setTimeout(() => setSearchValue(""), 100) + } + }, []) + + const onClearSearch = useCallback(() => { + setSearchValue("") + searchInputRef.current?.focus() + }, []) + + // Cleanup pending timeouts on unmount to prevent test flakiness. + useEffect(() => { + return () => { + if (selectTimeoutRef.current) clearTimeout(selectTimeoutRef.current) + if (closeTimeoutRef.current) clearTimeout(closeTimeoutRef.current) + } + }, []) + + useEscapeKey(open, () => setOpen(false)) + + const resolvedPlaceholder = placeholder ?? t("settings:common.select") + + const triggerNode = renderTrigger?.({ + displayValue, + isLoading, + placeholder: resolvedPlaceholder, + disabled, + }) + + return ( + + {tooltip ? ( + + + {triggerNode} + + + ) : ( + + {triggerNode} + + )} + + +
+ + {searchValue.length > 0 && ( +
+ +
+ )} +
+ + + {searchValue && ( +
{t("settings:modelPicker.noMatchFound")}
+ )} +
+ + {modelIds.map((model) => ( + + + {model} + + + + ))} + +
+ {!hideCustomModel && searchValue && !modelIds.includes(searchValue) && ( +
+ + {t("settings:modelPicker.useCustomModel", { modelId: searchValue })} + +
+ )} +
+
+
+ ) +} From 310fd5514b360f12afad158fad810de935a8379f Mon Sep 17 00:00:00 2001 From: seeones Date: Tue, 13 Oct 2026 22:19:42 +0800 Subject: [PATCH 08/12] fix(chat): address CodeRabbit review on model selector - ModelSelect: remove popover width dead-code ternary; all callers pass renderTrigger so align/sideOffset/width are now constants. - ChatModelSelector: include !apiConfiguration?.apiProvider in isDisabled so the trigger no longer opens a picker whose selection would be silently discarded by persistSelection guard. - useVsCodeLmModels: document why no requestId correlation is needed (stable query key => at most one in-flight queryFn invocation). - useVsCodeLmModels.spec: assert removeEventListener receives the same handler reference that addEventListener registered, instead of expect.any(Function). - ChatModelSelector.spec: rename the provider-less case to assert the trigger is disabled and the popover cannot be opened. --- .../src/components/chat/ChatModelSelector.tsx | 2 +- .../chat/__tests__/ChatModelSelector.spec.tsx | 16 +++++++++------- .../hooks/__tests__/useVsCodeLmModels.spec.tsx | 11 +++++++++-- .../src/components/ui/hooks/useVsCodeLmModels.ts | 4 ++++ .../components/ui/model-select/ModelSelect.tsx | 12 +++--------- 5 files changed, 26 insertions(+), 19 deletions(-) diff --git a/webview-ui/src/components/chat/ChatModelSelector.tsx b/webview-ui/src/components/chat/ChatModelSelector.tsx index 7b88c9f5ae..f3d95aed95 100644 --- a/webview-ui/src/components/chat/ChatModelSelector.tsx +++ b/webview-ui/src/components/chat/ChatModelSelector.tsx @@ -64,7 +64,7 @@ export const ChatModelSelector = ({ disabled = false, title, triggerClassName = return !providerConfig?.allowAll }, [organizationAllowList, provider]) - const isDisabled = disabled || !modelIdKey || !currentApiConfigName + const isDisabled = disabled || !modelIdKey || !currentApiConfigName || !apiConfiguration?.apiProvider return ( { }) }) - it("does not persist when no apiProvider is stored on the active profile", async () => { + it("disables the trigger when no apiProvider is stored on the active profile", async () => { // Profiles without apiProvider get their provider-specific fields stripped - // by the schema validator, so the adapter must refuse to write rather - // than silently lose the selection on reload. + // by the schema validator, so the adapter must disable the trigger rather + // than let the user pick a model that would be silently dropped on reload. setState({ apiConfiguration: {} }) renderSelector() - await act(async () => { - fireEvent.click(screen.getByTestId("chat-model-selector-trigger")) - }) + const trigger = screen.getByTestId("chat-model-selector-trigger") + expect(trigger).toBeDisabled() + // Clicking a disabled trigger must not open the popover, so no model + // option should be reachable. await act(async () => { - fireEvent.click(screen.getByTestId("model-option-model-a")) + fireEvent.click(trigger) }) + expect(screen.queryByTestId("model-option-model-a")).not.toBeInTheDocument() expect(mockPostMessage).not.toHaveBeenCalledWith(expect.objectContaining({ type: "upsertApiConfiguration" })) }) diff --git a/webview-ui/src/components/ui/hooks/__tests__/useVsCodeLmModels.spec.tsx b/webview-ui/src/components/ui/hooks/__tests__/useVsCodeLmModels.spec.tsx index e2c105d9b4..2bb772a750 100644 --- a/webview-ui/src/components/ui/hooks/__tests__/useVsCodeLmModels.spec.tsx +++ b/webview-ui/src/components/ui/hooks/__tests__/useVsCodeLmModels.spec.tsx @@ -88,19 +88,26 @@ describe("useVsCodeLmModels", () => { expect(result.current.data).toEqual([]) }) - it("removes the window message listener once the request resolves", async () => { + it("removes the same window message listener it registered once the request resolves", async () => { const { Wrapper } = wrapper() + const addSpy = vi.spyOn(window, "addEventListener") const removeSpy = vi.spyOn(window, "removeEventListener") + renderHook(() => useVsCodeLmModels(true), { wrapper: Wrapper }) + const registeredHandler = addSpy.mock.calls.find(([eventName]) => eventName === "message")?.[1] + expect(registeredHandler).toBeDefined() + emitMessage({ type: VsCodeLmModelsMessageType.vsCodeLmModels, vsCodeLmModels: [], }) await waitFor(() => { - expect(removeSpy).toHaveBeenCalledWith("message", expect.any(Function)) + expect(removeSpy).toHaveBeenCalledWith("message", registeredHandler) }) + + addSpy.mockRestore() removeSpy.mockRestore() }) }) diff --git a/webview-ui/src/components/ui/hooks/useVsCodeLmModels.ts b/webview-ui/src/components/ui/hooks/useVsCodeLmModels.ts index 6d99bed610..8361b01b30 100644 --- a/webview-ui/src/components/ui/hooks/useVsCodeLmModels.ts +++ b/webview-ui/src/components/ui/hooks/useVsCodeLmModels.ts @@ -5,6 +5,10 @@ import { type ExtensionMessage, VsCodeLmModelsMessageType } from "@roo-code/type import { vscode } from "@src/utils/vscode" +// The query key is a constant ("vsCodeLmModels"), so at most one in-flight +// request can exist at any moment. No requestId correlation is needed: if +// React Query retries, it aborts the previous signal before firing the next +// request, so responses are always matched to the current queryFn invocation. const getVsCodeLmModels = async (signal?: AbortSignal) => new Promise((resolve, reject) => { let settled = false diff --git a/webview-ui/src/components/ui/model-select/ModelSelect.tsx b/webview-ui/src/components/ui/model-select/ModelSelect.tsx index 635a8cdd95..d2673d1132 100644 --- a/webview-ui/src/components/ui/model-select/ModelSelect.tsx +++ b/webview-ui/src/components/ui/model-select/ModelSelect.tsx @@ -153,16 +153,10 @@ export const ModelSelect = ({ )} + align="start" + sideOffset={4}>
Date: Tue, 13 Oct 2026 22:32:33 +0800 Subject: [PATCH 09/12] fix(chat): harden useVsCodeLmModels abort path and restore settings popover width - useVsCodeLmModels: reject immediately if signal is already aborted before registering message listener or starting the timer. Extract abort handler into a named function registered with { once: true }, and remove it in cleanup. finish() now only checks settled, leaving abort semantics to the handler. - useVsCodeLmModels.spec: add an abort-path test that cancels the query, asserts the registered message handler is removed, and verifies a late response does not populate result.current.data. - ModelPicker: pass contentClassName w-[var(--radix-popover-trigger-width)] so the settings popover follows its combobox trigger width while chat keeps the 300px compact default. twMerge resolves the w-* conflict. --- .../src/components/settings/ModelPicker.tsx | 1 + .../__tests__/useVsCodeLmModels.spec.tsx | 29 ++++++++++++++ .../components/ui/hooks/useVsCodeLmModels.ts | 38 +++++++++++-------- 3 files changed, 52 insertions(+), 16 deletions(-) diff --git a/webview-ui/src/components/settings/ModelPicker.tsx b/webview-ui/src/components/settings/ModelPicker.tsx index 4176c8b023..726f278b59 100644 --- a/webview-ui/src/components/settings/ModelPicker.tsx +++ b/webview-ui/src/components/settings/ModelPicker.tsx @@ -137,6 +137,7 @@ export const ModelPicker = ({ onChange={onSelect} activeProvider={activeProvider} organizationAllowList={organizationAllowList} + contentClassName="w-[var(--radix-popover-trigger-width)]" renderTrigger={({ displayValue: value, placeholder }) => (