feat: add /backend command handler to MinimalTui

This commit is contained in:
William Valentin
2026-02-05 13:36:36 -08:00
parent 465b4a0c3c
commit f722cf2bf0
2 changed files with 113 additions and 1 deletions
+45 -1
View File
@@ -1,5 +1,7 @@
import { describe, it, expect } from 'vitest'; import { describe, it, expect, vi } from 'vitest';
import { formatPrompt, parseCommand } from './minimal.js'; import { formatPrompt, parseCommand } from './minimal.js';
import type { ModelConfig } from '../../config/schema.js';
import { MinimalTui } from './minimal.js';
describe('formatPrompt', () => { describe('formatPrompt', () => {
it('formats default prompt', () => { it('formats default prompt', () => {
@@ -34,3 +36,45 @@ describe('parseCommand (re-exported)', () => {
expect(result).toBeNull(); expect(result).toBeNull();
}); });
}); });
describe('MinimalTui backend command', () => {
it('switches local backend when provider is configured', async () => {
const mockSession = {
id: 'test',
getHistory: () => [],
addMessage: vi.fn(),
clear: vi.fn(),
};
const mockRouter = {
getTier: () => 'default' as const,
getAvailableTiers: () => ['default', 'local'],
setTier: vi.fn(() => true),
getLocalProviderName: () => 'ollama',
setLocalClient: vi.fn(),
chat: vi.fn(),
getClient: vi.fn(),
};
const localProviders: Record<string, ModelConfig> = {
llamacpp: {
provider: 'llamacpp',
model: '',
endpoint: 'http://localhost:8080',
},
};
const tui = new MinimalTui({
session: mockSession as any,
modelClient: mockRouter as any,
modelRouter: mockRouter as any,
systemPrompt: 'test',
localProviders,
});
// Access private method for testing
await (tui as any).handleBackendCommand('llamacpp');
expect(mockRouter.setLocalClient).toHaveBeenCalled();
});
});
+68
View File
@@ -4,6 +4,8 @@ import type { ModelClient, TokenUsage } from '../../models/types.js';
import type { ModelRouter, ModelTier } from '../../models/router.js'; import type { ModelRouter, ModelTier } from '../../models/router.js';
import { parseCommand, getHelpText, resolveModelAlias, type Command } from './commands.js'; import { parseCommand, getHelpText, resolveModelAlias, type Command } from './commands.js';
import { renderMarkdown } from './markdown.js'; import { renderMarkdown } from './markdown.js';
import type { ModelConfig } from '../../config/schema.js';
import { OllamaClient, LlamaCppClient } from '../../models/index.js';
export { parseCommand, type Command }; export { parseCommand, type Command };
@@ -21,6 +23,8 @@ export interface MinimalTuiConfig {
systemPrompt: string; systemPrompt: string;
onFullscreen?: () => void; onFullscreen?: () => void;
onTransfer?: (target: string) => void; onTransfer?: (target: string) => void;
localProviders?: Record<string, ModelConfig>;
currentLocalProvider?: string;
} }
export class MinimalTui { export class MinimalTui {
@@ -96,6 +100,10 @@ export class MinimalTui {
this.handleModelCommand(command.name); this.handleModelCommand(command.name);
break; break;
case 'backend':
this.handleBackendCommand(command.provider);
break;
case 'transfer': case 'transfer':
this.config.onTransfer?.(command.target); this.config.onTransfer?.(command.target);
break; break;
@@ -129,6 +137,66 @@ export class MinimalTui {
} }
} }
private handleBackendCommand(provider?: string): void {
const router = this.config.modelRouter;
if (!router) {
console.log('Backend switching not available.\n');
return;
}
if (!provider) {
const current = router.getLocalProviderName() ?? this.config.currentLocalProvider ?? 'unknown';
const available = this.getAvailableBackends();
console.log(`Current local backend: ${current}`);
console.log(`Available: ${available.join(', ')}\n`);
return;
}
const providerConfig = this.config.localProviders?.[provider];
if (!providerConfig) {
const available = this.getAvailableBackends();
console.log(`Backend '${provider}' not configured.`);
console.log(`Available: ${available.join(', ')}\n`);
return;
}
const client = this.createLocalClient(providerConfig);
if (!client) {
console.log(`Failed to create client for '${provider}'.\n`);
return;
}
router.setLocalClient(client, provider);
console.log(`Switched to backend: ${provider}\n`);
}
private getAvailableBackends(): string[] {
const backends: string[] = [];
if (this.config.currentLocalProvider) {
backends.push(this.config.currentLocalProvider);
}
if (this.config.localProviders) {
backends.push(...Object.keys(this.config.localProviders));
}
return [...new Set(backends)];
}
private createLocalClient(config: ModelConfig): ModelClient | null {
if (config.provider === 'ollama') {
return new OllamaClient({
model: config.model,
host: config.endpoint,
});
}
if (config.provider === 'llamacpp') {
return new LlamaCppClient({
endpoint: config.endpoint ?? 'http://localhost:8080',
authToken: config.auth_token,
});
}
return null;
}
private printStatus(): void { private printStatus(): void {
console.log(`Session: ${this.config.session.id}`); console.log(`Session: ${this.config.session.id}`);
console.log(`Messages: ${this.config.session.getHistory().length}`); console.log(`Messages: ${this.config.session.getHistory().length}`);