diff --git a/scripts/ad-hoc/backfill-servicekinds.mjs b/scripts/ad-hoc/backfill-servicekinds.mjs new file mode 100644 index 000000000000..63913cc2aaad --- /dev/null +++ b/scripts/ad-hoc/backfill-servicekinds.mjs @@ -0,0 +1,172 @@ +/** + * scripts/ad-hoc/backfill-servicekinds.mjs + * + * PR A (gate hardening, #10513): make `serviceKinds` REQUIRED on every provider + * in the catalog, backfilling the ~320 entries that never declared it. + * + * Design (pacocartones #10267): serviceKinds distinguishes a canonical provider + * that legitimately has no REGISTRY entry (search/audio/media/local/cloud-agent) + * from a half-removed provider whose catalog entry outlived its registry entry. + * Making the field mandatory turns "canonical provider with no REGISTRY entry" + * into a checkable invariant for `provider:remove --dry-run`. + * + * Rule: + * - LLM chat providers -> ["llm"] + * - Search providers -> ["webSearch"] (+["webFetch"] where known) + * - Pure-media providers -> [] (kinds derived from media registries) + * - Cloud agents / system / proxy-> [] (no direct chat registry path) + * + * Media kinds are NOT declared here — open-sse/config/mediaServiceKinds.ts + * derives them from the audio/video/music/image/embedding/ocr registries, so + * declaring them would duplicate (and drift from) that source of truth. + * + * USAGE: node --import tsx/esm scripts/ad-hoc/backfill-servicekinds.mjs + * Idempotent: only inserts where serviceKinds is absent. + */ +import { readFileSync, writeFileSync } from "node:fs"; +import { fileURLToPath } from "node:url"; +import path from "node:path"; + +const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../.."); + +// ── Section membership from the REAL catalog modules ──────────────────────── +import { SEARCH_PROVIDERS } from "../../src/shared/constants/providers/search.ts"; +import { AUDIO_ONLY_PROVIDERS } from "../../src/shared/constants/providers/audio.ts"; +import { CLOUD_AGENT_PROVIDERS } from "../../src/shared/constants/providers/cloud-agent.ts"; +import { SYSTEM_PROVIDERS } from "../../src/shared/constants/providers/system.ts"; +import { UPSTREAM_PROXY_PROVIDERS } from "../../src/shared/constants/providers/upstream-proxy.ts"; +import { OAUTH_PROVIDERS } from "../../src/shared/constants/providers/oauth.ts"; +import { WEB_COOKIE_PROVIDERS } from "../../src/shared/constants/providers/web-cookie.ts"; +import { LOCAL_PROVIDERS } from "../../src/shared/constants/providers/local.ts"; +import { APIKEY_PROVIDERS_GATEWAYS } from "../../src/shared/constants/providers/apikey/gateways.ts"; +import { APIKEY_PROVIDERS_FRONTIER } from "../../src/shared/constants/providers/apikey/frontier-labs.ts"; +import { APIKEY_PROVIDERS_INFERENCE } from "../../src/shared/constants/providers/apikey/inference-hosts.ts"; +import { APIKEY_PROVIDERS_ENTERPRISE } from "../../src/shared/constants/providers/apikey/enterprise-cloud.ts"; +import { APIKEY_PROVIDERS_REGIONAL } from "../../src/shared/constants/providers/apikey/regional.ts"; +import { APIKEY_PROVIDERS_SPECIALTY } from "../../src/shared/constants/providers/apikey/specialty-media.ts"; + +const SEARCH_IDS = new Set(Object.keys(SEARCH_PROVIDERS)); +const AUDIO_IDS = new Set(Object.keys(AUDIO_ONLY_PROVIDERS)); +const CLOUD_AGENT_IDS = new Set(Object.keys(CLOUD_AGENT_PROVIDERS)); +const SYSTEM_IDS = new Set(Object.keys(SYSTEM_PROVIDERS)); +const UPSTREAM_PROXY_IDS = new Set(Object.keys(UPSTREAM_PROXY_PROVIDERS)); + +// Search providers that ALSO fetch pages (declared webFetch today). +const SEARCH_WEBFETCH = new Set(["exa-search", "tavily-search", "firecrawl"]); + +// Pure-media / no-direct-chat providers -> [] (kinds come from registries). +// web-cookie image/video generators + local image runtimes + specialty-media +// image/embedding/music/video set members that have no chat facade. +const NO_LLM = new Set([ + // web-cookie image/video generators + "microsoft-designer-web", + "adobe-firefly", + // local image runtimes + "sdwebui", + "comfyui", + // specialty-media pure media (image/embedding/music/video, no chat facade) + "runwayml", + "ideogram", + "freepik", + // freepik foi renomeado para magnific na migration 160 — ambos os ids + // permanecem aqui para que uma re-execução não volte a marcá-lo como llm. + "magnific", + "suno", + "udio", + "voyage-ai", + "jina-ai", + "fal-ai", + "stability-ai", + "black-forest-labs", + "recraft", + "topaz", + "segmind", + "nomic", + "mixedbread", + "leonardo", + "haiper", + "kie", + "deepai", +]); + +/** Compute declared serviceKinds for a provider id (media kinds NOT included). */ +export function computeDeclaredServiceKinds(providerId) { + if (SEARCH_IDS.has(providerId)) { + return SEARCH_WEBFETCH.has(providerId) ? ["webSearch", "webFetch"] : ["webSearch"]; + } + if (NO_LLM.has(providerId)) return []; + if (AUDIO_IDS.has(providerId)) return []; + if (CLOUD_AGENT_IDS.has(providerId)) return []; + if (SYSTEM_IDS.has(providerId)) return []; + if (UPSTREAM_PROXY_IDS.has(providerId)) return []; + return ["llm"]; +} + +/** Insert `serviceKinds` after the `id:` line of a provider entry, if absent. */ +function insertIntoFile(filePath, providerId, kinds) { + const abs = path.join(ROOT, filePath); + const src = readFileSync(abs, "utf8"); + + const escaped = providerId.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); + // Multi-line entry ` \"provider-id\": {\n ... },` — full block capture. The + // whole-block capture makes the idempotency check see serviceKinds wherever it + // sits (before OR after the id line) without a file-global `includes` that + // would short-circuit every later entry after the first insert. + const entryRe = new RegExp(`^( {2})"?${escaped}"?(: \\{)([\\s\\S]*?)^( {2})},$`, "m"); + const match = entryRe.exec(src); + if (!match) { + console.error(` ✗ could not locate entry for ${providerId} in ${filePath}`); + return false; + } + // Per-entry idempotency: refuse when THIS entry already declares serviceKinds. + const block = match[0]; + if (/serviceKinds\s*:/.test(block)) return null; + // Insert after the `id: \"provider-id\",` line (4-space indent inside the block). + const idLineRe = new RegExp(`( {4}id: \"${escaped}\",)`); + const idMatch = idLineRe.exec(block); + if (!idMatch) { + console.error(` ✗ entry for ${providerId} in ${filePath} has no id line`); + return false; + } + const idLineEnd = match.index + idMatch.index + idMatch[1].length; + const insert = `\n serviceKinds: ${JSON.stringify(kinds)},`; + writeFileSync(abs, src.slice(0, idLineEnd) + insert + src.slice(idLineEnd)); + return true; +} + +// ── Files to process, derived from the section modules themselves ─────────── +const FILES = [ + ["src/shared/constants/providers/oauth.ts", OAUTH_PROVIDERS], + ["src/shared/constants/providers/web-cookie.ts", WEB_COOKIE_PROVIDERS], + ["src/shared/constants/providers/local.ts", LOCAL_PROVIDERS], + ["src/shared/constants/providers/search.ts", SEARCH_PROVIDERS], + ["src/shared/constants/providers/audio.ts", AUDIO_ONLY_PROVIDERS], + ["src/shared/constants/providers/upstream-proxy.ts", UPSTREAM_PROXY_PROVIDERS], + ["src/shared/constants/providers/cloud-agent.ts", CLOUD_AGENT_PROVIDERS], + ["src/shared/constants/providers/system.ts", SYSTEM_PROVIDERS], + ["src/shared/constants/providers/apikey/gateways.ts", APIKEY_PROVIDERS_GATEWAYS], + ["src/shared/constants/providers/apikey/frontier-labs.ts", APIKEY_PROVIDERS_FRONTIER], + ["src/shared/constants/providers/apikey/inference-hosts.ts", APIKEY_PROVIDERS_INFERENCE], + ["src/shared/constants/providers/apikey/enterprise-cloud.ts", APIKEY_PROVIDERS_ENTERPRISE], + ["src/shared/constants/providers/apikey/regional.ts", APIKEY_PROVIDERS_REGIONAL], + ["src/shared/constants/providers/apikey/specialty-media.ts", APIKEY_PROVIDERS_SPECIALTY], +]; + +let inserted = 0; +let skipped = 0; +let failed = 0; +for (const [file, sectionMap] of FILES) { + for (const id of Object.keys(sectionMap)) { + if (sectionMap[id]?.serviceKinds !== undefined) { + skipped += 1; + continue; + } + const kinds = computeDeclaredServiceKinds(id); + const result = insertIntoFile(file, id, kinds); + if (result === true) inserted += 1; + else if (result === false) failed += 1; + } +} +console.log( + `[backfill] inserted=${inserted} skipped(already-declared)=${skipped} failed=${failed}` +); diff --git a/scripts/check/check-provider-consistency.ts b/scripts/check/check-provider-consistency.ts index 88254eb45945..d3b9f62b0d54 100644 --- a/scripts/check/check-provider-consistency.ts +++ b/scripts/check/check-provider-consistency.ts @@ -7,6 +7,13 @@ // Catraca: exceções pré-existentes ficam em KNOWN_REGISTRY_ONLY; só NOVOS órfãos falham. // Stale-enforcement (6A.3): entrada em KNOWN_REGISTRY_ONLY que não suprime nenhum órfão // real → gate falha com instrução de remoção (evita furo de regressão silencioso). +// +// Reverse walk (#10513): providers.ts → REGISTRY. Um provider canônico cujo +// serviceKinds inclui "llm" DEVE ter entrada no REGISTRY — a não ser que esteja em +// KNOWN_CATALOG_ONLY (providers que roteiam via baseUrl de conexão / executor +// especializado sem entrada de registry). Isso torna provider:remove --dry-run +// verificável: um provider removido do REGISTRY mas esquecido em providers.ts +// aparece como órfão reverso e o gate falha. import { pathToFileURL } from "node:url"; import { AI_PROVIDERS, getProviderById } from "@/shared/constants/providers.ts"; import { REGISTRY } from "@omniroute/open-sse/config/providerRegistry.ts"; @@ -16,6 +23,46 @@ import { assertNoStale } from "./lib/allowlist.mjs"; // justificativa. Remover daqui ao registrar o provider em providers.ts. export const KNOWN_REGISTRY_ONLY: Record = {}; +/** + * Providers canônicos com serviceKinds llm que LEGITIMAMENTE não têm entrada no + * REGISTRY. Cada um roteia via baseUrl de conexão (providerSpecificData.baseUrl) ou + * executor especializado, então a ausência de registro não é órfão. + */ +export const KNOWN_CATALOG_ONLY: Record = { + "amazon-q": "OAuth/IDE provider roteado via KiroExecutor sem entrada de registry.", + zed: "OAuth/IDE provider (Zed) roteado via executor especializado; sem entrada de registry.", + piapi: "Gateway OpenAI-compatible roteado via baseUrl de conexão.", + getgoapi: "Gateway OpenAI-compatible roteado via baseUrl de conexão.", + laozhang: "Gateway OpenAI-compatible roteado via baseUrl de conexão.", + thebai: "Gateway OpenAI-compatible roteado via baseUrl de conexão.", + fenayai: "Gateway OpenAI-compatible roteado via baseUrl de conexão.", + empower: "Gateway OpenAI-compatible roteado via baseUrl de conexão.", + "arcee-ai": "API-key provider roteado via baseUrl de conexão.", + "azure-openai": "Azure OpenAI roteado via AzureOpenAIExecutor + baseUrl de conexão.", + "azure-ai": "Azure AI Foundry roteado via AzureAiExecutor + baseUrl de conexão.", + watsonx: "Enterprise provider roteado via baseUrl de conexão.", + oci: "OCI Generative AI roteado via baseUrl de conexão.", + sap: "SAP AI Core roteado via baseUrl de conexão.", + datarobot: "Enterprise provider roteado via baseUrl de conexão.", + clarifai: "Clarifai PAT roteado via baseUrl de conexão.", + "360ai": "Regional provider roteado via baseUrl de conexão.", + gitlab: "GitLab (non-Duo) roteado via executor especializado + baseUrl de conexão.", + "poe-web": "Web/cookie provider roteado via executor especializado (PoeWebExecutor).", + "venice-web": "Web/cookie provider roteado via executor especializado (VeniceWeb).", + "v0-vercel-web": "Web/cookie provider roteado via executor especializado (V0VercelWeb).", + "gemini-business": "Enterprise Gemini roteado via executor especializado + baseUrl de conexão.", + "ollama-local": "Local provider (Ollama) roteado via baseUrl de conexão; sem registry.", + "lm-studio": "Local provider (LM Studio) roteado via baseUrl de conexão.", + vllm: "Local provider (vLLM) roteado via baseUrl de conexão.", + lemonade: "Local provider roteado via baseUrl de conexão.", + llamafile: "Local provider roteado via baseUrl de conexão.", + "llama-cpp": "Local provider roteado via baseUrl de conexão.", + triton: "Local provider (Triton) roteado via baseUrl de conexão.", + "docker-model-runner": "Local provider roteado via baseUrl de conexão.", + xinference: "Local provider (XInference) roteado via baseUrl de conexão.", + oobabooga: "Local provider (Oobabooga) roteado via baseUrl de conexão.", +}; + /** Ids do REGISTRY que não são providers canônicos e não estão na allowlist. */ export function findOrphanRegistryIds( registryIds: string[], @@ -25,6 +72,24 @@ export function findOrphanRegistryIds( return registryIds.filter((id) => !isKnownProvider(id) && !(id in allowlist)); } +/** + * Providers canônicos com serviceKinds llm sem entrada no REGISTRY e fora da + * allowlist — metade de um provider:remove (registro apagado, catálogo esquecido). + */ +export function findCatalogOnlyLlmProviders( + canonicalProviders: Record, + registryIds: string[], + allowlist: Record +): string[] { + const registry = new Set(registryIds); + return Object.entries(canonicalProviders) + .filter(([id, p]) => { + if (registry.has(id) || id in allowlist) return false; + return Array.isArray(p.serviceKinds) && p.serviceKinds.includes("llm"); + }) + .map(([id]) => id); +} + function main(): void { const canonical = new Set(Object.keys(AI_PROVIDERS)); const isKnown = (id: string) => canonical.has(id) || Boolean(getProviderById(id)); @@ -42,9 +107,24 @@ function main(): void { ); process.exitCode = 1; } + // Reverse walk: llm-kind canonical provider sem REGISTRY = órfão reverso. + const catalogOnlyLlm = findCatalogOnlyLlmProviders( + AI_PROVIDERS as Record, + Object.keys(REGISTRY), + KNOWN_CATALOG_ONLY + ); + if (catalogOnlyLlm.length) { + console.error( + `[provider-consistency] ${catalogOnlyLlm.length} provider(s) canônico(s) llm sem entrada no REGISTRY:\n` + + catalogOnlyLlm.map((id) => ` ✗ ${id}`).join("\n") + + `\n → registre o provider em open-sse/config/providers/registry// ou adicione a KNOWN_CATALOG_ONLY (scripts/check/check-provider-consistency.ts) com justificativa — órfão reverso de um provider:remove incompleto?` + ); + process.exitCode = 1; + } + if (!process.exitCode) { console.log( - `[provider-consistency] OK — ${Object.keys(REGISTRY).length} entradas REGISTRY, ${canonical.size} providers canônicos, ${Object.keys(KNOWN_REGISTRY_ONLY).length} exceção(ões) conhecida(s)` + `[provider-consistency] OK — ${Object.keys(REGISTRY).length} entradas REGISTRY, ${canonical.size} providers canônicos, ${Object.keys(KNOWN_REGISTRY_ONLY).length} exceção(ões) registry-only, ${Object.keys(KNOWN_CATALOG_ONLY).length} catalog-only` ); } } diff --git a/src/shared/constants/providers/apikey/enterprise-cloud.ts b/src/shared/constants/providers/apikey/enterprise-cloud.ts index 66fa154f9598..49831b3c240f 100644 --- a/src/shared/constants/providers/apikey/enterprise-cloud.ts +++ b/src/shared/constants/providers/apikey/enterprise-cloud.ts @@ -5,6 +5,7 @@ export const APIKEY_PROVIDERS_ENTERPRISE = { "azure-openai": { id: "azure-openai", + serviceKinds: ["llm"], alias: "azure", name: "Azure OpenAI", icon: "cloud", @@ -17,6 +18,7 @@ export const APIKEY_PROVIDERS_ENTERPRISE = { }, "azure-ai": { id: "azure-ai", + serviceKinds: ["llm"], alias: "azure-ai", name: "Azure AI Foundry", icon: "cloud", @@ -31,6 +33,7 @@ export const APIKEY_PROVIDERS_ENTERPRISE = { }, bedrock: { id: "bedrock", + serviceKinds: ["llm"], alias: "bedrock", name: "Amazon Bedrock", icon: "cloud", @@ -45,6 +48,7 @@ export const APIKEY_PROVIDERS_ENTERPRISE = { }, watsonx: { id: "watsonx", + serviceKinds: ["llm"], alias: "watsonx", name: "IBM watsonx.ai Gateway", icon: "hub", @@ -59,6 +63,7 @@ export const APIKEY_PROVIDERS_ENTERPRISE = { }, oci: { id: "oci", + serviceKinds: ["llm"], alias: "oci", name: "OCI Generative AI", icon: "cloud", @@ -73,6 +78,7 @@ export const APIKEY_PROVIDERS_ENTERPRISE = { }, sap: { id: "sap", + serviceKinds: ["llm"], alias: "sap", name: "SAP Generative AI Hub", icon: "business", @@ -88,6 +94,7 @@ export const APIKEY_PROVIDERS_ENTERPRISE = { }, modal: { id: "modal", + serviceKinds: ["llm"], alias: "mdl", name: "Modal", icon: "cloud_queue", @@ -104,6 +111,7 @@ export const APIKEY_PROVIDERS_ENTERPRISE = { }, vertex: { id: "vertex", + serviceKinds: ["llm"], alias: "vertex", name: "Vertex AI", icon: "cloud", @@ -115,6 +123,7 @@ export const APIKEY_PROVIDERS_ENTERPRISE = { }, "vertex-partner": { id: "vertex-partner", + serviceKinds: ["llm"], alias: "vp", name: "Vertex AI Partners", icon: "cloud", @@ -125,6 +134,7 @@ export const APIKEY_PROVIDERS_ENTERPRISE = { }, "cloudflare-ai": { id: "cloudflare-ai", + serviceKinds: ["llm"], alias: "cf", name: "Cloudflare Workers AI", icon: "cloud", @@ -138,6 +148,7 @@ export const APIKEY_PROVIDERS_ENTERPRISE = { }, scaleway: { id: "scaleway", + serviceKinds: ["llm"], alias: "scw", name: "Scaleway AI", icon: "cloud", @@ -149,6 +160,7 @@ export const APIKEY_PROVIDERS_ENTERPRISE = { }, ovhcloud: { id: "ovhcloud", + serviceKinds: ["llm"], alias: "ovh", name: "OVHcloud AI", icon: "cloud", @@ -158,6 +170,7 @@ export const APIKEY_PROVIDERS_ENTERPRISE = { }, heroku: { id: "heroku", + serviceKinds: ["llm"], alias: "heroku", name: "Heroku AI", icon: "cloud_upload", @@ -167,6 +180,7 @@ export const APIKEY_PROVIDERS_ENTERPRISE = { }, databricks: { id: "databricks", + serviceKinds: ["llm"], alias: "databricks", name: "Databricks", icon: "table_chart", @@ -176,6 +190,7 @@ export const APIKEY_PROVIDERS_ENTERPRISE = { }, datarobot: { id: "datarobot", + serviceKinds: ["llm"], alias: "datarobot", name: "DataRobot", icon: "precision_manufacturing", @@ -190,6 +205,7 @@ export const APIKEY_PROVIDERS_ENTERPRISE = { }, clarifai: { id: "clarifai", + serviceKinds: ["llm"], alias: "clarifai", name: "Clarifai", icon: "hub", @@ -204,6 +220,7 @@ export const APIKEY_PROVIDERS_ENTERPRISE = { }, snowflake: { id: "snowflake", + serviceKinds: ["llm"], alias: "snowflake", name: "Snowflake Cortex", icon: "ac_unit", diff --git a/src/shared/constants/providers/apikey/frontier-labs.ts b/src/shared/constants/providers/apikey/frontier-labs.ts index 7bcd163974e2..d689714d3f6a 100644 --- a/src/shared/constants/providers/apikey/frontier-labs.ts +++ b/src/shared/constants/providers/apikey/frontier-labs.ts @@ -15,6 +15,7 @@ export const APIKEY_PROVIDERS_FRONTIER = { }, reka: { id: "reka", + serviceKinds: ["llm"], alias: "reka", name: "Reka", icon: "auto_awesome", @@ -82,6 +83,7 @@ export const APIKEY_PROVIDERS_FRONTIER = { }, blackbox: { id: "blackbox", + serviceKinds: ["llm"], alias: "bb", name: "Blackbox AI", icon: "view_in_ar", @@ -128,6 +130,7 @@ export const APIKEY_PROVIDERS_FRONTIER = { }, perplexity: { id: "perplexity", + serviceKinds: ["llm"], alias: "pplx", name: "Perplexity", icon: "search", @@ -152,6 +155,7 @@ export const APIKEY_PROVIDERS_FRONTIER = { }, cohere: { id: "cohere", + serviceKinds: ["llm"], alias: "cohere", name: "Cohere", icon: "hub", @@ -163,6 +167,7 @@ export const APIKEY_PROVIDERS_FRONTIER = { }, "meta-llama": { id: "meta-llama", + serviceKinds: ["llm"], alias: "meta", name: "Meta Llama API", icon: "smart_toy", @@ -172,6 +177,7 @@ export const APIKEY_PROVIDERS_FRONTIER = { }, morph: { id: "morph", + serviceKinds: ["llm"], alias: "morph", name: "Morph", icon: "auto_fix_high", @@ -183,6 +189,7 @@ export const APIKEY_PROVIDERS_FRONTIER = { }, galadriel: { id: "galadriel", + serviceKinds: ["llm"], alias: "galadriel", name: "Galadriel", icon: "auto_awesome", @@ -197,6 +204,7 @@ export const APIKEY_PROVIDERS_FRONTIER = { }, ai21: { id: "ai21", + serviceKinds: ["llm"], alias: "ai21", name: "AI21 Labs", icon: "psychology_alt", @@ -208,6 +216,7 @@ export const APIKEY_PROVIDERS_FRONTIER = { }, venice: { id: "venice", + serviceKinds: ["llm"], alias: "venice", name: "Venice.ai", icon: "travel_explore", @@ -217,6 +226,7 @@ export const APIKEY_PROVIDERS_FRONTIER = { }, codestral: { id: "codestral", + serviceKinds: ["llm"], alias: "codestral", name: "Codestral", icon: "terminal", @@ -226,6 +236,7 @@ export const APIKEY_PROVIDERS_FRONTIER = { }, upstage: { id: "upstage", + serviceKinds: ["llm"], alias: "upstage", name: "Upstage", icon: "trending_up", @@ -235,6 +246,7 @@ export const APIKEY_PROVIDERS_FRONTIER = { }, maritalk: { id: "maritalk", + serviceKinds: ["llm"], alias: "maritalk", name: "Maritalk", icon: "translate", @@ -244,6 +256,7 @@ export const APIKEY_PROVIDERS_FRONTIER = { }, "nous-research": { id: "nous-research", + serviceKinds: ["llm"], alias: "nous", name: "Nous Research", icon: "hub", @@ -259,6 +272,7 @@ export const APIKEY_PROVIDERS_FRONTIER = { }, "arcee-ai": { id: "arcee-ai", + serviceKinds: ["llm"], alias: "arcee", name: "Arcee AI", icon: "auto_awesome", @@ -272,6 +286,7 @@ export const APIKEY_PROVIDERS_FRONTIER = { }, liquid: { id: "liquid", + serviceKinds: ["llm"], alias: "liquid", name: "Liquid AI", icon: "water_drop", @@ -286,6 +301,7 @@ export const APIKEY_PROVIDERS_FRONTIER = { }, inception: { id: "inception", + serviceKinds: ["llm"], alias: "inception", name: "Inception", icon: "auto_awesome", @@ -299,6 +315,7 @@ export const APIKEY_PROVIDERS_FRONTIER = { }, writer: { id: "writer", + serviceKinds: ["llm"], alias: "writer", name: "Writer", icon: "auto_awesome", @@ -311,6 +328,7 @@ export const APIKEY_PROVIDERS_FRONTIER = { }, "muse-code": { id: "muse-code", + serviceKinds: ["llm"], alias: "mc", name: "Muse Code (Meta)", icon: "auto_awesome", diff --git a/src/shared/constants/providers/apikey/gateways.ts b/src/shared/constants/providers/apikey/gateways.ts index 4c8449e03966..1a37aab7f320 100644 --- a/src/shared/constants/providers/apikey/gateways.ts +++ b/src/shared/constants/providers/apikey/gateways.ts @@ -8,6 +8,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = { // OmniRoute's oneminai executor translates both directions. oneminai: { id: "oneminai", + serviceKinds: ["llm"], alias: "1min", name: "1min.AI", icon: "hub", @@ -25,6 +26,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = { // /v1/responses endpoint and 3 image models. Keys are `ir_live_…` bearer tokens. cheaperinference: { id: "cheaperinference", + serviceKinds: ["llm"], alias: "cinf", name: "Cheaper Inference", icon: "savings", @@ -52,6 +54,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = { }, "charm-hyper": { id: "charm-hyper", + serviceKinds: ["llm"], alias: "charm-hyper", name: "Charm Hyper", icon: "router", @@ -65,6 +68,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = { }, agentrouter: { id: "agentrouter", + serviceKinds: ["llm"], alias: "agentrouter", name: "AgentRouter", icon: "router", @@ -78,6 +82,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = { }, unorouter: { id: "unorouter", + serviceKinds: ["llm"], alias: "unorouter", name: "UnoRouter", icon: "unorouter", @@ -92,6 +97,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = { }, "command-code": { id: "command-code", + serviceKinds: ["llm"], alias: "cmd", name: "Command Code", icon: "terminal", @@ -117,6 +123,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = { }, opper: { id: "opper", + serviceKinds: ["llm"], alias: "opper", name: "Opper", icon: "router", @@ -131,6 +138,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = { }, requesty: { id: "requesty", + serviceKinds: ["llm"], alias: "requesty", name: "Requesty", icon: "router", @@ -146,6 +154,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = { }, "zylo-api": { id: "zylo-api", + serviceKinds: ["llm"], alias: "zylo", name: "Zylo API", icon: "hub", @@ -161,6 +170,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = { }, fastrouter: { id: "fastrouter", + serviceKinds: ["llm"], alias: "fastrouter", name: "FastRouter", icon: "speed", @@ -176,6 +186,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = { }, anyapi: { id: "anyapi", + serviceKinds: ["llm"], alias: "anyapi", name: "AnyAPI AI", icon: "hub", @@ -191,6 +202,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = { }, electronhub: { id: "electronhub", + serviceKinds: ["llm"], alias: "electronhub", name: "Electron Hub", icon: "hub", @@ -206,6 +218,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = { }, llmgateway: { id: "llmgateway", + serviceKinds: ["llm"], alias: "llmgateway", name: "LLM Gateway", icon: "router", @@ -221,6 +234,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = { }, "llm-kiwi": { id: "llm-kiwi", + serviceKinds: ["llm"], alias: "llmkiwi", name: "LLM.Kiwi", icon: "hub", @@ -236,6 +250,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = { }, literouter: { id: "literouter", + serviceKinds: ["llm"], alias: "literouter", name: "LiteRouter", icon: "router", @@ -251,6 +266,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = { }, "mnn-ai": { id: "mnn-ai", + serviceKinds: ["llm"], alias: "mnn-ai", name: "MNN AI", icon: "hub", @@ -265,6 +281,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = { }, "meganova-ai": { id: "meganova-ai", + serviceKinds: ["llm"], alias: "meganova-ai", name: "MegaNova AI", icon: "router", @@ -280,6 +297,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = { }, mixlayer: { id: "mixlayer", + serviceKinds: ["llm"], alias: "mixlayer", name: "Mixlayer", icon: "router", @@ -295,6 +313,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = { }, speka: { id: "speka", + serviceKinds: ["llm"], alias: "speka", name: "Speka AI", icon: "router", @@ -310,6 +329,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = { }, tokenreply: { id: "tokenreply", + serviceKinds: ["llm"], alias: "tokenreply", name: "TokenReply", icon: "router", @@ -325,6 +345,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = { }, "yolo-auto": { id: "yolo-auto", + serviceKinds: ["llm"], alias: "yolo-auto", name: "Yolo-Auto", icon: "auto_awesome", @@ -340,6 +361,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = { }, dxnt: { id: "dxnt", + serviceKinds: ["llm"], alias: "dxnt", name: "DXNT / DX Token", icon: "hub", @@ -355,6 +377,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = { }, "cloudcode-one": { id: "cloudcode-one", + serviceKinds: ["llm"], alias: "cloudcode-one", name: "CloudCode.ONE", icon: "router", @@ -370,6 +393,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = { }, ofoxai: { id: "ofoxai", + serviceKinds: ["llm"], alias: "ofoxai", name: "OfoxAI", icon: "router", @@ -385,6 +409,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = { }, zerolimitai: { id: "zerolimitai", + serviceKinds: ["llm"], alias: "zerolimitai", name: "ZeroLimitAI", icon: "router", @@ -400,6 +425,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = { }, chatanywhere: { id: "chatanywhere", + serviceKinds: ["llm"], alias: "chatanywhere", name: "ChatAnywhere", icon: "router", @@ -415,6 +441,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = { }, helyxai: { id: "helyxai", + serviceKinds: ["llm"], alias: "helyxai", name: "Helyx AI", icon: "hub", @@ -430,6 +457,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = { }, auriko: { id: "auriko", + serviceKinds: ["llm"], alias: "auriko", name: "Auriko", icon: "hub", @@ -445,6 +473,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = { }, "poixe-ai": { id: "poixe-ai", + serviceKinds: ["llm"], alias: "poixe-ai", name: "Poixe AI", icon: "router", @@ -460,6 +489,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = { }, "naga-ai": { id: "naga-ai", + serviceKinds: ["llm"], alias: "naga-ai", name: "Naga AI", icon: "router", @@ -475,6 +505,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = { }, "chat-oripe": { id: "chat-oripe", + serviceKinds: ["llm"], alias: "chat-oripe", name: "Chat Oripe", icon: "router", @@ -490,6 +521,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = { }, freeinference: { id: "freeinference", + serviceKinds: ["llm"], alias: "freeinference", name: "FreeInference", icon: "science", @@ -505,6 +537,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = { }, "free-ai": { id: "free-ai", + serviceKinds: ["llm"], alias: "free-ai", name: "Free.ai", icon: "hub", @@ -521,6 +554,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = { dgrid: { id: "dgrid", + serviceKinds: ["llm"], alias: "dgrid", name: "DGrid", icon: "router", @@ -538,6 +572,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = { }, qiniu: { id: "qiniu", + serviceKinds: ["llm"], alias: "qiniu", name: "Qiniu", icon: "cloud", @@ -552,6 +587,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = { }, orcarouter: { id: "orcarouter", + serviceKinds: ["llm"], alias: "orcarouter", name: "OrcaRouter", icon: "router", @@ -564,6 +600,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = { }, "api-airforce": { id: "api-airforce", + serviceKinds: ["llm"], alias: "af", name: "Api.airforce", icon: "flight", @@ -578,6 +615,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = { }, crof: { id: "crof", + serviceKinds: ["llm"], alias: "crof", name: "CrofAI", icon: "auto_awesome", @@ -587,6 +625,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = { }, bazaarlink: { id: "bazaarlink", + serviceKinds: ["llm"], alias: "bzl", name: "BazaarLink", icon: "storefront", @@ -603,6 +642,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = { }, synthetic: { id: "synthetic", + serviceKinds: ["llm"], alias: "synthetic", name: "Synthetic", icon: "verified_user", @@ -613,6 +653,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = { }, "kilo-gateway": { id: "kilo-gateway", + serviceKinds: ["llm"], alias: "kg", name: "Kilo Gateway", icon: "hub", @@ -623,6 +664,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = { }, wafer: { id: "wafer", + serviceKinds: ["llm"], alias: "wafer", name: "Wafer AI", icon: "layers", @@ -633,6 +675,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = { }, "opencode-zen": { id: "opencode-zen", + serviceKinds: ["llm"], alias: "opencode-zen", name: "OpenCode Zen", icon: "opencode", @@ -642,6 +685,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = { }, "opencode-go": { id: "opencode-go", + serviceKinds: ["llm"], alias: "opencode-go", name: "OpenCode Go", icon: "opencode", @@ -651,6 +695,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = { }, dahl: { id: "dahl", + serviceKinds: ["llm"], alias: "dahl", name: "Dahl", icon: "dahl", @@ -671,6 +716,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = { }, freetheai: { id: "freetheai", + serviceKinds: ["llm"], alias: "fta", name: "FreeTheAi", icon: "hub", @@ -684,6 +730,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = { }, "g4f-groq": { id: "g4f-groq", + serviceKinds: ["llm"], alias: "g4fgroq", name: "g4f.space — Groq", icon: "bolt", @@ -703,6 +750,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = { }, "g4f-gemini": { id: "g4f-gemini", + serviceKinds: ["llm"], alias: "g4fgem", name: "g4f.space — Gemini", icon: "bolt", @@ -722,6 +770,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = { }, "g4f-pollinations": { id: "g4f-pollinations", + serviceKinds: ["llm"], alias: "g4fpol", name: "g4f.space — Pollinations", icon: "bolt", @@ -741,6 +790,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = { }, "g4f-ollama": { id: "g4f-ollama", + serviceKinds: ["llm"], alias: "g4foll", name: "g4f.space — Ollama", icon: "bolt", @@ -760,6 +810,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = { }, "g4f-nvidia": { id: "g4f-nvidia", + serviceKinds: ["llm"], alias: "g4fnv", name: "g4f.space — NVIDIA", icon: "bolt", @@ -779,6 +830,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = { }, "vercel-ai-gateway": { id: "vercel-ai-gateway", + serviceKinds: ["llm"], alias: "vag", name: "Vercel AI Gateway", icon: "route", @@ -789,6 +841,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = { }, llm7: { id: "llm7", + serviceKinds: ["llm"], alias: "llm7", name: "LLM7.io", icon: "hub", @@ -804,6 +857,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = { }, llamagate: { id: "llamagate", + serviceKinds: ["llm"], alias: "llamagate", name: "LlamaGate", icon: "gate", @@ -813,6 +867,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = { }, gitlawb: { id: "gitlawb", + serviceKinds: ["llm"], alias: "glb", name: "Gitlawb Opengateway (MiMo)", icon: "hub", @@ -826,6 +881,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = { }, "gitlawb-gmi": { id: "gitlawb-gmi", + serviceKinds: ["llm"], alias: "glb-gmi", name: "Gitlawb Opengateway (GMI Cloud)", icon: "hub", @@ -839,6 +895,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = { }, nanogpt: { id: "nanogpt", + serviceKinds: ["llm"], alias: "nanogpt", name: "NanoGPT", icon: "chat", @@ -848,6 +905,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = { }, aimlapi: { id: "aimlapi", + serviceKinds: ["llm"], alias: "aiml", name: "AI/ML API", icon: "hub", @@ -861,6 +919,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = { }, novita: { id: "novita", + serviceKinds: ["llm"], alias: "novita", name: "Novita AI", icon: "auto_awesome", @@ -873,6 +932,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = { }, piapi: { id: "piapi", + serviceKinds: ["llm"], alias: "pi", name: "PiAPI", icon: "api", @@ -883,6 +943,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = { }, getgoapi: { id: "getgoapi", + serviceKinds: ["llm"], alias: "ggo", name: "GoAPI", icon: "rocket_launch", @@ -893,6 +954,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = { }, laozhang: { id: "laozhang", + serviceKinds: ["llm"], alias: "lz", name: "LaoZhang AI", icon: "hub", @@ -903,6 +965,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = { }, thebai: { id: "thebai", + serviceKinds: ["llm"], alias: "thebai", name: "TheB.AI", icon: "hub", @@ -914,6 +977,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = { }, bai: { id: "bai", + serviceKinds: ["llm"], alias: "bai", name: "b.ai", icon: "hub", @@ -927,6 +991,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = { }, fenayai: { id: "fenayai", + serviceKinds: ["llm"], alias: "fenayai", name: "FenayAI", icon: "hub", @@ -938,6 +1003,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = { }, empower: { id: "empower", + serviceKinds: ["llm"], alias: "empower", name: "Empower", icon: "hub", @@ -951,6 +1017,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = { }, poe: { id: "poe", + serviceKinds: ["llm"], alias: "poe", name: "Poe", icon: "hub", @@ -986,6 +1053,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = { // is `FACTORY_API_KEY` (Bearer). Subscription tier uses app.factory.ai quota. factory: { id: "factory", + serviceKinds: ["llm"], alias: "factory", name: "Factory", icon: "smart_toy", @@ -999,6 +1067,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = { }, bluesminds: { id: "bluesminds", + serviceKinds: ["llm"], alias: "bm", name: "BluesMinds", icon: "psychology", @@ -1013,6 +1082,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = { }, "freemodel-dev": { id: "freemodel-dev", + serviceKinds: ["llm"], alias: "fmd", name: "FreeModel.dev", icon: "auto_awesome", @@ -1027,6 +1097,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = { }, freeaiapikey: { id: "freeaiapikey", + serviceKinds: ["llm"], alias: "faik", name: "FreeAIAPIKey", icon: "vpn_key", @@ -1038,6 +1109,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = { }, zenmux: { id: "zenmux", + serviceKinds: ["llm"], alias: "zm", name: "ZenMux", icon: "neurology", @@ -1054,6 +1126,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = { }, openadapter: { id: "openadapter", + serviceKinds: ["llm"], alias: "oad", name: "OpenAdapter", icon: "hub", @@ -1070,6 +1143,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = { }, dit: { id: "dit", + serviceKinds: ["llm"], alias: "dai", name: "DIT.ai", icon: "hub", @@ -1083,6 +1157,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = { }, tokenrouter: { id: "tokenrouter", + serviceKinds: ["llm"], alias: "trk", name: "TokenRouter", icon: "hub", @@ -1099,6 +1174,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = { }, "token-kiosk": { id: "token-kiosk", + serviceKinds: ["llm"], alias: "tk", name: "Token Kiosk", icon: "hub", @@ -1112,6 +1188,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = { }, sumopod: { id: "sumopod", + serviceKinds: ["llm"], alias: "sumopod", name: "SumoPod", icon: "router", @@ -1126,6 +1203,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = { }, x5lab: { id: "x5lab", + serviceKinds: ["llm"], alias: "x5lab", name: "X5Lab", icon: "router", @@ -1140,6 +1218,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = { }, chenzk: { id: "chenzk", + serviceKinds: ["llm"], alias: "chenzk", name: "Chenzk API", icon: "hub", @@ -1153,6 +1232,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = { }, kenari: { id: "kenari", + serviceKinds: ["llm"], alias: "kenari", name: "Kenari", icon: "hub", @@ -1167,6 +1247,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = { }, navy: { id: "navy", + serviceKinds: ["llm"], alias: "navy", name: "NavyAI", icon: "hub", @@ -1186,6 +1267,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = { }, ainative: { id: "ainative", + serviceKinds: ["llm"], alias: "ainative", name: "AINative Studio", icon: "hub", @@ -1202,6 +1284,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = { }, aion: { id: "aion", + serviceKinds: ["llm"], alias: "aion", name: "Aion Labs", icon: "hub", @@ -1218,6 +1301,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = { }, routeway: { id: "routeway", + serviceKinds: ["llm"], alias: "routeway", name: "Routeway", icon: "hub", @@ -1234,6 +1318,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = { }, nara: { id: "nara", + serviceKinds: ["llm"], alias: "nara", name: "NaraRouter", icon: "hub", @@ -1250,6 +1335,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = { }, regolo: { id: "regolo", + serviceKinds: ["llm"], alias: "regolo", name: "Regolo AI", icon: "hub", @@ -1263,6 +1349,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = { }, "naga-ac": { id: "naga-ac", + serviceKinds: ["llm"], alias: "naga", name: "Naga.ac", icon: "bolt", @@ -1278,6 +1365,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = { }, "void-ai": { id: "void-ai", + serviceKinds: ["llm"], alias: "void-ai", name: "Void AI", icon: "science", @@ -1293,6 +1381,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = { }, helixmind: { id: "helixmind", + serviceKinds: ["llm"], alias: "helixmind", name: "HelixMind", icon: "hub", @@ -1314,6 +1403,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = { // convention for data-collecting free providers. logfare: { id: "logfare", + serviceKinds: ["llm"], alias: "logfare", name: "Logfare", icon: "auto_awesome", @@ -1334,6 +1424,7 @@ export const APIKEY_PROVIDERS_GATEWAYS = { // every model accepting the Anthropic and OpenAI protocols. tabitoken: { id: "tabitoken", + serviceKinds: ["llm"], alias: "tabitoken", name: "TabiToken", icon: "hub", diff --git a/src/shared/constants/providers/apikey/inference-hosts.ts b/src/shared/constants/providers/apikey/inference-hosts.ts index c3925a904065..84cd65ad4105 100644 --- a/src/shared/constants/providers/apikey/inference-hosts.ts +++ b/src/shared/constants/providers/apikey/inference-hosts.ts @@ -5,6 +5,7 @@ export const APIKEY_PROVIDERS_INFERENCE = { together: { id: "together", + serviceKinds: ["llm"], alias: "together", name: "Together AI", icon: "group_work", @@ -22,6 +23,7 @@ export const APIKEY_PROVIDERS_INFERENCE = { // advertised on signup. Bearer-token auth via Authorization: Bearer ov_sk_… openvecta: { id: "openvecta", + serviceKinds: ["llm"], alias: "openvecta", name: "OpenVecta", icon: "vector_polygon", @@ -36,6 +38,7 @@ export const APIKEY_PROVIDERS_INFERENCE = { // API-key auth via Authorization: Bearer sk-… on the same gateway as OAuth JWTs. "openference-api": { id: "openference-api", + serviceKinds: ["llm"], alias: "ofa", name: "Openference API", icon: "openference", @@ -47,6 +50,7 @@ export const APIKEY_PROVIDERS_INFERENCE = { }, poolside: { id: "poolside", + serviceKinds: ["llm"], alias: "poolside", name: "Poolside", icon: "memory", @@ -62,6 +66,7 @@ export const APIKEY_PROVIDERS_INFERENCE = { }, fireworks: { id: "fireworks", + serviceKinds: ["llm"], alias: "fireworks", name: "Fireworks AI", icon: "local_fire_department", @@ -73,6 +78,7 @@ export const APIKEY_PROVIDERS_INFERENCE = { }, cerebras: { id: "cerebras", + serviceKinds: ["llm"], alias: "cerebras", name: "Cerebras", icon: "memory", @@ -84,6 +90,7 @@ export const APIKEY_PROVIDERS_INFERENCE = { }, nvidia: { id: "nvidia", + serviceKinds: ["llm"], alias: "nvidia", name: "NVIDIA NIM", icon: "developer_board", @@ -95,6 +102,7 @@ export const APIKEY_PROVIDERS_INFERENCE = { }, nebius: { id: "nebius", + serviceKinds: ["llm"], alias: "nebius", name: "Nebius AI", icon: "cloud", @@ -106,6 +114,7 @@ export const APIKEY_PROVIDERS_INFERENCE = { }, nube: { id: "nube", + serviceKinds: ["llm"], alias: "nube", name: "Nube.sh", icon: "cloud", @@ -120,6 +129,7 @@ export const APIKEY_PROVIDERS_INFERENCE = { }, siliconflow: { id: "siliconflow", + serviceKinds: ["llm"], alias: "siliconflow", name: "SiliconFlow", icon: "cloud_queue", @@ -132,6 +142,7 @@ export const APIKEY_PROVIDERS_INFERENCE = { }, hyperbolic: { id: "hyperbolic", + serviceKinds: ["llm"], alias: "hyp", name: "Hyperbolic", icon: "bolt", @@ -143,6 +154,7 @@ export const APIKEY_PROVIDERS_INFERENCE = { }, "ollama-cloud": { id: "ollama-cloud", + serviceKinds: ["llm"], alias: "ollamacloud", name: "Ollama Cloud", icon: "cloud", @@ -153,6 +165,7 @@ export const APIKEY_PROVIDERS_INFERENCE = { }, huggingface: { id: "huggingface", + serviceKinds: ["llm"], alias: "hf", name: "HuggingFace", icon: "face", @@ -164,6 +177,7 @@ export const APIKEY_PROVIDERS_INFERENCE = { }, deepinfra: { id: "deepinfra", + serviceKinds: ["llm"], alias: "deepinfra", name: "DeepInfra", icon: "hub", @@ -175,6 +189,7 @@ export const APIKEY_PROVIDERS_INFERENCE = { }, "lambda-ai": { id: "lambda-ai", + serviceKinds: ["llm"], alias: "lambda", name: "Lambda AI", icon: "bolt", @@ -184,6 +199,7 @@ export const APIKEY_PROVIDERS_INFERENCE = { }, sambanova: { id: "sambanova", + serviceKinds: ["llm"], alias: "samba", name: "SambaNova", icon: "memory", @@ -195,6 +211,7 @@ export const APIKEY_PROVIDERS_INFERENCE = { }, nscale: { id: "nscale", + serviceKinds: ["llm"], alias: "nscale", name: "nScale", icon: "token", @@ -206,6 +223,7 @@ export const APIKEY_PROVIDERS_INFERENCE = { }, baseten: { id: "baseten", + serviceKinds: ["llm"], alias: "baseten", name: "Baseten", icon: "deployed_code", @@ -217,6 +235,7 @@ export const APIKEY_PROVIDERS_INFERENCE = { }, publicai: { id: "publicai", + serviceKinds: ["llm"], alias: "publicai", name: "PublicAI", icon: "public", @@ -230,6 +249,7 @@ export const APIKEY_PROVIDERS_INFERENCE = { }, "featherless-ai": { id: "featherless-ai", + serviceKinds: ["llm"], alias: "featherless", name: "Featherless AI", icon: "flutter_dash", @@ -241,6 +261,7 @@ export const APIKEY_PROVIDERS_INFERENCE = { }, friendliai: { id: "friendliai", + serviceKinds: ["llm"], alias: "friendli", name: "FriendliAI", icon: "handshake", @@ -252,6 +273,7 @@ export const APIKEY_PROVIDERS_INFERENCE = { }, wandb: { id: "wandb", + serviceKinds: ["llm"], alias: "wandb", name: "Weights & Biases Inference", icon: "monitoring", @@ -261,6 +283,7 @@ export const APIKEY_PROVIDERS_INFERENCE = { }, "inference-net": { id: "inference-net", + serviceKinds: ["llm"], alias: "inet", name: "Inference.net", icon: "dns", @@ -272,6 +295,7 @@ export const APIKEY_PROVIDERS_INFERENCE = { }, predibase: { id: "predibase", + serviceKinds: ["llm"], alias: "predibase", name: "Predibase", icon: "deployed_code_history", @@ -288,6 +312,7 @@ export const APIKEY_PROVIDERS_INFERENCE = { }, bytez: { id: "bytez", + serviceKinds: ["llm"], alias: "bytez", name: "Bytez", icon: "api", @@ -299,6 +324,7 @@ export const APIKEY_PROVIDERS_INFERENCE = { }, monsterapi: { id: "monsterapi", + serviceKinds: ["llm"], alias: "monster", name: "MonsterAPI", icon: "cloud", @@ -316,6 +342,7 @@ export const APIKEY_PROVIDERS_INFERENCE = { }, modelscope: { id: "modelscope", + serviceKinds: ["llm"], alias: "ms", name: "ModelScope", icon: "cloud", diff --git a/src/shared/constants/providers/apikey/regional.ts b/src/shared/constants/providers/apikey/regional.ts index 9c84c7ff6a64..a9c5701dfdd8 100644 --- a/src/shared/constants/providers/apikey/regional.ts +++ b/src/shared/constants/providers/apikey/regional.ts @@ -5,6 +5,7 @@ export const APIKEY_PROVIDERS_REGIONAL = { qianfan: { id: "qianfan", + serviceKinds: ["llm"], alias: "qianfan", name: "Baidu Qianfan", icon: "cloud", @@ -16,6 +17,7 @@ export const APIKEY_PROVIDERS_REGIONAL = { }, glm: { id: "glm", + serviceKinds: ["llm"], alias: "glm", name: "GLM Coding", icon: "code", @@ -25,6 +27,7 @@ export const APIKEY_PROVIDERS_REGIONAL = { }, "glm-cn": { id: "glm-cn", + serviceKinds: ["llm"], alias: "glmcn", name: "GLM Coding (China)", icon: "code", @@ -34,6 +37,7 @@ export const APIKEY_PROVIDERS_REGIONAL = { }, glmt: { id: "glmt", + serviceKinds: ["llm"], alias: "glmt", name: "GLM Thinking", icon: "psychology", @@ -44,6 +48,7 @@ export const APIKEY_PROVIDERS_REGIONAL = { }, "bailian-coding-plan": { id: "bailian-coding-plan", + serviceKinds: ["llm"], alias: "bcp", name: "Alibaba Token Plan", icon: "code", @@ -54,6 +59,7 @@ export const APIKEY_PROVIDERS_REGIONAL = { }, "qwen-cloud": { id: "qwen-cloud", + serviceKinds: ["llm"], alias: "qwc", name: "Qwen Cloud", icon: "cloud", @@ -64,6 +70,7 @@ export const APIKEY_PROVIDERS_REGIONAL = { }, "qwen-cloud-token-plan": { id: "qwen-cloud-token-plan", + serviceKinds: ["llm"], alias: "qct", name: "Qwen Cloud Token Plan", icon: "cloud", @@ -74,6 +81,7 @@ export const APIKEY_PROVIDERS_REGIONAL = { }, kimi: { id: "kimi", + serviceKinds: ["llm"], alias: "kimi", name: "Kimi (Legacy Moonshot API)", icon: "psychology", @@ -87,6 +95,7 @@ export const APIKEY_PROVIDERS_REGIONAL = { }, "kimi-coding-apikey": { id: "kimi-coding-apikey", + serviceKinds: ["llm"], alias: "kmca", name: "Kimi Code API Key", icon: "psychology", @@ -100,6 +109,7 @@ export const APIKEY_PROVIDERS_REGIONAL = { }, minimax: { id: "minimax", + serviceKinds: ["llm"], alias: "minimax", name: "Minimax Coding", icon: "memory", @@ -109,6 +119,7 @@ export const APIKEY_PROVIDERS_REGIONAL = { }, "minimax-cn": { id: "minimax-cn", + serviceKinds: ["llm"], alias: "minimax-cn", name: "Minimax (China)", icon: "memory", @@ -118,6 +129,7 @@ export const APIKEY_PROVIDERS_REGIONAL = { }, deepseek: { id: "deepseek", + serviceKinds: ["llm"], alias: "ds", name: "DeepSeek", icon: "bolt", @@ -129,6 +141,7 @@ export const APIKEY_PROVIDERS_REGIONAL = { }, zai: { id: "zai", + serviceKinds: ["llm"], alias: "zai", name: "Z.AI", icon: "psychology", @@ -139,6 +152,7 @@ export const APIKEY_PROVIDERS_REGIONAL = { }, alibaba: { id: "alibaba", + serviceKinds: ["llm"], alias: "ali", name: "Alibaba Cloud Model Studio", icon: "cloud_queue", @@ -150,6 +164,7 @@ export const APIKEY_PROVIDERS_REGIONAL = { }, "alibaba-cn": { id: "alibaba-cn", + serviceKinds: ["llm"], alias: "ali-cn", name: "Alibaba (China)", icon: "cloud_queue", @@ -161,6 +176,7 @@ export const APIKEY_PROVIDERS_REGIONAL = { }, longcat: { id: "longcat", + serviceKinds: ["llm"], alias: "lc", name: "LongCat AI", icon: "auto_awesome", @@ -173,6 +189,7 @@ export const APIKEY_PROVIDERS_REGIONAL = { }, moonshot: { id: "moonshot", + serviceKinds: ["llm"], alias: "moonshot", // Display name only — Kimi official-partnership rebrand (2026-07). The // catalog id/alias/routing stay "moonshot" (DB connections, combos, and @@ -192,6 +209,7 @@ export const APIKEY_PROVIDERS_REGIONAL = { }, volcengine: { id: "volcengine", + serviceKinds: ["llm"], alias: "volcengine", name: "Volcengine", icon: "local_fire_department", @@ -201,6 +219,7 @@ export const APIKEY_PROVIDERS_REGIONAL = { }, "volcengine-agent-plan": { id: "volcengine-agent-plan", + serviceKinds: ["llm"], alias: "veap", name: "Volcengine Ark Agent Plan", icon: "local_fire_department", @@ -211,6 +230,7 @@ export const APIKEY_PROVIDERS_REGIONAL = { }, "volcengine-coding-plan": { id: "volcengine-coding-plan", + serviceKinds: ["llm"], alias: "vecp", name: "Volcengine Ark Coding Plan", icon: "code", @@ -221,6 +241,7 @@ export const APIKEY_PROVIDERS_REGIONAL = { }, gigachat: { id: "gigachat", + serviceKinds: ["llm"], alias: "gigachat", name: "GigaChat (Sber)", icon: "lock_person", @@ -230,6 +251,7 @@ export const APIKEY_PROVIDERS_REGIONAL = { }, "xiaomi-mimo": { id: "xiaomi-mimo", + serviceKinds: ["llm"], alias: "mimo", name: "Xiaomi MiMo", icon: "devices", @@ -239,6 +261,7 @@ export const APIKEY_PROVIDERS_REGIONAL = { }, "xiaomi-mimo-token-plan": { id: "xiaomi-mimo-token-plan", + serviceKinds: ["llm"], alias: "mimotp", name: "Xiaomi MiMo Token Plan", icon: "devices", @@ -248,6 +271,7 @@ export const APIKEY_PROVIDERS_REGIONAL = { }, baidu: { id: "baidu", + serviceKinds: ["llm"], alias: "baidu", name: "Baidu (ERNIE)", icon: "auto_awesome", @@ -261,6 +285,7 @@ export const APIKEY_PROVIDERS_REGIONAL = { }, tencent: { id: "tencent", + serviceKinds: ["llm"], alias: "tencent", name: "Tencent Hunyuan", icon: "auto_awesome", @@ -274,6 +299,7 @@ export const APIKEY_PROVIDERS_REGIONAL = { }, iflytek: { id: "iflytek", + serviceKinds: ["llm"], alias: "iflytek", name: "iFlytek Spark", icon: "auto_awesome", @@ -288,6 +314,7 @@ export const APIKEY_PROVIDERS_REGIONAL = { }, baichuan: { id: "baichuan", + serviceKinds: ["llm"], alias: "baichuan", name: "Baichuan", icon: "auto_awesome", @@ -301,6 +328,7 @@ export const APIKEY_PROVIDERS_REGIONAL = { }, yi: { id: "yi", + serviceKinds: ["llm"], alias: "yi", name: "Yi (01.AI)", icon: "auto_awesome", @@ -315,6 +343,7 @@ export const APIKEY_PROVIDERS_REGIONAL = { }, stepfun: { id: "stepfun", + serviceKinds: ["llm"], alias: "stepfun", name: "StepFun", icon: "auto_awesome", @@ -336,6 +365,7 @@ export const APIKEY_PROVIDERS_REGIONAL = { }, coze: { id: "coze", + serviceKinds: ["llm"], alias: "coze", name: "Coze", icon: "smart_toy", @@ -349,6 +379,7 @@ export const APIKEY_PROVIDERS_REGIONAL = { }, "360ai": { id: "360ai", + serviceKinds: ["llm"], alias: "360ai", name: "360 AI", icon: "auto_awesome", @@ -362,6 +393,7 @@ export const APIKEY_PROVIDERS_REGIONAL = { }, doubao: { id: "doubao", + serviceKinds: ["llm"], alias: "doubao", name: "Doubao", icon: "auto_awesome", @@ -375,6 +407,7 @@ export const APIKEY_PROVIDERS_REGIONAL = { }, sensenova: { id: "sensenova", + serviceKinds: ["llm"], alias: "sensenova", name: "SenseNova", icon: "auto_awesome", @@ -395,6 +428,7 @@ export const APIKEY_PROVIDERS_REGIONAL = { }, sparkdesk: { id: "sparkdesk", + serviceKinds: ["llm"], alias: "sparkdesk", name: "SparkDesk", icon: "auto_awesome", @@ -409,6 +443,7 @@ export const APIKEY_PROVIDERS_REGIONAL = { }, hcnsec: { id: "hcnsec", + serviceKinds: ["llm"], alias: "hcnsec", name: "Huancheng Public API", icon: "security", @@ -423,6 +458,7 @@ export const APIKEY_PROVIDERS_REGIONAL = { }, agnes: { id: "agnes", + serviceKinds: ["llm"], alias: "agnes", name: "Agnes AI", icon: "auto_awesome", @@ -435,6 +471,7 @@ export const APIKEY_PROVIDERS_REGIONAL = { }, sealion: { id: "sealion", + serviceKinds: ["llm"], alias: "sealion", name: "SEA-LION", icon: "public", @@ -449,6 +486,7 @@ export const APIKEY_PROVIDERS_REGIONAL = { }, "clova-studio": { id: "clova-studio", + serviceKinds: ["llm"], alias: "clova", name: "Naver CLOVA Studio", icon: "auto_awesome", @@ -460,6 +498,7 @@ export const APIKEY_PROVIDERS_REGIONAL = { }, internlm: { id: "internlm", + serviceKinds: ["llm"], alias: "internlm", name: "InternLM (Intern-S1)", icon: "auto_awesome", @@ -471,6 +510,7 @@ export const APIKEY_PROVIDERS_REGIONAL = { }, "ant-ling": { id: "ant-ling", + serviceKinds: ["llm"], alias: "ling", name: "Ant Ling / Ring (inclusionAI)", icon: "auto_awesome", @@ -484,6 +524,7 @@ export const APIKEY_PROVIDERS_REGIONAL = { }, sarvam: { id: "sarvam", + serviceKinds: ["llm"], alias: "sarvam", name: "Sarvam AI", icon: "public", @@ -497,6 +538,7 @@ export const APIKEY_PROVIDERS_REGIONAL = { }, plamo: { id: "plamo", + serviceKinds: ["llm"], alias: "plamo", name: "PLaMo", icon: "public", @@ -509,6 +551,7 @@ export const APIKEY_PROVIDERS_REGIONAL = { }, typhoon: { id: "typhoon", + serviceKinds: ["llm"], alias: "typhoon", name: "Typhoon", icon: "public", diff --git a/src/shared/constants/providers/apikey/specialty-media.ts b/src/shared/constants/providers/apikey/specialty-media.ts index b6924d239e7b..c09574a24dff 100644 --- a/src/shared/constants/providers/apikey/specialty-media.ts +++ b/src/shared/constants/providers/apikey/specialty-media.ts @@ -5,6 +5,7 @@ export const APIKEY_PROVIDERS_SPECIALTY = { nlpcloud: { id: "nlpcloud", + serviceKinds: ["llm"], alias: "nlpc", name: "NLP Cloud", icon: "psychology", @@ -20,6 +21,7 @@ export const APIKEY_PROVIDERS_SPECIALTY = { }, runwayml: { id: "runwayml", + serviceKinds: [], alias: "runway", name: "Runway", icon: "movie", @@ -33,6 +35,7 @@ export const APIKEY_PROVIDERS_SPECIALTY = { }, kie: { id: "kie", + serviceKinds: [], alias: "kie", name: "KIE.AI", icon: "hub", @@ -42,6 +45,7 @@ export const APIKEY_PROVIDERS_SPECIALTY = { }, pollinations: { id: "pollinations", + serviceKinds: ["llm"], alias: "pol", name: "Pollinations AI", icon: "local_florist", @@ -57,6 +61,7 @@ export const APIKEY_PROVIDERS_SPECIALTY = { }, haiper: { id: "haiper", + serviceKinds: [], alias: "hp", name: "Haiper", icon: "videocam", @@ -67,6 +72,7 @@ export const APIKEY_PROVIDERS_SPECIALTY = { }, leonardo: { id: "leonardo", + serviceKinds: [], alias: "leo", name: "Leonardo AI", icon: "palette", @@ -77,6 +83,7 @@ export const APIKEY_PROVIDERS_SPECIALTY = { }, ideogram: { id: "ideogram", + serviceKinds: [], alias: "ideo", name: "Ideogram", icon: "image", @@ -87,6 +94,7 @@ export const APIKEY_PROVIDERS_SPECIALTY = { }, magnific: { id: "magnific", + serviceKinds: [], alias: "freepik", name: "Magnific", icon: "image", @@ -100,6 +108,7 @@ export const APIKEY_PROVIDERS_SPECIALTY = { }, suno: { id: "suno", + serviceKinds: [], alias: "suno", name: "Suno", icon: "music_note", @@ -110,6 +119,7 @@ export const APIKEY_PROVIDERS_SPECIALTY = { }, udio: { id: "udio", + serviceKinds: [], alias: "udio", name: "Udio", icon: "music_note", @@ -120,6 +130,7 @@ export const APIKEY_PROVIDERS_SPECIALTY = { }, "v0-vercel": { id: "v0-vercel", + serviceKinds: ["llm"], alias: "v0", name: "v0 (Vercel)", icon: "code_blocks", @@ -129,6 +140,7 @@ export const APIKEY_PROVIDERS_SPECIALTY = { }, gitlab: { id: "gitlab", + serviceKinds: ["llm"], alias: "gitlab", name: "GitLab Duo PAT", icon: "hub", @@ -140,6 +152,7 @@ export const APIKEY_PROVIDERS_SPECIALTY = { }, "voyage-ai": { id: "voyage-ai", + serviceKinds: [], alias: "voyage", name: "Voyage AI", icon: "blur_on", @@ -152,6 +165,7 @@ export const APIKEY_PROVIDERS_SPECIALTY = { }, "jina-ai": { id: "jina-ai", + serviceKinds: [], alias: "jina", name: "Jina AI (Foundation API)", icon: "sort", @@ -165,6 +179,7 @@ export const APIKEY_PROVIDERS_SPECIALTY = { }, "fal-ai": { id: "fal-ai", + serviceKinds: [], alias: "fal", name: "Fal.ai", icon: "image", @@ -174,6 +189,7 @@ export const APIKEY_PROVIDERS_SPECIALTY = { }, "stability-ai": { id: "stability-ai", + serviceKinds: [], alias: "stability", name: "Stability AI", icon: "image", @@ -183,6 +199,7 @@ export const APIKEY_PROVIDERS_SPECIALTY = { }, "black-forest-labs": { id: "black-forest-labs", + serviceKinds: [], alias: "bfl", name: "Black Forest Labs", icon: "image", @@ -192,6 +209,7 @@ export const APIKEY_PROVIDERS_SPECIALTY = { }, recraft: { id: "recraft", + serviceKinds: [], alias: "recraft", name: "Recraft", icon: "image", @@ -201,6 +219,7 @@ export const APIKEY_PROVIDERS_SPECIALTY = { }, topaz: { id: "topaz", + serviceKinds: [], alias: "topaz", name: "Topaz", icon: "image", @@ -210,6 +229,7 @@ export const APIKEY_PROVIDERS_SPECIALTY = { }, segmind: { id: "segmind", + serviceKinds: [], alias: "segmind", name: "Segmind", icon: "image", @@ -225,6 +245,7 @@ export const APIKEY_PROVIDERS_SPECIALTY = { }, dify: { id: "dify", + serviceKinds: ["llm"], alias: "dify", name: "Dify", icon: "smart_toy", @@ -238,6 +259,7 @@ export const APIKEY_PROVIDERS_SPECIALTY = { }, nomic: { id: "nomic", + serviceKinds: [], alias: "nomic", name: "Nomic", icon: "hub", @@ -251,6 +273,7 @@ export const APIKEY_PROVIDERS_SPECIALTY = { }, mixedbread: { id: "mixedbread", + serviceKinds: [], alias: "mxbai", name: "Mixedbread AI", icon: "hub", @@ -295,6 +318,7 @@ export const APIKEY_PROVIDERS_SPECIALTY = { }, deepai: { id: "deepai", + serviceKinds: [], alias: "deepai", name: "DeepAI", icon: "psychology", @@ -308,6 +332,7 @@ export const APIKEY_PROVIDERS_SPECIALTY = { }, "cursor-api": { id: "cursor-api", + serviceKinds: ["llm"], alias: "cua", name: "Cursor API", icon: "edit_note", diff --git a/src/shared/constants/providers/audio.ts b/src/shared/constants/providers/audio.ts index dabc87a921c2..e706b047d79a 100644 --- a/src/shared/constants/providers/audio.ts +++ b/src/shared/constants/providers/audio.ts @@ -5,6 +5,7 @@ export const AUDIO_ONLY_PROVIDERS = { deepgram: { id: "deepgram", + serviceKinds: [], alias: "dg", name: "Deepgram", icon: "mic", @@ -14,6 +15,7 @@ export const AUDIO_ONLY_PROVIDERS = { }, assemblyai: { id: "assemblyai", + serviceKinds: [], alias: "aai", name: "AssemblyAI", icon: "record_voice_over", @@ -23,6 +25,7 @@ export const AUDIO_ONLY_PROVIDERS = { }, soniox: { id: "soniox", + serviceKinds: [], alias: "sx", name: "Soniox", icon: "mic", @@ -32,6 +35,7 @@ export const AUDIO_ONLY_PROVIDERS = { }, elevenlabs: { id: "elevenlabs", + serviceKinds: [], alias: "el", name: "ElevenLabs", icon: "record_voice_over", @@ -41,6 +45,7 @@ export const AUDIO_ONLY_PROVIDERS = { }, cartesia: { id: "cartesia", + serviceKinds: [], alias: "cartesia", name: "Cartesia", icon: "spatial_audio", @@ -50,6 +55,7 @@ export const AUDIO_ONLY_PROVIDERS = { }, fishaudio: { id: "fishaudio", + serviceKinds: [], alias: "fishaudio", name: "Fish Audio", icon: "graphic_eq", @@ -59,6 +65,7 @@ export const AUDIO_ONLY_PROVIDERS = { }, playht: { id: "playht", + serviceKinds: [], alias: "playht", name: "PlayHT", icon: "play_circle", @@ -68,6 +75,7 @@ export const AUDIO_ONLY_PROVIDERS = { }, inworld: { id: "inworld", + serviceKinds: [], alias: "inworld", name: "Inworld", icon: "voice_chat", @@ -77,6 +85,7 @@ export const AUDIO_ONLY_PROVIDERS = { }, "aws-polly": { id: "aws-polly", + serviceKinds: [], alias: "polly", name: "AWS Polly", icon: "record_voice_over", @@ -88,6 +97,7 @@ export const AUDIO_ONLY_PROVIDERS = { }, gladia: { id: "gladia", + serviceKinds: [], alias: "gladia", name: "Gladia", icon: "record_voice_over", @@ -98,6 +108,7 @@ export const AUDIO_ONLY_PROVIDERS = { "rev-ai": { id: "rev-ai", + serviceKinds: [], alias: "revai", name: "Rev AI", icon: "record_voice_over", @@ -108,6 +119,7 @@ export const AUDIO_ONLY_PROVIDERS = { speechmatics: { id: "speechmatics", + serviceKinds: [], alias: "sm", name: "Speechmatics", icon: "record_voice_over", diff --git a/src/shared/constants/providers/cloud-agent.ts b/src/shared/constants/providers/cloud-agent.ts index 72bb6ca96cae..7c7f6eb1bcd4 100644 --- a/src/shared/constants/providers/cloud-agent.ts +++ b/src/shared/constants/providers/cloud-agent.ts @@ -5,6 +5,7 @@ export const CLOUD_AGENT_PROVIDERS = { jules: { id: "jules", + serviceKinds: [], alias: "jules", name: "Google Jules", icon: "engineering", @@ -15,6 +16,7 @@ export const CLOUD_AGENT_PROVIDERS = { }, devin: { id: "devin", + serviceKinds: [], alias: "devin", name: "Devin", icon: "smart_toy", @@ -25,6 +27,7 @@ export const CLOUD_AGENT_PROVIDERS = { }, "codex-cloud": { id: "codex-cloud", + serviceKinds: [], alias: "codex-cloud", name: "Codex Cloud", icon: "cloud", diff --git a/src/shared/constants/providers/local.ts b/src/shared/constants/providers/local.ts index a3e455d64f79..20264995e7cf 100644 --- a/src/shared/constants/providers/local.ts +++ b/src/shared/constants/providers/local.ts @@ -5,6 +5,7 @@ export const LOCAL_PROVIDERS = { "mlx-gemma": { id: "mlx-gemma", + serviceKinds: ["llm"], alias: "mlx-gemma", name: "MLX Gemma 26B", icon: "memory", @@ -18,6 +19,7 @@ export const LOCAL_PROVIDERS = { }, "mlx-qwen": { id: "mlx-qwen", + serviceKinds: ["llm"], alias: "mlx-qwen", name: "MLX Qwen 3.8 27B", icon: "memory", @@ -31,6 +33,7 @@ export const LOCAL_PROVIDERS = { }, "ollama-local": { id: "ollama-local", + serviceKinds: ["llm"], alias: "ollama", name: "Ollama", icon: "pets", @@ -44,6 +47,7 @@ export const LOCAL_PROVIDERS = { }, "lm-studio": { id: "lm-studio", + serviceKinds: ["llm"], alias: "lmstudio", name: "LM Studio", icon: "server", @@ -57,6 +61,7 @@ export const LOCAL_PROVIDERS = { }, vllm: { id: "vllm", + serviceKinds: ["llm"], alias: "vllm", name: "vLLM", icon: "memory", @@ -70,6 +75,7 @@ export const LOCAL_PROVIDERS = { }, lemonade: { id: "lemonade", + serviceKinds: ["llm"], alias: "lemonade", name: "Lemonade Server", icon: "bolt", @@ -83,6 +89,7 @@ export const LOCAL_PROVIDERS = { }, llamafile: { id: "llamafile", + serviceKinds: ["llm"], alias: "llamafile", name: "Llamafile", icon: "article", @@ -96,6 +103,7 @@ export const LOCAL_PROVIDERS = { }, "llama-cpp": { id: "llama-cpp", + serviceKinds: ["llm"], alias: "llamacpp", name: "llama.cpp", icon: "memory", @@ -109,6 +117,7 @@ export const LOCAL_PROVIDERS = { }, triton: { id: "triton", + serviceKinds: ["llm"], alias: "triton", name: "NVIDIA Triton", icon: "developer_board", @@ -122,6 +131,7 @@ export const LOCAL_PROVIDERS = { }, "docker-model-runner": { id: "docker-model-runner", + serviceKinds: ["llm"], alias: "dmr", name: "Docker Model Runner", icon: "inventory_2", @@ -135,6 +145,7 @@ export const LOCAL_PROVIDERS = { }, xinference: { id: "xinference", + serviceKinds: ["llm"], alias: "xinference", name: "XInference", icon: "hub", @@ -148,6 +159,7 @@ export const LOCAL_PROVIDERS = { }, oobabooga: { id: "oobabooga", + serviceKinds: ["llm"], alias: "ooba", name: "oobabooga", icon: "dns", @@ -161,6 +173,7 @@ export const LOCAL_PROVIDERS = { }, sdwebui: { id: "sdwebui", + serviceKinds: [], alias: "sdwebui", name: "SD WebUI", icon: "brush", @@ -174,6 +187,7 @@ export const LOCAL_PROVIDERS = { }, comfyui: { id: "comfyui", + serviceKinds: [], alias: "comfyui", name: "ComfyUI", icon: "account_tree", diff --git a/src/shared/constants/providers/oauth.ts b/src/shared/constants/providers/oauth.ts index 1d339bb6b728..52d40bebb666 100644 --- a/src/shared/constants/providers/oauth.ts +++ b/src/shared/constants/providers/oauth.ts @@ -7,6 +7,7 @@ import { GITLAB_DUO_OAUTH_SETUP_MESSAGE } from "@/shared/constants/gitlabDuoSetu export const OAUTH_PROVIDERS = { "ghe-copilot": { id: "ghe-copilot", + serviceKinds: ["llm"], alias: "ghe-copilot", name: "GitHub Enterprise Copilot", icon: "code", @@ -18,6 +19,7 @@ export const OAUTH_PROVIDERS = { }, "xai-oauth": { id: "xai-oauth", + serviceKinds: ["llm"], alias: "xao", name: "xAI OAuth (Grok)", icon: "auto_awesome", @@ -34,6 +36,7 @@ export const OAUTH_PROVIDERS = { }, openference: { id: "openference", + serviceKinds: ["llm"], alias: "of", name: "Openference", icon: "openference", @@ -47,6 +50,7 @@ export const OAUTH_PROVIDERS = { }, "grok-cli": { id: "grok-cli", + serviceKinds: ["llm"], alias: "gc", name: "Grok Build", icon: "bolt", @@ -58,6 +62,7 @@ export const OAUTH_PROVIDERS = { }, qoder: { id: "qoder", + serviceKinds: ["llm"], alias: "if", name: "Qoder", icon: "water_drop", @@ -68,6 +73,7 @@ export const OAUTH_PROVIDERS = { }, agy: { id: "agy", + serviceKinds: ["llm"], alias: "agy", name: "Antigravity CLI", icon: "terminal", @@ -82,6 +88,7 @@ export const OAUTH_PROVIDERS = { }, kiro: { id: "kiro", + serviceKinds: ["llm"], alias: "kr", name: "Kiro AI", icon: "psychology_alt", @@ -94,6 +101,7 @@ export const OAUTH_PROVIDERS = { }, "amazon-q": { id: "amazon-q", + serviceKinds: ["llm"], alias: "aq", name: "Amazon Q", icon: "cloud", @@ -106,6 +114,7 @@ export const OAUTH_PROVIDERS = { }, claude: { id: "claude", + serviceKinds: ["llm"], alias: "cc", name: "Claude Code", icon: "smart_toy", @@ -115,6 +124,7 @@ export const OAUTH_PROVIDERS = { }, antigravity: { id: "antigravity", + serviceKinds: ["llm"], alias: undefined, name: "Antigravity", icon: "rocket_launch", @@ -124,6 +134,7 @@ export const OAUTH_PROVIDERS = { }, codex: { id: "codex", + serviceKinds: ["llm"], alias: "cx", name: "OpenAI Codex", icon: "code", @@ -131,9 +142,10 @@ export const OAUTH_PROVIDERS = { subscriptionRisk: true, riskNoticeVariant: "oauth", }, - github: { id: "github", alias: "gh", name: "GitHub Copilot", icon: "code", color: "#333333" }, + github: { id: "github", serviceKinds: ["llm"], alias: "gh", name: "GitHub Copilot", icon: "code", color: "#333333" }, "gitlab-duo": { id: "gitlab-duo", + serviceKinds: ["llm"], alias: "gitlab-duo", name: "GitLab Duo", icon: "hub", @@ -145,6 +157,7 @@ export const OAUTH_PROVIDERS = { }, cursor: { id: "cursor", + serviceKinds: ["llm"], alias: "cu", name: "Cursor IDE", icon: "edit_note", @@ -154,6 +167,7 @@ export const OAUTH_PROVIDERS = { }, zed: { id: "zed", + serviceKinds: ["llm"], alias: "zd", name: "Zed IDE", icon: "code", @@ -165,6 +179,7 @@ export const OAUTH_PROVIDERS = { }, "zed-hosted": { id: "zed-hosted", + serviceKinds: ["llm"], alias: undefined, name: "Zed Hosted Models", icon: "code_blocks", @@ -178,6 +193,7 @@ export const OAUTH_PROVIDERS = { }, trae: { id: "trae", + serviceKinds: ["llm"], alias: "tr", name: "Trae", icon: "edit_square", @@ -189,6 +205,7 @@ export const OAUTH_PROVIDERS = { }, "kimi-coding": { id: "kimi-coding", + serviceKinds: ["llm"], alias: "kmc", name: "Kimi Code CLI", icon: "psychology", @@ -204,6 +221,7 @@ export const OAUTH_PROVIDERS = { }, kilocode: { id: "kilocode", + serviceKinds: ["llm"], alias: "kc", name: "Kilo Code", icon: "code", @@ -218,6 +236,7 @@ export const OAUTH_PROVIDERS = { }, cline: { id: "cline", + serviceKinds: ["llm"], alias: "cl", name: "Cline", icon: "smart_toy", @@ -228,6 +247,7 @@ export const OAUTH_PROVIDERS = { }, clinepass: { id: "clinepass", + serviceKinds: ["llm"], alias: "cp", name: "ClinePass", icon: "smart_toy", @@ -241,6 +261,7 @@ export const OAUTH_PROVIDERS = { }, "devin-desktop": { id: "devin-desktop", + serviceKinds: ["llm"], alias: undefined, name: "Devin Desktop", icon: "terminal", @@ -254,6 +275,7 @@ export const OAUTH_PROVIDERS = { }, "devin-cli": { id: "devin-cli", + serviceKinds: ["llm"], alias: "dv", name: "Devin CLI", icon: "terminal", @@ -265,6 +287,7 @@ export const OAUTH_PROVIDERS = { }, "codebuddy-cn": { id: "codebuddy-cn", + serviceKinds: ["llm"], alias: "cbcn", name: "CodeBuddy CN", icon: "smart_toy", diff --git a/src/shared/constants/providers/search.ts b/src/shared/constants/providers/search.ts index efc528aa9b1b..1649858ad7e1 100644 --- a/src/shared/constants/providers/search.ts +++ b/src/shared/constants/providers/search.ts @@ -5,6 +5,7 @@ export const SEARCH_PROVIDERS = { "perplexity-search": { id: "perplexity-search", + serviceKinds: ["webSearch"], alias: "pplx-search", name: "Perplexity Search", icon: "search", @@ -27,6 +28,7 @@ export const SEARCH_PROVIDERS = { }, "brave-search": { id: "brave-search", + serviceKinds: ["webSearch"], alias: "brave-search", name: "Brave Search", icon: "travel_explore", @@ -92,6 +94,7 @@ export const SEARCH_PROVIDERS = { }, "google-pse-search": { id: "google-pse-search", + serviceKinds: ["webSearch"], alias: "google-pse", name: "Google Programmable Search", icon: "travel_explore", @@ -113,6 +116,7 @@ export const SEARCH_PROVIDERS = { }, "linkup-search": { id: "linkup-search", + serviceKinds: ["webSearch"], alias: "linkup", name: "Linkup Search", icon: "public", @@ -123,6 +127,7 @@ export const SEARCH_PROVIDERS = { }, "searchapi-search": { id: "searchapi-search", + serviceKinds: ["webSearch"], alias: "searchapi", name: "SearchAPI", icon: "manage_search", @@ -133,6 +138,7 @@ export const SEARCH_PROVIDERS = { }, "youcom-search": { id: "youcom-search", + serviceKinds: ["webSearch"], alias: "youcom-search", name: "You.com Search", icon: "travel_explore", @@ -143,6 +149,7 @@ export const SEARCH_PROVIDERS = { }, "searxng-search": { id: "searxng-search", + serviceKinds: ["webSearch"], alias: "searxng", name: "SearXNG Search", icon: "search", @@ -179,6 +186,7 @@ export const SEARCH_PROVIDERS = { }, "ollama-search": { id: "ollama-search", + serviceKinds: ["webSearch"], alias: "ollama-search", name: "Ollama Search", icon: "search", diff --git a/src/shared/constants/providers/system.ts b/src/shared/constants/providers/system.ts index 0500dc6cfa90..fb0bb354c3be 100644 --- a/src/shared/constants/providers/system.ts +++ b/src/shared/constants/providers/system.ts @@ -5,6 +5,7 @@ export const SYSTEM_PROVIDERS = { auto: { id: "auto", + serviceKinds: [], alias: "auto", name: "Auto (Zero-Config)", icon: "auto_awesome", diff --git a/src/shared/constants/providers/upstream-proxy.ts b/src/shared/constants/providers/upstream-proxy.ts index 691b44762454..e4fba683a9a3 100644 --- a/src/shared/constants/providers/upstream-proxy.ts +++ b/src/shared/constants/providers/upstream-proxy.ts @@ -5,6 +5,7 @@ export const UPSTREAM_PROXY_PROVIDERS = { cliproxyapi: { id: "cliproxyapi", + serviceKinds: [], alias: "cpa", name: "CLIProxyAPI", icon: "proxy", @@ -20,6 +21,7 @@ export const UPSTREAM_PROXY_PROVIDERS = { }, "9router": { id: "9router", + serviceKinds: [], alias: "nr", name: "9router", icon: "router", diff --git a/src/shared/constants/providers/web-cookie.ts b/src/shared/constants/providers/web-cookie.ts index 4e1acc22d258..e079cec5e1d9 100644 --- a/src/shared/constants/providers/web-cookie.ts +++ b/src/shared/constants/providers/web-cookie.ts @@ -5,6 +5,7 @@ export const WEB_COOKIE_PROVIDERS = { "chatgpt-web-codex": { id: "chatgpt-web-codex", + serviceKinds: ["llm"], alias: "cgpt-codex", name: "ChatGPT Web (Codex)", icon: "terminal", @@ -19,6 +20,7 @@ export const WEB_COOKIE_PROVIDERS = { }, "grok-web": { id: "grok-web", + serviceKinds: ["llm"], alias: "gw", name: "Grok Web (Subscription)", icon: "auto_awesome", @@ -32,6 +34,7 @@ export const WEB_COOKIE_PROVIDERS = { }, "gemini-web": { id: "gemini-web", + serviceKinds: ["llm"], alias: "gweb", name: "Gemini Web (Free)", icon: "auto_awesome", @@ -47,6 +50,7 @@ export const WEB_COOKIE_PROVIDERS = { }, "perplexity-web": { id: "perplexity-web", + serviceKinds: ["llm"], alias: "pplx-web", name: "Perplexity Web (Pro/Max)", icon: "search", @@ -60,6 +64,7 @@ export const WEB_COOKIE_PROVIDERS = { }, "blackbox-web": { id: "blackbox-web", + serviceKinds: ["llm"], alias: "bb-web", name: "Blackbox Web (Subscription)", icon: "view_in_ar", @@ -74,6 +79,7 @@ export const WEB_COOKIE_PROVIDERS = { }, "muse-spark-web": { id: "muse-spark-web", + serviceKinds: ["llm"], alias: "ms-web", name: "Muse Spark Web (Meta AI)", icon: "auto_awesome", @@ -90,6 +96,7 @@ export const WEB_COOKIE_PROVIDERS = { }, "claude-web": { id: "claude-web", + serviceKinds: ["llm"], alias: "cw", name: "Claude Web", icon: "auto_awesome", @@ -105,6 +112,7 @@ export const WEB_COOKIE_PROVIDERS = { }, "deepseek-web": { id: "deepseek-web", + serviceKinds: ["llm"], alias: "ds-web", name: "DeepSeek Web", icon: "auto_awesome", @@ -119,6 +127,7 @@ export const WEB_COOKIE_PROVIDERS = { }, "copilot-web": { id: "copilot-web", + serviceKinds: ["llm"], alias: "copilot", name: "Microsoft Copilot Web", icon: "auto_awesome", @@ -132,6 +141,7 @@ export const WEB_COOKIE_PROVIDERS = { }, "copilot-m365-web": { id: "copilot-m365-web", + serviceKinds: ["llm"], alias: "m365copilot", name: "Microsoft 365 Copilot (BizChat)", icon: "business_center", @@ -145,6 +155,7 @@ export const WEB_COOKIE_PROVIDERS = { }, "t3-web": { id: "t3-web", + serviceKinds: ["llm"], alias: "t3chat", name: "t3.chat (Pro/Free)", icon: "auto_awesome", @@ -161,6 +172,7 @@ export const WEB_COOKIE_PROVIDERS = { }, "inner-ai": { id: "inner-ai", + serviceKinds: ["llm"], alias: "in-ai", name: "Inner.ai (Subscription)", icon: "auto_awesome", @@ -175,6 +187,7 @@ export const WEB_COOKIE_PROVIDERS = { }, "adapta-web": { id: "adapta-web", + serviceKinds: ["llm"], alias: "adp-web", name: "Adapta.org (Adapta One Web)", icon: "auto_awesome", @@ -191,6 +204,7 @@ export const WEB_COOKIE_PROVIDERS = { // Wire id stays `lmarena` for DB/combo/model-prefix back-compat. // Product rebranded LMArena → Arena (arena.ai) in Jan 2026. id: "lmarena", + serviceKinds: ["llm"], alias: "lma", name: "Arena (Free)", icon: "auto_awesome", @@ -206,6 +220,7 @@ export const WEB_COOKIE_PROVIDERS = { }, "yuanbao-web": { id: "yuanbao-web", + serviceKinds: ["llm"], alias: "ybw", name: "Tencent Yuanbao (Free)", icon: "auto_awesome", @@ -221,6 +236,7 @@ export const WEB_COOKIE_PROVIDERS = { }, "tencent-aistudio-web": { id: "tencent-aistudio-web", + serviceKinds: ["llm"], alias: "tasw", name: "Tencent AI Studio (Free)", icon: "auto_awesome", @@ -236,6 +252,7 @@ export const WEB_COOKIE_PROVIDERS = { }, huggingchat: { id: "huggingchat", + serviceKinds: ["llm"], // huggingchat is addressed by its own id as alias (stable routing; the // historical "hc" alias collided with another provider and was retired). alias: "huggingchat", @@ -252,6 +269,7 @@ export const WEB_COOKIE_PROVIDERS = { }, "poe-web": { id: "poe-web", + serviceKinds: ["llm"], alias: "poe", name: "Poe Web (Subscription)", icon: "auto_awesome", @@ -264,6 +282,7 @@ export const WEB_COOKIE_PROVIDERS = { }, "venice-web": { id: "venice-web", + serviceKinds: ["llm"], alias: "ven", name: "Venice Web (Privacy)", icon: "auto_awesome", @@ -275,6 +294,7 @@ export const WEB_COOKIE_PROVIDERS = { }, "v0-vercel-web": { id: "v0-vercel-web", + serviceKinds: ["llm"], // #6343: was "v0", colliding with the unrelated "v0-vercel" API-key provider's // alias. Aliases resolve 1:1 to a provider id, so the dashboard's model-string // routing always picked v0-vercel, silently hiding this provider's own @@ -292,6 +312,7 @@ export const WEB_COOKIE_PROVIDERS = { }, "kimi-web": { id: "kimi-web", + serviceKinds: ["llm"], // Legacy "kimi" API provider keeps the short alias; web variant uses its own id. alias: "kimi-web", name: "Kimi Web", @@ -306,6 +327,7 @@ export const WEB_COOKIE_PROVIDERS = { }, "doubao-web": { id: "doubao-web", + serviceKinds: ["llm"], alias: "db", name: "Dola Web (ByteDance)", icon: "auto_awesome", @@ -319,6 +341,7 @@ export const WEB_COOKIE_PROVIDERS = { }, "gemini-business": { id: "gemini-business", + serviceKinds: ["llm"], alias: "gembiz", name: "Gemini Business (Enterprise)", icon: "business_center", @@ -333,6 +356,7 @@ export const WEB_COOKIE_PROVIDERS = { }, "zenmux-free": { id: "zenmux-free", + serviceKinds: ["llm"], alias: "zmf", name: "ZenMux Free (Web)", icon: "bolt", @@ -347,6 +371,7 @@ export const WEB_COOKIE_PROVIDERS = { }, "tinycms-web": { id: "tinycms-web", + serviceKinds: ["llm"], alias: "tcw", name: "TinyCMS Web (Free/Sub)", icon: "layers", @@ -361,6 +386,7 @@ export const WEB_COOKIE_PROVIDERS = { }, "zai-web": { id: "zai-web", + serviceKinds: ["llm"], alias: "zw", name: "Z.ai Web", icon: "auto_awesome", @@ -377,6 +403,7 @@ export const WEB_COOKIE_PROVIDERS = { }, promptql: { id: "promptql", + serviceKinds: ["llm"], alias: "pql", name: "PromptQL (Unofficial/Experimental)", icon: "auto_awesome", @@ -390,6 +417,7 @@ export const WEB_COOKIE_PROVIDERS = { }, "notion-web": { id: "notion-web", + serviceKinds: ["llm"], alias: "nw", name: "Notion AI Web (Unofficial/Experimental)", icon: "auto_awesome", @@ -409,6 +437,7 @@ export const WEB_COOKIE_PROVIDERS = { }, "adobe-firefly": { id: "adobe-firefly", + serviceKinds: [], alias: "firefly", name: "Adobe Firefly (Image/Video)", icon: "auto_awesome", @@ -422,6 +451,7 @@ export const WEB_COOKIE_PROVIDERS = { }, hyperagent: { id: "hyperagent", + serviceKinds: ["llm"], alias: "ha", name: "HyperAgent (Unofficial/Experimental)", icon: "auto_awesome", @@ -435,6 +465,7 @@ export const WEB_COOKIE_PROVIDERS = { }, "conol-web": { id: "conol-web", + serviceKinds: ["llm"], alias: "cnl", name: "Conol (Unofficial/Experimental)", icon: "auto_awesome", diff --git a/src/shared/validation/providerSchema.ts b/src/shared/validation/providerSchema.ts index 929108e55595..3c77b41523a7 100644 --- a/src/shared/validation/providerSchema.ts +++ b/src/shared/validation/providerSchema.ts @@ -31,7 +31,7 @@ export const ProviderSchema = z.object({ authHint: z.string().optional(), apiHint: z.string().optional(), oauthProviderId: z.string().min(1).optional(), - serviceKinds: z.array(z.enum(SERVICE_KIND_VALUES)).optional(), + serviceKinds: z.array(z.enum(SERVICE_KIND_VALUES)), noAuth: z.boolean().optional(), anonymousFallback: z.boolean().optional(), managedAccount: z.boolean().optional(), diff --git a/tests/unit/check-provider-consistency.test.ts b/tests/unit/check-provider-consistency.test.ts index a02f8ad70ae0..5b493402a344 100644 --- a/tests/unit/check-provider-consistency.test.ts +++ b/tests/unit/check-provider-consistency.test.ts @@ -1,6 +1,13 @@ import { test } from "node:test"; import assert from "node:assert"; -import { findOrphanRegistryIds, KNOWN_REGISTRY_ONLY } from "../../scripts/check/check-provider-consistency.ts"; +import { AI_PROVIDERS } from "@/shared/constants/providers.ts"; +import { REGISTRY } from "@omniroute/open-sse/config/providerRegistry.ts"; +import { + findOrphanRegistryIds, + findCatalogOnlyLlmProviders, + KNOWN_REGISTRY_ONLY, + KNOWN_CATALOG_ONLY, +} from "../../scripts/check/check-provider-consistency.ts"; import { reportStaleEntries } from "../../scripts/check/lib/allowlist.mjs"; const known = new Set(["openai", "anthropic", "gemini"]); @@ -43,3 +50,52 @@ test("stale-enforcement: live repo has zero stale entries in KNOWN_REGISTRY_ONLY // catch any entry added without a corresponding live orphan. assert.deepEqual(Object.keys(KNOWN_REGISTRY_ONLY as Record), []); }); + +// --- reverse walk (providers.ts → REGISTRY, #10513) --- + +test("no reverse orphans when every llm provider has a REGISTRY entry", () => { + const canonical = { + openai: { serviceKinds: ["llm"] }, + deepgram: { serviceKinds: [] }, // media-only, no registry needed + }; + assert.deepEqual(findCatalogOnlyLlmProviders(canonical, ["openai"], {}), []); +}); + +test("flags an llm-kind canonical provider without REGISTRY entry (half-removed)", () => { + const canonical = { + deadprovider: { serviceKinds: ["llm"] }, + openai: { serviceKinds: ["llm"] }, + }; + assert.deepEqual(findCatalogOnlyLlmProviders(canonical, ["openai"], {}), ["deadprovider"]); +}); + +test("non-llm providers without REGISTRY are not flagged (search/audio/local/media)", () => { + const canonical = { + "perplexity-search": { serviceKinds: ["webSearch"] }, + deepgram: { serviceKinds: [] }, + }; + assert.deepEqual(findCatalogOnlyLlmProviders(canonical, [], {}), []); +}); + +test("allowlisted catalog-only providers are not flagged", () => { + const canonical = { + "azure-openai": { serviceKinds: ["llm"] }, + }; + assert.deepEqual( + findCatalogOnlyLlmProviders(canonical, [], { "azure-openai": "connection baseUrl" }), + [] + ); +}); + +test("KNOWN_CATALOG_ONLY covers every live llm provider without REGISTRY entry", () => { + // Live-repo invariant: the allowlist + REGISTRY must together cover every + // llm-kind canonical provider. A NEW llm provider added to the catalog without + // a REGISTRY entry (or an allowlist entry) fails here — the exact gap + // pacocartones identified for provider:remove --dry-run verifiability. + const leftover = findCatalogOnlyLlmProviders( + AI_PROVIDERS as Record, + Object.keys(REGISTRY as Record), + KNOWN_CATALOG_ONLY + ); + assert.deepEqual(leftover, []); +});