import type { UnifiedProviderConfig, ByokVendor, OnDeviceBackend } from "./provider-mode.js"; /** * Google's OpenAI-compatible chat completions endpoint. Used when the user * picks Google as a BYOK vendor — Google is dispatched as OpenAI-compat * because every cloud client (web, mobile, desktop, cli) already understands * the OpenAI wire protocol. Single source of truth. */ export declare const GOOGLE_OPENAI_COMPAT_URL = "https://generativelanguage.googleapis.com/v1beta/openai"; /** Canonical Anthropic API base URL. */ export declare const ANTHROPIC_CANONICAL_URL = "https://api.anthropic.com"; /** Canonical OpenAI API base URL. */ export declare const OPENAI_CANONICAL_URL = "https://api.openai.com/v1"; /** * Canonical DeepSeek API base URL. DeepSeek exposes an OpenAI-compatible * chat-completions endpoint at `{base}/chat/completions`; the BYOK arm * routes through `OpenAIProvider` the same way Google does. Single * source of truth — surfaces that need a CORS proxy or dev rewrite * substitute via `env.cloudBaseUrl`. */ export declare const DEEPSEEK_CANONICAL_URL = "https://api.deepseek.com"; /** * Canonical Groq API base URL. Groq exposes an OpenAI-compatible * chat-completions endpoint at `{base}/chat/completions` (the * `/openai/v1` path segment is part of Groq's URL — they namespace * the OpenAI-shape API explicitly). The BYOK arm routes through * `OpenAIProvider`, same path as Google / DeepSeek. Single source of * truth — surfaces that need a CORS proxy or dev rewrite substitute * via `env.cloudBaseUrl`. */ export declare const GROQ_CANONICAL_URL = "https://api.groq.com/openai/v1"; /** Default Motebit Cloud relay URL. Surfaces may override via env. */ export declare const DEFAULT_MOTEBIT_CLOUD_URL = "https://api.motebit.com"; /** Default WebLLM model when none specified — small enough to fit on most devices. */ export declare const DEFAULT_WEBLLM_MODEL = "Llama-3.2-3B-Instruct-q4f16_1-MLC"; /** * Normalize a local-inference server URL so that it points at the * OpenAI-compatible chat completions base path. Auto-appends `/v1` if * the URL doesn't already contain it. Idempotent. * * Every supported local server (Ollama via its OpenAI shim, LM Studio, * llama.cpp, Jan, vLLM, text-generation-webui) exposes * `{base}/v1/chat/completions`. Users typically type just the host * (`http://localhost:11434`) — this helper completes the path so the * client can call `{normalized}/chat/completions` directly. * * Examples: * "http://localhost:11434" → "http://localhost:11434/v1" * "http://localhost:11434/v1" → "http://localhost:11434/v1" * "http://localhost:1234/" → "http://localhost:1234/v1" * "http://192.168.1.42:11434" → "http://192.168.1.42:11434/v1" * "/api/ollama" → "/api/ollama/v1" (dev proxy path) */ export declare function normalizeLocalServerEndpoint(url: string): string; /** Default chat model for a BYOK vendor. */ export declare function defaultModelForVendor(vendor: ByokVendor): string; /** * Canonical (vendor-published) base URL for a BYOK vendor. Surfaces that * need to substitute a CORS proxy or dev-mode path receive this canonical * URL via the resolver and may rewrite it. */ export declare function canonicalVendorBaseUrl(vendor: ByokVendor): string; /** * Discriminated union describing what concrete provider class the surface * should instantiate, with all decision logic already resolved. The surface's * job is reduced to a transport switch + class construction. */ export type ProviderSpec = CloudProviderSpec | WebLLMProviderSpec | AppleFoundationModelsSpec | MlxProviderSpec; /** * Cloud HTTP provider — used for Anthropic, OpenAI, Google (via OpenAI-compat), * Motebit Cloud (anthropic protocol via relay), and OpenAI-compat local * servers (LM Studio, llama.cpp, etc.). * * The `wireProtocol` discriminates between Anthropic's messages API and * OpenAI's chat completions API. The surface uses this to pick the right * concrete class (`AnthropicProvider` or `OpenAIProvider`) to instantiate. */ export interface CloudProviderSpec { kind: "cloud"; /** Wire protocol family this client speaks. */ wireProtocol: "anthropic" | "openai"; /** API key to use. Empty string for motebit-cloud (server injects). */ apiKey: string; model: string; /** Already-resolved base URL — env.cloudBaseUrl has been applied. */ baseUrl: string; maxTokens?: number; temperature?: number; /** Extra HTTP headers (e.g., x-proxy-token for motebit-cloud). */ extraHeaders?: Record; } /** Browser-only WebLLM provider — runs in-browser via WebGPU. */ export interface WebLLMProviderSpec { kind: "webllm"; model: string; maxTokens?: number; temperature?: number; } /** Apple Foundation Models — iOS 26+ / macOS 26+ only. */ export interface AppleFoundationModelsSpec { kind: "apple-fm"; model?: string; maxTokens?: number; } /** MLX runtime — Apple Silicon only. */ export interface MlxProviderSpec { kind: "mlx"; model?: string; maxTokens?: number; } /** * Per-surface environment that captures the only things the resolver can't * decide on its own: platform-specific URL routing, which on-device backends * are physically supported, and motebit-cloud session state. * * Each surface constructs one of these once (or per call if the session * state changes) and passes it to `resolveProviderSpec`. The interface is * intentionally narrow — anything that can be computed from a * `UnifiedProviderConfig` alone stays inside the resolver. */ export interface ResolverEnv { /** * Resolve the actual base URL for a cloud provider given its canonical * vendor URL. Most surfaces return `canonical` unchanged. Browser surfaces * substitute a CORS proxy for vendors that block direct browser calls. * Tauri dev mode substitutes a Vite proxy path. * * The function form (rather than a static map) lets surfaces compute the * substitution lazily based on runtime state (e.g., `isTauri`). */ cloudBaseUrl(wireProtocol: "anthropic" | "openai", canonical: string): string; /** * Default URL for the on-device local-server backend when the user * hasn't supplied an endpoint. The resolver auto-appends `/v1` via * `normalizeLocalServerEndpoint`, so this can be a bare host. Use * `localServerBaseUrl` to translate the user-supplied URL into a * surface-specific transport URL (e.g., a Vite dev proxy path). */ defaultLocalServerUrl: string; /** * Optional translator from a logical local-server URL into the actual URL * the provider should call. Most surfaces return the input unchanged. * Desktop dev mode substitutes the Vite proxy path `/api/ollama` for any * Ollama-shaped logical URL — but the dispatch decision (Ollama-native vs * OpenAI-compat) is made BEFORE this substitution, on the logical URL. * * This separation lets surfaces use proxy/rewrite paths without losing * the resolver's ability to dispatch on the user's intent. */ localServerBaseUrl?(logical: string): string; /** * Which on-device backends this surface can physically run. * - web: webllm, local-server * - mobile: apple-fm, mlx, local-server * - desktop: local-server (today; could grow) * - cli: local-server */ supportedBackends: ReadonlySet; /** * Base URL for motebit-cloud requests. Each surface resolves this from * its own session state / env (proxy session, VITE_PROXY_URL, etc.). * Falls back to `DEFAULT_MOTEBIT_CLOUD_URL` if absent. */ motebitCloudBaseUrl?: string; /** * Extra HTTP headers to attach to motebit-cloud requests. Typically * `{ "x-proxy-token": "..." }` from the surface's proxy session state. */ motebitCloudHeaders?: Record; /** * Default model for motebit-cloud when the config doesn't specify. * Most surfaces leave this undefined (resolver falls back to * `DEFAULT_PROXY_MODEL`); the relay session may override based on tier. */ motebitCloudDefaultModel?: string; } /** * Thrown when the user picks an on-device backend that the current surface * doesn't physically support (e.g., apple-fm on web). Surfaces should * present a graceful error rather than letting it propagate. */ export declare class UnsupportedBackendError extends Error { backend: OnDeviceBackend; constructor(backend: OnDeviceBackend); } /** * Resolve a `UnifiedProviderConfig` (the user's choice) against a surface's * `ResolverEnv` (its physical capabilities) to produce a normalized * `ProviderSpec` (what the surface should instantiate). * * Pure function. No I/O. No side effects. Tested once, used everywhere. * * @throws {UnsupportedBackendError} if the chosen on-device backend isn't * in `env.supportedBackends`. Surfaces should catch and present a * user-facing message. */ export declare function resolveProviderSpec(config: UnifiedProviderConfig, env: ResolverEnv): ProviderSpec; //# sourceMappingURL=provider-resolver.d.ts.map