ClipSpacesClipSpaces Docs
Back to app

All releases

Bring-your-own-AI: multi-provider, multi-model

The AI assistant is no longer hardwired to one server-held OpenRouter key. Users can supply their own provider + model + key (billed to them), and self-hosters can write a server-wide config from the settings page. The model choice is now provider-agnostic across OpenRouter, OpenAI, Anthropic (native), and any OpenAI-compatible self-hosted endpoint (Ollama / LM Studio / vLLM).

Added

  • supabase/migrations/20260627000100_ai_credentials.sql — per-user AI config (provider, model, vision_model, base_url, context_window, api_key_encrypted). Mirrors connections secret handling: the key is stored AES-256-GCM-encrypted and the ciphertext column is REVOKEd from the browser role (read/written only via the service role). Types added to lib/supabase/types.ts.
  • lib/ai/types.ts — shared, client-safe types (ProviderId, AICredentialView, ResolvedAIConfig) + provider base URLs and the Anthropic-model test that gates prompt caching.
  • lib/ai/providers.ts — one callModel() adapter over two wire dialects: OpenAI-compatible (openrouter/openai/custom) and Anthropic Messages (anthropic). cache_control ephemeral breakpoints are emitted only for Anthropic-family models; actionable errors for 401/402/404.
  • lib/ai/config.ts — credential resolver (user DB → server file → env) with AES-256-GCM encrypt/decrypt (keyed by AI_CREDENTIALS_KEY), plus upsert/delete/getCredentialView. A user row without a key borrows the host key when providers match ("my model on the host's account").
  • lib/ai/budget.ts — context budgeting keyed off the model's window (board context vs. history), replacing the fixed MAX_HISTORY/char caps.
  • app/api/ai/credentials/route.ts — GET/PUT/DELETE the user's AI config (key encrypted before storage, never returned).
  • app/api/ai/config-file/route.ts — self-host only (ALLOW_AI_CONFIG_FILE=1): writes/reads ai.config.json (mode 0600, gitignored).
  • components/AISettingsPanel.tsx — settings sheet to pick provider/model/key, with a "My account" vs "This server" target (the latter shown only when the server enables the config file). Opened via a new gear in the Ask AI header.

Changed

  • app/api/ai/route.ts — resolves config per request and calls callModel() instead of a hardcoded OpenRouter fetch; board context + history now trimmed by the budget allocator. Returns a clear "AI isn't configured" error when nothing resolves. Existing OPENROUTER_* env vars still work (lowest-priority fallback).
  • lib/ai-enrich.ts — image captioning uses the resolved config's vision model/key/endpoint (OpenAI-compatible providers); skipped for anthropic.
  • .env.example — documents AI_CREDENTIALS_KEY, ALLOW_AI_CONFIG_FILE, AI_CONFIG_PATH, and generic AI_PROVIDER/AI_API_KEY/AI_MODEL/AI_BASE_URL/ AI_CONTEXT_WINDOW alongside the legacy OPENROUTER_* names.

Note: storing user keys requires AI_CREDENTIALS_KEY (32-byte base64/hex). The migration must be applied before users can save credentials.