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
80 lines
3.4 KiB
Markdown
80 lines
3.4 KiB
Markdown
# 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
|
|
|
|
1. **No presets** — Direct `provider/model` targeting per tier. YAGNI.
|
|
2. **Full override** — When you set a tier, it fully replaces the previous client.
|
|
3. **Local tier excluded** — `/model local` continues to use `/backend` for switching. Local models are a different concern.
|
|
4. **Auth** — Config-based `api_key` for most providers. `/login` OAuth flow for GitHub Copilot (already implemented).
|
|
5. **Merged into /model** — No separate `/provider` command. 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` — returns `provider/model` string for display
|
|
- Track labels in a `Map<ModelTier, string>` populated at construction and updated by `setClient()`
|
|
|
|
### 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 `Command` type: `{ 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:
|
|
1. Receive `{ type: 'model', name: 'default', providerModel: 'github-copilot/claude-sonnet-4-5' }`
|
|
2. Parse provider and model from `providerModel`
|
|
3. Call `createClientFromProvider(provider, model)` to instantiate client
|
|
4. Call `router.setClient('default', client, 'github-copilot/claude-sonnet-4-5')`
|
|
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 |
|