UNPKG

plazbot-cli

Version:
213 lines (179 loc) 7.96 kB
import { Command } from 'commander'; import { Agent } from 'plazbot'; import { getStoredCredentials } from '../../utils/credentials'; import { logger } from '../../utils/logger'; import { AgentCommandOptions, AgentResponse, AgentSource } from '../../types/agent'; import { theme, section } from '../../utils/ui'; import crypto from 'crypto'; import readline from 'readline'; import chalk from 'chalk'; const COMMANDS_HELP = ` ${chalk.bold('Comandos disponibles:')} ${chalk.hex('#4CAF50')('/exit')} Terminar conversacion ${chalk.hex('#4CAF50')('/clear')} Limpiar pantalla ${chalk.hex('#4CAF50')('/info')} Informacion de la sesion ${chalk.hex('#4CAF50')('/sources')} Mostrar/ocultar fuentes ${chalk.hex('#4CAF50')('/help')} Mostrar estos comandos `; export const chatCommand = new Command('chat') .description('Inicia una sesion de chat interactiva con un agente') .requiredOption('-a, --agent-id <id>', 'ID del agente') .option('-s, --session-id <id>', 'ID de sesion (opcional)') .option('-m, --multiple-answers', 'Permitir multiples respuestas', false) .option('--dev', 'Usar ambiente de desarrollo', false) .action(async (options: AgentCommandOptions & { agentId: string; sessionId?: string; multipleAnswers?: boolean; }) => { try { const credentials = await getStoredCredentials(); const agent = new Agent({ workspaceId: credentials.workspace, apiKey: credentials.apiKey, zone: credentials.zone, ...(options.dev && { customUrl: "http://localhost:5090" }) }); const sessionId = options.sessionId || crypto.randomUUID(); let showSources = true; // Cargar info del agente let agentInfo: any = null; try { process.stdout.write(chalk.gray(' Conectando con agente...')); agentInfo = await agent.getAgentById({ id: options.agentId }); process.stdout.write('\r' + ' '.repeat(40) + '\r'); } catch { process.stdout.write('\r' + ' '.repeat(40) + '\r'); } const rl = readline.createInterface({ input: process.stdin, output: process.stdout }); // Pantalla de chat console.clear(); const agentName = agentInfo?.name || 'Agente'; const toolCalling = agentInfo?.useToolCalling ? chalk.hex('#4CAF50')(' [Tool Calling]') : ''; console.log(); console.log(chalk.hex('#4CAF50')(' ┌' + '─'.repeat(58) + '┐')); console.log(chalk.hex('#4CAF50')(' │') + chalk.bold(` ${agentName}${toolCalling}`).padEnd(68) + chalk.hex('#4CAF50')('│')); console.log(chalk.hex('#4CAF50')(' │') + chalk.gray(` Session: ${sessionId.substring(0, 8)}...`).padEnd(68) + chalk.hex('#4CAF50')('│')); console.log(chalk.hex('#4CAF50')(' │') + chalk.gray(' /help para ver comandos').padEnd(68) + chalk.hex('#4CAF50')('│')); console.log(chalk.hex('#4CAF50')(' └' + '─'.repeat(58) + '┘')); console.log(); // Saludo del agente if (agentInfo?.instructions?.greeting) { const timestamp = new Date().toLocaleTimeString('es-ES', { hour: '2-digit', minute: '2-digit' }); console.log(chalk.hex('#4CAF50')(` ${agentName}`) + chalk.gray(` ${timestamp}`)); console.log(chalk.white(` ${agentInfo.instructions.greeting}`)); console.log(); } const askQuestion = () => { rl.question(chalk.hex('#2196F3')(' Tu > '), async (question) => { if (!question.trim()) { askQuestion(); return; } // Comandos especiales if (question.toLowerCase() === '/exit') { console.log(chalk.gray('\n Sesion terminada.\n')); rl.close(); return; } if (question.toLowerCase() === '/clear') { console.clear(); askQuestion(); return; } if (question.toLowerCase() === '/help') { console.log(COMMANDS_HELP); askQuestion(); return; } if (question.toLowerCase() === '/info') { console.log(section('Informacion de sesion')); logger.label('Agent ID', options.agentId); logger.label('Session ID', sessionId); logger.label('Agente', agentName); logger.label('Tool Calling', agentInfo?.useToolCalling ? 'Activado' : 'Desactivado'); logger.label('AI Provider', agentInfo?.customAIConfig ? (agentInfo.aiProviders?.[0]?.provider || 'Custom') : 'Default'); console.log(); askQuestion(); return; } if (question.toLowerCase() === '/sources') { showSources = !showSources; console.log(chalk.gray(` Fuentes: ${showSources ? 'activadas' : 'desactivadas'}`)); console.log(); askQuestion(); return; } try { process.stdout.write(chalk.gray(' ...pensando\n')); const response = await agent.onMessage({ agentId: options.agentId, question, sessionId, multipleAnswers: options.multipleAnswers }) as AgentResponse & { actionsExecuted?: any[] }; const timestamp = new Date().toLocaleTimeString('es-ES', { hour: '2-digit', minute: '2-digit' }); // Mostrar tool calls si hay if (response.actionsExecuted && response.actionsExecuted.length > 0) { response.actionsExecuted.forEach((action: any) => { console.log(chalk.hex('#FFA726')(` ⚡ Tool: ${action.name || action.intent || 'action'}`)); }); } // Respuesta del agente console.log(); console.log(chalk.hex('#4CAF50')(` ${agentName}`) + chalk.gray(` ${timestamp}`)); // Formatear respuesta (soporte basico de markdown) const formattedAnswer = formatResponse(response.answer); console.log(formattedAnswer); console.log(); // Fuentes if (showSources && response.sources && response.sources.length > 0) { console.log(chalk.gray(' Fuentes:')); response.sources.forEach((source: AgentSource) => { console.log(chalk.gray(` - ${source.title || 'Sin titulo'}`)); if (source.url) console.log(chalk.gray(` ${source.url}`)); }); console.log(); } askQuestion(); } catch (error) { const message = error instanceof Error ? error.message : 'Error desconocido'; console.log(chalk.hex('#EF5350')(`\n ✖ Error: ${message}\n`)); askQuestion(); } }); }; askQuestion(); } catch (error) { const message = error instanceof Error ? error.message : 'Error desconocido'; logger.error(message); process.exit(1); } }); function formatResponse(text: string): string { if (!text) return ''; return text.split('\n').map(line => { // Headers if (line.startsWith('### ')) return chalk.bold.hex('#4CAF50')(' ' + line.substring(4)); if (line.startsWith('## ')) return chalk.bold.hex('#4CAF50')(' ' + line.substring(3)); if (line.startsWith('# ')) return chalk.bold.hex('#4CAF50')(' ' + line.substring(2)); // Bold line = line.replace(/\*\*(.*?)\*\*/g, (_, text) => chalk.bold(text)); // Italic line = line.replace(/\*(.*?)\*/g, (_, text) => chalk.italic(text)); // Code inline line = line.replace(/`(.*?)`/g, (_, text) => chalk.hex('#FFA726')(text)); // List items if (line.match(/^\s*[-*]\s/)) { return chalk.white(' ' + line.replace(/^\s*[-*]\s/, ' • ')); } // Numbered lists if (line.match(/^\s*\d+\.\s/)) { return chalk.white(' ' + line); } return chalk.white(' ' + line); }).join('\n'); }