diff --git a/src/cli/tui.ts b/src/cli/tui.ts index de513af..d764072 100644 --- a/src/cli/tui.ts +++ b/src/cli/tui.ts @@ -43,77 +43,21 @@ export function registerTuiCommand(program: Command): void { // Dynamic imports to keep CLI startup fast const { SessionStore, SessionManager } = await import('../session/index.js'); - const { AnthropicClient, OpenAIClient, OllamaClient, LlamaCppClient, GitHubModelsClient, GeminiClient, BedrockClient, ModelRouter } = await import('../models/index.js'); const { MinimalTui, startFullscreenTui } = await import('../frontends/tui/index.js'); const { NativeAgent } = await import('../backends/index.js'); const { ToolRegistry, ToolExecutor, allBuiltinTools, createWebSearchTools, createProcessTools, ProcessManager } = await import('../tools/index.js'); const { HookEngine } = await import('../hooks/index.js'); + const { createModelRouter } = await import('../daemon/index.js'); const dataDir = resolve(homedir(), '.local/share/flynn'); mkdirSync(dataDir, { recursive: true }); const sessionStore = new SessionStore(resolve(dataDir, 'sessions.db')); const sessionManager = new SessionManager(sessionStore); - const models = config.models; - // Provider-agnostic client factory for TUI - function createClient(cfg: typeof models.default) { - switch (cfg.provider) { - case 'anthropic': - return new AnthropicClient({ model: cfg.model, apiKey: cfg.api_key, authToken: cfg.auth_token }); - case 'openai': - return new OpenAIClient({ model: cfg.model, apiKey: cfg.api_key }); - case 'gemini': - return new GeminiClient({ model: cfg.model, apiKey: cfg.api_key }); - case 'ollama': - return new OllamaClient({ model: cfg.model, host: cfg.endpoint, numGpu: cfg.num_gpu }); - case 'llamacpp': - return new LlamaCppClient({ endpoint: cfg.endpoint ?? 'http://localhost:8080', model: cfg.model, authToken: cfg.auth_token }); - case 'openrouter': - return new OpenAIClient({ model: cfg.model, apiKey: cfg.api_key ?? process.env.OPENROUTER_API_KEY, baseURL: cfg.endpoint ?? 'https://openrouter.ai/api/v1' }); - case 'bedrock': - return new BedrockClient({ model: cfg.model, region: cfg.endpoint, accessKeyId: cfg.api_key, secretAccessKey: cfg.auth_token }); - case 'github': - return new GitHubModelsClient({ - model: cfg.model, - apiKey: cfg.api_key, - endpoint: cfg.endpoint, - onLoginRequired: async () => { - const { loginGitHub } = await import('../auth/index.js'); - console.log('\nGitHub authentication required. Starting login flow...'); - return loginGitHub((userCode, verificationUri) => { - console.log(`\nVisit: ${verificationUri}`); - console.log(`Enter code: ${userCode}\n`); - console.log('Waiting for authorization...'); - }); - }, - }); - default: - throw new Error(`Unknown provider: ${cfg.provider}`); - } - } - - const defaultClient = createClient(models.default); - const fastClient = models.fast ? createClient(models.fast) : undefined; - const complexClient = models.complex ? createClient(models.complex) : undefined; - const localClient = models.local ? createClient(models.local) : undefined; - - const fallbackChain = []; - for (const providerName of models.fallback_chain) { - if (providerName === 'openai') { - fallbackChain.push(new OpenAIClient({ model: 'gpt-4o' })); - } else if (providerName === 'local' && localClient) { - fallbackChain.push(localClient); - } - } - - const modelRouter = new ModelRouter({ - default: defaultClient, - fast: fastClient, - complex: complexClient, - local: localClient, - fallbackChain, - }); + // Reuse the daemon's model router factory — includes auto-fallback, + // local_providers, retry config, and per-tier fallback logic. + const modelRouter = createModelRouter(config); const systemPrompt = loadSystemPrompt(); diff --git a/src/daemon/index.ts b/src/daemon/index.ts index 6fed3a1..276147c 100644 --- a/src/daemon/index.ts +++ b/src/daemon/index.ts @@ -175,7 +175,7 @@ export function createAutoFallbackClient(tierConfig: { provider: string; model: }); } -function createModelRouter(config: Config): ModelRouter { +export function createModelRouter(config: Config): ModelRouter { const models = config.models; const defaultClient = createClientFromConfig(models.default);