From 57cfaccceb6e87db3acb78db6ed4d3237a60c8e6 Mon Sep 17 00:00:00 2001 From: decolua Date: Sun, 5 Apr 2026 21:25:00 +0700 Subject: [PATCH] Fix ModelSelectModal --- open-sse/config/providerModels.js | 4 +--- package.json | 2 +- src/shared/components/ModelSelectModal.js | 17 ++++++++++------- src/shared/constants/providers.js | 2 +- 4 files changed, 13 insertions(+), 12 deletions(-) diff --git a/open-sse/config/providerModels.js b/open-sse/config/providerModels.js index e5496aa..74b2576 100644 --- a/open-sse/config/providerModels.js +++ b/open-sse/config/providerModels.js @@ -396,9 +396,7 @@ export const PROVIDER_MODELS = { { id: "text-embedding-005", name: "Text Embedding 005", type: "embedding" }, { id: "text-embedding-004", name: "Text Embedding 004 (Legacy)", type: "embedding" }, ], - openrouter: [ - // { id: "openrouter/free", name: "Free Models (Auto)" }, - ], + openrouter: [], glm: [ { id: "glm-5.1", name: "GLM 5.1" }, { id: "glm-5", name: "GLM 5" }, diff --git a/package.json b/package.json index b71f659..8903c72 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "9router-app", - "version": "0.3.75", + "version": "0.3.78", "description": "9Router web dashboard", "private": true, "scripts": { diff --git a/src/shared/components/ModelSelectModal.js b/src/shared/components/ModelSelectModal.js index 9e5218e..62c5a37 100644 --- a/src/shared/components/ModelSelectModal.js +++ b/src/shared/components/ModelSelectModal.js @@ -4,11 +4,12 @@ import { useState, useMemo, useEffect } from "react"; import PropTypes from "prop-types"; import Modal from "./Modal"; import { getModelsByProviderId, PROVIDER_ID_TO_ALIAS } from "@/shared/constants/models"; -import { OAUTH_PROVIDERS, APIKEY_PROVIDERS, isOpenAICompatibleProvider, isAnthropicCompatibleProvider } from "@/shared/constants/providers"; +import { OAUTH_PROVIDERS, APIKEY_PROVIDERS, FREE_TIER_PROVIDERS, isOpenAICompatibleProvider, isAnthropicCompatibleProvider } from "@/shared/constants/providers"; -// Provider order: OAuth first, then API Key (matches dashboard/providers) +// Provider order: OAuth first, then Free Tier, then API Key (matches dashboard/providers) const PROVIDER_ORDER = [ ...Object.keys(OAUTH_PROVIDERS), + ...Object.keys(FREE_TIER_PROVIDERS), ...Object.keys(APIKEY_PROVIDERS), ]; @@ -57,7 +58,7 @@ export default function ModelSelectModal({ if (isOpen) fetchProviderNodes(); }, [isOpen]); - const allProviders = useMemo(() => ({ ...OAUTH_PROVIDERS, ...APIKEY_PROVIDERS }), []); + const allProviders = useMemo(() => ({ ...OAUTH_PROVIDERS, ...FREE_TIER_PROVIDERS, ...APIKEY_PROVIDERS }), []); // Group models by provider with priority order const groupedModels = useMemo(() => { @@ -142,16 +143,18 @@ export default function ModelSelectModal({ const hardcodedModels = getModelsByProviderId(providerId); const hardcodedIds = new Set(hardcodedModels.map((m) => m.id)); - // Custom models user added via "Add Model" button (alias === modelId pattern) + // Custom models: if no hardcoded models (e.g. openrouter), show all aliases for this provider + // Otherwise only show aliases where aliasName === modelId ("Add Model" button pattern) + const hasHardcoded = hardcodedModels.length > 0; const customModels = Object.entries(modelAliases) .filter(([aliasName, fullModel]) => fullModel.startsWith(`${alias}/`) && - aliasName === fullModel.replace(`${alias}/`, "") && + (hasHardcoded ? aliasName === fullModel.replace(`${alias}/`, "") : true) && !hardcodedIds.has(fullModel.replace(`${alias}/`, "")) ) - .map(([, fullModel]) => { + .map(([aliasName, fullModel]) => { const modelId = fullModel.replace(`${alias}/`, ""); - return { id: modelId, name: modelId, value: fullModel, isCustom: true }; + return { id: modelId, name: aliasName, value: fullModel, isCustom: true }; }); const allModels = [ diff --git a/src/shared/constants/providers.js b/src/shared/constants/providers.js index 9f94c63..710a6df 100644 --- a/src/shared/constants/providers.js +++ b/src/shared/constants/providers.js @@ -13,7 +13,7 @@ export const FREE_PROVIDERS = { // Free Tier Providers (has free access but may require account/API key) export const FREE_TIER_PROVIDERS = { - openrouter: { id: "openrouter", alias: "openrouter", name: "OpenRouter", icon: "router", color: "#F97316", textIcon: "OR", passthroughModels: true, website: "https://openrouter.ai", notice: { text: "Free tier: 27+ free models, no credit card needed, 200 req/day. After $10 credit: 1,000 req/day.", apiKeyUrl: "https://openrouter.ai/settings/keys" }, modelsFetcher: { url: "https://openrouter.ai/api/v1/models", type: "openrouter-free" } }, + openrouter: { id: "openrouter", alias: "openrouter", name: "OpenRouter", icon: "router", color: "#F97316", textIcon: "OR", website: "https://openrouter.ai", notice: { text: "Free tier: 27+ free models, no credit card needed, 200 req/day. After $10 credit: 1,000 req/day.", apiKeyUrl: "https://openrouter.ai/settings/keys" }, modelsFetcher: { url: "https://openrouter.ai/api/v1/models", type: "openrouter-free" } }, nvidia: { id: "nvidia", alias: "nvidia", name: "NVIDIA NIM", icon: "developer_board", color: "#76B900", textIcon: "NV", website: "https://developer.nvidia.com/nim", notice: { text: "Free access for NVIDIA Developer Program members (prototyping & testing).", apiKeyUrl: "https://build.nvidia.com/settings/api-keys" } }, ollama: { id: "ollama", alias: "ollama", name: "Ollama Cloud", icon: "cloud", color: "#ffffffff", textIcon: "OL", website: "https://ollama.com", notice: { text: "Free tier: light usage, 1 cloud model at a time (limits reset every 5h & 7d). Pro $20/mo ยท Max $100/mo.", apiKeyUrl: "https://ollama.com/settings/keys" } }, vertex: { id: "vertex", alias: "vx", name: "Vertex AI", icon: "cloud", color: "#4285F4", textIcon: "VX", website: "https://cloud.google.com/vertex-ai", notice: { text: "New Google Cloud accounts get $300 free credits. Requires GCP project + Service Account with Vertex AI API enabled.", apiKeyUrl: "https://console.cloud.google.com/iam-admin/serviceaccounts" } },