/** * Canonical LLM provider + model catalog. Single source of truth for * every place that names a model, used by: * * - dashboard pickers: AI nodes, LLM credentials, voice agents * - api defaults: the AI node's `model` @Prop, the cheap model the * tool generator and the fact extractor pick per provider * - api summarization: context windows drive the chunk size * * It lived in `dashboard/lib/llm-models.ts` until 2026-08-18, with a * comment arguing model strings were "dashboard chrome only". They were * not: the api had its own hardcoded copies and nothing synced them. The * picker offered `claude-haiku-4-5` while the api minted nodes on * `claude-sonnet-4-20250514`, retired two months earlier. Same class of * bug `credentials.ts` exists to kill — both sides import one list now. * * NOT here: the models HostWebhook runs on its own key (see the api's * `common/llm-models.ts`) and the voice-platform catalogs. Retell and * Vapi accept their own spellings — Retell says `claude-5-sonnet`, Vapi * demands the dated Haiku id — so those live with their backends and * follow the platform's docs, not the provider's. * * Last verified against provider docs: 2026-08-18 * - Anthropic: https://platform.claude.com/docs/en/about-claude/models/overview * - OpenAI: https://developers.openai.com/api/docs/models * - Google: https://ai.google.dev/gemini-api/docs/models * - Groq: https://console.groq.com/docs/models * * NOT verified against docs, and on purpose: OpenRouter. Its catalog is not a * list anybody types — see `LLM_MODELS.openrouter` and `openrouter.ts`. */ export type LlmProvider = 'anthropic' | 'openai' | 'google' | 'groq' /** * A router, not a lab: OpenRouter resells ~425 models from everybody else * behind one key. That is why it is the first provider here whose catalog * is EMPTY below and fetched live instead — the shape of the entry is in * `openrouter.ts`, and the price of each model travels with the model. */ | 'openrouter'; export interface LlmProviderOption { value: LlmProvider; label: string; } export interface LlmModelOption { value: string; /** Friendly label for pickers; defaults to `value` when absent. */ label?: string; /** * The suggested default for new selections — exactly one per provider. * * It carries more weight than "preselected in a dropdown": the api * reads it through `getDefaultModel` for the model a new AI node is * born with, and for the cheap model it picks when generating a tool * definition or extracting memory facts. So the recommended entry must * be the cheapest CURRENT-tier model of that provider — pick a * flagship here and every background call gets expensive at once. */ recommended?: boolean; } export declare const LLM_PROVIDERS: ReadonlyArray; export declare const LLM_MODELS: Record>; /** * Effective context window per model, in TOKENS. The api sizes * summarization chunks from this; a miss falls back to a conservative * 32k window, which still produces a summary — just chopped into far * more map calls than needed. That silence is why this table went four * months without a single current model in it. * * Includes ids the pickers no longer offer: the AI node's model field is * a free-text datalist, so a node may hold one by hand. * * ⚠️ NOT here: OpenRouter's ids. Same reason its models are not in * `LLM_MODELS` — its API publishes `context_length` per model, so the number * travels with the model instead of being copied 425 times into this table. * Whoever chunks for an OpenRouter model reads it from the fetched entry * (`ModeloDeOpenRouter.context_length`); a lookup here misses and falls back * to the conservative 32k, which still summarizes, just in more calls. */ export declare const MODEL_CONTEXT_WINDOWS: Record; /** * Lo más que un modelo puede ESCRIBIR en una sola respuesta, en TOKENS: el * techo de `max_tokens` (Anthropic), de `max_completion_tokens` (OpenAI, Groq) * y de `generationConfig.maxOutputTokens` (Gemini). * * Existe porque pedir más no da más: el proveedor contesta 400 y el nodo se * cae. Un AI Node con Max Tokens = 10.000.000 no escribe más que con 128.000; * sólo falla. Con esta tabla, quien llama al modelo puede mandar el techo en * vez del 400, y el panel puede decirlo antes de que pase. * * Misma forma que `MODEL_CONTEXT_WINDOWS` —id PELADO, tokens con separador— y * las mismas claves: los modelos de `LLM_MODELS` de los cuatro laboratorios, * más los ids legacy que el campo de texto libre del nodo todavía puede tener. * Para buscar, `salidaMaximaDelModelo`, que sabe quitar prefijo y fecha; un * acceso directo con `[modelo]` no los quita. * * Last verified against provider docs: 2026-10-06 * - Anthropic: https://platform.claude.com/docs/en/models//overview * (p. ej. https://platform.claude.com/docs/en/models/haiku-4-5/overview) * - OpenAI: https://developers.openai.com/api/docs/models/ * (p. ej. https://developers.openai.com/api/docs/models/gpt-4o) * - Google: https://ai.google.dev/gemini-api/docs/models/ * (p. ej. https://ai.google.dev/gemini-api/docs/models/gemini-3.5-flash) * - Groq: https://console.groq.com/docs/models y, para los retirados, * https://console.groq.com/docs/deprecations * Anthropic y Google, con dos lecturas independientes que coinciden; OpenAI y * Groq, con una, ficha por ficha. * * ⚠️ Lo que NO está, y por qué: * * - **OpenRouter.** Por la misma regla que su catálogo: cada entrada de su * API trae su propio tope (`top_provider.max_completion_tokens`), así que * se lee de ahí con `salidaMaximaDeOpenRouter` en vez de copiarse aquí. Y * no coincide con la del laboratorio: el 2026-10-06 OpenRouter servía * `openai/gpt-oss-20b` con 32.768, no con los 65.536 de Groq. * - **Los modelos que su proveedor da por retirados** (`MODELOS_RETIRADOS`). * Su doc ya no publica tope, y sin cifra publicada no se topa; además, * cualquier petición a uno de ellos falla antes de que el tope importe. * - **Un modelo que no esté**, sin más. La regla es que una clave que falta * NO topa: se manda lo que pidió el usuario y, si se pasa, el proveedor lo * dice. Un tope inventado es peor que ninguno, porque corta en silencio a * un modelo que podía escribir más. */ export declare const MODEL_MAX_OUTPUT_TOKENS: Record; /** * Lo más que `modelo` puede escribir en una respuesta, en tokens, o * `undefined` si no lo sabemos —y entonces NO se topa—. * * Busca en este orden, y para en la primera que encuentra: * * 1. el id tal cual: `claude-haiku-4-5`, `openai/gpt-oss-20b`; * 2. sin el prefijo de laboratorio: `anthropic/claude-sonnet-5`, * `models/gemini-3.5-flash`; * 3. sin el sufijo de fecha, `-AAAAMMDD` o `-AAAA-MM-DD`: * `claude-haiku-4-5-20251001`, `gpt-4o-2024-08-06` (también con prefijo). * * ⚠️ Sin búsqueda difusa por raíz, a diferencia de la ventana de contexto en * la api. Allí equivocarse sólo trocea de más; aquí un tope de otro modelo * cortaría la respuesta de uno que puede escribir más —`claude-sonnet-5-5` no * es `claude-sonnet-5`—, o mandaría uno que el modelo rechaza. Si no está, * `undefined`. * * ⚠️ No mira el proveedor. Un id de OpenRouter como `anthropic/claude-…` se * encuentra por el paso 2, pero el tope de OpenRouter es el suyo y puede ser * otro: para ese proveedor, `salidaMaximaDeOpenRouter`. Decidir a qué * proveedores se aplica esta tabla es de quien llama. */ export declare function salidaMaximaDelModelo(modelo: string): number | undefined; /** Un modelo que su proveedor ya no sirve, con el día y la página que lo dicen. */ export interface ModeloRetirado { provider: LlmProvider; /** El id tal cual lo escribe el proveedor: el mismo que tenía `LLM_MODELS`. */ model: string; /** El día desde el que el proveedor contesta con error, `AAAA-MM-DD`. */ retiredOn: string; /** La página del proveedor que lo dice. */ source: string; } /** * Los modelos que su proveedor ya retiró y que por eso salieron de * `LLM_MODELS`. * * [2026-10-06] Existe porque quitar un modelo del selector no lo quita de lo * que ya lo lleva: el campo del nodo es texto libre y la credencial guarda el * que se eligió. Ésos siguen mandando el id y el proveedor contesta con un * error. Con esta lista, quien vea uno puede decir por qué falla y desde * cuándo sin esperar a que falle. * * ⚠️ Es un AVISO, no una puerta. Nadie debe negarse a llamar a un modelo por * estar aquí: una retirada puede no ser para todos —la de `qwen/qwen3.6-27b` * es para free y developer; un contrato enterprise lo sigue teniendo— y quien * manda es la respuesta del proveedor. * * ⚠️ Salir del catálogo NO es salir de `MODEL_PRICING` (platform-contracts): * allí se quedan, porque las trazas viejas tienen que seguir cuadrando. * * Reglas, que fija un test: nada de aquí puede estar en `LLM_MODELS` (si * vuelve, el test se pone rojo), y cada fila lleva su fecha y su fuente. * Los retirados de antes de esta lista que nombran los comentarios de * `LLM_MODELS` (los llama de Groq, los `-20250514` de Anthropic, o1, las * previews de Gemini) no están: entrarían de uno en uno, cada uno comprobado * contra su página. * * Last verified against provider docs: 2026-10-06 * - Groq: https://console.groq.com/docs/deprecations */ export declare const MODELOS_RETIRADOS: ReadonlyArray; /** * La fila de `MODELOS_RETIRADOS` de `model` en `provider`, o `undefined` si no * está retirado o no lo sabemos. * * `provider` admite también el tipo de credencial (`llm_groq`), como * `getModelsFor`. `model` se busca con las mismas reglas que * `salidaMaximaDelModelo` —tal cual, sin prefijo de laboratorio, sin sufijo de * fecha— y sin búsqueda difusa: `groq/compound-max` no es `groq/compound`. * * ⚠️ El proveedor SÍ cuenta, a diferencia de `salidaMaximaDelModelo`: que Groq * retire `qwen/qwen3.6-27b` no dice nada del mismo id servido por otro, p. ej. * por OpenRouter. * * Compara con `===` sobre la lista, no con `[id]` sobre un objeto, así que * `'constructor'` o `'__proto__'` no encuentran nada de `Object.prototype`. */ export declare function modeloRetirado(provider: string, model: string): ModeloRetirado | undefined; /** * The model catalog for a provider. Accepts both the raw provider name * (`"anthropic"`) and the `llm_*` credential type prefix * (`"llm_anthropic"`) so call sites that key off credential type can * pass the type directly without stripping. */ export declare function getModelsFor(provider: string): ReadonlyArray; /** * The suggested default model for a provider, or `''` for one we do not * catalog (Ollama runs whatever the user pulled, so it has no entry — * callers fall back to the node's own model there). * * ⚠️ `'openrouter'` is the second `''`, and unlike Ollama it IS a provider in * `LLM_PROVIDERS`, so callers that assumed "every provider in the list has a * default" now have a case to handle. It is deliberate: its catalog is live * (see `LLM_MODELS.openrouter`) and no static pick would survive. Treat `''` * as "the user must choose", not as "fall back to something" — a node born * with an empty model must not be sent to the API as-is. */ export declare function getDefaultModel(provider: string): string; /** The friendly label for a model value, or the value itself. */ export declare function getModelLabel(value: string): string;