import type { Config, ModelsDevModel, ModelsDevProvider, ProviderConfig } from '@wrongstack/core/types'; /** * Auto-discovery of an OpenAI-compatible server's model catalog. * * Many proxy/gateway servers (omniroute, LiteLLM, vLLM, LM Studio, …) expose a * `/v1/models` endpoint that returns far richer metadata than the bare OpenAI * spec — per-model `capabilities`, `context_length`, `max_output_tokens`, * `input_modalities`, a display `name`, etc. This module fetches that list and * maps it onto a `ModelsDevProvider` so the discovered models flow through the * exact same registry path as catalog (models.dev) models: factories are built * for them and per-model `Capabilities` resolve automatically — no hand-entered * model lists or capability overrides required. * * The wire format is the OpenAI "list" object. We read the documented OpenAI * fields and the common extended fields; anything missing degrades to a sane * default rather than failing. */ /** One entry from a `/v1/models` response. Only the fields we read are typed. */ interface CompatibleModelEntry { id?: unknown; name?: unknown; description?: unknown; context_length?: unknown; max_input_tokens?: unknown; max_output_tokens?: unknown; /** OpenAI-spec field used by some servers in place of the extended ones. */ max_tokens?: unknown; /** Vercel AI Gateway names the context window this way. */ context_window?: unknown; input_modalities?: unknown; output_modalities?: unknown; /** Vercel AI Gateway nests both directions under one object. */ modalities?: { input?: unknown; output?: unknown; }; created?: unknown; capabilities?: { tool_calling?: unknown; tools?: unknown; reasoning?: unknown; thinking?: unknown; vision?: unknown; temperature?: unknown; }; /** OpenRouter nests modalities here rather than at the top level. */ architecture?: { input_modalities?: unknown; output_modalities?: unknown; }; /** OpenRouter reports the routed upstream's real ceilings here. */ top_provider?: { context_length?: unknown; max_completion_tokens?: unknown; }; /** * OpenRouter enumerates supported request parameters instead of a * capabilities object. The ARRAY'S PRESENCE is itself the signal: a server * that lists its parameters and omits `tools` is saying "no tools", whereas * a server that sends no array at all is saying nothing. */ supported_parameters?: unknown; /** Per-token USD, as STRINGS on both OpenRouter and the Vercel Gateway. */ pricing?: Record; /** * Model class. The Gateway sends `type` on `/v1/models`; `modelType` is the * AI SDK's own metadata field. Measured against the live endpoint: 315 models, * of which only 208 are `language` — the rest are embedding/video/image/ * reranking/transcription/realtime/speech and must never reach a chat picker. */ type?: unknown; modelType?: unknown; } /** One provider that should have its model list fetched at boot. */ export interface DiscoveryTarget { id: string; cfg: ProviderConfig; baseUrl: string; apiKey?: string | undefined; /** Stable cache key. Shared so every host hits the same cache entries. */ cacheKey: string; } /** * Providers eligible for `/v1/models` auto-discovery, with their resolved base * URL and key. * * Single source of truth for BOTH hosts (CLI boot and the WebUI server). They * previously carried near-identical private copies whose cache keys used * different separators, so the two never shared a cache entry despite writing * to the same file. * * The preset is looked up by the config key AND by `cfg.type`, so a user alias * (`gateway-work` → `type: "ai-gateway"`) inherits `autoDiscover` and the * default base URL instead of silently opting out of discovery. */ export declare function resolveDiscoveryTargets(config: Config): DiscoveryTarget[]; export interface DiscoverOptions { /** Server base URL, e.g. `http://localhost:20128/v1`. */ baseUrl: string; /** Bearer token. Some local servers accept any value; pass what you have. */ apiKey?: string | undefined; /** Extra headers merged into the request. */ headers?: Record | undefined; /** Display name for the resulting provider (defaults to the id). */ providerName?: string | undefined; /** Abort the fetch after this many ms (default 8000). 0 disables. */ timeoutMs?: number | undefined; fetchImpl?: typeof fetch | undefined; } /** Map one `/v1/models` entry to a `ModelsDevModel`. Returns undefined when the * entry has no usable id. */ export declare function mapCompatibleModel(entry: CompatibleModelEntry): ModelsDevModel | undefined; /** * Fetch and map a `/v1/models` listing into a `ModelsDevProvider`. Resolves to * `undefined` (never throws) on any network/parse/shape failure or an empty * list, so callers can treat discovery as best-effort and fall back to a cache. */ export declare function discoverOpenAICompatibleModels(providerId: string, opts: DiscoverOptions): Promise; export {}; //# sourceMappingURL=auto-discover.d.ts.map