import { createInterface } from 'node:readline'; import { Command } from 'commander'; import pc from 'picocolors'; import { AgentLoop } from '../agent/loop.ts'; import { MessageBus } from '../bus/queue.ts'; import type { Config } from '../config/types.ts'; import { makeProvider } from '../provider/index.ts'; export function agentCommand(program: Command, config: Config, workspace: string): void { program .command('agent') .description('Run the agent interactively or send a single message.') .option('-m, --message ', 'Single message to process (non-interactive)') .option('-M, --model ', 'Model override') .action(async (opts: { config?: string; message?: string; model?: string }) => { const model = opts.model ?? config.agent.model; const provider = makeProvider( config.providers, model, config.agent.maxTokens, config.agent.temperature, ); const bus = new MessageBus(); const agentLoop = new AgentLoop({ bus, provider, workspace, model, maxIterations: config.agent.maxToolIterations, contextWindowTokens: config.agent.contextWindowTokens, braveApiKey: config.tools.web.braveApiKey, webProxy: config.tools.web.proxy, execConfig: config.tools.exec, restrictToWorkspace: config.tools.restrictToWorkspace, }); // Single-shot mode if (opts.message) { const result = await agentLoop.processDirect(opts.message); console.log(result); return; } // Interactive mode console.info(pc.green('nanobot interactive mode. Type your message, Ctrl+C to exit.')); const rl = createInterface({ input: process.stdin, output: process.stdout }); const promptUser = () => { rl.question(pc.cyan('You: '), async (input) => { const text = input.trim(); if (!text) { promptUser(); return; } const onProgress = async (content: string, opts?: { toolHint?: boolean }) => { if (opts?.toolHint) { process.stdout.write(pc.dim(` [${content}]\n`)); } else { process.stdout.write(pc.dim(` ${content}\n`)); } }; const result = await agentLoop.processDirect( text, 'cli:interactive', 'cli', 'interactive', onProgress, ); console.log(pc.bold('Bot:'), result); promptUser(); }); }; rl.on('close', () => { agentLoop.stop(); process.exit(0); }); promptUser(); }); }