OpenRouter added as third LLM provider, but tool-use format is broken and missing migration
idukeric wires up OpenRouter as an alternative to direct Claude and Gemini keys, with a cleaner generic `PUT /user/api-keys` route and frontend model selection. The direction is sound; the implementation has enough bugs that it needs a rewrite before use.
The design intent: store a single openrouter_api_key in the user profile, route any model whose ID starts with anthropic/ or openai/ (or contains "openrouter") through https://openrouter.ai/api/v1/chat/completions, and let users access anthropic/claude-3.5-sonnet, openai/gpt-4-turbo, and anthropic/claude-3-haiku without needing direct vendor keys. The PUT /user/api-keys route accepts a provider-keyed object, which is more extensible than separate per-provider endpoints.
The bugs are concrete. openrouter.ts sends system as a top-level field (Anthropic convention) instead of a system-role message inside the messages array as OpenRouter expects. Tool formatting is worse: toClaudeTools() shapes definitions in Anthropic's format, those get passed to OpenRouter's OpenAI-compatible function-calling endpoint, and then tool results come back as Anthropic-format {type: "tool_result", tool_use_id} blocks. Multi-turn tool loops will not function. There's also a typo - openrouterApikey vs openrouterApiKey - and GET /user/models is missing authentication.
The missing Supabase migration is the most immediate problem. The code reads user_profiles.openrouter_api_key but the column is never created. Any deployment applying this commit gets an error on the first profile fetch.
The package-lock changes - dropping react/react-dom/scheduler peer entries from the backend lockfile and stripping dev: true from ~25 @img native binaries on the frontend - look like environmental noise from a different npm install. Drop those hunks when cherry-picking.
Spotted something wrong? Or know the PR text has fresher detail than the writeup above?