plazbot-cli 0.2.4 → 0.2.5
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.
- package/dist/commands/agent/create.js +4 -2
- package/dist/commands/agent/get.js +128 -93
- package/dist/commands/agent/monitor.js +7 -1
- package/dist/commands/agent/wizard.js +173 -9
- package/package.json +1 -1
- package/src/commands/agent/create.ts +4 -2
- package/src/commands/agent/get.ts +140 -101
- package/src/commands/agent/monitor.ts +7 -1
- package/src/commands/agent/wizard.ts +200 -9
|
@@ -73,7 +73,7 @@ exports.createCommand = new commander_1.Command('create')
|
|
|
73
73
|
}
|
|
74
74
|
else {
|
|
75
75
|
// Modo wizard interactivo
|
|
76
|
-
agentConfig = await (0, wizard_1.runAgentWizard)(credentials.zone);
|
|
76
|
+
agentConfig = await (0, wizard_1.runAgentWizard)(credentials.zone, credentials.workspace, credentials.apiKey, options.dev);
|
|
77
77
|
const inquirer = await Promise.resolve().then(() => __importStar(require('inquirer')));
|
|
78
78
|
const { confirm } = await inquirer.default.prompt([{
|
|
79
79
|
type: 'confirm',
|
|
@@ -99,7 +99,9 @@ exports.createCommand = new commander_1.Command('create')
|
|
|
99
99
|
}
|
|
100
100
|
logger_1.logger.label('Tool Calling', agentConfig.useToolCalling ? 'Activado' : 'Desactivado');
|
|
101
101
|
if (agentConfig.channels && agentConfig.channels.length > 0) {
|
|
102
|
-
|
|
102
|
+
agentConfig.channels.forEach((ch) => {
|
|
103
|
+
logger_1.logger.label(`Canal (${ch.channel})`, ch.key);
|
|
104
|
+
});
|
|
103
105
|
}
|
|
104
106
|
console.log();
|
|
105
107
|
logger_1.logger.dim('Siguiente paso: plazbot agent chat -a ' + (result.agentId || '<agentId>'));
|
|
@@ -1,153 +1,188 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
6
|
exports.getCommand = void 0;
|
|
4
7
|
const commander_1 = require("commander");
|
|
5
8
|
const plazbot_1 = require("plazbot");
|
|
6
9
|
const credentials_1 = require("../../utils/credentials");
|
|
7
10
|
const logger_1 = require("../../utils/logger");
|
|
11
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
8
12
|
exports.getCommand = new commander_1.Command('get')
|
|
9
13
|
.description('Obtiene información detallada de un agente específico')
|
|
10
14
|
.argument('<agentId>', 'ID del agente a consultar')
|
|
15
|
+
.option('-w, --workspace <id>', 'Workspace ID (sobreescribe config local)')
|
|
16
|
+
.option('-z, --zone <zone>', 'Zona LA o EU (sobreescribe config local)')
|
|
17
|
+
.option('--raw', 'Mostrar el JSON completo sin formatear', false)
|
|
11
18
|
.option('--dev', 'Usar ambiente de desarrollo', false)
|
|
12
19
|
.action(async (agentId, options) => {
|
|
13
20
|
try {
|
|
14
|
-
// Obtener credenciales guardadas
|
|
15
21
|
const credentials = await (0, credentials_1.getStoredCredentials)();
|
|
16
|
-
|
|
22
|
+
const effectiveWorkspace = options.workspace || credentials.workspace;
|
|
23
|
+
const effectiveZone = (options.zone?.toUpperCase() === 'EU' ? 'EU' : options.zone?.toUpperCase() === 'LA' ? 'LA' : credentials.zone);
|
|
24
|
+
if (options.workspace || options.zone) {
|
|
25
|
+
console.log(chalk_1.default.hex('#FFA726')(`\n Modo soporte: workspace=${effectiveWorkspace} zona=${effectiveZone}`));
|
|
26
|
+
}
|
|
17
27
|
const agent = new plazbot_1.Agent({
|
|
18
|
-
workspaceId:
|
|
28
|
+
workspaceId: effectiveWorkspace,
|
|
19
29
|
apiKey: credentials.apiKey,
|
|
20
|
-
zone:
|
|
30
|
+
zone: effectiveZone,
|
|
21
31
|
...(options.dev && { customUrl: "http://localhost:5090" })
|
|
22
32
|
});
|
|
23
|
-
//
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
33
|
+
// El SDK retorna { success, agent: {...} }
|
|
34
|
+
const response = await agent.getAgentById({ id: agentId });
|
|
35
|
+
const agentData = response.agent || response.data || response;
|
|
36
|
+
// Modo JSON crudo
|
|
37
|
+
if (options.raw) {
|
|
38
|
+
console.log(JSON.stringify(agentData, null, 2));
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
const label = (key, value) => {
|
|
42
|
+
const v = value !== undefined && value !== null && value !== '' ? String(value) : chalk_1.default.gray('—');
|
|
43
|
+
console.log(` ${chalk_1.default.gray(key + ':')} ${chalk_1.default.white(v)}`);
|
|
44
|
+
};
|
|
45
|
+
const sectionHeader = (title) => {
|
|
46
|
+
console.log();
|
|
47
|
+
console.log(chalk_1.default.bold.hex('#4CAF50')(` ${title}`));
|
|
48
|
+
console.log(chalk_1.default.gray(' ' + '─'.repeat(40)));
|
|
49
|
+
};
|
|
50
|
+
console.log();
|
|
51
|
+
console.log(chalk_1.default.hex('#4CAF50')(' ┌' + '─'.repeat(58) + '┐'));
|
|
52
|
+
console.log(chalk_1.default.hex('#4CAF50')(' │') + chalk_1.default.bold(` ${agentData.name || 'Agente'}`).padEnd(68) + chalk_1.default.hex('#4CAF50')('│'));
|
|
53
|
+
console.log(chalk_1.default.hex('#4CAF50')(' │') + chalk_1.default.gray(` ${agentId}`).padEnd(68) + chalk_1.default.hex('#4CAF50')('│'));
|
|
54
|
+
console.log(chalk_1.default.hex('#4CAF50')(' └' + '─'.repeat(58) + '┘'));
|
|
55
|
+
// Informacion basica
|
|
56
|
+
sectionHeader('Informacion Basica');
|
|
57
|
+
label('ID', agentData.id);
|
|
58
|
+
label('Nombre', agentData.name);
|
|
59
|
+
label('Descripcion', agentData.description);
|
|
60
|
+
label('Estado', agentData.enable ? chalk_1.default.hex('#66BB6A')('Activo') : chalk_1.default.hex('#EF5350')('Inactivo'));
|
|
61
|
+
label('Zona', agentData.zone);
|
|
62
|
+
label('Buffer', agentData.buffer);
|
|
63
|
+
label('Color', agentData.color);
|
|
64
|
+
label('Pregunta inicial', agentData.question);
|
|
65
|
+
label('Zona horaria', agentData.timezone);
|
|
66
|
+
label('Mostrar en chat', agentData.showInChat ? 'Si' : 'No');
|
|
67
|
+
label('Tool Calling', agentData.useToolCalling ? 'Activado' : 'Desactivado');
|
|
40
68
|
// Tags
|
|
41
69
|
if (agentData.tags && agentData.tags.length > 0) {
|
|
42
|
-
|
|
70
|
+
label('Tags', agentData.tags.join(', '));
|
|
71
|
+
}
|
|
72
|
+
// Prompt
|
|
73
|
+
if (agentData.prompt) {
|
|
74
|
+
sectionHeader('Prompt');
|
|
75
|
+
const promptPreview = agentData.prompt.length > 200
|
|
76
|
+
? agentData.prompt.substring(0, 200) + '...'
|
|
77
|
+
: agentData.prompt;
|
|
78
|
+
console.log(chalk_1.default.white(' ' + promptPreview.split('\n').join('\n ')));
|
|
43
79
|
}
|
|
44
80
|
// Ejemplos
|
|
45
81
|
if (agentData.examples && agentData.examples.length > 0) {
|
|
46
|
-
|
|
47
|
-
logger_1.logger.divider();
|
|
82
|
+
sectionHeader('Ejemplos');
|
|
48
83
|
agentData.examples.forEach((example) => {
|
|
49
|
-
|
|
84
|
+
console.log(chalk_1.default.white(` - ${example.value || example}`));
|
|
50
85
|
});
|
|
51
86
|
}
|
|
52
87
|
// Instrucciones
|
|
53
88
|
if (agentData.instructions) {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
logger_1.logger.info(`Temas a evitar: ${instructions.avoidTopics.join(', ')}`);
|
|
89
|
+
sectionHeader('Instrucciones');
|
|
90
|
+
const inst = agentData.instructions;
|
|
91
|
+
label('Tono', inst.tone);
|
|
92
|
+
label('Estilo', inst.style);
|
|
93
|
+
label('Personalidad', inst.personality);
|
|
94
|
+
label('Objetivo', inst.objective);
|
|
95
|
+
label('Idioma', inst.language);
|
|
96
|
+
label('Emojis', inst.emojis ? 'Si' : 'No');
|
|
97
|
+
label('Formato preferido', inst.preferredFormat);
|
|
98
|
+
label('Max palabras', inst.maxWords);
|
|
99
|
+
if (inst.avoidTopics && inst.avoidTopics.length > 0) {
|
|
100
|
+
label('Temas a evitar', inst.avoidTopics.join(', '));
|
|
67
101
|
}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
logger_1.logger.info(`Saludo: ${instructions.greeting}`);
|
|
102
|
+
label('Solo responder si sabe', inst.respondOnlyIfKnows ? 'Si' : 'No');
|
|
103
|
+
label('Saludo', inst.greeting);
|
|
71
104
|
}
|
|
72
105
|
// Persona
|
|
73
106
|
if (agentData.person) {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
logger_1.logger.info(`Es humano: ${person.isHuman ? 'Sí' : 'No'}`);
|
|
107
|
+
sectionHeader('Persona');
|
|
108
|
+
const p = agentData.person;
|
|
109
|
+
label('Nombre', p.name);
|
|
110
|
+
label('Rol', p.role);
|
|
111
|
+
label('Primera persona', p.speaksInFirstPerson ? 'Si' : 'No');
|
|
112
|
+
label('Es humano', p.isHuman ? 'Si' : 'No');
|
|
81
113
|
}
|
|
82
114
|
// Fallbacks
|
|
83
115
|
if (agentData.fallbacks) {
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
logger_1.logger.info(`No entiende: ${fallbacks.doNotUnderstand}`);
|
|
116
|
+
sectionHeader('Fallbacks');
|
|
117
|
+
const fb = agentData.fallbacks;
|
|
118
|
+
label('Sin respuesta', fb.noAnswer);
|
|
119
|
+
label('Error de servicio', fb.serviceError);
|
|
120
|
+
label('No entiende', fb.doNotUnderstand);
|
|
90
121
|
}
|
|
91
122
|
// Reglas
|
|
92
123
|
if (agentData.rules) {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
logger_1.logger.info(`Horario de atención: ${rules.doNotRespondOutsideHours}`);
|
|
124
|
+
sectionHeader('Reglas');
|
|
125
|
+
const r = agentData.rules;
|
|
126
|
+
label('No mencionar precios', r.doNotMentionPrices ? 'Si' : 'No');
|
|
127
|
+
label('No diagnosticar', r.doNotDiagnose ? 'Si' : 'No');
|
|
128
|
+
if (r.doNotRespondOutsideHours) {
|
|
129
|
+
label('Fuera de horario', r.doNotRespondOutsideHours);
|
|
100
130
|
}
|
|
101
131
|
}
|
|
102
132
|
// Servicios
|
|
103
133
|
if (agentData.services && agentData.services.length > 0) {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
service.requiredFields.forEach((field) => {
|
|
116
|
-
logger_1.logger.info(` - ${field.name} (${field.type}): ${field.description}`);
|
|
134
|
+
sectionHeader(`Servicios (${agentData.services.length})`);
|
|
135
|
+
agentData.services.forEach((svc, i) => {
|
|
136
|
+
console.log(chalk_1.default.hex('#2196F3')(` ${i + 1}. ${svc.intent || svc.reference || 'Servicio'}`));
|
|
137
|
+
label(' Referencia', svc.reference);
|
|
138
|
+
label(' Habilitado', svc.enabled ? 'Si' : 'No');
|
|
139
|
+
label(' Metodo', svc.method);
|
|
140
|
+
label(' Endpoint', svc.endpoint);
|
|
141
|
+
if (svc.requiredFields && svc.requiredFields.length > 0) {
|
|
142
|
+
console.log(chalk_1.default.gray(' Campos:'));
|
|
143
|
+
svc.requiredFields.forEach((f) => {
|
|
144
|
+
console.log(chalk_1.default.white(` - ${f.name} (${f.type}): ${f.description || ''}`));
|
|
117
145
|
});
|
|
118
146
|
}
|
|
119
147
|
});
|
|
120
148
|
}
|
|
121
149
|
// Acciones
|
|
122
150
|
if (agentData.actions && agentData.actions.length > 0) {
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
if (action.tags) {
|
|
131
|
-
logger_1.logger.info(`Tags: ${action.tags.join(', ')}`);
|
|
151
|
+
sectionHeader(`Acciones (${agentData.actions.length})`);
|
|
152
|
+
agentData.actions.forEach((act, i) => {
|
|
153
|
+
console.log(chalk_1.default.hex('#FFA726')(` ${i + 1}. ${act.intent || act.reference || 'Accion'}`));
|
|
154
|
+
label(' Referencia', act.reference);
|
|
155
|
+
label(' Habilitado', act.enabled ? 'Si' : 'No');
|
|
156
|
+
if (act.tags && act.tags.length > 0) {
|
|
157
|
+
label(' Tags', act.tags.join(', '));
|
|
132
158
|
}
|
|
133
|
-
|
|
134
|
-
if (action.action) {
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
159
|
+
label(' Respuesta', act.responseMessage);
|
|
160
|
+
if (act.action && act.action.length > 0) {
|
|
161
|
+
console.log(chalk_1.default.gray(' Sub-acciones:'));
|
|
162
|
+
act.action.forEach((sa) => {
|
|
163
|
+
console.log(chalk_1.default.white(` - ${sa.type}: ${sa.value || ''}`));
|
|
138
164
|
});
|
|
139
165
|
}
|
|
140
166
|
});
|
|
141
167
|
}
|
|
142
168
|
// Canales
|
|
143
169
|
if (agentData.channels && agentData.channels.length > 0) {
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
170
|
+
sectionHeader(`Canales (${agentData.channels.length})`);
|
|
171
|
+
agentData.channels.forEach((ch) => {
|
|
172
|
+
console.log(chalk_1.default.white(` ${chalk_1.default.hex('#22d3ee')(ch.channel || 'canal')}: ${ch.key || ''}`));
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
// AI Config
|
|
176
|
+
if (agentData.customAIConfig && agentData.aiProviders && agentData.aiProviders.length > 0) {
|
|
177
|
+
sectionHeader('Modelo IA');
|
|
178
|
+
agentData.aiProviders.forEach((ai) => {
|
|
179
|
+
label('Proveedor', ai.provider);
|
|
180
|
+
label('Modelo', ai.model);
|
|
148
181
|
});
|
|
149
182
|
}
|
|
150
|
-
|
|
183
|
+
console.log();
|
|
184
|
+
console.log(chalk_1.default.gray(' Usa --raw para ver el JSON completo'));
|
|
185
|
+
console.log();
|
|
151
186
|
if (options.dev) {
|
|
152
187
|
logger_1.logger.warning('Ambiente: desarrollo');
|
|
153
188
|
}
|
|
@@ -104,6 +104,7 @@ function printHeader(agentName) {
|
|
|
104
104
|
const COMMANDS_HELP = `
|
|
105
105
|
${chalk_1.default.bold('Comandos disponibles:')}
|
|
106
106
|
${chalk_1.default.hex('#4CAF50')('/filter <tipo>')} Toggle filtro por tipo (ej: msg_in, error, tool_call)
|
|
107
|
+
${chalk_1.default.hex('#4CAF50')('/filter clear')} Quitar todos los filtros
|
|
107
108
|
${chalk_1.default.hex('#4CAF50')('/filters')} Mostrar filtros activos
|
|
108
109
|
${chalk_1.default.hex('#4CAF50')('/clear')} Limpiar pantalla
|
|
109
110
|
${chalk_1.default.hex('#4CAF50')('/json')} Toggle modo JSON expandido
|
|
@@ -236,7 +237,12 @@ exports.monitorCommand = new commander_1.Command('monitor')
|
|
|
236
237
|
if (cmd.startsWith('/filter ')) {
|
|
237
238
|
const filterType = cmd.substring(8).trim();
|
|
238
239
|
if (!filterType) {
|
|
239
|
-
console.log(chalk_1.default.gray(' Uso: /filter <tipo>'));
|
|
240
|
+
console.log(chalk_1.default.gray(' Uso: /filter <tipo> | /filter clear'));
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
if (filterType === 'clear') {
|
|
244
|
+
activeFilters.clear();
|
|
245
|
+
console.log(chalk_1.default.gray(' Todos los filtros removidos (mostrando todos)'));
|
|
240
246
|
return;
|
|
241
247
|
}
|
|
242
248
|
if (activeFilters.has(filterType)) {
|
|
@@ -5,6 +5,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.runAgentWizard = runAgentWizard;
|
|
7
7
|
const inquirer_1 = __importDefault(require("inquirer"));
|
|
8
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
9
|
+
const axios_1 = __importDefault(require("axios"));
|
|
10
|
+
const ora_1 = __importDefault(require("ora"));
|
|
8
11
|
const ui_1 = require("../../utils/ui");
|
|
9
12
|
const MODELS = {
|
|
10
13
|
openai: ['gpt-4o', 'gpt-4', 'gpt-3.5-turbo', 'o1-preview', 'o1-mini'],
|
|
@@ -12,7 +15,157 @@ const MODELS = {
|
|
|
12
15
|
gemini: ['gemini-2.0-flash', 'gemini-1.5-pro', 'gemini-1.5-flash'],
|
|
13
16
|
};
|
|
14
17
|
const COLORS = ['blue', 'green', 'orange', 'gray', 'white'];
|
|
15
|
-
|
|
18
|
+
function getBaseUrl(zone, dev) {
|
|
19
|
+
if (dev)
|
|
20
|
+
return 'http://localhost:5090';
|
|
21
|
+
return zone === 'EU' ? 'https://apieu.plazbot.com' : 'https://api.plazbot.com';
|
|
22
|
+
}
|
|
23
|
+
const CHANNEL_CHOICES = [
|
|
24
|
+
{ name: 'WhatsApp', value: 'whatsapp' },
|
|
25
|
+
{ name: 'WhatsApp Business', value: 'whatsapp_business' },
|
|
26
|
+
{ name: 'Instagram', value: 'instagram' },
|
|
27
|
+
{ name: 'Messenger', value: 'facebook' },
|
|
28
|
+
];
|
|
29
|
+
const CHANNEL_AGENT_MAP = {
|
|
30
|
+
whatsapp: 'whatsapp',
|
|
31
|
+
whatsapp_business: 'whatsapp',
|
|
32
|
+
instagram: 'instagram',
|
|
33
|
+
facebook: 'facebook',
|
|
34
|
+
};
|
|
35
|
+
async function connectChannelFlow(ctx) {
|
|
36
|
+
const channels = [];
|
|
37
|
+
const baseUrl = getBaseUrl(ctx.zone, ctx.dev);
|
|
38
|
+
const headers = {
|
|
39
|
+
'Authorization': `Bearer ${ctx.apiKey}`,
|
|
40
|
+
'x-workspace-id': ctx.workspaceId,
|
|
41
|
+
'Content-Type': 'application/json',
|
|
42
|
+
};
|
|
43
|
+
let addMore = true;
|
|
44
|
+
while (addMore) {
|
|
45
|
+
const { channelType } = await inquirer_1.default.prompt([{
|
|
46
|
+
type: 'list',
|
|
47
|
+
name: 'channelType',
|
|
48
|
+
message: 'Que canal deseas conectar?',
|
|
49
|
+
choices: CHANNEL_CHOICES,
|
|
50
|
+
}]);
|
|
51
|
+
const channelLabel = CHANNEL_CHOICES.find(c => c.value === channelType)?.name || channelType;
|
|
52
|
+
// Generar link de onboarding
|
|
53
|
+
const spinner = (0, ora_1.default)({ text: chalk_1.default.gray('Generando link de conexion...'), spinner: 'dots', color: 'green' }).start();
|
|
54
|
+
try {
|
|
55
|
+
const linkRes = await axios_1.default.post(`${baseUrl}/api/workspace/${ctx.workspaceId}/onboarding-link`, { type: channelType }, { headers });
|
|
56
|
+
if (!linkRes.data?.success) {
|
|
57
|
+
spinner.fail(chalk_1.default.hex('#EF5350')(`Error: ${linkRes.data?.message || 'No se pudo generar el link'}`));
|
|
58
|
+
const { tryManual } = await inquirer_1.default.prompt([{
|
|
59
|
+
type: 'confirm', name: 'tryManual',
|
|
60
|
+
message: 'Deseas ingresar el numero manualmente?', default: false,
|
|
61
|
+
}]);
|
|
62
|
+
if (tryManual) {
|
|
63
|
+
const { key } = await inquirer_1.default.prompt([
|
|
64
|
+
{ type: 'input', name: 'key', message: `ID/numero del canal ${channelLabel}:`, validate: (v) => v.length > 0 || 'Requerido' },
|
|
65
|
+
]);
|
|
66
|
+
channels.push({ channel: CHANNEL_AGENT_MAP[channelType], key, multianswer: false });
|
|
67
|
+
}
|
|
68
|
+
const { more } = await inquirer_1.default.prompt([{ type: 'confirm', name: 'more', message: 'Conectar otro canal?', default: false }]);
|
|
69
|
+
addMore = more;
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
const shortUrl = linkRes.data.data?.shortUrl || '';
|
|
73
|
+
spinner.stop();
|
|
74
|
+
// Mostrar link en box visual
|
|
75
|
+
console.log();
|
|
76
|
+
console.log(chalk_1.default.hex('#4CAF50')(' ┌' + '─'.repeat(64) + '┐'));
|
|
77
|
+
console.log(chalk_1.default.hex('#4CAF50')(' │') + chalk_1.default.bold(` Envia este link para conectar ${channelLabel}:`).padEnd(74) + chalk_1.default.hex('#4CAF50')('│'));
|
|
78
|
+
console.log(chalk_1.default.hex('#4CAF50')(' │') + ' '.padEnd(64) + chalk_1.default.hex('#4CAF50')('│'));
|
|
79
|
+
console.log(chalk_1.default.hex('#4CAF50')(' │') + chalk_1.default.hex('#22d3ee')(` ${shortUrl}`).padEnd(74) + chalk_1.default.hex('#4CAF50')('│'));
|
|
80
|
+
console.log(chalk_1.default.hex('#4CAF50')(' │') + ' '.padEnd(64) + chalk_1.default.hex('#4CAF50')('│'));
|
|
81
|
+
console.log(chalk_1.default.hex('#4CAF50')(' └' + '─'.repeat(64) + '┘'));
|
|
82
|
+
console.log();
|
|
83
|
+
// Snapshot de integraciones actuales
|
|
84
|
+
let prevIntegrationIds = new Set();
|
|
85
|
+
try {
|
|
86
|
+
const wkRes = await axios_1.default.get(`${baseUrl}/api/workspace/${ctx.workspaceId}`, { headers });
|
|
87
|
+
const integrations = wkRes.data?.integrations || wkRes.data?.data?.integrations || [];
|
|
88
|
+
prevIntegrationIds = new Set(integrations.map((i) => i.id));
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
// Si falla, se parte de vacio
|
|
92
|
+
}
|
|
93
|
+
// Polling para detectar nueva integracion
|
|
94
|
+
const pollSpinner = (0, ora_1.default)({ text: chalk_1.default.gray('Esperando conexion... (Ctrl+C para cancelar)'), spinner: 'dots', color: 'cyan' }).start();
|
|
95
|
+
const POLL_INTERVAL = 5000;
|
|
96
|
+
const MAX_POLLS = 60; // 5 minutos
|
|
97
|
+
let detected = null;
|
|
98
|
+
for (let i = 0; i < MAX_POLLS; i++) {
|
|
99
|
+
await new Promise(r => setTimeout(r, POLL_INTERVAL));
|
|
100
|
+
try {
|
|
101
|
+
const wkRes = await axios_1.default.get(`${baseUrl}/api/workspace/${ctx.workspaceId}`, { headers });
|
|
102
|
+
const integrations = wkRes.data?.integrations || wkRes.data?.data?.integrations || [];
|
|
103
|
+
// Buscar integraciones nuevas del tipo correcto
|
|
104
|
+
const targetType = channelType === 'whatsapp_business' ? 'whatsapp' : channelType;
|
|
105
|
+
const newOnes = integrations.filter((ig) => !prevIntegrationIds.has(ig.id) && ig.type === targetType);
|
|
106
|
+
if (newOnes.length > 0) {
|
|
107
|
+
detected = newOnes[0];
|
|
108
|
+
break;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
catch {
|
|
112
|
+
// Ignorar errores de poll individual
|
|
113
|
+
}
|
|
114
|
+
const elapsed = Math.floor(((i + 1) * POLL_INTERVAL) / 1000);
|
|
115
|
+
pollSpinner.text = chalk_1.default.gray(`Esperando conexion... ${elapsed}s`);
|
|
116
|
+
}
|
|
117
|
+
if (detected) {
|
|
118
|
+
pollSpinner.succeed(chalk_1.default.hex('#4ade80')(`Conexion detectada: ${detected.aliasName || detected.id} (${channelLabel})`));
|
|
119
|
+
const { associate } = await inquirer_1.default.prompt([{
|
|
120
|
+
type: 'confirm', name: 'associate',
|
|
121
|
+
message: 'Deseas asociar este canal al agente?', default: true,
|
|
122
|
+
}]);
|
|
123
|
+
if (associate) {
|
|
124
|
+
channels.push({
|
|
125
|
+
channel: CHANNEL_AGENT_MAP[channelType],
|
|
126
|
+
key: detected.id,
|
|
127
|
+
multianswer: false,
|
|
128
|
+
});
|
|
129
|
+
console.log(chalk_1.default.hex('#4ade80')(' Canal asociado correctamente.'));
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
pollSpinner.warn(chalk_1.default.hex('#FFA726')('Timeout: no se detecto una conexion.'));
|
|
134
|
+
const { action } = await inquirer_1.default.prompt([{
|
|
135
|
+
type: 'list', name: 'action',
|
|
136
|
+
message: 'Que deseas hacer?',
|
|
137
|
+
choices: [
|
|
138
|
+
{ name: 'Ingresar numero/ID manualmente', value: 'manual' },
|
|
139
|
+
{ name: 'Saltar este paso', value: 'skip' },
|
|
140
|
+
],
|
|
141
|
+
}]);
|
|
142
|
+
if (action === 'manual') {
|
|
143
|
+
const { key } = await inquirer_1.default.prompt([
|
|
144
|
+
{ type: 'input', name: 'key', message: `ID/numero del canal ${channelLabel}:`, validate: (v) => v.length > 0 || 'Requerido' },
|
|
145
|
+
]);
|
|
146
|
+
channels.push({ channel: CHANNEL_AGENT_MAP[channelType], key, multianswer: false });
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
catch (err) {
|
|
151
|
+
spinner.fail(chalk_1.default.hex('#EF5350')(`Error al generar link: ${err instanceof Error ? err.message : err}`));
|
|
152
|
+
const { tryManual } = await inquirer_1.default.prompt([{
|
|
153
|
+
type: 'confirm', name: 'tryManual',
|
|
154
|
+
message: 'Deseas ingresar el numero manualmente?', default: false,
|
|
155
|
+
}]);
|
|
156
|
+
if (tryManual) {
|
|
157
|
+
const { key } = await inquirer_1.default.prompt([
|
|
158
|
+
{ type: 'input', name: 'key', message: `ID/numero del canal ${channelLabel}:`, validate: (v) => v.length > 0 || 'Requerido' },
|
|
159
|
+
]);
|
|
160
|
+
channels.push({ channel: CHANNEL_AGENT_MAP[channelType], key, multianswer: false });
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
const { more } = await inquirer_1.default.prompt([{ type: 'confirm', name: 'more', message: 'Conectar otro canal?', default: false }]);
|
|
164
|
+
addMore = more;
|
|
165
|
+
}
|
|
166
|
+
return channels;
|
|
167
|
+
}
|
|
168
|
+
async function runAgentWizard(zone, workspaceId, apiKey, dev) {
|
|
16
169
|
console.log((0, ui_1.section)('Crear nuevo agente de IA'));
|
|
17
170
|
console.log(ui_1.theme.muted(' Responde las siguientes preguntas para configurar tu agente.\n'));
|
|
18
171
|
// Paso 1: Informacion basica
|
|
@@ -283,16 +436,20 @@ async function runAgentWizard(zone) {
|
|
|
283
436
|
isDefault: true,
|
|
284
437
|
});
|
|
285
438
|
}
|
|
286
|
-
// Paso 7:
|
|
287
|
-
console.log(ui_1.theme.bold('\n Paso 7/8:
|
|
288
|
-
|
|
289
|
-
const {
|
|
439
|
+
// Paso 7: Conectar canal
|
|
440
|
+
console.log(ui_1.theme.bold('\n Paso 7/8: Conectar canal'));
|
|
441
|
+
let channels = [];
|
|
442
|
+
const { addChannel } = await inquirer_1.default.prompt([{
|
|
290
443
|
type: 'confirm',
|
|
291
|
-
name: '
|
|
292
|
-
message: '
|
|
444
|
+
name: 'addChannel',
|
|
445
|
+
message: 'Deseas conectar un canal (WhatsApp, Instagram, Messenger)?',
|
|
293
446
|
default: false,
|
|
294
447
|
}]);
|
|
295
|
-
if (
|
|
448
|
+
if (addChannel && workspaceId && apiKey) {
|
|
449
|
+
channels = await connectChannelFlow({ zone, workspaceId, apiKey, dev: dev || false });
|
|
450
|
+
}
|
|
451
|
+
else if (addChannel) {
|
|
452
|
+
// Fallback manual si no hay credenciales para API
|
|
296
453
|
const wa = await inquirer_1.default.prompt([
|
|
297
454
|
{ type: 'input', name: 'key', message: 'Numero de WhatsApp (con codigo de pais):', validate: (v) => v.length > 0 || 'Requerido' },
|
|
298
455
|
{ type: 'confirm', name: 'multianswer', message: 'Permitir multiples respuestas?', default: false },
|
|
@@ -363,7 +520,14 @@ async function runAgentWizard(zone) {
|
|
|
363
520
|
console.log((0, ui_1.kvPair)('Servicios', String(config.services.length)));
|
|
364
521
|
console.log((0, ui_1.kvPair)('Acciones', String(config.actions.length)));
|
|
365
522
|
console.log((0, ui_1.kvPair)('AI Provider', config.customAIConfig ? config.aiProviders[0]?.provider + ' / ' + config.aiProviders[0]?.model : 'Default (Plazbot)'));
|
|
366
|
-
|
|
523
|
+
if (config.channels.length > 0) {
|
|
524
|
+
config.channels.forEach((ch, i) => {
|
|
525
|
+
console.log((0, ui_1.kvPair)(`Canal ${i + 1} (${ch.channel})`, ch.key));
|
|
526
|
+
});
|
|
527
|
+
}
|
|
528
|
+
else {
|
|
529
|
+
console.log((0, ui_1.kvPair)('Canales', 'No configurado'));
|
|
530
|
+
}
|
|
367
531
|
console.log();
|
|
368
532
|
return config;
|
|
369
533
|
}
|
package/package.json
CHANGED
|
@@ -37,7 +37,7 @@ export const createCommand = new Command('create')
|
|
|
37
37
|
logger.json(agentConfig);
|
|
38
38
|
} else {
|
|
39
39
|
// Modo wizard interactivo
|
|
40
|
-
agentConfig = await runAgentWizard(credentials.zone);
|
|
40
|
+
agentConfig = await runAgentWizard(credentials.zone, credentials.workspace, credentials.apiKey, options.dev);
|
|
41
41
|
|
|
42
42
|
const inquirer = await import('inquirer');
|
|
43
43
|
const { confirm } = await inquirer.default.prompt([{
|
|
@@ -70,7 +70,9 @@ export const createCommand = new Command('create')
|
|
|
70
70
|
logger.label('Tool Calling', agentConfig.useToolCalling ? 'Activado' : 'Desactivado');
|
|
71
71
|
|
|
72
72
|
if (agentConfig.channels && agentConfig.channels.length > 0) {
|
|
73
|
-
|
|
73
|
+
agentConfig.channels.forEach((ch: any) => {
|
|
74
|
+
logger.label(`Canal (${ch.channel})`, ch.key);
|
|
75
|
+
});
|
|
74
76
|
}
|
|
75
77
|
|
|
76
78
|
console.log();
|
|
@@ -3,127 +3,158 @@ import { Agent } from 'plazbot';
|
|
|
3
3
|
import { getStoredCredentials } from '../../utils/credentials';
|
|
4
4
|
import { logger } from '../../utils/logger';
|
|
5
5
|
import { AgentCommandOptions } from '../../types/agent';
|
|
6
|
+
import chalk from 'chalk';
|
|
6
7
|
|
|
7
8
|
export const getCommand = new Command('get')
|
|
8
9
|
.description('Obtiene información detallada de un agente específico')
|
|
9
10
|
.argument('<agentId>', 'ID del agente a consultar')
|
|
11
|
+
.option('-w, --workspace <id>', 'Workspace ID (sobreescribe config local)')
|
|
12
|
+
.option('-z, --zone <zone>', 'Zona LA o EU (sobreescribe config local)')
|
|
13
|
+
.option('--raw', 'Mostrar el JSON completo sin formatear', false)
|
|
10
14
|
.option('--dev', 'Usar ambiente de desarrollo', false)
|
|
11
|
-
.action(async (agentId: string, options: AgentCommandOptions) => {
|
|
15
|
+
.action(async (agentId: string, options: AgentCommandOptions & { raw: boolean; workspace?: string; zone?: string }) => {
|
|
12
16
|
try {
|
|
13
|
-
// Obtener credenciales guardadas
|
|
14
17
|
const credentials = await getStoredCredentials();
|
|
15
|
-
|
|
16
|
-
|
|
18
|
+
|
|
19
|
+
const effectiveWorkspace = options.workspace || credentials.workspace;
|
|
20
|
+
const effectiveZone = (options.zone?.toUpperCase() === 'EU' ? 'EU' : options.zone?.toUpperCase() === 'LA' ? 'LA' : credentials.zone) as 'LA' | 'EU';
|
|
21
|
+
|
|
22
|
+
if (options.workspace || options.zone) {
|
|
23
|
+
console.log(chalk.hex('#FFA726')(`\n Modo soporte: workspace=${effectiveWorkspace} zona=${effectiveZone}`));
|
|
24
|
+
}
|
|
25
|
+
|
|
17
26
|
const agent = new Agent({
|
|
18
|
-
workspaceId:
|
|
27
|
+
workspaceId: effectiveWorkspace,
|
|
19
28
|
apiKey: credentials.apiKey,
|
|
20
|
-
zone:
|
|
29
|
+
zone: effectiveZone,
|
|
21
30
|
...(options.dev && { customUrl: "http://localhost:5090" })
|
|
22
31
|
});
|
|
23
32
|
|
|
24
|
-
//
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
33
|
+
// El SDK retorna { success, agent: {...} }
|
|
34
|
+
const response: any = await agent.getAgentById({ id: agentId });
|
|
35
|
+
const agentData = response.agent || response.data || response;
|
|
36
|
+
|
|
37
|
+
// Modo JSON crudo
|
|
38
|
+
if (options.raw) {
|
|
39
|
+
console.log(JSON.stringify(agentData, null, 2));
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const label = (key: string, value: any) => {
|
|
44
|
+
const v = value !== undefined && value !== null && value !== '' ? String(value) : chalk.gray('—');
|
|
45
|
+
console.log(` ${chalk.gray(key + ':')} ${chalk.white(v)}`);
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const sectionHeader = (title: string) => {
|
|
49
|
+
console.log();
|
|
50
|
+
console.log(chalk.bold.hex('#4CAF50')(` ${title}`));
|
|
51
|
+
console.log(chalk.gray(' ' + '─'.repeat(40)));
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
console.log();
|
|
55
|
+
console.log(chalk.hex('#4CAF50')(' ┌' + '─'.repeat(58) + '┐'));
|
|
56
|
+
console.log(chalk.hex('#4CAF50')(' │') + chalk.bold(` ${agentData.name || 'Agente'}`).padEnd(68) + chalk.hex('#4CAF50')('│'));
|
|
57
|
+
console.log(chalk.hex('#4CAF50')(' │') + chalk.gray(` ${agentId}`).padEnd(68) + chalk.hex('#4CAF50')('│'));
|
|
58
|
+
console.log(chalk.hex('#4CAF50')(' └' + '─'.repeat(58) + '┘'));
|
|
59
|
+
|
|
60
|
+
// Informacion basica
|
|
61
|
+
sectionHeader('Informacion Basica');
|
|
62
|
+
label('ID', agentData.id);
|
|
63
|
+
label('Nombre', agentData.name);
|
|
64
|
+
label('Descripcion', agentData.description);
|
|
65
|
+
label('Estado', agentData.enable ? chalk.hex('#66BB6A')('Activo') : chalk.hex('#EF5350')('Inactivo'));
|
|
66
|
+
label('Zona', agentData.zone);
|
|
67
|
+
label('Buffer', agentData.buffer);
|
|
68
|
+
label('Color', agentData.color);
|
|
69
|
+
label('Pregunta inicial', agentData.question);
|
|
70
|
+
label('Zona horaria', agentData.timezone);
|
|
71
|
+
label('Mostrar en chat', agentData.showInChat ? 'Si' : 'No');
|
|
72
|
+
label('Tool Calling', agentData.useToolCalling ? 'Activado' : 'Desactivado');
|
|
73
|
+
|
|
44
74
|
// Tags
|
|
45
75
|
if (agentData.tags && agentData.tags.length > 0) {
|
|
46
|
-
|
|
76
|
+
label('Tags', agentData.tags.join(', '));
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Prompt
|
|
80
|
+
if (agentData.prompt) {
|
|
81
|
+
sectionHeader('Prompt');
|
|
82
|
+
const promptPreview = agentData.prompt.length > 200
|
|
83
|
+
? agentData.prompt.substring(0, 200) + '...'
|
|
84
|
+
: agentData.prompt;
|
|
85
|
+
console.log(chalk.white(' ' + promptPreview.split('\n').join('\n ')));
|
|
47
86
|
}
|
|
48
87
|
|
|
49
88
|
// Ejemplos
|
|
50
89
|
if (agentData.examples && agentData.examples.length > 0) {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
logger.info(`- ${example.value} (${example.color})`);
|
|
90
|
+
sectionHeader('Ejemplos');
|
|
91
|
+
agentData.examples.forEach((example: any) => {
|
|
92
|
+
console.log(chalk.white(` - ${example.value || example}`));
|
|
55
93
|
});
|
|
56
94
|
}
|
|
57
95
|
|
|
58
96
|
// Instrucciones
|
|
59
97
|
if (agentData.instructions) {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
logger.info(`Temas a evitar: ${instructions.avoidTopics.join(', ')}`);
|
|
98
|
+
sectionHeader('Instrucciones');
|
|
99
|
+
const inst = agentData.instructions;
|
|
100
|
+
label('Tono', inst.tone);
|
|
101
|
+
label('Estilo', inst.style);
|
|
102
|
+
label('Personalidad', inst.personality);
|
|
103
|
+
label('Objetivo', inst.objective);
|
|
104
|
+
label('Idioma', inst.language);
|
|
105
|
+
label('Emojis', inst.emojis ? 'Si' : 'No');
|
|
106
|
+
label('Formato preferido', inst.preferredFormat);
|
|
107
|
+
label('Max palabras', inst.maxWords);
|
|
108
|
+
if (inst.avoidTopics && inst.avoidTopics.length > 0) {
|
|
109
|
+
label('Temas a evitar', inst.avoidTopics.join(', '));
|
|
73
110
|
}
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
logger.info(`Saludo: ${instructions.greeting}`);
|
|
111
|
+
label('Solo responder si sabe', inst.respondOnlyIfKnows ? 'Si' : 'No');
|
|
112
|
+
label('Saludo', inst.greeting);
|
|
77
113
|
}
|
|
78
114
|
|
|
79
115
|
// Persona
|
|
80
116
|
if (agentData.person) {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
logger.info(`Es humano: ${person.isHuman ? 'Sí' : 'No'}`);
|
|
117
|
+
sectionHeader('Persona');
|
|
118
|
+
const p = agentData.person;
|
|
119
|
+
label('Nombre', p.name);
|
|
120
|
+
label('Rol', p.role);
|
|
121
|
+
label('Primera persona', p.speaksInFirstPerson ? 'Si' : 'No');
|
|
122
|
+
label('Es humano', p.isHuman ? 'Si' : 'No');
|
|
88
123
|
}
|
|
89
124
|
|
|
90
125
|
// Fallbacks
|
|
91
126
|
if (agentData.fallbacks) {
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
logger.info(`No entiende: ${fallbacks.doNotUnderstand}`);
|
|
127
|
+
sectionHeader('Fallbacks');
|
|
128
|
+
const fb = agentData.fallbacks;
|
|
129
|
+
label('Sin respuesta', fb.noAnswer);
|
|
130
|
+
label('Error de servicio', fb.serviceError);
|
|
131
|
+
label('No entiende', fb.doNotUnderstand);
|
|
98
132
|
}
|
|
99
133
|
|
|
100
134
|
// Reglas
|
|
101
135
|
if (agentData.rules) {
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
logger.info(`Horario de atención: ${rules.doNotRespondOutsideHours}`);
|
|
136
|
+
sectionHeader('Reglas');
|
|
137
|
+
const r = agentData.rules;
|
|
138
|
+
label('No mencionar precios', r.doNotMentionPrices ? 'Si' : 'No');
|
|
139
|
+
label('No diagnosticar', r.doNotDiagnose ? 'Si' : 'No');
|
|
140
|
+
if (r.doNotRespondOutsideHours) {
|
|
141
|
+
label('Fuera de horario', r.doNotRespondOutsideHours);
|
|
109
142
|
}
|
|
110
143
|
}
|
|
111
144
|
|
|
112
145
|
// Servicios
|
|
113
146
|
if (agentData.services && agentData.services.length > 0) {
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
service.requiredFields.forEach((field: any) => {
|
|
126
|
-
logger.info(` - ${field.name} (${field.type}): ${field.description}`);
|
|
147
|
+
sectionHeader(`Servicios (${agentData.services.length})`);
|
|
148
|
+
agentData.services.forEach((svc: any, i: number) => {
|
|
149
|
+
console.log(chalk.hex('#2196F3')(` ${i + 1}. ${svc.intent || svc.reference || 'Servicio'}`));
|
|
150
|
+
label(' Referencia', svc.reference);
|
|
151
|
+
label(' Habilitado', svc.enabled ? 'Si' : 'No');
|
|
152
|
+
label(' Metodo', svc.method);
|
|
153
|
+
label(' Endpoint', svc.endpoint);
|
|
154
|
+
if (svc.requiredFields && svc.requiredFields.length > 0) {
|
|
155
|
+
console.log(chalk.gray(' Campos:'));
|
|
156
|
+
svc.requiredFields.forEach((f: any) => {
|
|
157
|
+
console.log(chalk.white(` - ${f.name} (${f.type}): ${f.description || ''}`));
|
|
127
158
|
});
|
|
128
159
|
}
|
|
129
160
|
});
|
|
@@ -131,21 +162,19 @@ export const getCommand = new Command('get')
|
|
|
131
162
|
|
|
132
163
|
// Acciones
|
|
133
164
|
if (agentData.actions && agentData.actions.length > 0) {
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
if (action.tags) {
|
|
142
|
-
logger.info(`Tags: ${action.tags.join(', ')}`);
|
|
165
|
+
sectionHeader(`Acciones (${agentData.actions.length})`);
|
|
166
|
+
agentData.actions.forEach((act: any, i: number) => {
|
|
167
|
+
console.log(chalk.hex('#FFA726')(` ${i + 1}. ${act.intent || act.reference || 'Accion'}`));
|
|
168
|
+
label(' Referencia', act.reference);
|
|
169
|
+
label(' Habilitado', act.enabled ? 'Si' : 'No');
|
|
170
|
+
if (act.tags && act.tags.length > 0) {
|
|
171
|
+
label(' Tags', act.tags.join(', '));
|
|
143
172
|
}
|
|
144
|
-
|
|
145
|
-
if (action.action) {
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
173
|
+
label(' Respuesta', act.responseMessage);
|
|
174
|
+
if (act.action && act.action.length > 0) {
|
|
175
|
+
console.log(chalk.gray(' Sub-acciones:'));
|
|
176
|
+
act.action.forEach((sa: any) => {
|
|
177
|
+
console.log(chalk.white(` - ${sa.type}: ${sa.value || ''}`));
|
|
149
178
|
});
|
|
150
179
|
}
|
|
151
180
|
});
|
|
@@ -153,19 +182,29 @@ export const getCommand = new Command('get')
|
|
|
153
182
|
|
|
154
183
|
// Canales
|
|
155
184
|
if (agentData.channels && agentData.channels.length > 0) {
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
logger.info(`${channel.channel}: ${channel.key}`);
|
|
185
|
+
sectionHeader(`Canales (${agentData.channels.length})`);
|
|
186
|
+
agentData.channels.forEach((ch: any) => {
|
|
187
|
+
console.log(chalk.white(` ${chalk.hex('#22d3ee')(ch.channel || 'canal')}: ${ch.key || ''}`));
|
|
160
188
|
});
|
|
161
189
|
}
|
|
162
190
|
|
|
163
|
-
|
|
164
|
-
|
|
191
|
+
// AI Config
|
|
192
|
+
if (agentData.customAIConfig && agentData.aiProviders && agentData.aiProviders.length > 0) {
|
|
193
|
+
sectionHeader('Modelo IA');
|
|
194
|
+
agentData.aiProviders.forEach((ai: any) => {
|
|
195
|
+
label('Proveedor', ai.provider);
|
|
196
|
+
label('Modelo', ai.model);
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
console.log();
|
|
201
|
+
console.log(chalk.gray(' Usa --raw para ver el JSON completo'));
|
|
202
|
+
console.log();
|
|
203
|
+
|
|
165
204
|
if (options.dev) {
|
|
166
205
|
logger.warning('Ambiente: desarrollo');
|
|
167
206
|
}
|
|
168
|
-
|
|
207
|
+
|
|
169
208
|
} catch (error) {
|
|
170
209
|
const message = error instanceof Error ? error.message : 'Error desconocido al obtener el agente';
|
|
171
210
|
logger.error(message);
|
|
@@ -135,6 +135,7 @@ function printHeader(agentName: string) {
|
|
|
135
135
|
const COMMANDS_HELP = `
|
|
136
136
|
${chalk.bold('Comandos disponibles:')}
|
|
137
137
|
${chalk.hex('#4CAF50')('/filter <tipo>')} Toggle filtro por tipo (ej: msg_in, error, tool_call)
|
|
138
|
+
${chalk.hex('#4CAF50')('/filter clear')} Quitar todos los filtros
|
|
138
139
|
${chalk.hex('#4CAF50')('/filters')} Mostrar filtros activos
|
|
139
140
|
${chalk.hex('#4CAF50')('/clear')} Limpiar pantalla
|
|
140
141
|
${chalk.hex('#4CAF50')('/json')} Toggle modo JSON expandido
|
|
@@ -291,7 +292,12 @@ export const monitorCommand = new Command('monitor')
|
|
|
291
292
|
if (cmd.startsWith('/filter ')) {
|
|
292
293
|
const filterType = cmd.substring(8).trim();
|
|
293
294
|
if (!filterType) {
|
|
294
|
-
console.log(chalk.gray(' Uso: /filter <tipo>'));
|
|
295
|
+
console.log(chalk.gray(' Uso: /filter <tipo> | /filter clear'));
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
if (filterType === 'clear') {
|
|
299
|
+
activeFilters.clear();
|
|
300
|
+
console.log(chalk.gray(' Todos los filtros removidos (mostrando todos)'));
|
|
295
301
|
return;
|
|
296
302
|
}
|
|
297
303
|
if (activeFilters.has(filterType)) {
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import inquirer from 'inquirer';
|
|
2
2
|
import chalk from 'chalk';
|
|
3
|
+
import axios from 'axios';
|
|
4
|
+
import ora from 'ora';
|
|
3
5
|
import { theme, section, kvPair } from '../../utils/ui';
|
|
4
6
|
|
|
5
7
|
interface AgentConfig {
|
|
@@ -94,7 +96,187 @@ const MODELS: Record<string, string[]> = {
|
|
|
94
96
|
|
|
95
97
|
const COLORS = ['blue', 'green', 'orange', 'gray', 'white'];
|
|
96
98
|
|
|
97
|
-
|
|
99
|
+
interface WizardContext {
|
|
100
|
+
zone: string;
|
|
101
|
+
workspaceId: string;
|
|
102
|
+
apiKey: string;
|
|
103
|
+
dev: boolean;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function getBaseUrl(zone: string, dev: boolean): string {
|
|
107
|
+
if (dev) return 'http://localhost:5090';
|
|
108
|
+
return zone === 'EU' ? 'https://apieu.plazbot.com' : 'https://api.plazbot.com';
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const CHANNEL_CHOICES = [
|
|
112
|
+
{ name: 'WhatsApp', value: 'whatsapp' },
|
|
113
|
+
{ name: 'WhatsApp Business', value: 'whatsapp_business' },
|
|
114
|
+
{ name: 'Instagram', value: 'instagram' },
|
|
115
|
+
{ name: 'Messenger', value: 'facebook' },
|
|
116
|
+
];
|
|
117
|
+
|
|
118
|
+
const CHANNEL_AGENT_MAP: Record<string, string> = {
|
|
119
|
+
whatsapp: 'whatsapp',
|
|
120
|
+
whatsapp_business: 'whatsapp',
|
|
121
|
+
instagram: 'instagram',
|
|
122
|
+
facebook: 'facebook',
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
async function connectChannelFlow(ctx: WizardContext): Promise<AgentChannel[]> {
|
|
126
|
+
const channels: AgentChannel[] = [];
|
|
127
|
+
const baseUrl = getBaseUrl(ctx.zone, ctx.dev);
|
|
128
|
+
const headers = {
|
|
129
|
+
'Authorization': `Bearer ${ctx.apiKey}`,
|
|
130
|
+
'x-workspace-id': ctx.workspaceId,
|
|
131
|
+
'Content-Type': 'application/json',
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
let addMore = true;
|
|
135
|
+
while (addMore) {
|
|
136
|
+
const { channelType } = await (inquirer as any).prompt([{
|
|
137
|
+
type: 'list',
|
|
138
|
+
name: 'channelType',
|
|
139
|
+
message: 'Que canal deseas conectar?',
|
|
140
|
+
choices: CHANNEL_CHOICES,
|
|
141
|
+
}]);
|
|
142
|
+
|
|
143
|
+
const channelLabel = CHANNEL_CHOICES.find(c => c.value === channelType)?.name || channelType;
|
|
144
|
+
|
|
145
|
+
// Generar link de onboarding
|
|
146
|
+
const spinner = ora({ text: chalk.gray('Generando link de conexion...'), spinner: 'dots', color: 'green' }).start();
|
|
147
|
+
|
|
148
|
+
try {
|
|
149
|
+
const linkRes = await axios.post(
|
|
150
|
+
`${baseUrl}/api/workspace/${ctx.workspaceId}/onboarding-link`,
|
|
151
|
+
{ type: channelType },
|
|
152
|
+
{ headers }
|
|
153
|
+
);
|
|
154
|
+
|
|
155
|
+
if (!linkRes.data?.success) {
|
|
156
|
+
spinner.fail(chalk.hex('#EF5350')(`Error: ${linkRes.data?.message || 'No se pudo generar el link'}`));
|
|
157
|
+
const { tryManual } = await (inquirer as any).prompt([{
|
|
158
|
+
type: 'confirm', name: 'tryManual',
|
|
159
|
+
message: 'Deseas ingresar el numero manualmente?', default: false,
|
|
160
|
+
}]);
|
|
161
|
+
if (tryManual) {
|
|
162
|
+
const { key } = await (inquirer as any).prompt([
|
|
163
|
+
{ type: 'input', name: 'key', message: `ID/numero del canal ${channelLabel}:`, validate: (v: string) => v.length > 0 || 'Requerido' },
|
|
164
|
+
]);
|
|
165
|
+
channels.push({ channel: CHANNEL_AGENT_MAP[channelType], key, multianswer: false });
|
|
166
|
+
}
|
|
167
|
+
const { more } = await (inquirer as any).prompt([{ type: 'confirm', name: 'more', message: 'Conectar otro canal?', default: false }]);
|
|
168
|
+
addMore = more;
|
|
169
|
+
continue;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
const shortUrl = linkRes.data.data?.shortUrl || '';
|
|
173
|
+
spinner.stop();
|
|
174
|
+
|
|
175
|
+
// Mostrar link en box visual
|
|
176
|
+
console.log();
|
|
177
|
+
console.log(chalk.hex('#4CAF50')(' ┌' + '─'.repeat(64) + '┐'));
|
|
178
|
+
console.log(chalk.hex('#4CAF50')(' │') + chalk.bold(` Envia este link para conectar ${channelLabel}:`).padEnd(74) + chalk.hex('#4CAF50')('│'));
|
|
179
|
+
console.log(chalk.hex('#4CAF50')(' │') + ' '.padEnd(64) + chalk.hex('#4CAF50')('│'));
|
|
180
|
+
console.log(chalk.hex('#4CAF50')(' │') + chalk.hex('#22d3ee')(` ${shortUrl}`).padEnd(74) + chalk.hex('#4CAF50')('│'));
|
|
181
|
+
console.log(chalk.hex('#4CAF50')(' │') + ' '.padEnd(64) + chalk.hex('#4CAF50')('│'));
|
|
182
|
+
console.log(chalk.hex('#4CAF50')(' └' + '─'.repeat(64) + '┘'));
|
|
183
|
+
console.log();
|
|
184
|
+
|
|
185
|
+
// Snapshot de integraciones actuales
|
|
186
|
+
let prevIntegrationIds: Set<string> = new Set();
|
|
187
|
+
try {
|
|
188
|
+
const wkRes = await axios.get(`${baseUrl}/api/workspace/${ctx.workspaceId}`, { headers });
|
|
189
|
+
const integrations = wkRes.data?.integrations || wkRes.data?.data?.integrations || [];
|
|
190
|
+
prevIntegrationIds = new Set(integrations.map((i: any) => i.id));
|
|
191
|
+
} catch {
|
|
192
|
+
// Si falla, se parte de vacio
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Polling para detectar nueva integracion
|
|
196
|
+
const pollSpinner = ora({ text: chalk.gray('Esperando conexion... (Ctrl+C para cancelar)'), spinner: 'dots', color: 'cyan' }).start();
|
|
197
|
+
const POLL_INTERVAL = 5000;
|
|
198
|
+
const MAX_POLLS = 60; // 5 minutos
|
|
199
|
+
let detected: any = null;
|
|
200
|
+
|
|
201
|
+
for (let i = 0; i < MAX_POLLS; i++) {
|
|
202
|
+
await new Promise(r => setTimeout(r, POLL_INTERVAL));
|
|
203
|
+
try {
|
|
204
|
+
const wkRes = await axios.get(`${baseUrl}/api/workspace/${ctx.workspaceId}`, { headers });
|
|
205
|
+
const integrations = wkRes.data?.integrations || wkRes.data?.data?.integrations || [];
|
|
206
|
+
|
|
207
|
+
// Buscar integraciones nuevas del tipo correcto
|
|
208
|
+
const targetType = channelType === 'whatsapp_business' ? 'whatsapp' : channelType;
|
|
209
|
+
const newOnes = integrations.filter((ig: any) =>
|
|
210
|
+
!prevIntegrationIds.has(ig.id) && ig.type === targetType
|
|
211
|
+
);
|
|
212
|
+
|
|
213
|
+
if (newOnes.length > 0) {
|
|
214
|
+
detected = newOnes[0];
|
|
215
|
+
break;
|
|
216
|
+
}
|
|
217
|
+
} catch {
|
|
218
|
+
// Ignorar errores de poll individual
|
|
219
|
+
}
|
|
220
|
+
const elapsed = Math.floor(((i + 1) * POLL_INTERVAL) / 1000);
|
|
221
|
+
pollSpinner.text = chalk.gray(`Esperando conexion... ${elapsed}s`);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
if (detected) {
|
|
225
|
+
pollSpinner.succeed(chalk.hex('#4ade80')(`Conexion detectada: ${detected.aliasName || detected.id} (${channelLabel})`));
|
|
226
|
+
|
|
227
|
+
const { associate } = await (inquirer as any).prompt([{
|
|
228
|
+
type: 'confirm', name: 'associate',
|
|
229
|
+
message: 'Deseas asociar este canal al agente?', default: true,
|
|
230
|
+
}]);
|
|
231
|
+
|
|
232
|
+
if (associate) {
|
|
233
|
+
channels.push({
|
|
234
|
+
channel: CHANNEL_AGENT_MAP[channelType],
|
|
235
|
+
key: detected.id,
|
|
236
|
+
multianswer: false,
|
|
237
|
+
});
|
|
238
|
+
console.log(chalk.hex('#4ade80')(' Canal asociado correctamente.'));
|
|
239
|
+
}
|
|
240
|
+
} else {
|
|
241
|
+
pollSpinner.warn(chalk.hex('#FFA726')('Timeout: no se detecto una conexion.'));
|
|
242
|
+
const { action } = await (inquirer as any).prompt([{
|
|
243
|
+
type: 'list', name: 'action',
|
|
244
|
+
message: 'Que deseas hacer?',
|
|
245
|
+
choices: [
|
|
246
|
+
{ name: 'Ingresar numero/ID manualmente', value: 'manual' },
|
|
247
|
+
{ name: 'Saltar este paso', value: 'skip' },
|
|
248
|
+
],
|
|
249
|
+
}]);
|
|
250
|
+
if (action === 'manual') {
|
|
251
|
+
const { key } = await (inquirer as any).prompt([
|
|
252
|
+
{ type: 'input', name: 'key', message: `ID/numero del canal ${channelLabel}:`, validate: (v: string) => v.length > 0 || 'Requerido' },
|
|
253
|
+
]);
|
|
254
|
+
channels.push({ channel: CHANNEL_AGENT_MAP[channelType], key, multianswer: false });
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
} catch (err) {
|
|
259
|
+
spinner.fail(chalk.hex('#EF5350')(`Error al generar link: ${err instanceof Error ? err.message : err}`));
|
|
260
|
+
const { tryManual } = await (inquirer as any).prompt([{
|
|
261
|
+
type: 'confirm', name: 'tryManual',
|
|
262
|
+
message: 'Deseas ingresar el numero manualmente?', default: false,
|
|
263
|
+
}]);
|
|
264
|
+
if (tryManual) {
|
|
265
|
+
const { key } = await (inquirer as any).prompt([
|
|
266
|
+
{ type: 'input', name: 'key', message: `ID/numero del canal ${channelLabel}:`, validate: (v: string) => v.length > 0 || 'Requerido' },
|
|
267
|
+
]);
|
|
268
|
+
channels.push({ channel: CHANNEL_AGENT_MAP[channelType], key, multianswer: false });
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
const { more } = await (inquirer as any).prompt([{ type: 'confirm', name: 'more', message: 'Conectar otro canal?', default: false }]);
|
|
273
|
+
addMore = more;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
return channels;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
export async function runAgentWizard(zone: string, workspaceId?: string, apiKey?: string, dev?: boolean): Promise<AgentConfig> {
|
|
98
280
|
console.log(section('Crear nuevo agente de IA'));
|
|
99
281
|
console.log(theme.muted(' Responde las siguientes preguntas para configurar tu agente.\n'));
|
|
100
282
|
|
|
@@ -383,17 +565,20 @@ export async function runAgentWizard(zone: string): Promise<AgentConfig> {
|
|
|
383
565
|
});
|
|
384
566
|
}
|
|
385
567
|
|
|
386
|
-
// Paso 7:
|
|
387
|
-
console.log(theme.bold('\n Paso 7/8:
|
|
388
|
-
|
|
389
|
-
const {
|
|
568
|
+
// Paso 7: Conectar canal
|
|
569
|
+
console.log(theme.bold('\n Paso 7/8: Conectar canal'));
|
|
570
|
+
let channels: AgentChannel[] = [];
|
|
571
|
+
const { addChannel } = await (inquirer as any).prompt([{
|
|
390
572
|
type: 'confirm',
|
|
391
|
-
name: '
|
|
392
|
-
message: '
|
|
573
|
+
name: 'addChannel',
|
|
574
|
+
message: 'Deseas conectar un canal (WhatsApp, Instagram, Messenger)?',
|
|
393
575
|
default: false,
|
|
394
576
|
}]);
|
|
395
577
|
|
|
396
|
-
if (
|
|
578
|
+
if (addChannel && workspaceId && apiKey) {
|
|
579
|
+
channels = await connectChannelFlow({ zone, workspaceId, apiKey, dev: dev || false });
|
|
580
|
+
} else if (addChannel) {
|
|
581
|
+
// Fallback manual si no hay credenciales para API
|
|
397
582
|
const wa = await (inquirer as any).prompt([
|
|
398
583
|
{ type: 'input', name: 'key', message: 'Numero de WhatsApp (con codigo de pais):', validate: (v: string) => v.length > 0 || 'Requerido' },
|
|
399
584
|
{ type: 'confirm', name: 'multianswer', message: 'Permitir multiples respuestas?', default: false },
|
|
@@ -468,7 +653,13 @@ export async function runAgentWizard(zone: string): Promise<AgentConfig> {
|
|
|
468
653
|
console.log(kvPair('Servicios', String(config.services.length)));
|
|
469
654
|
console.log(kvPair('Acciones', String(config.actions.length)));
|
|
470
655
|
console.log(kvPair('AI Provider', config.customAIConfig ? config.aiProviders[0]?.provider + ' / ' + config.aiProviders[0]?.model : 'Default (Plazbot)'));
|
|
471
|
-
|
|
656
|
+
if (config.channels.length > 0) {
|
|
657
|
+
config.channels.forEach((ch, i) => {
|
|
658
|
+
console.log(kvPair(`Canal ${i + 1} (${ch.channel})`, ch.key));
|
|
659
|
+
});
|
|
660
|
+
} else {
|
|
661
|
+
console.log(kvPair('Canales', 'No configurado'));
|
|
662
|
+
}
|
|
472
663
|
console.log();
|
|
473
664
|
|
|
474
665
|
return config;
|