feat: add /backend command handler to MinimalTui
This commit is contained in:
@@ -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();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -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}`);
|
||||||
|
|||||||
Reference in New Issue
Block a user