[Extensibility 1/4] refactor: table-driven LLM provider registry
From the PR description
Summary
Replaces the per-provider if/else chains in the LLM dispatch layer and the per-provider switch in the API-key lookup with a table-driven provider registry. Adding a provider (including OpenAI-compatible endpoints - the path endorsed in #20) becomes a single registerProvider() / registerApiKeyProvider() call, with no edits to call sites.
Behavior is preserved: same three built-in providers, same env-var precedence, same model routing, same API-key status results. This is the base of a 4-PR extensibility series - demo mode, Ollama, and Vertex AI each become one self-contained file on top of it.
Changes
backend/src/lib/llm/registry.ts(new):LLMProviderAdaptercontract +registerProvider/findProviderForModel/ friends.backend/src/core/apiKeyProviders.ts(new): provider → env-var table replacing the hand-maintainedswitchandPROVIDERSarray.backend/src/lib/llm/index.ts,models.ts,userApiKeys.ts,types.ts: dispatch through the registry;Providerbecomes an open string id.- Tests:
registry.test.ts+models.test.ts(20 tests - registration, first-match-wins routing, model-set union, provider inference).
Why
Today every new provider requires touching each dispatch site, the model tables, and the API-key switch. With the registry, local LLMs and other OpenAI-compatible endpoints plug in from a single setup file.
Testing
On this branch, on upstream's own harness: npm test in backend/ - 20 files, 279 passed, 5 skipped. tsc build clean.
Provenance
Mechanical port of code running in amal66/mike (main). Fork-only features intertwined with this code (air-gap branches, retry/circuit-breaker wrapper) were omitted, not rewritten. Full hunk-by-hunk provenance in amal66#27.
🤖 Generated with Claude Code
Our analysis
Introduce a registry for LLM providers — read the full analysis →
Think the analysis missed something the PR description covers?
Capture this PR into my fork
Download a Markdown prompt that tells Claude how to port every
commit in this PR into your working tree. Run it via
claude -p < capture-pull-259.md from
inside the repo you want the changes in.