diff --git a/webview-ui/src/components/chat/ChatView.tsx b/webview-ui/src/components/chat/ChatView.tsx
index c287a99cbb..419537b361 100644
--- a/webview-ui/src/components/chat/ChatView.tsx
+++ b/webview-ui/src/components/chat/ChatView.tsx
@@ -4,6 +4,9 @@ import { forwardRef, useCallback, useEffect, useImperativeHandle, useMemo, useRe
import { useDeepCompareEffect, useEvent, useMount } from "react-use"
import { Virtuoso, type VirtuosoHandle } from "react-virtuoso"
import styled from "styled-components"
+import removeMd from "remove-markdown"
+import { Trans } from "react-i18next"
+
import {
ClineAsk,
ClineMessage,
@@ -16,11 +19,19 @@ import { findLast } from "@roo/shared/array"
import { combineApiRequests } from "@roo/shared/combineApiRequests"
import { combineCommandSequences } from "@roo/shared/combineCommandSequences"
import { getApiMetrics } from "@roo/shared/getApiMetrics"
+import { AudioType } from "@roo/shared/WebviewMessage"
+import { getAllModes } from "@roo/shared/modes"
+
import { useExtensionState } from "@src/context/ExtensionStateContext"
import { vscode } from "@src/utils/vscode"
+import { normalizeApiConfiguration } from "@src/utils/normalizeApiConfiguration"
+import { validateCommand } from "@src/utils/command-validation"
+import { useAppTranslation } from "@src/i18n/TranslationContext"
+
+import TelemetryBanner from "../common/TelemetryBanner"
import HistoryPreview from "../history/HistoryPreview"
import RooHero from "../welcome/RooHero"
-import { normalizeApiConfiguration } from "../settings/ApiOptions"
+
import Announcement from "./Announcement"
import BrowserSessionRow from "./BrowserSessionRow"
import ChatRow from "./ChatRow"
@@ -28,13 +39,7 @@ import ChatTextArea from "./ChatTextArea"
import TaskHeader from "./TaskHeader"
import AutoApproveMenu from "./AutoApproveMenu"
import SystemPromptWarning from "./SystemPromptWarning"
-import { AudioType } from "@roo/shared/WebviewMessage"
-import { validateCommand } from "@src/utils/command-validation"
-import { getAllModes } from "@roo/shared/modes"
-import TelemetryBanner from "../common/TelemetryBanner"
-import { useAppTranslation } from "@/i18n/TranslationContext"
-import removeMd from "remove-markdown"
-import { Trans } from "react-i18next"
+
interface ChatViewProps {
isHidden: boolean
showAnnouncement: boolean
diff --git a/webview-ui/src/components/chat/TaskHeader.tsx b/webview-ui/src/components/chat/TaskHeader.tsx
index d08684d932..9fe3cf5c9d 100644
--- a/webview-ui/src/components/chat/TaskHeader.tsx
+++ b/webview-ui/src/components/chat/TaskHeader.tsx
@@ -6,14 +6,14 @@ import { CloudUpload, CloudDownload } from "lucide-react"
import { ClineMessage } from "@roo/shared/ExtensionMessage"
-import { getMaxTokensForModel } from "@/utils/model-utils"
-import { formatLargeNumber } from "@/utils/format"
-import { cn } from "@/lib/utils"
-import { Button } from "@/components/ui"
+import { getMaxTokensForModel } from "@src/utils/model-utils"
+import { formatLargeNumber } from "@src/utils/format"
+import { cn } from "@src/lib/utils"
+import { Button } from "@src/components/ui"
import { useExtensionState } from "@src/context/ExtensionStateContext"
+import { normalizeApiConfiguration } from "@src/utils/normalizeApiConfiguration"
import Thumbnails from "../common/Thumbnails"
-import { normalizeApiConfiguration } from "../settings/ApiOptions"
import { TaskActions } from "./TaskActions"
import { ContextWindowProgress } from "./ContextWindowProgress"
diff --git a/webview-ui/src/components/settings/ApiOptions.tsx b/webview-ui/src/components/settings/ApiOptions.tsx
index afefe70d86..0242346f81 100644
--- a/webview-ui/src/components/settings/ApiOptions.tsx
+++ b/webview-ui/src/components/settings/ApiOptions.tsx
@@ -11,48 +11,34 @@ import { ExternalLinkIcon } from "@radix-ui/react-icons"
import {
ApiConfiguration,
ModelInfo,
- anthropicDefaultModelId,
- anthropicModels,
azureOpenAiDefaultApiVersion,
- bedrockDefaultModelId,
- bedrockModels,
- deepSeekDefaultModelId,
- deepSeekModels,
- geminiDefaultModelId,
- geminiModels,
glamaDefaultModelId,
glamaDefaultModelInfo,
mistralDefaultModelId,
- mistralModels,
openAiModelInfoSaneDefaults,
- openAiNativeDefaultModelId,
- openAiNativeModels,
openRouterDefaultModelId,
openRouterDefaultModelInfo,
- vertexDefaultModelId,
- vertexModels,
unboundDefaultModelId,
unboundDefaultModelInfo,
requestyDefaultModelId,
requestyDefaultModelInfo,
- xaiDefaultModelId,
- xaiModels,
ApiProvider,
- vscodeLlmModels,
- vscodeLlmDefaultModelId,
} from "@roo/shared/api"
import { ExtensionMessage } from "@roo/shared/ExtensionMessage"
+import { AWS_REGIONS } from "@roo/shared/aws_regions"
-import { vscode } from "@/utils/vscode"
-import { validateApiConfiguration, validateModelId, validateBedrockArn } from "@/utils/validate"
+import { vscode } from "@src/utils/vscode"
+import { validateApiConfiguration, validateModelId, validateBedrockArn } from "@src/utils/validate"
+import { normalizeApiConfiguration } from "@src/utils/normalizeApiConfiguration"
import {
useOpenRouterModelProviders,
OPENROUTER_DEFAULT_PROVIDER_NAME,
-} from "@/components/ui/hooks/useOpenRouterModelProviders"
-import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, SelectSeparator, Button } from "@/components/ui"
-import { MODELS_BY_PROVIDER, PROVIDERS, VERTEX_REGIONS, REASONING_MODELS } from "./constants"
-import { AWS_REGIONS } from "@roo/shared/aws_regions"
+} from "@src/components/ui/hooks/useOpenRouterModelProviders"
+import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, Button } from "@src/components/ui"
+
import { VSCodeButtonLink } from "../common/VSCodeButtonLink"
+
+import { MODELS_BY_PROVIDER, PROVIDERS, VERTEX_REGIONS, REASONING_MODELS } from "./constants"
import { ModelInfoView } from "./ModelInfoView"
import { ModelPicker } from "./ModelPicker"
import { TemperatureControl } from "./TemperatureControl"
@@ -281,6 +267,7 @@ const ApiOptions = ({
// Helper function to get the documentation URL and name for the currently selected provider
const getSelectedProviderDocUrl = (): { url: string; name: string } | undefined => {
const displayName = getProviderDisplayName(selectedProvider)
+
if (!displayName) {
return undefined
}
@@ -294,6 +281,49 @@ const ApiOptions = ({
}
}
+ const onApiProviderChange = useCallback(
+ (value: ApiProvider) => {
+ // It would be much easier to have a single attribute that stores
+ // the modelId, but we have a separate attribute for each of
+ // OpenRouter, Glama, Unbound, and Requesty.
+ // If you switch to one of these providers and the corresponding
+ // modelId is not set then you immediately end up in an error state.
+ // To address that we set the modelId to the default value for th
+ // provider if it's not already set.
+ switch (value) {
+ case "openrouter":
+ if (!apiConfiguration.openRouterModelId) {
+ setApiConfigurationField("openRouterModelId", openRouterDefaultModelId)
+ }
+ break
+ case "glama":
+ if (!apiConfiguration.glamaModelId) {
+ setApiConfigurationField("glamaModelId", glamaDefaultModelId)
+ }
+ break
+ case "unbound":
+ if (!apiConfiguration.unboundModelId) {
+ setApiConfigurationField("unboundModelId", unboundDefaultModelId)
+ }
+ break
+ case "requesty":
+ if (!apiConfiguration.requestyModelId) {
+ setApiConfigurationField("requestyModelId", requestyDefaultModelId)
+ }
+ break
+ }
+
+ setApiConfigurationField("apiProvider", value)
+ },
+ [
+ setApiConfigurationField,
+ apiConfiguration.openRouterModelId,
+ apiConfiguration.glamaModelId,
+ apiConfiguration.unboundModelId,
+ apiConfiguration.requestyModelId,
+ ],
+ )
+
return (
@@ -312,16 +342,12 @@ const ApiOptions = ({
)}
-