import type { Command } from 'commander'; import { withAuth } from './with-auth.js'; import { selectItem } from './select-dialog.js'; import { fetchAgentConfigs, createAgentConfig, updateAgentConfig, deleteAgentConfig, fetchProjects, fetchProviders, } from '../tui/gateway-api.js'; import type { AgentConfigInfo } from '../tui/gateway-api.js'; function formatAgent(a: AgentConfigInfo): string { const sys = a.isSystem ? ' [system]' : ''; return `${a.name}${sys} — ${a.provider}/${a.model} (${a.status})`; } function showAgentDetail(a: AgentConfigInfo) { console.log(` ID: ${a.id}`); console.log(` Name: ${a.name}`); console.log(` Provider: ${a.provider}`); console.log(` Model: ${a.model}`); console.log(` Status: ${a.status}`); console.log(` System: ${a.isSystem ? 'yes' : 'no'}`); console.log(` Project: ${a.projectId ?? '—'}`); console.log(` System Prompt: ${a.systemPrompt ? `${a.systemPrompt.slice(0, 80)}...` : '—'}`); console.log(` Tools: ${a.allowedTools ? a.allowedTools.join(', ') : 'all'}`); console.log(` Skills: ${a.skills ? a.skills.join(', ') : '—'}`); console.log(` Created: ${new Date(a.createdAt).toLocaleString()}`); } export function registerAgentCommand(program: Command) { const cmd = program .command('agent') .description('Manage agent configurations') .option('-g, --gateway ', 'Gateway URL', 'http://localhost:14242') .option('--list', 'List all agents') .option('--new', 'Create a new agent') .option('--show ', 'Show agent details') .option('--update ', 'Update an agent') .option('--delete ', 'Delete an agent') .action( async (opts: { gateway: string; list?: boolean; new?: boolean; show?: string; update?: string; delete?: string; }) => { const auth = await withAuth(opts.gateway); if (opts.list) { return listAgents(auth.gateway, auth.cookie); } if (opts.new) { return createAgentWizard(auth.gateway, auth.cookie); } if (opts.show) { return showAgent(auth.gateway, auth.cookie, opts.show); } if (opts.update) { return updateAgentWizard(auth.gateway, auth.cookie, opts.update); } if (opts.delete) { return deleteAgent(auth.gateway, auth.cookie, opts.delete); } // Default: interactive select return interactiveSelect(auth.gateway, auth.cookie); }, ); return cmd; } async function resolveAgent( gateway: string, cookie: string, idOrName: string, ): Promise { const agents = await fetchAgentConfigs(gateway, cookie); return agents.find((a) => a.id === idOrName || a.name === idOrName); } async function listAgents(gateway: string, cookie: string) { const agents = await fetchAgentConfigs(gateway, cookie); if (agents.length === 0) { console.log('No agents found.'); return; } console.log(`Agents (${agents.length}):\n`); for (const a of agents) { const sys = a.isSystem ? ' [system]' : ''; const project = a.projectId ? ` project=${a.projectId.slice(0, 8)}` : ''; console.log(` ${a.name}${sys} ${a.provider}/${a.model} ${a.status}${project}`); } } async function showAgent(gateway: string, cookie: string, idOrName: string) { const agent = await resolveAgent(gateway, cookie, idOrName); if (!agent) { console.error(`Agent "${idOrName}" not found.`); process.exit(1); } showAgentDetail(agent); } async function interactiveSelect(gateway: string, cookie: string) { const agents = await fetchAgentConfigs(gateway, cookie); const selected = await selectItem(agents, { message: 'Select an agent:', render: formatAgent, emptyMessage: 'No agents found. Create one with `mosaic agent --new`.', }); if (selected) { showAgentDetail(selected); } } async function createAgentWizard(gateway: string, cookie: string) { const readline = await import('node:readline'); const rl = readline.createInterface({ input: process.stdin, output: process.stdout }); const ask = (q: string): Promise => new Promise((resolve) => rl.question(q, resolve)); try { const name = await ask('Agent name: '); if (!name.trim()) { console.error('Name is required.'); return; } // Project selection const projects = await fetchProjects(gateway, cookie); let projectId: string | undefined; if (projects.length > 0) { const selected = await selectItem(projects, { message: 'Assign to project (optional):', render: (p) => `${p.name} (${p.status})`, }); if (selected) projectId = selected.id; } // Provider / model selection const providers = await fetchProviders(gateway, cookie); let provider = 'default'; let model = 'default'; if (providers.length > 0) { const allModels = providers.flatMap((p) => p.models.map((m) => ({ provider: p.name, model: m.id, label: `${p.name}/${m.id}` })), ); if (allModels.length > 0) { const selected = await selectItem(allModels, { message: 'Select model:', render: (m) => m.label, }); if (selected) { provider = selected.provider; model = selected.model; } } } const systemPrompt = await ask('System prompt (optional, press Enter to skip): '); const agent = await createAgentConfig(gateway, cookie, { name: name.trim(), provider, model, projectId, systemPrompt: systemPrompt.trim() || undefined, }); console.log(`\nAgent "${agent.name}" created (${agent.id}).`); } finally { rl.close(); } } async function updateAgentWizard(gateway: string, cookie: string, idOrName: string) { const agent = await resolveAgent(gateway, cookie, idOrName); if (!agent) { console.error(`Agent "${idOrName}" not found.`); process.exit(1); } const readline = await import('node:readline'); const rl = readline.createInterface({ input: process.stdin, output: process.stdout }); const ask = (q: string): Promise => new Promise((resolve) => rl.question(q, resolve)); try { console.log(`Updating agent: ${agent.name}\n`); const name = await ask(`Name [${agent.name}]: `); const systemPrompt = await ask(`System prompt [${agent.systemPrompt ? 'set' : 'none'}]: `); const updates: Record = {}; if (name.trim()) updates['name'] = name.trim(); if (systemPrompt.trim()) updates['systemPrompt'] = systemPrompt.trim(); if (Object.keys(updates).length === 0) { console.log('No changes.'); return; } const updated = await updateAgentConfig(gateway, cookie, agent.id, updates); console.log(`\nAgent "${updated.name}" updated.`); } finally { rl.close(); } } async function deleteAgent(gateway: string, cookie: string, idOrName: string) { const agent = await resolveAgent(gateway, cookie, idOrName); if (!agent) { console.error(`Agent "${idOrName}" not found.`); process.exit(1); } if (agent.isSystem) { console.error('Cannot delete system agents.'); process.exit(1); } const readline = await import('node:readline'); const rl = readline.createInterface({ input: process.stdin, output: process.stdout }); const answer = await new Promise((resolve) => rl.question(`Delete agent "${agent.name}"? (y/N): `, resolve), ); rl.close(); if (answer.toLowerCase() !== 'y') { console.log('Cancelled.'); return; } await deleteAgentConfig(gateway, cookie, agent.id); console.log(`Agent "${agent.name}" deleted.`); }