d4530a7034
- ModelRouter: add setClient(), labels map, getLabel(), getAllLabels() - TUI commands: parse /model <tier> <provider/model> syntax with autocompletion - TUI minimal: handle provider switching via createClientFromConfig factory - Daemon: wire initial labels into router config - Fix /model alias mappings (opus=complex, sonnet=default, haiku=fast) - Add design doc and update state.json with feature status
3.4 KiB
3.4 KiB
Provider/Model Runtime Switching
Date: 2026-02-06 Status: In Progress
Goal
Enable easy runtime switching of model providers per tier via the /model command, using provider/model syntax.
Commands
/model — Show all tiers with provider/model labels
/model fast — Switch active tier (existing behavior)
/model default github-copilot/claude-sonnet-4-5 — Change default tier's provider+model
/model complex anthropic/claude-opus-4 — Change complex tier's provider+model
/model fast github-copilot/gpt-4o-mini — Change fast tier's provider+model
Design Decisions
- No presets — Direct
provider/modeltargeting per tier. YAGNI. - Full override — When you set a tier, it fully replaces the previous client.
- Local tier excluded —
/model localcontinues to use/backendfor switching. Local models are a different concern. - Auth — Config-based
api_keyfor most providers./loginOAuth flow for GitHub Copilot (already implemented). - Merged into /model — No separate
/providercommand. Everything lives under/model.
Implementation
1. ModelRouter (src/models/router.ts)
- Add
setClient(tier: ModelTier, client: ModelClient, label: string)— replaces a tier's client at runtime - Add
getLabel(tier: ModelTier): string— returnsprovider/modelstring for display - Track labels in a
Map<ModelTier, string>populated at construction and updated bysetClient()
2. Client Factory (src/daemon/index.ts)
Extract createClientFromProvider(provider: string, model: string, opts?: { apiKey?: string; endpoint?: string }): ModelClient factory function from the existing inline client creation logic. Used by both daemon startup and runtime /model switching.
3. Command Parser (src/frontends/tui/commands.ts)
- Extend
Commandtype:{ type: 'model'; name?: string; providerModel?: string } - Parse
/model <tier> <provider/model>— split on space to get tier + provider/model - Parse provider/model string: split on first
/to get provider and model name - Update autocompletion to suggest available providers after tier name
- Update tooltips
4. Daemon Wiring (src/daemon/index.ts)
Handle the new command variant:
- Receive
{ type: 'model', name: 'default', providerModel: 'github-copilot/claude-sonnet-4-5' } - Parse provider and model from
providerModel - Call
createClientFromProvider(provider, model)to instantiate client - Call
router.setClient('default', client, 'github-copilot/claude-sonnet-4-5') - Respond with confirmation message
5. Provider Name Mapping
Map short provider names to client constructors:
| Provider Name | Client Class |
|---|---|
anthropic |
AnthropicClient |
openai |
OpenAIClient |
github / github-copilot |
GitHubModelsClient |
gemini |
GeminiClient |
bedrock |
BedrockClient |
ollama |
OllamaClient |
llamacpp |
LlamaCppClient |
Files Changed
| File | Change |
|---|---|
src/models/router.ts |
Add setClient(), getLabel(), label tracking |
src/models/router.test.ts |
Tests for new methods |
src/frontends/tui/commands.ts |
Extended parser, completions, tooltips |
src/frontends/tui/commands.test.ts |
Tests for new parsing |
src/daemon/index.ts |
Extract factory, wire new command handler |