Spaces:
Runtime error
Runtime error
| /** | |
| * Service kind — declarative tag for what a provider can do beyond basic LLM chat. | |
| * Affects UI filtering and playground routing; does not influence request routing. | |
| */ | |
| export type ServiceKind = | |
| | "llm" | |
| | "embedding" | |
| | "image" | |
| | "imageToText" | |
| | "tts" | |
| | "stt" | |
| | "webSearch" | |
| | "webFetch" | |
| | "video" | |
| | "music"; | |
| export type RiskNoticeVariant = "oauth" | "webCookie" | "deprecated" | "embedded-service"; | |
| export interface ProviderRiskNoticeFields { | |
| subscriptionRisk?: boolean; | |
| riskNoticeVariant?: RiskNoticeVariant; | |
| isEmbeddedService?: boolean; | |
| } | |
| import { NOAUTH_PROVIDERS } from "./providers/noauth"; | |
| import { OAUTH_PROVIDERS } from "./providers/oauth"; | |
| import { WEB_COOKIE_PROVIDERS } from "./providers/web-cookie"; | |
| import { APIKEY_PROVIDERS } from "./providers/apikey"; | |
| import { LOCAL_PROVIDERS } from "./providers/local"; | |
| import { SEARCH_PROVIDERS } from "./providers/search"; | |
| import { AUDIO_ONLY_PROVIDERS } from "./providers/audio"; | |
| import { UPSTREAM_PROXY_PROVIDERS } from "./providers/upstream-proxy"; | |
| import { CLOUD_AGENT_PROVIDERS } from "./providers/cloud-agent"; | |
| import { SYSTEM_PROVIDERS } from "./providers/system"; | |
| export const FREE_PROVIDERS = {}; | |
| // No-auth Providers | |
| export const FREE_APIKEY_PROVIDER_IDS = new Set([ | |
| "qoder", | |
| "mimocode", | |
| "opencode", | |
| // codebuddy-cn is OAuth-primary but the Tencent gateway also accepts a direct | |
| // API key (Authorization: Bearer). Admit it through the same managed-provider | |
| // gate so POST /api/providers accepts the dual-auth shape. | |
| "codebuddy-cn", | |
| ]); | |
| export function supportsApiKeyOnFreeProvider(providerId: unknown): boolean { | |
| return typeof providerId === "string" && FREE_APIKEY_PROVIDER_IDS.has(providerId); | |
| } | |
| // Web / Cookie Providers | |
| // API Key Providers | |
| // Sub-categories within APIKEY_PROVIDERS (used by dashboard and catalog views). | |
| export const IMAGE_ONLY_PROVIDER_IDS = new Set([ | |
| "nanobanana", | |
| "fal-ai", | |
| "stability-ai", | |
| "black-forest-labs", | |
| "recraft", | |
| "topaz", | |
| ]); | |
| export const AGGREGATOR_PROVIDER_IDS = new Set([ | |
| "openrouter", | |
| "synthetic", | |
| "kilo-gateway", | |
| "aimlapi", | |
| "novita", | |
| "piapi", | |
| "getgoapi", | |
| "laozhang", | |
| "vercel-ai-gateway", | |
| "agentrouter", | |
| "glhf", | |
| "cablyai", | |
| "thebai", | |
| "fenayai", | |
| "empower", | |
| "poe", | |
| "chutes", | |
| "hackclub", | |
| ]); | |
| export const ENTERPRISE_CLOUD_PROVIDER_IDS = new Set([ | |
| "azure-openai", | |
| "azure-ai", | |
| "bedrock", | |
| "watsonx", | |
| "oci", | |
| "sap", | |
| "vertex", | |
| "vertex-partner", | |
| "databricks", | |
| "datarobot", | |
| "clarifai", | |
| "snowflake", | |
| "heroku", | |
| "modal", | |
| ]); | |
| export const VIDEO_PROVIDER_IDS = new Set([ | |
| "runwayml", | |
| "veoaifree-web", | |
| "pollinations", | |
| "minimax", | |
| "together", | |
| "replicate", | |
| "haiper", | |
| "leonardo", | |
| ]); | |
| // IDE Providers: editors with built-in AI subscription (separate section in UI). | |
| // These providers live in OAUTH_PROVIDERS but render under "IDE Providers" | |
| // instead of "OAuth Providers" to avoid visual duplication. | |
| export const IDE_PROVIDER_IDS = new Set(["cursor", "zed", "trae"]); | |
| export const EMBEDDING_RERANK_PROVIDER_IDS = new Set(["voyage-ai", "jina-ai"]); | |
| // Local / Self-Hosted Providers | |
| // Search Providers | |
| // Audio Only Providers | |
| export const OPENAI_COMPATIBLE_PREFIX = "openai-compatible-"; | |
| export const ANTHROPIC_COMPATIBLE_PREFIX = "anthropic-compatible-"; | |
| export const CLAUDE_CODE_COMPATIBLE_PREFIX = "anthropic-compatible-cc-"; | |
| export function isOpenAICompatibleProvider(providerId: unknown): providerId is string { | |
| return typeof providerId === "string" && providerId.startsWith(OPENAI_COMPATIBLE_PREFIX); | |
| } | |
| export function isAnthropicCompatibleProvider(providerId: unknown): providerId is string { | |
| return typeof providerId === "string" && providerId.startsWith(ANTHROPIC_COMPATIBLE_PREFIX); | |
| } | |
| export function isClaudeCodeCompatibleProvider(providerId: unknown): providerId is string { | |
| return typeof providerId === "string" && providerId.startsWith(CLAUDE_CODE_COMPATIBLE_PREFIX); | |
| } | |
| export function isLocalProvider(providerId: unknown): boolean { | |
| return ( | |
| typeof providerId === "string" && | |
| Object.prototype.hasOwnProperty.call(LOCAL_PROVIDERS, providerId) | |
| ); | |
| } | |
| export const SELF_HOSTED_CHAT_PROVIDER_IDS = new Set([ | |
| "lm-studio", | |
| "vllm", | |
| "lemonade", | |
| "llamafile", | |
| "llama-cpp", | |
| "triton", | |
| "docker-model-runner", | |
| "xinference", | |
| "oobabooga", | |
| ]); | |
| export function isSelfHostedChatProvider(providerId: unknown): boolean { | |
| return typeof providerId === "string" && SELF_HOSTED_CHAT_PROVIDER_IDS.has(providerId); | |
| } | |
| export function providerAllowsOptionalApiKey(providerId: unknown): boolean { | |
| return ( | |
| // ponytail: any noAuth provider auto-qualifies — no per-provider maintenance | |
| (typeof providerId === "string" && providerId in NOAUTH_PROVIDERS) || | |
| providerId === "searxng-search" || | |
| providerId === "pollinations" || | |
| providerId === "copilot-web" || | |
| providerId === "hackclub" || | |
| providerId === "huggingchat" || | |
| providerId === "gitlawb" || | |
| providerId === "gitlawb-gmi" || | |
| isLocalProvider(providerId) || | |
| isSelfHostedChatProvider(providerId) || | |
| isOpenAICompatibleProvider(providerId) || | |
| isAnthropicCompatibleProvider(providerId) | |
| ); | |
| } | |
| /** | |
| * Providers explicitly excluded from bulk API key add — auth is heterogeneous, | |
| * OAuth-based, multi-field, or requires manual setup per connection. | |
| */ | |
| const BULK_API_KEY_EXCLUDED = new Set([ | |
| "vertex", | |
| "vertex-partner", | |
| "ollama-local", | |
| "grok-web", | |
| "perplexity-web", | |
| "blackbox-web", | |
| "muse-spark-web", | |
| "deepseek-web", | |
| "inner-ai", | |
| "qoder", | |
| "google-pse-search", | |
| "command-code", | |
| "azure", | |
| "cloudflare-ai", | |
| ]); | |
| export function supportsBulkApiKey(providerId: unknown): boolean { | |
| if (typeof providerId !== "string" || !providerId) return false; | |
| if (BULK_API_KEY_EXCLUDED.has(providerId)) return false; | |
| if (isLocalProvider(providerId)) return false; | |
| if (isSelfHostedChatProvider(providerId)) return false; | |
| if (isClaudeCodeCompatibleProvider(providerId)) return false; | |
| return true; | |
| } | |
| // ── System Providers (virtual, not user-connectable) ────────────────────────── | |
| const _PROVIDER_SECTIONS = [ | |
| NOAUTH_PROVIDERS, | |
| OAUTH_PROVIDERS, | |
| APIKEY_PROVIDERS, | |
| WEB_COOKIE_PROVIDERS, | |
| LOCAL_PROVIDERS, | |
| SEARCH_PROVIDERS, | |
| AUDIO_ONLY_PROVIDERS, | |
| UPSTREAM_PROXY_PROVIDERS, | |
| CLOUD_AGENT_PROVIDERS, | |
| SYSTEM_PROVIDERS, | |
| ] as const; | |
| let _aiProviders: Record<string, any> | null = null; | |
| function getOrCreateAiProviders(): Record<string, any> { | |
| if (!_aiProviders) { | |
| _aiProviders = {}; | |
| for (const section of _PROVIDER_SECTIONS) { | |
| Object.assign(_aiProviders, section); | |
| } | |
| } | |
| return _aiProviders; | |
| } | |
| let _ALIAS_TO_ID: Record<string, string> | null = null; | |
| function getOrCreateAliasToId(): Record<string, string> { | |
| if (!_ALIAS_TO_ID) { | |
| _ALIAS_TO_ID = {}; | |
| for (const section of _PROVIDER_SECTIONS) { | |
| for (const p of Object.values(section)) { | |
| if ((p as any).alias) _ALIAS_TO_ID[(p as any).alias] = (p as any).id; | |
| } | |
| } | |
| } | |
| return _ALIAS_TO_ID; | |
| } | |
| let _ID_TO_ALIAS: Record<string, string> | null = null; | |
| function getOrCreateIdToAlias(): Record<string, string> { | |
| if (!_ID_TO_ALIAS) { | |
| _ID_TO_ALIAS = {}; | |
| for (const section of _PROVIDER_SECTIONS) { | |
| for (const p of Object.values(section)) { | |
| _ID_TO_ALIAS[(p as any).id] = (p as any).alias || (p as any).id; | |
| } | |
| } | |
| } | |
| return _ID_TO_ALIAS; | |
| } | |
| export function getProviderById(id: string) { | |
| return ( | |
| (NOAUTH_PROVIDERS as Record<string, any>)[id] ?? | |
| (OAUTH_PROVIDERS as Record<string, any>)[id] ?? | |
| (APIKEY_PROVIDERS as Record<string, any>)[id] ?? | |
| (WEB_COOKIE_PROVIDERS as Record<string, any>)[id] ?? | |
| (LOCAL_PROVIDERS as Record<string, any>)[id] ?? | |
| (SEARCH_PROVIDERS as Record<string, any>)[id] ?? | |
| (AUDIO_ONLY_PROVIDERS as Record<string, any>)[id] ?? | |
| (UPSTREAM_PROXY_PROVIDERS as Record<string, any>)[id] ?? | |
| (CLOUD_AGENT_PROVIDERS as Record<string, any>)[id] ?? | |
| (SYSTEM_PROVIDERS as Record<string, any>)[id] ?? | |
| undefined | |
| ); | |
| } | |
| export const AI_PROVIDERS = new Proxy({} as Record<string, any>, { | |
| get(_, key) { | |
| if (key === "then") return undefined; | |
| return typeof key === "string" ? getOrCreateAiProviders()[key] : undefined; | |
| }, | |
| ownKeys() { | |
| return Reflect.ownKeys(getOrCreateAiProviders()); | |
| }, | |
| has(_, key) { | |
| return key in getOrCreateAiProviders(); | |
| }, | |
| getOwnPropertyDescriptor(_, key) { | |
| const obj = getOrCreateAiProviders(); | |
| if (typeof key === "string" && key in obj) { | |
| return { configurable: true, enumerable: true, value: obj[key] }; | |
| } | |
| return undefined; | |
| }, | |
| }); | |
| export type AiProviderId = | |
| | keyof typeof NOAUTH_PROVIDERS | |
| | keyof typeof OAUTH_PROVIDERS | |
| | keyof typeof APIKEY_PROVIDERS | |
| | keyof typeof WEB_COOKIE_PROVIDERS | |
| | keyof typeof LOCAL_PROVIDERS | |
| | keyof typeof SEARCH_PROVIDERS | |
| | keyof typeof AUDIO_ONLY_PROVIDERS | |
| | keyof typeof UPSTREAM_PROXY_PROVIDERS | |
| | keyof typeof CLOUD_AGENT_PROVIDERS | |
| | keyof typeof SYSTEM_PROVIDERS; | |
| export type AiProviderDefinition = | |
| | (typeof NOAUTH_PROVIDERS)[keyof typeof NOAUTH_PROVIDERS] | |
| | (typeof OAUTH_PROVIDERS)[keyof typeof OAUTH_PROVIDERS] | |
| | (typeof APIKEY_PROVIDERS)[keyof typeof APIKEY_PROVIDERS] | |
| | (typeof WEB_COOKIE_PROVIDERS)[keyof typeof WEB_COOKIE_PROVIDERS] | |
| | (typeof LOCAL_PROVIDERS)[keyof typeof LOCAL_PROVIDERS] | |
| | (typeof SEARCH_PROVIDERS)[keyof typeof SEARCH_PROVIDERS] | |
| | (typeof AUDIO_ONLY_PROVIDERS)[keyof typeof AUDIO_ONLY_PROVIDERS] | |
| | (typeof UPSTREAM_PROXY_PROVIDERS)[keyof typeof UPSTREAM_PROXY_PROVIDERS] | |
| | (typeof CLOUD_AGENT_PROVIDERS)[keyof typeof CLOUD_AGENT_PROVIDERS] | |
| | (typeof SYSTEM_PROVIDERS)[keyof typeof SYSTEM_PROVIDERS]; | |
| // Auth methods | |
| export const AUTH_METHODS = { | |
| oauth: { id: "oauth", name: "OAuth", icon: "lock" }, | |
| apikey: { id: "apikey", name: "API Key", icon: "key" }, | |
| }; | |
| export function getProviderByAlias(alias: string): AiProviderDefinition | null { | |
| for (const section of _PROVIDER_SECTIONS) { | |
| for (const provider of Object.values(section)) { | |
| if (provider.alias === alias || provider.id === alias) { | |
| return provider as AiProviderDefinition; | |
| } | |
| } | |
| } | |
| return null; | |
| } | |
| // Helper: Get provider ID from alias | |
| export function resolveProviderId(aliasOrId: string): string { | |
| const provider = getProviderByAlias(aliasOrId); | |
| return provider?.id || aliasOrId; | |
| } | |
| export function getProviderAlias(providerId: string): string { | |
| const provider = getProviderById(providerId); | |
| return provider?.alias || providerId; | |
| } | |
| export const ALIAS_TO_ID = new Proxy({} as Record<string, string>, { | |
| get(_, key) { | |
| return typeof key === "string" ? getOrCreateAliasToId()[key] : undefined; | |
| }, | |
| ownKeys() { | |
| return Reflect.ownKeys(getOrCreateAliasToId()); | |
| }, | |
| has(_, key) { | |
| return key in getOrCreateAliasToId(); | |
| }, | |
| getOwnPropertyDescriptor(_, key) { | |
| const obj = getOrCreateAliasToId(); | |
| if (typeof key === "string" && key in obj) { | |
| return { configurable: true, enumerable: true, value: obj[key] }; | |
| } | |
| return undefined; | |
| }, | |
| }); | |
| export const ID_TO_ALIAS = new Proxy({} as Record<string, string>, { | |
| get(_, key) { | |
| return typeof key === "string" ? getOrCreateIdToAlias()[key] : undefined; | |
| }, | |
| ownKeys() { | |
| return Reflect.ownKeys(getOrCreateIdToAlias()); | |
| }, | |
| has(_, key) { | |
| return key in getOrCreateIdToAlias(); | |
| }, | |
| getOwnPropertyDescriptor(_, key) { | |
| const obj = getOrCreateIdToAlias(); | |
| if (typeof key === "string" && key in obj) { | |
| return { configurable: true, enumerable: true, value: obj[key] }; | |
| } | |
| return undefined; | |
| }, | |
| }); | |
| // Providers that support usage/quota API | |
| export const USAGE_SUPPORTED_PROVIDERS = [ | |
| "antigravity", | |
| "agy", | |
| "gemini-cli", | |
| "kiro", | |
| "amazon-q", | |
| "github", | |
| "codex", | |
| "claude", | |
| "cursor", | |
| "kimi-coding", | |
| "kimi-coding-apikey", | |
| "glm", | |
| "glm-cn", | |
| "zai", | |
| "glmt", | |
| "opencode-go", | |
| "ollama-cloud", | |
| "minimax", | |
| "minimax-cn", | |
| "crof", | |
| "nanogpt", | |
| "deepseek", | |
| "xiaomi-mimo", | |
| "vertex", | |
| "vertex-partner", | |
| "codebuddy-cn", | |
| ]; | |
| // ── Zod validation at module load (Phase 7.2) ── | |
| // Re-export the extracted data catalogs so external importers of providers.ts are unchanged. | |
| export { | |
| NOAUTH_PROVIDERS, | |
| OAUTH_PROVIDERS, | |
| WEB_COOKIE_PROVIDERS, | |
| APIKEY_PROVIDERS, | |
| LOCAL_PROVIDERS, | |
| SEARCH_PROVIDERS, | |
| AUDIO_ONLY_PROVIDERS, | |
| UPSTREAM_PROXY_PROVIDERS, | |
| CLOUD_AGENT_PROVIDERS, | |
| SYSTEM_PROVIDERS, | |
| }; | |
| import { validateProviders } from "../validation/providerSchema"; | |
| validateProviders(NOAUTH_PROVIDERS, "NOAUTH_PROVIDERS"); | |
| validateProviders(OAUTH_PROVIDERS, "OAUTH_PROVIDERS"); | |
| validateProviders(APIKEY_PROVIDERS, "APIKEY_PROVIDERS"); | |
| validateProviders(WEB_COOKIE_PROVIDERS, "WEB_COOKIE_PROVIDERS"); | |
| validateProviders(LOCAL_PROVIDERS, "LOCAL_PROVIDERS"); | |
| validateProviders(SEARCH_PROVIDERS, "SEARCH_PROVIDERS"); | |
| validateProviders(AUDIO_ONLY_PROVIDERS, "AUDIO_ONLY_PROVIDERS"); | |
| validateProviders(UPSTREAM_PROXY_PROVIDERS, "UPSTREAM_PROXY_PROVIDERS"); | |
| validateProviders(CLOUD_AGENT_PROVIDERS, "CLOUD_AGENT_PROVIDERS"); | |