feat(backend): auto-stop/start daemon when switching backends
- Add local_providers with ollama and llamacpp configurations - /backend command now stops current daemon before starting new one - Start backends as detached processes to avoid blocking TUI - Wait 500ms for daemon to initialize before switching
This commit is contained in:
@@ -194,7 +194,7 @@ export class MinimalTui {
|
||||
break;
|
||||
|
||||
case 'backend':
|
||||
this.handleBackendCommand(command.provider);
|
||||
await this.handleBackendCommand(command.provider);
|
||||
break;
|
||||
|
||||
case 'login':
|
||||
@@ -277,7 +277,7 @@ export class MinimalTui {
|
||||
}
|
||||
}
|
||||
|
||||
private handleBackendCommand(provider?: string): void {
|
||||
private async handleBackendCommand(provider?: string): Promise<void> {
|
||||
const router = this.config.modelRouter;
|
||||
if (!router) {
|
||||
console.log('Backend switching not available.\n');
|
||||
@@ -300,6 +300,17 @@ export class MinimalTui {
|
||||
return;
|
||||
}
|
||||
|
||||
// Stop current daemon if running
|
||||
const currentBackend = router.getLocalProviderName();
|
||||
if (currentBackend && currentBackend !== provider) {
|
||||
console.log(`${colors.gray}Stopping ${currentBackend}...${colors.reset}`);
|
||||
await this.stopBackend(currentBackend);
|
||||
}
|
||||
|
||||
// Start new daemon
|
||||
console.log(`${colors.gray}Starting ${provider}...${colors.reset}`);
|
||||
await this.startBackend(provider, providerConfig);
|
||||
|
||||
const client = this.createLocalClient(providerConfig);
|
||||
if (!client) {
|
||||
console.log(`Failed to create client for '${provider}'.\n`);
|
||||
@@ -307,7 +318,53 @@ export class MinimalTui {
|
||||
}
|
||||
|
||||
router.setLocalClient(client, provider);
|
||||
console.log(`Switched to backend: ${provider}\n`);
|
||||
console.log(`${colors.gray}Switched to backend: ${provider}${colors.reset}\n`);
|
||||
}
|
||||
|
||||
private async stopBackend(provider: string): Promise<void> {
|
||||
try {
|
||||
const { spawn } = await import('child_process');
|
||||
let processName: string;
|
||||
switch (provider) {
|
||||
case 'ollama':
|
||||
processName = 'ollama';
|
||||
break;
|
||||
case 'llamacpp':
|
||||
processName = 'llama-server';
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
await new Promise<void>((resolve) => {
|
||||
spawn('pkill', [processName]).on('close', resolve);
|
||||
});
|
||||
} catch (error) {
|
||||
// Ignore errors stopping backends
|
||||
}
|
||||
}
|
||||
|
||||
private async startBackend(provider: string, config: ModelConfig): Promise<void> {
|
||||
try {
|
||||
const { spawn } = await import('child_process');
|
||||
const args: string[] = [];
|
||||
|
||||
switch (provider) {
|
||||
case 'ollama':
|
||||
spawn('ollama', ['serve'], { detached: true, stdio: 'ignore' }).unref();
|
||||
break;
|
||||
case 'llamacpp':
|
||||
args.push('--model', config.model);
|
||||
args.push('--port', new URL(config.endpoint ?? 'http://localhost:8080').port || '8080');
|
||||
args.push('--host', '0.0.0.0');
|
||||
spawn('llama-server', args, { detached: true, stdio: 'ignore' }).unref();
|
||||
break;
|
||||
}
|
||||
|
||||
// Wait briefly for the daemon to start
|
||||
await new Promise(resolve => setTimeout(resolve, 500));
|
||||
} catch (error) {
|
||||
console.log(`${colors.gray}Warning: Failed to start ${provider}: ${error instanceof Error ? error.message : String(error)}${colors.reset}\n`);
|
||||
}
|
||||
}
|
||||
|
||||
private async handleLoginCommand(provider?: string): Promise<void> {
|
||||
|
||||
Reference in New Issue
Block a user