OpenRouter multi-model adapter and Voyage AI semantic search added in one PR
Chris-o-O adds five additional LLMs through a single OpenRouter key and bolts on pgvector-backed semantic search using Voyage's legal-domain embedding model. Both are the two most-requested gaps in the upstream codebase, landed together in commit `3279a584`.
The OpenRouter adapter (backend/src/lib/llm/openrouter.ts) plugs into the existing Claude/Gemini provider abstraction - same pattern, different endpoint. GPT-4o, GPT-4 Turbo, Mistral Large, Llama 3.3 70B, and Gemma 3 27B are added to the model roster via models.ts. A per-user openrouter_api_key column lands in user_profiles; the frontend wires it through ModelToggle and account settings.
Semantic search uses Voyage AI's voyage-law-2 (1024-dim, legal-tuned) rather than the default OpenAI or Cohere embedder. Documents are chunked at fixed 800-token windows with 150-token overlap, preserving [Page N] markers. The document_chunks table stores embeddings, and a match_document_chunks RPC does cosine similarity search via pgvector. Indexing fires on document upload; results surface through a /search/semantic endpoint and a semantic_search LLM tool, with a SemanticSearchWidget on ProjectPage.
A few things to check before importing: the match_document_chunks function is security definer and trusts the backend to pass the right p_user_id - no client-side tenant isolation. Indexing is fire-and-forget with no retry or backfill path, so documents uploaded before the migration exists will have no embeddings. Chunking is naive fixed-window; no sentence or paragraph boundary awareness. Migration 001_add_openrouter_voyage.sql requires the vector extension to be enabled in the Supabase dashboard before running.
The two features ship in one commit, which makes cherry-picking awkward. Splitting them on import is worth the effort.
Spotted something wrong? Or know the PR text has fresher detail than the writeup above?