UNPKG

plazbot-cli

Version:
476 lines (439 loc) 15.7 kB
import inquirer from 'inquirer'; import chalk from 'chalk'; import { theme, section, kvPair } from '../../utils/ui'; interface AgentConfig { name: string; description?: string; prompt: string; buffer: number; zone: string; color: string; useToolCalling: boolean; customAIConfig: boolean; aiProviders: AIProvider[]; instructions: AgentInstructions; person: AgentPerson; fallbacks: AgentFallbacks; services: AgentService[]; actions: AgentAction[]; channels: AgentChannel[]; examples: AgentExample[]; tags: string[]; } interface AIProvider { provider: string; model: string; apiToken: string; temperature: number; maxTokens: number; isDefault: boolean; } interface AgentInstructions { tone: string; style: string; personality: string; objective: string; language: string; emojis: boolean; } interface AgentPerson { name: string; role: string; speaksInFirstPerson: boolean; } interface AgentFallbacks { noAnswer: string; serviceError: string; doNotUnderstand: string; } interface AgentService { intent: string; reference: string; enabled: boolean; method: string; endpoint: string; requiredFields: { name: string; type: string; description: string; promptHint: string }[]; headers: Record<string, string>; bodyTemplate: Record<string, string>; responseMapping: Record<string, string>; responseMessage: string; responseConditions: { condition: string; message: string }[]; } interface AgentAction { intent: string; reference: string; enabled: boolean; requiredFields: { name: string; type: string; description: string; promptHint: string }[]; responseMessage: string; action: { type: string; value: string }[]; } interface AgentChannel { channel: string; key: string; multianswer: boolean; } interface AgentExample { value: string; color: string; } const MODELS: Record<string, string[]> = { openai: ['gpt-4o', 'gpt-4', 'gpt-3.5-turbo', 'o1-preview', 'o1-mini'], claude: ['claude-3-5-sonnet-20241022', 'claude-3-opus-20240229', 'claude-3-haiku-20240307'], gemini: ['gemini-2.0-flash', 'gemini-1.5-pro', 'gemini-1.5-flash'], }; const COLORS = ['blue', 'green', 'orange', 'gray', 'white']; export async function runAgentWizard(zone: string): Promise<AgentConfig> { console.log(section('Crear nuevo agente de IA')); console.log(theme.muted(' Responde las siguientes preguntas para configurar tu agente.\n')); // Paso 1: Informacion basica console.log(theme.bold('\n Paso 1/8: Informacion basica')); const basic = await (inquirer as any).prompt([ { type: 'input', name: 'name', message: 'Nombre del agente:', validate: (v: string) => v.length > 0 || 'El nombre es requerido', }, { type: 'input', name: 'description', message: 'Descripcion breve:', default: '', }, { type: 'input', name: 'prompt', message: 'Prompt del sistema (instrucciones principales):', default: 'Eres un asistente virtual amigable y profesional.', }, { type: 'number', name: 'buffer', message: 'Buffer de conversacion (3-20 mensajes):', default: 5, validate: (v: number) => (v >= 3 && v <= 20) || 'Debe ser entre 3 y 20', }, { type: 'list', name: 'color', message: 'Color del agente:', choices: COLORS, default: 'blue', }, ]); // Paso 2: Personalidad console.log(theme.bold('\n Paso 2/8: Personalidad e instrucciones')); const personality = await (inquirer as any).prompt([ { type: 'list', name: 'tone', message: 'Tono de comunicacion:', choices: ['profesional', 'amigable', 'formal', 'casual', 'tecnico', 'empatico'], default: 'profesional', }, { type: 'list', name: 'style', message: 'Estilo de respuesta:', choices: ['conciso', 'detallado', 'conversacional', 'directo'], default: 'conciso', }, { type: 'input', name: 'personality', message: 'Personalidad en una frase:', default: 'Servicial y conocedor', }, { type: 'input', name: 'objective', message: 'Objetivo principal del agente:', default: 'Ayudar a los usuarios con sus consultas', }, { type: 'list', name: 'language', message: 'Idioma principal:', choices: ['Espanol', 'English', 'Portugues', 'Frances'], default: 'Espanol', }, { type: 'confirm', name: 'useEmojis', message: 'Usar emojis en respuestas?', default: true, }, ]); // Paso 3: Persona console.log(theme.bold('\n Paso 3/8: Identidad del agente')); const person = await (inquirer as any).prompt([ { type: 'input', name: 'name', message: 'Nombre del personaje (como se presenta):', default: basic.name, }, { type: 'input', name: 'role', message: 'Rol (ej: Asistente de ventas, Soporte tecnico):', default: 'Asistente virtual', }, { type: 'confirm', name: 'firstPerson', message: 'Hablar en primera persona?', default: true, }, ]); // Paso 4: Fallbacks console.log(theme.bold('\n Paso 4/8: Mensajes de fallback')); const fallbacks = await (inquirer as any).prompt([ { type: 'input', name: 'noAnswer', message: 'Cuando no tiene respuesta:', default: 'Lo siento, no tengo informacion sobre eso. Puedo ayudarte con otra consulta?', }, { type: 'input', name: 'serviceError', message: 'Cuando hay error de servicio:', default: 'Disculpa, estamos experimentando dificultades tecnicas. Intenta de nuevo en unos momentos.', }, { type: 'input', name: 'misunderstanding', message: 'Cuando no entiende la pregunta:', default: 'No estoy seguro de entender tu consulta. Podrias reformularla?', }, ]); // Paso 5: Tool Calling console.log(theme.bold('\n Paso 5/8: Tool Calling')); console.log(theme.muted(' Tool Calling permite al agente ejecutar acciones automaticas\n')); const { useToolCalling } = await (inquirer as any).prompt([ { type: 'confirm', name: 'useToolCalling', message: 'Activar Tool Calling?', default: true, }, ]); // Servicios (API calls) const services: AgentService[] = []; if (useToolCalling) { const { addServices } = await (inquirer as any).prompt([{ type: 'confirm', name: 'addServices', message: 'Agregar servicios externos (API calls)?', default: false, }]); if (addServices) { let addMore = true; while (addMore) { console.log(theme.muted('\n Nuevo servicio:')); const svc = await (inquirer as any).prompt([ { type: 'input', name: 'intent', message: 'Nombre/intent del servicio:', validate: (v: string) => v.length > 0 || 'Requerido' }, { type: 'input', name: 'reference', message: 'Palabras clave de referencia:', default: '' }, { type: 'list', name: 'method', message: 'Metodo HTTP:', choices: ['GET', 'POST'] }, { type: 'input', name: 'endpoint', message: 'URL del endpoint:', validate: (v: string) => v.length > 0 || 'Requerido' }, { type: 'input', name: 'responseMessage', message: 'Mensaje de respuesta:', default: '' }, ]); // Required fields const fields: AgentService['requiredFields'] = []; const { addFields } = await (inquirer as any).prompt([{ type: 'confirm', name: 'addFields', message: 'Agregar campos requeridos?', default: false, }]); if (addFields) { let moreFields = true; while (moreFields) { const field = await (inquirer as any).prompt([ { type: 'input', name: 'name', message: 'Nombre del campo:' }, { type: 'list', name: 'type', message: 'Tipo:', choices: ['string', 'number', 'boolean', 'date'] }, { type: 'input', name: 'description', message: 'Descripcion:' }, { type: 'input', name: 'promptHint', message: 'Hint para el LLM:' }, ]); fields.push(field); const { more } = await (inquirer as any).prompt([{ type: 'confirm', name: 'more', message: 'Agregar otro campo?', default: false }]); moreFields = more; } } services.push({ intent: svc.intent, reference: svc.reference, enabled: true, method: svc.method, endpoint: svc.endpoint, requiredFields: fields, headers: {}, bodyTemplate: {}, responseMapping: {}, responseMessage: svc.responseMessage, responseConditions: [], }); const { more } = await (inquirer as any).prompt([{ type: 'confirm', name: 'more', message: 'Agregar otro servicio?', default: false }]); addMore = more; } } } // Acciones const actions: AgentAction[] = []; if (useToolCalling) { const { addActions } = await (inquirer as any).prompt([{ type: 'confirm', name: 'addActions', message: 'Agregar acciones (tag, stage, asignar agente)?', default: false, }]); if (addActions) { let addMore = true; while (addMore) { console.log(theme.muted('\n Nueva accion:')); const act = await (inquirer as any).prompt([ { type: 'input', name: 'intent', message: 'Nombre/intent de la accion:', validate: (v: string) => v.length > 0 || 'Requerido' }, { type: 'input', name: 'reference', message: 'Palabras clave de referencia:', default: '' }, { type: 'list', name: 'actionType', message: 'Tipo de accion:', choices: [ { name: 'Agendar evento', value: 'action.event.add' }, { name: 'Actualizar evento (reagendar)', value: 'action.event.update' }, { name: 'Listar eventos', value: 'action.event.list' }, { name: 'Eliminar evento (cancelar)', value: 'action.event.delete' }, { name: 'Agregar tag', value: 'action.tag' }, { name: 'Cambiar stage', value: 'action.stage' }, { name: 'Derivar a agente humano', value: 'action.agentShutDown' }, { name: 'Marcar como resuelto', value: 'action.solved' }, { name: 'Asignar agente', value: 'action.asign' }, { name: 'Segmentacion', value: 'action.segmentation' }, ], }, { type: 'input', name: 'actionValue', message: 'Valor de la accion:', default: '' }, { type: 'input', name: 'responseMessage', message: 'Mensaje de respuesta:', default: '' }, ]); actions.push({ intent: act.intent, reference: act.reference, enabled: true, requiredFields: [], responseMessage: act.responseMessage, action: [{ type: act.actionType, value: act.actionValue }], }); const { more } = await (inquirer as any).prompt([{ type: 'confirm', name: 'more', message: 'Agregar otra accion?', default: false }]); addMore = more; } } } // Paso 6: AI Provider console.log(theme.bold('\n Paso 6/8: Proveedor de IA')); const { configureAI } = await (inquirer as any).prompt([{ type: 'confirm', name: 'configureAI', message: 'Configurar proveedor de IA personalizado?', default: false, }]); const aiProviders: AIProvider[] = []; if (configureAI) { const ai = await (inquirer as any).prompt([ { type: 'list', name: 'provider', message: 'Proveedor:', choices: ['openai', 'claude', 'gemini'] }, ]); const models = MODELS[ai.provider] || MODELS.openai; const aiConfig = await (inquirer as any).prompt([ { type: 'list', name: 'model', message: 'Modelo:', choices: models }, { type: 'password', name: 'apiToken', message: 'API Token:', mask: '*', validate: (v: string) => v.length > 0 || 'Requerido' }, { type: 'number', name: 'temperature', message: 'Temperatura (0-2):', default: 0.7 }, { type: 'number', name: 'maxTokens', message: 'Max tokens (1024-16384):', default: 4096 }, ]); aiProviders.push({ provider: ai.provider, model: aiConfig.model, apiToken: aiConfig.apiToken, temperature: aiConfig.temperature, maxTokens: aiConfig.maxTokens, isDefault: true, }); } // Paso 7: Canal WhatsApp console.log(theme.bold('\n Paso 7/8: Canal WhatsApp')); const channels: AgentChannel[] = []; const { addWhatsApp } = await (inquirer as any).prompt([{ type: 'confirm', name: 'addWhatsApp', message: 'Conectar a un numero de WhatsApp?', default: false, }]); if (addWhatsApp) { const wa = await (inquirer as any).prompt([ { type: 'input', name: 'key', message: 'Numero de WhatsApp (con codigo de pais):', validate: (v: string) => v.length > 0 || 'Requerido' }, { type: 'confirm', name: 'multianswer', message: 'Permitir multiples respuestas?', default: false }, ]); channels.push({ channel: 'whatsapp', key: wa.key, multianswer: wa.multianswer }); } // Paso 8: Ejemplos console.log(theme.bold('\n Paso 8/8: Ejemplos de conversacion')); const examples: AgentExample[] = []; const { addExamples } = await (inquirer as any).prompt([{ type: 'confirm', name: 'addExamples', message: 'Agregar ejemplos de conversacion?', default: false, }]); if (addExamples) { let addMore = true; while (addMore) { const ex = await (inquirer as any).prompt([ { type: 'input', name: 'user', message: 'Mensaje del usuario:' }, { type: 'input', name: 'agent', message: 'Respuesta del agente:' }, ]); examples.push({ value: `Usuario: ${ex.user}\nAgente: ${ex.agent}`, color: 'blue' }); const { more } = await (inquirer as any).prompt([{ type: 'confirm', name: 'more', message: 'Agregar otro ejemplo?', default: false }]); addMore = more; } } // Armar config final (alineado con agent.config.schema.json del backend) const config: AgentConfig = { name: basic.name, description: basic.description || '', prompt: basic.prompt, buffer: basic.buffer, zone, color: basic.color, useToolCalling, customAIConfig: configureAI, aiProviders, instructions: { tone: personality.tone, style: personality.style, personality: personality.personality, objective: personality.objective, language: personality.language, emojis: personality.useEmojis, }, person: { name: person.name, role: person.role, speaksInFirstPerson: person.firstPerson, }, fallbacks: { noAnswer: fallbacks.noAnswer, serviceError: fallbacks.serviceError, doNotUnderstand: fallbacks.misunderstanding, }, services, actions, channels, examples, tags: [], }; // Preview console.log(section('Vista previa de la configuracion')); console.log(kvPair('Nombre', config.name)); console.log(kvPair('Prompt', config.prompt.substring(0, 80) + '...')); console.log(kvPair('Tool Calling', config.useToolCalling ? 'Activado' : 'Desactivado')); console.log(kvPair('Servicios', String(config.services.length))); console.log(kvPair('Acciones', String(config.actions.length))); console.log(kvPair('AI Provider', config.customAIConfig ? config.aiProviders[0]?.provider + ' / ' + config.aiProviders[0]?.model : 'Default (Plazbot)')); console.log(kvPair('Canal WhatsApp', config.channels.length > 0 ? config.channels[0].key : 'No configurado')); console.log(); return config; }