feat: sync PROVIDER_NAMES with config schema and update README docs
Extract MODEL_PROVIDERS const from config schema as single source of truth for provider names. PROVIDER_NAMES in TUI commands now imports from schema instead of maintaining a hardcoded list. Adds tests verifying sync. Updates README TUI Commands section with /model hot-swap documentation, supported providers, and runtime model switching examples.
This commit is contained in:
@@ -185,19 +185,46 @@ pnpm tui:fs
|
|||||||
| Command | Description |
|
| Command | Description |
|
||||||
|---------|-------------|
|
|---------|-------------|
|
||||||
| `/help` | Show help |
|
| `/help` | Show help |
|
||||||
|
| `/model` | Show all model tiers and which is active |
|
||||||
|
| `/model <tier>` | Switch active tier (`local`, `default`, `fast`, `complex`, or aliases `ollama`, `sonnet`, `haiku`, `opus`) |
|
||||||
|
| `/model <tier> <provider/model>` | Hot-swap a tier's provider and model at runtime |
|
||||||
|
| `/backend [provider]` | Show or switch local backend (`ollama`, `llamacpp`) |
|
||||||
|
| `/login [provider]` | Authenticate with GitHub (OAuth device flow) |
|
||||||
| `/reset` | Clear history |
|
| `/reset` | Clear history |
|
||||||
| `/status` | Show session info |
|
| `/status` | Show session info |
|
||||||
| `/compact` | Compact conversation context |
|
| `/compact` | Compact conversation context |
|
||||||
| `/usage` | Show token usage and cost |
|
| `/usage` | Show token usage and cost |
|
||||||
| `/verbose` | Toggle verbose output mode |
|
| `/verbose` | Toggle verbose output mode |
|
||||||
| `/local` | Switch to local model |
|
|
||||||
| `/cloud` | Switch to cloud model |
|
|
||||||
| `/model` | Show model info and options |
|
|
||||||
| `/pair` | Generate/list/revoke DM pairing codes |
|
| `/pair` | Generate/list/revoke DM pairing codes |
|
||||||
| `/fullscreen` | Switch to fullscreen mode |
|
| `/fullscreen` | Switch to fullscreen mode |
|
||||||
| `/transfer telegram` | Transfer session to Telegram |
|
| `/transfer <dest>` | Transfer session to another frontend |
|
||||||
| `/quit` | Exit |
|
| `/quit` | Exit |
|
||||||
|
|
||||||
|
#### Runtime Model Switching
|
||||||
|
|
||||||
|
Switch providers and models on the fly without editing config or restarting:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Show current tiers
|
||||||
|
/model
|
||||||
|
|
||||||
|
# Switch active tier
|
||||||
|
/model fast
|
||||||
|
/model complex
|
||||||
|
|
||||||
|
# Hot-swap a tier's provider/model
|
||||||
|
/model default anthropic/claude-sonnet-4
|
||||||
|
/model default zhipuai/glm-4.7
|
||||||
|
/model fast github/gpt-4o-mini
|
||||||
|
/model local ollama/glm-4.7-flash
|
||||||
|
```
|
||||||
|
|
||||||
|
The provider name must match a supported provider (`anthropic`, `openai`, `gemini`, `ollama`, `llamacpp`, `openrouter`, `bedrock`, `github`, `zhipuai`, `xai`). Tab completion is available for both tiers and provider names.
|
||||||
|
|
||||||
|
For cloud Zhipu models, ensure `ZHIPUAI_API_KEY` is set or `api_key` is configured in the relevant tier.
|
||||||
|
|
||||||
|
**Note:** The `/model` command works in the TUI only. WebChat sessions inherit the active tier from the daemon.
|
||||||
|
|
||||||
## Running as Service
|
## Running as Service
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
+1
-1
@@ -1,2 +1,2 @@
|
|||||||
export { loadConfig, deepMerge } from './loader.js';
|
export { loadConfig, deepMerge } from './loader.js';
|
||||||
export { configSchema, type Config, type TelegramConfig, type ModelConfig, type CronJobConfig, type AgentsConfig, type CompactionConfig, type ToolProfile, type ToolOverrideConfig, type ToolsConfig, type SandboxConfig, type AgentConfigEntry, type RoutingConfig, type ServerConfig } from './schema.js';
|
export { configSchema, MODEL_PROVIDERS, type ModelProvider, type Config, type TelegramConfig, type ModelConfig, type CronJobConfig, type AgentsConfig, type CompactionConfig, type ToolProfile, type ToolOverrideConfig, type ToolsConfig, type SandboxConfig, type AgentConfigEntry, type RoutingConfig, type ServerConfig } from './schema.js';
|
||||||
|
|||||||
@@ -38,8 +38,13 @@ const serverSchema = z.object({
|
|||||||
lock: z.boolean().default(false),
|
lock: z.boolean().default(false),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/** All supported model provider identifiers. Used by the config schema and TUI autocompletion. */
|
||||||
|
export const MODEL_PROVIDERS = ['anthropic', 'openai', 'gemini', 'ollama', 'llamacpp', 'openrouter', 'bedrock', 'github', 'zhipuai', 'xai'] as const;
|
||||||
|
|
||||||
|
export type ModelProvider = (typeof MODEL_PROVIDERS)[number];
|
||||||
|
|
||||||
const modelConfigBaseSchema = z.object({
|
const modelConfigBaseSchema = z.object({
|
||||||
provider: z.enum(['anthropic', 'openai', 'gemini', 'ollama', 'llamacpp', 'openrouter', 'bedrock', 'github', 'zhipuai', 'xai']),
|
provider: z.enum(MODEL_PROVIDERS),
|
||||||
model: z.string(),
|
model: z.string(),
|
||||||
endpoint: z.string().optional(),
|
endpoint: z.string().optional(),
|
||||||
api_key: z.string().optional(),
|
api_key: z.string().optional(),
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { describe, it, expect } from 'vitest';
|
import { describe, it, expect } from 'vitest';
|
||||||
import { parseCommand, getHelpText } from './commands.js';
|
import { parseCommand, getHelpText, getCommandCompletions, PROVIDER_NAMES } from './commands.js';
|
||||||
|
import { MODEL_PROVIDERS } from '../../config/index.js';
|
||||||
|
|
||||||
describe('parseCommand', () => {
|
describe('parseCommand', () => {
|
||||||
it('parses /quit command', () => {
|
it('parses /quit command', () => {
|
||||||
@@ -130,3 +131,33 @@ describe('/pair command', () => {
|
|||||||
expect(parseCommand('/pair revoke telegram 12345')).toEqual({ type: 'pair', action: 'revoke', args: 'telegram 12345' });
|
expect(parseCommand('/pair revoke telegram 12345')).toEqual({ type: 'pair', action: 'revoke', args: 'telegram 12345' });
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('PROVIDER_NAMES', () => {
|
||||||
|
it('matches all providers from the config schema', () => {
|
||||||
|
expect(PROVIDER_NAMES).toEqual(MODEL_PROVIDERS);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('includes zhipuai, openrouter, and xai', () => {
|
||||||
|
expect(PROVIDER_NAMES).toContain('zhipuai');
|
||||||
|
expect(PROVIDER_NAMES).toContain('openrouter');
|
||||||
|
expect(PROVIDER_NAMES).toContain('xai');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('getCommandCompletions', () => {
|
||||||
|
it('suggests all providers when typing /model default with partial provider', () => {
|
||||||
|
// Typing any character after the tier triggers provider suggestions
|
||||||
|
const completions = getCommandCompletions('/model default a');
|
||||||
|
expect(completions).toContain('/model default anthropic');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('filters provider suggestions by partial input', () => {
|
||||||
|
const completions = getCommandCompletions('/model default zh');
|
||||||
|
expect(completions).toEqual(['/model default zhipuai']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('completes xai provider', () => {
|
||||||
|
const completions = getCommandCompletions('/model fast x');
|
||||||
|
expect(completions).toEqual(['/model fast xai']);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -139,6 +139,8 @@ Commands:
|
|||||||
`.trim();
|
`.trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
import { MODEL_PROVIDERS } from '../../config/index.js';
|
||||||
|
|
||||||
export type ModelAlias = 'local' | 'default' | 'fast' | 'complex' | 'opus' | 'sonnet' | 'haiku' | 'ollama';
|
export type ModelAlias = 'local' | 'default' | 'fast' | 'complex' | 'opus' | 'sonnet' | 'haiku' | 'ollama';
|
||||||
|
|
||||||
// List of all slash commands for autocompletion
|
// List of all slash commands for autocompletion
|
||||||
@@ -186,8 +188,8 @@ export const COMMAND_TOOLTIPS: Record<string, string> = {
|
|||||||
// Model aliases for /model command autocompletion
|
// Model aliases for /model command autocompletion
|
||||||
export const MODEL_ALIASES = ['local', 'default', 'fast', 'complex', 'opus', 'sonnet', 'haiku', 'ollama'];
|
export const MODEL_ALIASES = ['local', 'default', 'fast', 'complex', 'opus', 'sonnet', 'haiku', 'ollama'];
|
||||||
|
|
||||||
// Provider names for /model <tier> <provider/model> syntax
|
// Provider names for /model <tier> <provider/model> syntax — derived from config schema
|
||||||
export const PROVIDER_NAMES = ['anthropic', 'openai', 'github-copilot', 'gemini', 'bedrock', 'ollama', 'llamacpp'];
|
export const PROVIDER_NAMES: readonly string[] = MODEL_PROVIDERS;
|
||||||
|
|
||||||
// Model alias descriptions
|
// Model alias descriptions
|
||||||
export const MODEL_TOOLTIPS: Record<string, string> = {
|
export const MODEL_TOOLTIPS: Record<string, string> = {
|
||||||
|
|||||||
Reference in New Issue
Block a user