diff --git a/webview-ui/src/components/settings/ModelInfoView.tsx b/webview-ui/src/components/settings/ModelInfoView.tsx index fff55eda55..34feecb2bb 100644 --- a/webview-ui/src/components/settings/ModelInfoView.tsx +++ b/webview-ui/src/components/settings/ModelInfoView.tsx @@ -79,7 +79,7 @@ export const ModelInfoView = ({ supportsLabel={t("settings:modelInfo.supportsPromptCache")} doesNotSupportLabel={t("settings:modelInfo.noPromptCache")} />, - apiProvider === "gemini" && ( + apiProvider === providerIdentifiers.gemini && ( {selectedModelId.includes("pro-preview") ? t("settings:modelInfo.gemini.billingEstimate") diff --git a/webview-ui/src/components/settings/ModelPicker.tsx b/webview-ui/src/components/settings/ModelPicker.tsx index e32806343d..64707f6313 100644 --- a/webview-ui/src/components/settings/ModelPicker.tsx +++ b/webview-ui/src/components/settings/ModelPicker.tsx @@ -3,7 +3,13 @@ import { VSCodeLink } from "@vscode/webview-ui-toolkit/react" import { Trans } from "react-i18next" import { ChevronsUpDown, Check, X, Info } from "lucide-react" -import { type ProviderSettings, type ModelInfo, type OrganizationAllowList, isRetiredProvider } from "@roo-code/types" +import { + type ProviderSettings, + type ModelInfo, + type OrganizationAllowList, + isRetiredProvider, + providerIdentifiers, +} from "@roo-code/types" import { useAppTranslation } from "@src/i18n/TranslationContext" import { useSelectedModel } from "@/components/ui/hooks/useSelectedModel" @@ -305,7 +311,7 @@ export const ModelPicker = ({ hidePricing={hidePricing} /> )} - {!hidePricing && apiConfiguration.apiProvider !== "mimo" && ( + {!hidePricing && apiConfiguration.apiProvider !== providerIdentifiers.mimo && (
{ } describe("ModelInfoView service tier pricing", () => { + it("shows Gemini billing guidance for the canonical Gemini provider", () => { + render( + , + ) + + expect(screen.getByText("settings:modelInfo.gemini.billingEstimate")).toBeInTheDocument() + }) + it("shows OpenAI Native tier prices with per-field fallback to Standard pricing", () => { const modelInfo: ModelInfo = { ...baseModelInfo, diff --git a/webview-ui/src/components/settings/constants.ts b/webview-ui/src/components/settings/constants.ts index 15061e333d..7e5e10db6b 100644 --- a/webview-ui/src/components/settings/constants.ts +++ b/webview-ui/src/components/settings/constants.ts @@ -1,6 +1,7 @@ import { type ProviderName, type ModelInfo, + providerIdentifiers, anthropicModels, bedrockModels, deepSeekModels, @@ -22,57 +23,57 @@ import { } from "@roo-code/types" export const MODELS_BY_PROVIDER: Partial>> = { - anthropic: anthropicModels, - bedrock: bedrockModels, - deepseek: deepSeekModels, - moonshot: moonshotModels, - gemini: geminiModels, - mistral: mistralModels, - "openai-native": openAiNativeModels, - "openai-codex": openAiCodexModels, - "qwen-code": qwenCodeModels, - vertex: vertexModels, - xai: xaiModels, - sambanova: sambaNovaModels, - zai: internationalZAiModels, - fireworks: fireworksModels, - friendli: friendliModels, - minimax: minimaxModels, - mimo: mimoModels, - baseten: basetenModels, + [providerIdentifiers.anthropic]: anthropicModels, + [providerIdentifiers.bedrock]: bedrockModels, + [providerIdentifiers.deepseek]: deepSeekModels, + [providerIdentifiers.moonshot]: moonshotModels, + [providerIdentifiers.gemini]: geminiModels, + [providerIdentifiers.mistral]: mistralModels, + [providerIdentifiers.openaiNative]: openAiNativeModels, + [providerIdentifiers.openaiCodex]: openAiCodexModels, + [providerIdentifiers.qwenCode]: qwenCodeModels, + [providerIdentifiers.vertex]: vertexModels, + [providerIdentifiers.xai]: xaiModels, + [providerIdentifiers.sambanova]: sambaNovaModels, + [providerIdentifiers.zai]: internationalZAiModels, + [providerIdentifiers.fireworks]: fireworksModels, + [providerIdentifiers.friendli]: friendliModels, + [providerIdentifiers.minimax]: minimaxModels, + [providerIdentifiers.mimo]: mimoModels, + [providerIdentifiers.baseten]: basetenModels, } -export const PROVIDERS = [ - { value: "openrouter", label: "OpenRouter", proxy: false }, - { value: "anthropic", label: "Anthropic", proxy: false }, - { value: "gemini", label: "Google Gemini", proxy: false }, - { value: "deepseek", label: "DeepSeek", proxy: false }, - { value: "moonshot", label: "Moonshot", proxy: false }, - { value: "kimi-code", label: "Kimi Code", proxy: false }, - { value: "openai-native", label: "OpenAI", proxy: false }, - { value: "openai-codex", label: "OpenAI - ChatGPT Plus/Pro", proxy: false }, - { value: "openai", label: "OpenAI Compatible", proxy: true }, - { value: "qwen-code", label: "Qwen Code", proxy: false }, - { value: "vertex", label: "GCP Vertex AI", proxy: false }, - { value: "bedrock", label: "Amazon Bedrock", proxy: false }, - { value: "vscode-lm", label: "VS Code LM API", proxy: false }, - { value: "mistral", label: "Mistral", proxy: false }, - { value: "lmstudio", label: "LM Studio", proxy: true }, - { value: "ollama", label: "Ollama", proxy: true }, - { value: "requesty", label: "Requesty", proxy: false }, - { value: "xai", label: "xAI (Grok)", proxy: false }, - { value: "litellm", label: "LiteLLM", proxy: true }, - { value: "sambanova", label: "SambaNova", proxy: false }, - { value: "zai", label: "Z.ai", proxy: false }, - { value: "fireworks", label: "Fireworks AI", proxy: false }, - { value: "friendli", label: "Friendli", proxy: false }, - { value: "vercel-ai-gateway", label: "Vercel AI Gateway", proxy: false }, - { value: "opencode-go", label: "Opencode Go", proxy: false }, - { value: "kenari", label: "Kenari", proxy: false }, - { value: "zoo-gateway", label: "Zoo Gateway", proxy: false }, - { value: "minimax", label: "MiniMax", proxy: false }, - { value: "mimo", label: "Xiaomi MiMo", proxy: false }, - { value: "baseten", label: "Baseten", proxy: false }, - { value: "unbound", label: "Unbound", proxy: false }, - { value: "poe", label: "Poe", proxy: false }, +export const PROVIDERS: Array<{ value: string; label: string; proxy: boolean }> = [ + { value: providerIdentifiers.openrouter, label: "OpenRouter", proxy: false }, + { value: providerIdentifiers.anthropic, label: "Anthropic", proxy: false }, + { value: providerIdentifiers.gemini, label: "Google Gemini", proxy: false }, + { value: providerIdentifiers.deepseek, label: "DeepSeek", proxy: false }, + { value: providerIdentifiers.moonshot, label: "Moonshot", proxy: false }, + { value: providerIdentifiers.kimiCode, label: "Kimi Code", proxy: false }, + { value: providerIdentifiers.openaiNative, label: "OpenAI", proxy: false }, + { value: providerIdentifiers.openaiCodex, label: "OpenAI - ChatGPT Plus/Pro", proxy: false }, + { value: providerIdentifiers.openai, label: "OpenAI Compatible", proxy: true }, + { value: providerIdentifiers.qwenCode, label: "Qwen Code", proxy: false }, + { value: providerIdentifiers.vertex, label: "GCP Vertex AI", proxy: false }, + { value: providerIdentifiers.bedrock, label: "Amazon Bedrock", proxy: false }, + { value: providerIdentifiers.vscodeLm, label: "VS Code LM API", proxy: false }, + { value: providerIdentifiers.mistral, label: "Mistral", proxy: false }, + { value: providerIdentifiers.lmstudio, label: "LM Studio", proxy: true }, + { value: providerIdentifiers.ollama, label: "Ollama", proxy: true }, + { value: providerIdentifiers.requesty, label: "Requesty", proxy: false }, + { value: providerIdentifiers.xai, label: "xAI (Grok)", proxy: false }, + { value: providerIdentifiers.litellm, label: "LiteLLM", proxy: true }, + { value: providerIdentifiers.sambanova, label: "SambaNova", proxy: false }, + { value: providerIdentifiers.zai, label: "Z.ai", proxy: false }, + { value: providerIdentifiers.fireworks, label: "Fireworks AI", proxy: false }, + { value: providerIdentifiers.friendli, label: "Friendli", proxy: false }, + { value: providerIdentifiers.vercelAiGateway, label: "Vercel AI Gateway", proxy: false }, + { value: providerIdentifiers.opencodeGo, label: "Opencode Go", proxy: false }, + { value: providerIdentifiers.kenari, label: "Kenari", proxy: false }, + { value: providerIdentifiers.zooGateway, label: "Zoo Gateway", proxy: false }, + { value: providerIdentifiers.minimax, label: "MiniMax", proxy: false }, + { value: providerIdentifiers.mimo, label: "Xiaomi MiMo", proxy: false }, + { value: providerIdentifiers.baseten, label: "Baseten", proxy: false }, + { value: providerIdentifiers.unbound, label: "Unbound", proxy: false }, + { value: providerIdentifiers.poe, label: "Poe", proxy: false }, ].sort((a, b) => a.label.localeCompare(b.label))