/** * Provider registry — single entry point for the messages route to call * any LLM backend. Picks the right adapter based on the model id prefix * and resolves the correct API key (user's saved key OR server env var). */ import { getModelMeta } from "./models"; import { callOpenAI } from "./openai"; import { callAnthropic } from "./anthropic"; import { callHuggingFace } from "./huggingface"; import { callGroq } from "./groq"; import { callMuAPI } from "./muapi"; import { callGradio } from "./gradio"; export function resolveApiKey(provider, opts = {}) { const { customApiKey, hfAccessToken } = opts; const envMap = { openai: "OPENAI_API_KEY", anthropic: "ANTHROPIC_API_KEY", huggingface: "HF_TOKEN", groq: "GROQ_API_KEY", muapi: "MU_API_KEY", }; if (customApiKey) { const k = customApiKey.trim(); if (provider === "openai" && k.startsWith("sk-")) return k; if (provider === "anthropic" && k.startsWith("sk-ant")) return k; if (provider === "groq" && k.startsWith("gsk_")) return k; if (provider === "huggingface" && k.startsWith("hf_")) return k; if (provider === "muapi" && k.startsWith("mu_")) return k; if (!envMap[provider]) return k; } if (provider === "huggingface" || provider === "gradio") { if (hfAccessToken?.startsWith("hf_")) return hfAccessToken; } const envVar = envMap[provider]; if (envVar) return process.env[envVar] || null; return null; } export async function callLLM(opts) { const { model, messages, systemPrompt = "", temperature = 1.0, maxTokens = 2048, reasoning = false, stream = false, onToken, customApiKey, hfAccessToken, } = opts; const meta = getModelMeta(model); if (!meta) throw new Error(`Unknown model: ${model}`); const provider = meta.provider; const apiKey = resolveApiKey(provider, { customApiKey, hfAccessToken }); if (provider === "gradio") { const lastUser = [...messages].reverse().find((m) => m.role === "user"); return callGradio({ model, prompt: lastUser?.content || "", systemPrompt, history: messages, apiKey, }); } if (provider === "muapi") { if (!apiKey) throw new Error("No API key available for MuAPI. Set MU_API_KEY env var or save a personal MuAPI key."); const lastUser = [...messages].reverse().find((m) => m.role === "user"); return callMuAPI({ model, prompt: lastUser?.content || "", systemPrompt, temperature, maxTokens, reasoning, imageUrl: lastUser?.imageUrl, apiKey, }); } if (!apiKey) { throw new Error(`No API key available for ${provider}. Set the matching env var or save a personal key.`); } const fullMessages = systemPrompt ? [{ role: "system", content: systemPrompt }, ...messages] : messages; switch (provider) { case "openai": return callOpenAI({ model, messages: fullMessages, temperature, maxTokens, reasoning, stream, apiKey, onToken }); case "anthropic": return callAnthropic({ model, messages, system: systemPrompt, temperature, maxTokens, stream, apiKey, onToken }); case "huggingface": return callHuggingFace({ model, messages: fullMessages, temperature, maxTokens, stream, apiKey, onToken }); case "groq": return callGroq({ model, messages: fullMessages, temperature, maxTokens, reasoning, stream, apiKey, onToken }); default: throw new Error(`Provider ${provider} is not implemented.`); } } export { getModelMeta };