plazbot-cli 0.1.3 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/.claude/settings.local.json +14 -0
  2. package/CLAUDE.md +92 -0
  3. package/README.md +1 -1
  4. package/dist/cli.js +14 -5
  5. package/dist/commands/agent/ai-config.js +107 -0
  6. package/dist/commands/agent/chat.js +130 -34
  7. package/dist/commands/agent/copy.js +37 -0
  8. package/dist/commands/agent/create.js +80 -17
  9. package/dist/commands/agent/files.js +142 -0
  10. package/dist/commands/agent/index.js +14 -2
  11. package/dist/commands/agent/set.js +127 -0
  12. package/dist/commands/agent/templates.js +240 -0
  13. package/dist/commands/agent/tools.js +161 -0
  14. package/dist/commands/agent/wizard.js +369 -0
  15. package/dist/commands/whatsapp/broadcast.js +97 -0
  16. package/dist/commands/whatsapp/channels.js +86 -0
  17. package/dist/commands/whatsapp/chat.js +74 -0
  18. package/dist/commands/whatsapp/index.js +11 -2
  19. package/dist/commands/whatsapp/send-template.js +51 -14
  20. package/dist/commands/whatsapp/send.js +10 -10
  21. package/dist/commands/whatsapp/widget.js +64 -0
  22. package/dist/utils/banner.js +87 -0
  23. package/dist/utils/logger.js +27 -6
  24. package/dist/utils/ui.js +111 -0
  25. package/package.json +10 -2
  26. package/src/cli.ts +13 -5
  27. package/src/commands/agent/ai-config.ts +112 -0
  28. package/src/commands/agent/chat.ts +149 -40
  29. package/src/commands/agent/copy.ts +40 -0
  30. package/src/commands/agent/create.ts +58 -23
  31. package/src/commands/agent/files.ts +158 -0
  32. package/src/commands/agent/index.ts +14 -2
  33. package/src/commands/agent/set.ts +137 -0
  34. package/src/commands/agent/templates.ts +249 -0
  35. package/src/commands/agent/tools.ts +167 -0
  36. package/src/commands/agent/wizard.ts +475 -0
  37. package/src/commands/whatsapp/broadcast.ts +100 -0
  38. package/src/commands/whatsapp/channels.ts +98 -0
  39. package/src/commands/whatsapp/chat.ts +77 -0
  40. package/src/commands/whatsapp/index.ts +11 -2
  41. package/src/commands/whatsapp/send-template.ts +57 -19
  42. package/src/commands/whatsapp/send.ts +15 -14
  43. package/src/commands/whatsapp/widget.ts +67 -0
  44. package/src/utils/banner.ts +94 -0
  45. package/src/utils/logger.ts +26 -7
  46. package/src/utils/ui.ts +109 -0
  47. package/dist/commands/message/delete-webhook.js +0 -39
  48. package/dist/commands/message/index.js +0 -14
  49. package/dist/commands/message/register-webhook.js +0 -42
  50. package/dist/commands/message/send-template.js +0 -42
  51. package/dist/commands/message/send.js +0 -42
@@ -0,0 +1,158 @@
1
+ import { Command } from 'commander';
2
+ import { Agent } from 'plazbot';
3
+ import { getStoredCredentials } from '../../utils/credentials';
4
+ import { logger } from '../../utils/logger';
5
+ import { createSpinner, createTable, theme, section, statusBadge } from '../../utils/ui';
6
+ import { AgentCommandOptions } from '../../types/agent';
7
+
8
+ const filesGroup = new Command('files')
9
+ .description('Gestionar archivos de la base de conocimiento del agente');
10
+
11
+ // Listar archivos
12
+ filesGroup.command('list')
13
+ .description('Listar archivos del agente')
14
+ .argument('<agentId>', 'ID del agente')
15
+ .option('--dev', 'Usar ambiente de desarrollo', false)
16
+ .action(async (agentId: string, options: AgentCommandOptions) => {
17
+ try {
18
+ const credentials = await getStoredCredentials();
19
+ const agent = new Agent({
20
+ workspaceId: credentials.workspace,
21
+ apiKey: credentials.apiKey,
22
+ zone: credentials.zone,
23
+ ...(options.dev && { customUrl: "http://localhost:5090" })
24
+ });
25
+
26
+ const spinner = createSpinner('Cargando archivos...');
27
+ spinner.start();
28
+ const agentData = await agent.getAgentById({ id: agentId });
29
+ spinner.stop();
30
+
31
+ const files = agentData.files || [];
32
+ console.log(section('Archivos - ' + (agentData.name || agentId)));
33
+
34
+ if (files.length === 0) {
35
+ console.log(theme.muted('\n No hay archivos en la base de conocimiento'));
36
+ console.log(theme.muted(' Usa: plazbot agent files add <agentId> --url <url>\n'));
37
+ return;
38
+ }
39
+
40
+ const rows = files.map((f: any) => [
41
+ f.fileId || f.id || 'N/A',
42
+ f.name || f.reference || 'Sin nombre',
43
+ (f.tags || []).join(', ') || '-',
44
+ ]);
45
+
46
+ console.log(createTable(['ID', 'Nombre', 'Tags'], rows));
47
+
48
+ } catch (error) {
49
+ const message = error instanceof Error ? error.message : 'Error desconocido';
50
+ logger.error(message);
51
+ process.exit(1);
52
+ }
53
+ });
54
+
55
+ // Agregar archivo
56
+ filesGroup.command('add')
57
+ .description('Agregar archivo a la base de conocimiento')
58
+ .argument('<agentId>', 'ID del agente')
59
+ .requiredOption('-u, --url <url>', 'URL del archivo (PDF, DOC, DOCX)')
60
+ .option('-r, --reference <name>', 'Nombre de referencia', 'documento')
61
+ .option('-t, --tags <tags>', 'Tags separados por coma', '')
62
+ .option('--dev', 'Usar ambiente de desarrollo', false)
63
+ .action(async (agentId: string, options: any) => {
64
+ try {
65
+ const credentials = await getStoredCredentials();
66
+ const agent = new Agent({
67
+ workspaceId: credentials.workspace,
68
+ apiKey: credentials.apiKey,
69
+ zone: credentials.zone,
70
+ ...(options.dev && { customUrl: "http://localhost:5090" })
71
+ });
72
+
73
+ const spinner = createSpinner('Subiendo archivo...');
74
+ spinner.start();
75
+
76
+ const tags = options.tags ? options.tags.split(',').map((t: string) => t.trim()) : [];
77
+ const result = await agent.addFile({
78
+ fileUrl: options.url,
79
+ reference: options.reference,
80
+ agentId,
81
+ tags,
82
+ });
83
+
84
+ spinner.succeed('Archivo agregado');
85
+
86
+ if (result?.fileId || result?.id) {
87
+ logger.label('File ID', result.fileId || result.id);
88
+ logger.dim('El archivo esta siendo procesado. Verifica con:');
89
+ logger.dim(`plazbot agent files status ${result.fileId || result.id}`);
90
+ }
91
+
92
+ } catch (error) {
93
+ const message = error instanceof Error ? error.message : 'Error desconocido';
94
+ logger.error(message);
95
+ process.exit(1);
96
+ }
97
+ });
98
+
99
+ // Verificar estado
100
+ filesGroup.command('status')
101
+ .description('Verificar estado de procesamiento de un archivo')
102
+ .argument('<fileId>', 'ID del archivo')
103
+ .option('--dev', 'Usar ambiente de desarrollo', false)
104
+ .action(async (fileId: string, options: AgentCommandOptions) => {
105
+ try {
106
+ const credentials = await getStoredCredentials();
107
+ const agent = new Agent({
108
+ workspaceId: credentials.workspace,
109
+ apiKey: credentials.apiKey,
110
+ zone: credentials.zone,
111
+ ...(options.dev && { customUrl: "http://localhost:5090" })
112
+ });
113
+
114
+ const spinner = createSpinner('Verificando...');
115
+ spinner.start();
116
+ const result = await agent.validateFile({ fileId });
117
+ spinner.stop();
118
+
119
+ logger.title('Estado del archivo');
120
+ logger.label('File ID', fileId);
121
+ logger.label('Estado', result?.status || result?.stateId === 2 ? 'Completado' : 'En proceso');
122
+
123
+ } catch (error) {
124
+ const message = error instanceof Error ? error.message : 'Error desconocido';
125
+ logger.error(message);
126
+ process.exit(1);
127
+ }
128
+ });
129
+
130
+ // Eliminar archivo
131
+ filesGroup.command('delete')
132
+ .description('Eliminar archivo de la base de conocimiento')
133
+ .argument('<agentId>', 'ID del agente')
134
+ .argument('<fileId>', 'ID del archivo')
135
+ .option('--dev', 'Usar ambiente de desarrollo', false)
136
+ .action(async (agentId: string, fileId: string, options: AgentCommandOptions) => {
137
+ try {
138
+ const credentials = await getStoredCredentials();
139
+ const agent = new Agent({
140
+ workspaceId: credentials.workspace,
141
+ apiKey: credentials.apiKey,
142
+ zone: credentials.zone,
143
+ ...(options.dev && { customUrl: "http://localhost:5090" })
144
+ });
145
+
146
+ const spinner = createSpinner('Eliminando archivo...');
147
+ spinner.start();
148
+ await agent.deleteFile({ fileId, agentId });
149
+ spinner.succeed('Archivo eliminado');
150
+
151
+ } catch (error) {
152
+ const message = error instanceof Error ? error.message : 'Error desconocido';
153
+ logger.error(message);
154
+ process.exit(1);
155
+ }
156
+ });
157
+
158
+ export const filesCommand = filesGroup;
@@ -7,9 +7,15 @@ import { updateCommand } from './update';
7
7
  import { enableCommand } from './enable-widget';
8
8
  import { chatCommand } from './chat';
9
9
  import { messageCommand } from './on-message';
10
+ import { toolsCommand } from './tools';
11
+ import { aiConfigCommand } from './ai-config';
12
+ import { templatesCommand } from './templates';
13
+ import { copyCommand } from './copy';
14
+ import { filesCommand } from './files';
15
+ import { setCommand } from './set';
10
16
 
11
17
  export const agentCommands = new Command('agent')
12
- .description('Comandos relacionados con agentes')
18
+ .description('Comandos relacionados con agentes de IA')
13
19
  .addCommand(listCommand)
14
20
  .addCommand(getCommand)
15
21
  .addCommand(deleteCommand)
@@ -17,4 +23,10 @@ export const agentCommands = new Command('agent')
17
23
  .addCommand(updateCommand)
18
24
  .addCommand(enableCommand)
19
25
  .addCommand(chatCommand)
20
- .addCommand(messageCommand);
26
+ .addCommand(messageCommand)
27
+ .addCommand(toolsCommand)
28
+ .addCommand(aiConfigCommand)
29
+ .addCommand(templatesCommand)
30
+ .addCommand(copyCommand)
31
+ .addCommand(filesCommand)
32
+ .addCommand(setCommand);
@@ -0,0 +1,137 @@
1
+ import { Command } from 'commander';
2
+ import { Agent } from 'plazbot';
3
+ import inquirer from 'inquirer';
4
+ import { getStoredCredentials } from '../../utils/credentials';
5
+ import { logger } from '../../utils/logger';
6
+ import { createSpinner, theme, section, kvPair } from '../../utils/ui';
7
+ import { AgentCommandOptions } from '../../types/agent';
8
+
9
+ const setGroup = new Command('set')
10
+ .description('Configurar rapidamente propiedades del agente');
11
+
12
+ // Set greeting
13
+ setGroup.command('greeting')
14
+ .description('Cambiar el saludo del agente')
15
+ .argument('<agentId>', 'ID del agente')
16
+ .argument('<greeting>', 'Nuevo saludo')
17
+ .option('--dev', 'Usar ambiente de desarrollo', false)
18
+ .action(async (agentId: string, greeting: string, options: AgentCommandOptions) => {
19
+ try {
20
+ const credentials = await getStoredCredentials();
21
+ const agent = new Agent({
22
+ workspaceId: credentials.workspace,
23
+ apiKey: credentials.apiKey,
24
+ zone: credentials.zone,
25
+ ...(options.dev && { customUrl: "http://localhost:5090" })
26
+ });
27
+
28
+ const spinner = createSpinner('Actualizando saludo...');
29
+ spinner.start();
30
+ await agent.setGreeting(agentId, greeting);
31
+ spinner.succeed('Saludo actualizado');
32
+ logger.label('Nuevo saludo', greeting);
33
+
34
+ } catch (error) {
35
+ const message = error instanceof Error ? error.message : 'Error desconocido';
36
+ logger.error(message);
37
+ process.exit(1);
38
+ }
39
+ });
40
+
41
+ // Set instructions (wizard)
42
+ setGroup.command('instructions')
43
+ .description('Configurar instrucciones del agente')
44
+ .argument('<agentId>', 'ID del agente')
45
+ .option('--dev', 'Usar ambiente de desarrollo', false)
46
+ .action(async (agentId: string, options: AgentCommandOptions) => {
47
+ try {
48
+ const credentials = await getStoredCredentials();
49
+ const agent = new Agent({
50
+ workspaceId: credentials.workspace,
51
+ apiKey: credentials.apiKey,
52
+ zone: credentials.zone,
53
+ ...(options.dev && { customUrl: "http://localhost:5090" })
54
+ });
55
+
56
+ // Cargar instrucciones actuales
57
+ const loadSpinner = createSpinner('Cargando...');
58
+ loadSpinner.start();
59
+ const agentData = await agent.getAgentById({ id: agentId });
60
+ loadSpinner.stop();
61
+
62
+ const current = agentData.instructions || {};
63
+ console.log(section('Instrucciones - ' + (agentData.name || agentId)));
64
+
65
+ const answers = await (inquirer as any).prompt([
66
+ { type: 'list', name: 'tone', message: 'Tono:', choices: ['profesional', 'amigable', 'formal', 'casual', 'tecnico', 'empatico'], default: current.tone || 'profesional' },
67
+ { type: 'list', name: 'style', message: 'Estilo:', choices: ['conciso', 'detallado', 'conversacional', 'directo'], default: current.style || 'conciso' },
68
+ { type: 'input', name: 'personality', message: 'Personalidad:', default: current.personality || '' },
69
+ { type: 'input', name: 'objective', message: 'Objetivo:', default: current.objective || '' },
70
+ { type: 'list', name: 'language', message: 'Idioma:', choices: ['Espanol', 'English', 'Portugues'], default: current.language || 'Espanol' },
71
+ { type: 'confirm', name: 'useEmojis', message: 'Usar emojis?', default: current.useEmojis === 'si' },
72
+ ]);
73
+
74
+ const instructions = {
75
+ ...current,
76
+ tone: answers.tone,
77
+ style: answers.style,
78
+ personality: answers.personality,
79
+ objective: answers.objective,
80
+ language: answers.language,
81
+ useEmojis: answers.useEmojis ? 'si' : 'no',
82
+ };
83
+
84
+ const spinner = createSpinner('Guardando instrucciones...');
85
+ spinner.start();
86
+ await agent.setInstructions(agentId, instructions);
87
+ spinner.succeed('Instrucciones actualizadas');
88
+
89
+ } catch (error) {
90
+ const message = error instanceof Error ? error.message : 'Error desconocido';
91
+ logger.error(message);
92
+ process.exit(1);
93
+ }
94
+ });
95
+
96
+ // Set persona (wizard)
97
+ setGroup.command('persona')
98
+ .description('Configurar la persona del agente')
99
+ .argument('<agentId>', 'ID del agente')
100
+ .option('--dev', 'Usar ambiente de desarrollo', false)
101
+ .action(async (agentId: string, options: AgentCommandOptions) => {
102
+ try {
103
+ const credentials = await getStoredCredentials();
104
+ const agent = new Agent({
105
+ workspaceId: credentials.workspace,
106
+ apiKey: credentials.apiKey,
107
+ zone: credentials.zone,
108
+ ...(options.dev && { customUrl: "http://localhost:5090" })
109
+ });
110
+
111
+ const loadSpinner = createSpinner('Cargando...');
112
+ loadSpinner.start();
113
+ const agentData = await agent.getAgentById({ id: agentId });
114
+ loadSpinner.stop();
115
+
116
+ const current = agentData.person || {};
117
+ console.log(section('Persona - ' + (agentData.name || agentId)));
118
+
119
+ const answers = await (inquirer as any).prompt([
120
+ { type: 'input', name: 'name', message: 'Nombre del personaje:', default: current.name || '' },
121
+ { type: 'input', name: 'role', message: 'Rol:', default: current.role || '' },
122
+ { type: 'confirm', name: 'firstPerson', message: 'Hablar en primera persona?', default: current.firstPerson !== false },
123
+ ]);
124
+
125
+ const spinner = createSpinner('Guardando persona...');
126
+ spinner.start();
127
+ await agent.setPersona(agentId, answers);
128
+ spinner.succeed('Persona actualizada');
129
+
130
+ } catch (error) {
131
+ const message = error instanceof Error ? error.message : 'Error desconocido';
132
+ logger.error(message);
133
+ process.exit(1);
134
+ }
135
+ });
136
+
137
+ export const setCommand = setGroup;
@@ -0,0 +1,249 @@
1
+ import { Command } from 'commander';
2
+ import inquirer from 'inquirer';
3
+ import { logger } from '../../utils/logger';
4
+ import { theme, section, kvPair, createTable } from '../../utils/ui';
5
+
6
+ interface Template {
7
+ name: string;
8
+ description: string;
9
+ industry: string;
10
+ config: any;
11
+ }
12
+
13
+ const TEMPLATES: Template[] = [
14
+ {
15
+ name: 'Asistente de Ventas',
16
+ description: 'Agente especializado en atencion al cliente y ventas',
17
+ industry: 'Ventas',
18
+ config: {
19
+ name: 'Asistente de Ventas',
20
+ prompt: 'Eres un asistente de ventas profesional y amigable. Tu objetivo es ayudar a los clientes a encontrar los productos o servicios que necesitan, responder sus preguntas y guiarlos en el proceso de compra.',
21
+ buffer: 10,
22
+ color: 'blue',
23
+ useToolCalling: true,
24
+ instructions: {
25
+ tone: 'amigable',
26
+ style: 'conversacional',
27
+ personality: 'Entusiasta y servicial',
28
+ objective: 'Ayudar al cliente a encontrar el producto ideal y cerrar la venta',
29
+ language: 'Espanol',
30
+ emojis: true,
31
+ },
32
+ person: { name: 'Ana', role: 'Asesora de ventas', speaksInFirstPerson: true },
33
+ fallbacks: {
34
+ noAnswer: 'No tengo informacion sobre eso, pero puedo conectarte con un asesor especializado.',
35
+ serviceError: 'Disculpa, estamos experimentando dificultades. Un asesor te atendera pronto.',
36
+ doNotUnderstand: 'Podrias darme mas detalles sobre lo que buscas?',
37
+ },
38
+ actions: [
39
+ { intent: 'derivar_asesor', reference: 'hablar con humano, asesor, agente', enabled: true, requiredFields: [], responseMessage: 'Te conecto con un asesor ahora mismo.', action: [{ type: 'action.agentShutDown', value: '' }] },
40
+ { intent: 'etiquetar_interesado', reference: 'interesado, quiere comprar', enabled: true, requiredFields: [], responseMessage: '', action: [{ type: 'action.tag', value: 'interesado' }] },
41
+ ],
42
+ services: [],
43
+ channels: [],
44
+ examples: [
45
+ { value: 'Usuario: Hola, quiero informacion sobre sus productos\nAgente: Hola! Con gusto te ayudo. Que tipo de producto estas buscando?', color: 'blue' },
46
+ { value: 'Usuario: Cuanto cuesta?\nAgente: El precio depende del plan que elijas. Te cuento las opciones disponibles...', color: 'blue' },
47
+ ],
48
+ tags: ['ventas', 'atencion-cliente'],
49
+ },
50
+ },
51
+ {
52
+ name: 'Soporte Tecnico IT',
53
+ description: 'Agente para soporte tecnico y resolucion de problemas',
54
+ industry: 'Tecnologia',
55
+ config: {
56
+ name: 'Soporte Tecnico',
57
+ prompt: 'Eres un agente de soporte tecnico especializado. Tu objetivo es diagnosticar problemas tecnicos, guiar al usuario paso a paso en la solucion y escalar cuando sea necesario.',
58
+ buffer: 8,
59
+ color: 'green',
60
+ useToolCalling: true,
61
+ instructions: {
62
+ tone: 'profesional',
63
+ style: 'detallado',
64
+ personality: 'Paciente y tecnico',
65
+ objective: 'Resolver problemas tecnicos del usuario de forma eficiente',
66
+ language: 'Espanol',
67
+ emojis: false,
68
+ },
69
+ person: { name: 'Carlos', role: 'Especialista de soporte', speaksInFirstPerson: true },
70
+ fallbacks: {
71
+ noAnswer: 'No puedo resolver este caso automaticamente. Voy a escalarlo a un tecnico especializado.',
72
+ serviceError: 'Hay un problema con nuestros sistemas. Un tecnico te contactara pronto.',
73
+ doNotUnderstand: 'Puedes describir el problema con mas detalle? Que mensaje de error ves?',
74
+ },
75
+ actions: [
76
+ { intent: 'escalar_ticket', reference: 'escalar, tecnico, no funciona', enabled: true, requiredFields: [], responseMessage: 'Escalando tu caso a un tecnico especializado.', action: [{ type: 'action.agentShutDown', value: '' }] },
77
+ { intent: 'etiquetar_urgente', reference: 'urgente, critico, caido', enabled: true, requiredFields: [], responseMessage: '', action: [{ type: 'action.tag', value: 'urgente' }] },
78
+ ],
79
+ services: [],
80
+ channels: [],
81
+ examples: [],
82
+ tags: ['soporte', 'IT'],
83
+ },
84
+ },
85
+ {
86
+ name: 'Asistente de Clinica',
87
+ description: 'Agente para clinicas medicas: citas, horarios e informacion',
88
+ industry: 'Salud',
89
+ config: {
90
+ name: 'Asistente de Clinica',
91
+ prompt: 'Eres un asistente virtual de una clinica medica. Tu objetivo es ayudar a los pacientes a agendar citas, consultar horarios de atencion, y proporcionar informacion general sobre los servicios de la clinica. NUNCA des diagnosticos medicos ni recomendaciones de tratamiento.',
92
+ buffer: 5,
93
+ color: 'green',
94
+ useToolCalling: true,
95
+ instructions: {
96
+ tone: 'empatico',
97
+ style: 'conciso',
98
+ personality: 'Amable y profesional',
99
+ objective: 'Facilitar la gestion de citas y brindar informacion de la clinica',
100
+ language: 'Espanol',
101
+ emojis: true,
102
+ },
103
+ person: { name: 'Sofia', role: 'Asistente de clinica', speaksInFirstPerson: true },
104
+ fallbacks: {
105
+ noAnswer: 'No tengo esa informacion. Te recomiendo llamar directamente a la clinica.',
106
+ serviceError: 'Disculpa, nuestro sistema esta temporalmente fuera de servicio.',
107
+ doNotUnderstand: 'Podrias repetir tu consulta? Estoy aqui para ayudarte con citas, horarios o informacion de la clinica.',
108
+ },
109
+ actions: [
110
+ { intent: 'derivar_recepcion', reference: 'hablar con recepcion, persona real', enabled: true, requiredFields: [], responseMessage: 'Te conecto con recepcion ahora.', action: [{ type: 'action.agentShutDown', value: '' }] },
111
+ ],
112
+ services: [],
113
+ channels: [],
114
+ examples: [],
115
+ tags: ['clinica', 'salud', 'citas'],
116
+ },
117
+ },
118
+ {
119
+ name: 'Asistente de Restaurante',
120
+ description: 'Agente para restaurantes: menu, reservas y pedidos',
121
+ industry: 'Gastronomia',
122
+ config: {
123
+ name: 'Asistente de Restaurante',
124
+ prompt: 'Eres un asistente virtual de un restaurante. Tu objetivo es ayudar a los clientes con informacion del menu, tomar reservas, informar sobre horarios de atencion y responder consultas generales sobre el restaurante.',
125
+ buffer: 5,
126
+ color: 'orange',
127
+ useToolCalling: true,
128
+ instructions: {
129
+ tone: 'amigable',
130
+ style: 'conversacional',
131
+ personality: 'Calido y entusiasta sobre la comida',
132
+ objective: 'Brindar informacion del restaurante y facilitar reservas',
133
+ language: 'Espanol',
134
+ emojis: true,
135
+ },
136
+ person: { name: 'Marco', role: 'Anfitrion virtual', speaksInFirstPerson: true },
137
+ fallbacks: {
138
+ noAnswer: 'No tengo esa informacion. Te recomiendo llamar al restaurante.',
139
+ serviceError: 'Disculpa, nuestro sistema tiene problemas. Llamanos para hacer tu reserva.',
140
+ doNotUnderstand: 'Perdon, no entendi. Puedo ayudarte con el menu, reservas u horarios.',
141
+ },
142
+ actions: [],
143
+ services: [],
144
+ channels: [],
145
+ examples: [
146
+ { value: 'Usuario: Quiero hacer una reserva\nAgente: Con gusto! Para cuantas personas y que dia tienes en mente?', color: 'orange' },
147
+ ],
148
+ tags: ['restaurante', 'reservas'],
149
+ },
150
+ },
151
+ {
152
+ name: 'Asistente Inmobiliario',
153
+ description: 'Agente para inmobiliarias: propiedades, visitas y consultas',
154
+ industry: 'Inmobiliario',
155
+ config: {
156
+ name: 'Asistente Inmobiliario',
157
+ prompt: 'Eres un asistente virtual de una inmobiliaria. Tu objetivo es ayudar a los clientes a encontrar propiedades que se ajusten a sus necesidades, agendar visitas y responder consultas sobre el proceso de compra o alquiler.',
158
+ buffer: 8,
159
+ color: 'blue',
160
+ useToolCalling: true,
161
+ instructions: {
162
+ tone: 'profesional',
163
+ style: 'detallado',
164
+ personality: 'Conocedor y confiable',
165
+ objective: 'Ayudar al cliente a encontrar la propiedad ideal',
166
+ language: 'Espanol',
167
+ emojis: true,
168
+ },
169
+ person: { name: 'Diego', role: 'Asesor inmobiliario', speaksInFirstPerson: true },
170
+ fallbacks: {
171
+ noAnswer: 'No tengo informacion sobre esa propiedad. Dejame conectarte con un asesor.',
172
+ serviceError: 'Nuestro sistema esta temporalmente fuera de servicio. Un asesor te contactara.',
173
+ doNotUnderstand: 'Podrias darme mas detalles? Que tipo de propiedad buscas?',
174
+ },
175
+ actions: [
176
+ { intent: 'derivar_asesor', reference: 'asesor, visita, contactar', enabled: true, requiredFields: [], responseMessage: 'Te conecto con un asesor inmobiliario.', action: [{ type: 'action.agentShutDown', value: '' }] },
177
+ { intent: 'etiquetar_interesado', reference: 'interesado, quiere comprar, quiere alquilar', enabled: true, requiredFields: [], responseMessage: '', action: [{ type: 'action.tag', value: 'interesado' }] },
178
+ ],
179
+ services: [],
180
+ channels: [],
181
+ examples: [],
182
+ tags: ['inmobiliario', 'propiedades'],
183
+ },
184
+ },
185
+ ];
186
+
187
+ export const templatesCommand = new Command('templates')
188
+ .description('Ver y usar plantillas de agentes pre-configurados')
189
+ .option('--dev', 'Usar ambiente de desarrollo', false)
190
+ .action(async () => {
191
+ try {
192
+ console.log(section('Plantillas de agentes'));
193
+ console.log(theme.muted(' Selecciona una plantilla para crear un agente pre-configurado\n'));
194
+
195
+ const rows = TEMPLATES.map((t, i) => [
196
+ String(i + 1),
197
+ t.name,
198
+ t.industry,
199
+ t.description,
200
+ ]);
201
+ console.log(createTable(['#', 'Nombre', 'Industria', 'Descripcion'], rows));
202
+
203
+ const { selected } = await (inquirer as any).prompt([{
204
+ type: 'list',
205
+ name: 'selected',
206
+ message: 'Selecciona una plantilla:',
207
+ choices: [
208
+ ...TEMPLATES.map((t, i) => ({ name: `${t.name} (${t.industry})`, value: i })),
209
+ { name: 'Cancelar', value: -1 },
210
+ ],
211
+ }]);
212
+
213
+ if (selected === -1) return;
214
+
215
+ const template = TEMPLATES[selected];
216
+ console.log(section(template.name));
217
+ console.log(kvPair('Industria', template.industry));
218
+ console.log(kvPair('Descripcion', template.description));
219
+ console.log(kvPair('Tool Calling', template.config.useToolCalling ? 'Si' : 'No'));
220
+ console.log(kvPair('Acciones', String(template.config.actions.length)));
221
+ console.log(kvPair('Persona', `${template.config.person.name} - ${template.config.person.role}`));
222
+ console.log();
223
+
224
+ const { action } = await (inquirer as any).prompt([{
225
+ type: 'list',
226
+ name: 'action',
227
+ message: 'Que deseas hacer?',
228
+ choices: [
229
+ { name: 'Crear agente con esta plantilla', value: 'create' },
230
+ { name: 'Ver JSON completo', value: 'json' },
231
+ { name: 'Cancelar', value: 'cancel' },
232
+ ],
233
+ }]);
234
+
235
+ if (action === 'json') {
236
+ logger.json(template.config);
237
+ }
238
+
239
+ if (action === 'create') {
240
+ logger.success(`Usa: plazbot agent create y selecciona la plantilla "${template.name}" durante el wizard`);
241
+ logger.dim('O exporta el JSON: plazbot agent templates (selecciona Ver JSON)');
242
+ }
243
+
244
+ } catch (error) {
245
+ const message = error instanceof Error ? error.message : 'Error desconocido';
246
+ logger.error(message);
247
+ process.exit(1);
248
+ }
249
+ });