create-bk-agent 0.22.0 → 0.22.2

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.
@@ -0,0 +1,159 @@
1
+ version: 1
2
+ id: atencion-ticket
3
+ name: "Atención de Ticket — {{payload.ticket_id}}"
4
+ description: >
5
+ Pipeline completo de atención a un ticket de soporte: triage y priorización,
6
+ resolución L1 con la base de conocimiento, comunicación al cliente con gate de
7
+ aprobación, y registro de aprendizajes en la KB.
8
+
9
+ steps:
10
+ - id: s1-triage
11
+ agent: triage-agent
12
+ depends_on: []
13
+ task: |
14
+ Clasificar y priorizar el siguiente ticket de soporte entrante.
15
+
16
+ DATOS DEL TICKET:
17
+ - ID: {{payload.ticket_id}}
18
+ - Cliente: {{payload.cliente}}
19
+ - Plan/Tier: {{payload.plan}}
20
+ - Canal de entrada: {{payload.canal}}
21
+ - Asunto: {{payload.asunto}}
22
+ - Descripción del problema: {{payload.descripcion}}
23
+ - Información del entorno (si la proporcionó): {{payload.entorno}}
24
+
25
+ Producir el triage completo:
26
+
27
+ 1. PRIORIDAD
28
+ - P1 Crítico: sistema caído, impacto en producción, sin workaround
29
+ - P2 Alto: funcionalidad core degradada, impacto en operaciones
30
+ - P3 Medio: bug con workaround disponible o feature parcialmente afectada
31
+ - P4 Bajo: consulta, mejora sugerida o cosmético
32
+
33
+ 2. TIPO DE ISSUE
34
+ - Bug / Error técnico
35
+ - Consulta / "How to"
36
+ - Solicitud de feature / mejora
37
+ - Problema de rendimiento / performance
38
+ - Acceso / permisos / facturación
39
+ - Integración con terceros
40
+
41
+ 3. ÁREA DE PRODUCTO AFECTADA
42
+ Identificar qué módulo, API o componente está involucrado basándose en la descripción.
43
+
44
+ 4. NIVEL DE SOPORTE REQUERIDO
45
+ - L1: resoluble con documentación existente o procedimiento estándar
46
+ - L2: requiere investigación técnica, acceso a logs o análisis de código
47
+ - L3: requiere escalación a ingeniería, posible bug en producción
48
+
49
+ 5. SLA APLICABLE
50
+ Tiempo de respuesta y resolución según prioridad y plan del cliente.
51
+
52
+ 6. INFORMACIÓN FALTANTE
53
+ Lista de datos adicionales que necesitamos del cliente para resolver más rápido
54
+ (si aplica).
55
+
56
+ 7. CONTEXTO PARA EL AGENTE DE SOPORTE
57
+ Resumen ejecutivo de 3-4 líneas con lo que sabe el siguiente agente para arrancar.
58
+
59
+ - id: s2-resolucion
60
+ agent: support-agent
61
+ depends_on: [s1-triage]
62
+ task: |
63
+ Resolver el ticket de soporte usando la base de conocimiento.
64
+
65
+ TRIAGE DEL TICKET:
66
+ {{steps.s1-triage.output}}
67
+
68
+ TICKET ORIGINAL:
69
+ - Cliente: {{payload.cliente}} (Plan: {{payload.plan}})
70
+ - Asunto: {{payload.asunto}}
71
+ - Descripción: {{payload.descripcion}}
72
+ - Entorno: {{payload.entorno}}
73
+
74
+ Produce la respuesta de soporte L1:
75
+
76
+ 1. DIAGNÓSTICO
77
+ Qué está causando el problema según la descripción y la base de conocimiento.
78
+
79
+ 2. SOLUCIÓN PASO A PASO
80
+ Instrucciones claras y numeradas para que el cliente resuelva el problema.
81
+ Si hay un workaround mientras se investiga la causa raíz, indicarlo primero.
82
+
83
+ 3. VERIFICACIÓN
84
+ Cómo sabe el cliente que el problema se resolvió (qué debe ver/comprobar).
85
+
86
+ 4. ESTADO DE RESOLUCIÓN
87
+ - RESUELTO: el problema tiene solución documentada y completa
88
+ - NECESITA_INFO: falta información del cliente para continuar
89
+ - ESCALAR_L2: el issue supera el alcance de L1, necesita investigación técnica
90
+ - WORKAROUND: hay solución temporal pero el root cause requiere L2
91
+
92
+ 5. ARTÍCULOS DE KB UTILIZADOS
93
+ Lista de artículos o secciones de la documentación consultados (para tracking).
94
+
95
+ - id: s3-comunicacion
96
+ agent: communication-agent
97
+ depends_on: [s1-triage, s2-resolucion]
98
+ gate: true
99
+ gate_criteria:
100
+ - "La respuesta es clara y accionable — el cliente sabe exactamente qué hacer"
101
+ - "El tono es empático sin ser condescendiente"
102
+ - "Si el issue no se resuelve completamente, se explica el próximo paso y el tiempo estimado"
103
+ - "No se incluye jerga interna ni información confidencial"
104
+ task: |
105
+ Redactar la respuesta al cliente para el ticket {{payload.ticket_id}}.
106
+
107
+ TRIAGE:
108
+ {{steps.s1-triage.output}}
109
+
110
+ RESOLUCIÓN L1:
111
+ {{steps.s2-resolucion.output}}
112
+
113
+ DATOS DEL CLIENTE:
114
+ - Nombre: {{payload.cliente}}
115
+ - Canal: {{payload.canal}}
116
+ - Plan: {{payload.plan}}
117
+
118
+ Redactar la comunicación completa:
119
+
120
+ ## Asunto del email / título de la respuesta
121
+ Claro, específico, que transmita que estamos trabajando en ello.
122
+
123
+ ## Cuerpo de la respuesta
124
+ - Apertura: reconocer el problema con empatía (1-2 líneas, sin excesos)
125
+ - Diagnóstico explicado en términos del cliente (no jerga técnica interna)
126
+ - Solución o próximos pasos numerados y claros
127
+ - Tiempo estimado si el problema no está completamente resuelto
128
+ - Cierre: cómo contactarnos si la solución no funciona o hay preguntas
129
+
130
+ ## Notas internas (no van al cliente)
131
+ - Información de contexto para el agente que haga seguimiento
132
+ - Acciones pendientes del equipo de soporte
133
+
134
+ - id: s4-kb
135
+ agent: knowledge-agent
136
+ depends_on: [s2-resolucion, s3-comunicacion]
137
+ task: |
138
+ Analizar el ticket resuelto y proponer mejoras a la base de conocimiento.
139
+
140
+ TICKET: {{payload.asunto}}
141
+ TRIAGE: {{steps.s1-triage.output}}
142
+ RESOLUCIÓN: {{steps.s2-resolucion.output}}
143
+
144
+ Evaluar:
145
+
146
+ 1. ¿EXISTE ARTÍCULO EN LA KB?
147
+ - SÍ, está actualizado → no se requiere acción
148
+ - SÍ, pero está desactualizado o incompleto → proponer actualización
149
+ - NO → proponer nuevo artículo
150
+
151
+ 2. PROPUESTA DE CONTENIDO (si aplica)
152
+ Si se necesita crear o actualizar un artículo, redactar el borrador completo
153
+ siguiendo la estructura: título + descripción del problema + causa + solución
154
+ paso a paso + verificación + casos relacionados.
155
+
156
+ 3. MEJORAS AL PROCESO
157
+ Si este ticket reveló un gap en el proceso de atención (pregunta frecuente no
158
+ documentada, procedimiento ambiguo, criterio de escalación poco claro), proponer
159
+ la mejora específica.
@@ -0,0 +1,218 @@
1
+ version: 1
2
+ id: incidente-critico
3
+ name: "Incidente Crítico — {{payload.incidente_id}}"
4
+ description: >
5
+ Gestión de incidentes P1/P2: confirmación y escalación con gate, diagnóstico
6
+ técnico profundo, plan de resolución con gate de aprobación, comunicado externo
7
+ al cliente y postmortem para prevenir recurrencias.
8
+
9
+ steps:
10
+ - id: s1-confirmacion
11
+ agent: triage-agent
12
+ depends_on: []
13
+ gate: true
14
+ gate_criteria:
15
+ - "La prioridad P1/P2 está correctamente justificada con el impacto real"
16
+ - "El alcance del incidente está definido (cuántos clientes, qué funcionalidades)"
17
+ - "Se identificó el canal de comunicación de crisis y los responsables en guardia"
18
+ - "Hay un War Room o canal de coordinación definido"
19
+ task: |
20
+ Confirmar y documentar el incidente crítico para activar el protocolo de respuesta.
21
+
22
+ DATOS DEL INCIDENTE:
23
+ - ID: {{payload.incidente_id}}
24
+ - Reportado por: {{payload.reportado_por}}
25
+ - Fecha/hora de detección: {{payload.hora_deteccion}}
26
+ - Descripción inicial: {{payload.descripcion}}
27
+ - Sistemas afectados: {{payload.sistemas_afectados}}
28
+ - Clientes impactados (estimado): {{payload.clientes_impactados}}
29
+ - Síntomas observados: {{payload.sintomas}}
30
+
31
+ Producir el documento de apertura del incidente:
32
+
33
+ 1. CLASIFICACIÓN
34
+ - Prioridad confirmada: P1 / P2 con justificación
35
+ - Tipo de incidente: outage total / degradación / pérdida de datos / seguridad / rendimiento
36
+ - Sistemas afectados con nivel de impacto por sistema
37
+
38
+ 2. ALCANCE DEL IMPACTO
39
+ - Clientes afectados (cantidad y segmento)
40
+ - Funcionalidades no disponibles o degradadas
41
+ - Impacto en negocio estimado (revenue, operaciones, reputación)
42
+
43
+ 3. HIPÓTESIS INICIALES
44
+ 3 hipótesis de causa raíz ordenadas por probabilidad.
45
+
46
+ 4. PLAN DE RESPUESTA INMEDIATA
47
+ - Acciones en las próximas 15 minutos
48
+ - Responsable de cada acción (rol)
49
+ - Canal de coordinación del equipo (War Room)
50
+
51
+ 5. COMUNICACIÓN INICIAL
52
+ - A quién notificar dentro de la empresa (escalación interna)
53
+ - Si se debe notificar proactivamente a clientes ahora o esperar diagnóstico
54
+
55
+ - id: s2-diagnostico
56
+ agent: technical-agent
57
+ depends_on: [s1-confirmacion]
58
+ task: |
59
+ Realizar el diagnóstico técnico profundo del incidente.
60
+
61
+ DOCUMENTO DE APERTURA DEL INCIDENTE:
62
+ {{steps.s1-confirmacion.output}}
63
+
64
+ INFORMACIÓN TÉCNICA DISPONIBLE:
65
+ - Sistemas afectados: {{payload.sistemas_afectados}}
66
+ - Síntomas: {{payload.sintomas}}
67
+ - Logs o errores disponibles: {{payload.logs}}
68
+ - Cambios recientes en producción: {{payload.cambios_recientes}}
69
+
70
+ Producir el diagnóstico técnico:
71
+
72
+ 1. ANÁLISIS DE CAUSA RAÍZ
73
+ Evaluación de cada hipótesis con la evidencia disponible.
74
+ Conclusión: causa raíz confirmada o hipótesis más probable con nivel de confianza.
75
+
76
+ 2. ÁRBOL DE IMPACTO
77
+ Qué sistemas dependen del sistema afectado y cómo se propaga el fallo.
78
+
79
+ 3. OPCIONES DE RESOLUCIÓN
80
+ Para cada opción: descripción, tiempo estimado, riesgo, impacto secundario.
81
+ - Opción A (más rápida): workaround o rollback
82
+ - Opción B (más definitiva): fix en producción
83
+ - Opción C (si aplica): fallback o degraded mode
84
+
85
+ 4. RECOMENDACIÓN
86
+ Qué opción ejecutar primero y por qué, con los pasos concretos.
87
+
88
+ 5. RIESGOS DE LA INTERVENCIÓN
89
+ Qué puede salir mal al aplicar la solución y cómo mitigarlo.
90
+
91
+ - id: s3-plan-resolucion
92
+ agent: escalation-agent
93
+ depends_on: [s2-diagnostico]
94
+ gate: true
95
+ gate_criteria:
96
+ - "La opción de resolución elegida está aprobada por el responsable técnico"
97
+ - "Hay un rollback plan definido si la solución empeora el incidente"
98
+ - "El tiempo estimado de resolución está actualizado y es realista"
99
+ - "Se definió quién ejecuta cada paso (no puede quedar sin responsable asignado)"
100
+ task: |
101
+ Diseñar y coordinar el plan de resolución del incidente.
102
+
103
+ DIAGNÓSTICO TÉCNICO:
104
+ {{steps.s2-diagnostico.output}}
105
+
106
+ CONTEXTO DEL INCIDENTE:
107
+ ID: {{payload.incidente_id}} | Sistemas: {{payload.sistemas_afectados}}
108
+ Clientes impactados: {{payload.clientes_impactados}}
109
+
110
+ Producir el plan de resolución:
111
+
112
+ 1. DECISIÓN DE RESOLUCIÓN
113
+ Opción elegida con justificación y aprobación requerida.
114
+
115
+ 2. RUNBOOK DE EJECUCIÓN
116
+ Pasos numerados con:
117
+ - Acción específica
118
+ - Responsable (rol)
119
+ - Tiempo estimado
120
+ - Criterio de verificación (cómo saber que el paso funcionó)
121
+
122
+ 3. ROLLBACK PLAN
123
+ Si el fix empeora el incidente, qué hacer en los primeros 5 minutos.
124
+
125
+ 4. CRITERIO DE RESOLUCIÓN
126
+ Cómo sabemos que el incidente está cerrado (métricas, checks, confirmación).
127
+
128
+ 5. COMUNICACIÓN DURANTE LA RESOLUCIÓN
129
+ - Cada cuánto actualizar a clientes (ej: cada 30 minutos)
130
+ - Qué decirle al equipo interno
131
+ - Cuándo declarar "resuelto" públicamente
132
+
133
+ 6. EQUIPO DE GUARDIA
134
+ Roles y responsabilidades durante la ejecución del plan.
135
+
136
+ - id: s4-comunicado-externo
137
+ agent: communication-agent
138
+ depends_on: [s1-confirmacion, s3-plan-resolucion]
139
+ task: |
140
+ Redactar las comunicaciones externas para el incidente {{payload.incidente_id}}.
141
+
142
+ CONTEXTO DEL INCIDENTE:
143
+ {{steps.s1-confirmacion.output}}
144
+
145
+ PLAN DE RESOLUCIÓN:
146
+ {{steps.s3-plan-resolucion.output}}
147
+
148
+ Redactar los 3 comunicados necesarios:
149
+
150
+ ## 1. COMUNICADO DE APERTURA (enviar ahora)
151
+ - Qué está pasando (sin jerga técnica, en términos de impacto al cliente)
152
+ - Qué estamos haciendo para resolverlo
153
+ - Tiempo estimado de resolución (dar rango, no promesas exactas)
154
+ - Dónde ver actualizaciones (status page, canal de comunicación)
155
+ - Contacto para urgencias
156
+
157
+ ## 2. ACTUALIZACIONES DE PROGRESO (template reutilizable)
158
+ Template con placeholders para actualizar cada 30 minutos durante el incidente:
159
+ - [HORA] Estado actual
160
+ - [AVANCE] Qué se hizo
161
+ - [PRÓXIMOS PASOS] Qué sigue
162
+ - [ETA] Estimación actualizada
163
+
164
+ ## 3. COMUNICADO DE CIERRE
165
+ - Confirmación de que el incidente fue resuelto
166
+ - Descripción breve de qué pasó y cómo se resolvió (sin exponer vulnerabilidades)
167
+ - Medidas tomadas para que no vuelva a ocurrir
168
+ - Disculpas y reconocimiento del impacto
169
+ - Crédito/compensación si aplica según política
170
+
171
+ - id: s5-postmortem
172
+ agent: technical-agent
173
+ depends_on: [s2-diagnostico, s3-plan-resolucion, s4-comunicado-externo]
174
+ task: |
175
+ Redactar el documento de postmortem del incidente {{payload.incidente_id}}.
176
+
177
+ DIAGNÓSTICO TÉCNICO:
178
+ {{steps.s2-diagnostico.output}}
179
+
180
+ PLAN Y RESOLUCIÓN:
181
+ {{steps.s3-plan-resolucion.output}}
182
+
183
+ DATOS DEL INCIDENTE:
184
+ - Hora de detección: {{payload.hora_deteccion}}
185
+ - Sistemas afectados: {{payload.sistemas_afectados}}
186
+ - Clientes impactados: {{payload.clientes_impactados}}
187
+
188
+ Estructura del postmortem (blameless — sin culpables, solo sistemas y procesos):
189
+
190
+ ## Resumen Ejecutivo
191
+ 3-4 líneas: qué pasó, cuánto duró, impacto total.
192
+
193
+ ## Timeline
194
+ Cronología minuto a minuto desde la detección hasta la resolución.
195
+
196
+ ## Causa Raíz
197
+ Causa técnica confirmada. Usar "5 Whys" para llegar al root cause real.
198
+
199
+ ## Factores Contribuyentes
200
+ Condiciones que hicieron posible o empeoraron el incidente.
201
+
202
+ ## Qué Funcionó Bien
203
+ Partes del proceso de respuesta que fueron efectivas.
204
+
205
+ ## Qué No Funcionó
206
+ Gaps en detección, respuesta, comunicación o herramientas.
207
+
208
+ ## Acciones Correctivas
209
+ Lista priorizada de mejoras con responsable y fecha límite:
210
+ - Acciones de remediación inmediata (ya implementadas)
211
+ - Acciones de prevención a corto plazo (< 2 semanas)
212
+ - Acciones estructurales a mediano plazo (< 3 meses)
213
+
214
+ ## Métricas del Incidente
215
+ - MTTD (Mean Time to Detect)
216
+ - MTTA (Mean Time to Acknowledge)
217
+ - MTTR (Mean Time to Resolve)
218
+ - Clientes impactados y duración del impacto
@@ -0,0 +1,98 @@
1
+ version: 1
2
+
3
+ orchestrator:
4
+ name: "Orquestador de Soporte al Cliente"
5
+ provider: __PROVIDER_ID__
6
+ vault:
7
+ path: ./vault
8
+ embedder: simple # change to "ollama" in production for better semantic search
9
+
10
+ __PROVIDERS_BLOCK__
11
+
12
+ flows:
13
+ - id: atencion-ticket
14
+ file: ./flows/atencion-ticket.yaml
15
+ trigger: "ticket|soporte|consulta|problema|error|bug|incidencia|reclamo|ayuda|no funciona|falla"
16
+
17
+ - id: incidente-critico
18
+ file: ./flows/incidente-critico.yaml
19
+ trigger: "incidente|crítico|caído|urgente|p1|p2|emergencia|producción|caída del sistema|outage"
20
+
21
+ agents:
22
+ - id: triage-agent
23
+ name: "Agente de Triage"
24
+ description: >
25
+ Clasifica y prioriza tickets de soporte entrantes. Determina la urgencia (P1-P4),
26
+ el tipo de issue (bug, consulta, facturación, feature request), el área de producto
27
+ afectada y el nivel de soporte requerido (L1/L2/L3). Genera el contexto inicial
28
+ para el agente que tomará el ticket.
29
+ capabilities: [triage, clasificacion, prioridad, sla, routing, diagnostico-inicial]
30
+ provider: __PROVIDER_ID__
31
+ domain: soporte
32
+
33
+ - id: support-agent
34
+ name: "Agente de Soporte L1"
35
+ description: >
36
+ Maneja tickets de soporte de nivel 1: consultas frecuentes, configuraciones estándar,
37
+ procedimientos documentados y troubleshooting básico. Usa la base de conocimiento para
38
+ dar respuestas precisas y consistentes. Si no puede resolver, prepara el contexto
39
+ para escalación a L2 con toda la información necesaria.
40
+ capabilities: [l1, soporte, faq, troubleshooting, kb, resolucion, guia-paso-a-paso]
41
+ provider: __PROVIDER_ID__
42
+ domain: soporte
43
+
44
+ - id: technical-agent
45
+ name: "Agente Técnico L2"
46
+ description: >
47
+ Investigación técnica profunda de issues complejos. Diagnóstico de root cause,
48
+ análisis de logs, identificación de bugs, propuesta de workarounds y soluciones
49
+ definitivas. Documenta hallazgos técnicos para el equipo de ingeniería y para
50
+ enriquecer la base de conocimiento.
51
+ capabilities: [l2, tecnico, diagnostico, root-cause, logs, bugs, workaround, ingenieria]
52
+ provider: __PROVIDER_ID__
53
+ domain: soporte
54
+ gate: true
55
+ gate_criteria:
56
+ - "El diagnóstico incluye el root cause o una hipótesis sólida con evidencia"
57
+ - "Se propone al menos un workaround inmediato para desbloquear al cliente"
58
+ - "La solución propuesta no implica cambios de datos o configuración sin respaldo"
59
+ - "Se documentaron los pasos de reproducción del issue"
60
+
61
+ - id: escalation-agent
62
+ name: "Agente de Escalación L3"
63
+ description: >
64
+ Gestiona incidentes críticos y escalaciones a ingeniería. Coordina la respuesta
65
+ ante outages, define el plan de acción con responsables y tiempos, y asegura que
66
+ se mantenga informado al cliente durante todo el incidente. Lidera el proceso de
67
+ postmortem y seguimiento de acciones correctivas.
68
+ capabilities: [l3, escalacion, incidente, outage, coordinacion, postmortem, p1, p2]
69
+ provider: __PROVIDER_ID__
70
+ domain: soporte
71
+ gate: true
72
+ gate_criteria:
73
+ - "La escalación a ingeniería está justificada y el impacto está cuantificado"
74
+ - "Hay un responsable asignado (nombre o rol) para cada acción del plan"
75
+ - "El cliente fue notificado del incidente y del tiempo estimado de resolución"
76
+ - "Se definió el criterio de resolución: cómo sabemos que el incidente está cerrado"
77
+
78
+ - id: communication-agent
79
+ name: "Agente de Comunicación"
80
+ description: >
81
+ Redacta todas las comunicaciones hacia el cliente: respuestas a tickets, actualizaciones
82
+ de estado durante incidentes, emails de cierre, solicitudes de información adicional y
83
+ encuestas de satisfacción. Adapta el tono y nivel técnico al perfil del cliente.
84
+ Asegura que cada comunicación sea clara, empática y accionable.
85
+ capabilities: [comunicacion, redaccion, email, respuesta-cliente, estado, cierre, empatia]
86
+ provider: __PROVIDER_ID__
87
+ domain: soporte
88
+
89
+ - id: knowledge-agent
90
+ name: "Agente de Base de Conocimiento"
91
+ description: >
92
+ Mantiene y mejora la base de conocimiento de soporte. Identifica gaps de documentación
93
+ a partir de tickets resueltos, propone nuevos artículos o actualizaciones de los
94
+ existentes, y sugiere mejoras en los procedimientos de atención para reducir el tiempo
95
+ de resolución en futuros tickets similares.
96
+ capabilities: [knowledge-base, documentacion, kb, articulos, mejora-continua, procedimientos]
97
+ provider: __PROVIDER_ID__
98
+ domain: soporte
@@ -0,0 +1,210 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Test runner for the soporte orchestrator
4
+ *
5
+ * Usage:
6
+ * node test-flow.mjs atencion-ticket # standard ticket (triage → L1 → gate → KB)
7
+ * node test-flow.mjs incidente-critico # P1 incident (gate → diagnosis → gate → comms → postmortem)
8
+ * node test-flow.mjs dynamic # dynamic planning (no flow match)
9
+ */
10
+
11
+ import { spawn } from 'node:child_process';
12
+ import { createInterface } from 'node:readline';
13
+ import * as path from 'node:path';
14
+ import * as fs from 'node:fs';
15
+ import * as url from 'node:url';
16
+
17
+ const __dirname = path.dirname(url.fileURLToPath(import.meta.url));
18
+ const CONFIG_PATH = path.resolve(__dirname, 'orchestrator.yaml');
19
+ const SERVER_PATH = path.resolve(
20
+ __dirname,
21
+ 'node_modules/@backendkit-labs/orchestrator-agent/dist/server.js',
22
+ );
23
+
24
+ // ── Sample payloads ───────────────────────────────────────────────────────────
25
+
26
+ const FLOWS = {
27
+ 'atencion-ticket': {
28
+ flow_id: 'atencion-ticket',
29
+ task: 'Atender ticket de soporte: error al exportar reportes en formato Excel',
30
+ payload: {
31
+ ticket_id: 'TKT-2024-1547',
32
+ cliente: 'Acme Corp',
33
+ plan: 'Professional',
34
+ canal: 'Portal de soporte',
35
+ asunto: 'Error al exportar reportes en formato Excel — aparece "Download failed"',
36
+ descripcion: 'Desde ayer a la tarde, cuando intento descargar cualquier reporte en formato Excel (no en CSV), me aparece el mensaje "Download failed" y no se genera ningún archivo. El botón de descarga en PDF sí funciona bien. Lo probé en Chrome y Firefox con el mismo resultado. Necesito los reportes para una reunión de directorio mañana a las 10hs.',
37
+ entorno: 'Chrome 124, Windows 11, cuenta admin. La sesión expira correctamente y puedo hacer todo lo demás en la plataforma sin problemas.',
38
+ },
39
+ },
40
+ 'incidente-critico': {
41
+ flow_id: 'incidente-critico',
42
+ task: 'Gestionar incidente crítico: plataforma inaccesible para clientes Enterprise',
43
+ payload: {
44
+ incidente_id: 'INC-2024-003',
45
+ reportado_por: 'Sistema de monitoreo + 3 clientes Enterprise simultáneamente',
46
+ hora_deteccion: '2024-06-14 09:23 ART',
47
+ descripcion: 'La plataforma devuelve error 503 para todos los usuarios. El health check de la API principal está fallando. Múltiples clientes Enterprise están llamando al número de emergencias.',
48
+ sistemas_afectados: 'API principal (/api/v3/*), Dashboard web, Mobile app. La base de datos parece responder (status page de RDS en verde).',
49
+ clientes_impactados: 'Estimado 100% de usuarios activos en este momento (~340 sesiones activas según los últimos logs disponibles)',
50
+ sintomas: 'HTTP 503 en todas las rutas de la API. Los worker processes de Node.js no están respondiendo. Los logs muestran "FATAL: Cannot allocate memory" repetidamente desde las 09:18.',
51
+ logs: 'FATAL: Cannot allocate memory in static TLS block\nnode: Cannot allocate memory\nAborted (core dumped)\nRestarting worker... (intent 47 en los últimos 5 minutos)',
52
+ cambios_recientes: 'Deploy de v3.4.1 a las 08:45 (35 minutos antes del incidente). El deploy incluyó actualización de una dependencia de procesamiento de imágenes.',
53
+ },
54
+ },
55
+ 'dynamic': {
56
+ flow_id: undefined,
57
+ task: process.env.TASK ?? 'Analizar los tickets de la última semana e identificar los 3 problemas más frecuentes que deberían documentarse como artículos de KB',
58
+ payload: {},
59
+ },
60
+ };
61
+
62
+ // ── MCP Client (stdio) ────────────────────────────────────────────────────────
63
+
64
+ class McpClient {
65
+ constructor(serverPath) {
66
+ this._nextId = 1;
67
+ this._pending = new Map();
68
+
69
+ const env = { ...process.env };
70
+ const dotenv = path.join(__dirname, '.env');
71
+ if (fs.existsSync(dotenv)) {
72
+ for (const line of fs.readFileSync(dotenv, 'utf-8').split('\n')) {
73
+ const m = line.match(/^\s*([A-Z_][A-Z0-9_]*)\s*=\s*(.*?)\s*$/);
74
+ if (m && m[2] && !(m[1] in env)) env[m[1]] = m[2].replace(/^["']|["']$/g, '');
75
+ }
76
+ }
77
+
78
+ this._proc = spawn('node', [serverPath], { stdio: ['pipe', 'pipe', 'inherit'], env });
79
+
80
+ const rl = createInterface({ input: this._proc.stdout });
81
+ rl.on('line', (line) => {
82
+ if (!line.trim()) return;
83
+ try {
84
+ const msg = JSON.parse(line);
85
+ if (msg.id !== undefined && this._pending.has(msg.id)) {
86
+ const { resolve, reject } = this._pending.get(msg.id);
87
+ this._pending.delete(msg.id);
88
+ if (msg.error) reject(new Error(msg.error.message ?? JSON.stringify(msg.error)));
89
+ else resolve(msg.result);
90
+ }
91
+ } catch {}
92
+ });
93
+
94
+ this._proc.on('error', (err) => console.error('[MCP] error:', err.message));
95
+ }
96
+
97
+ _send(msg) { this._proc.stdin.write(JSON.stringify(msg) + '\n'); }
98
+
99
+ async initialize() {
100
+ const id = this._nextId++;
101
+ const p = new Promise((res, rej) => this._pending.set(id, { resolve: res, reject: rej }));
102
+ this._send({ jsonrpc: '2.0', id, method: 'initialize', params: {
103
+ protocolVersion: '2024-11-05', capabilities: {},
104
+ clientInfo: { name: 'test-flow', version: '0.1.0' },
105
+ }});
106
+ await p;
107
+ this._send({ jsonrpc: '2.0', method: 'notifications/initialized', params: {} });
108
+ }
109
+
110
+ async callTool(name, args) {
111
+ const id = this._nextId++;
112
+ const p = new Promise((res, rej) => {
113
+ this._pending.set(id, { resolve: res, reject: rej });
114
+ setTimeout(() => {
115
+ if (this._pending.has(id)) { this._pending.delete(id); rej(new Error(`Timeout: ${name}`)); }
116
+ }, 120_000);
117
+ });
118
+ this._send({ jsonrpc: '2.0', id, method: 'tools/call', params: { name, arguments: args } });
119
+ return p;
120
+ }
121
+
122
+ close() { this._proc.stdin.end(); }
123
+ }
124
+
125
+ // ── Helpers ───────────────────────────────────────────────────────────────────
126
+
127
+ const extractText = (r) => r?.content?.filter(c => c.type === 'text').map(c => c.text).join('\n') ?? String(r);
128
+ const sleep = (ms) => new Promise(r => setTimeout(r, ms));
129
+
130
+ function printSection(title, text) {
131
+ const line = '─'.repeat(60);
132
+ console.log(`\n${line}\n ${title}\n${line}`);
133
+ console.log(text);
134
+ }
135
+
136
+ // ── Main ──────────────────────────────────────────────────────────────────────
137
+
138
+ async function main() {
139
+ const flowKey = process.argv[2] ?? 'atencion-ticket';
140
+ const flowDef = FLOWS[flowKey];
141
+ if (!flowDef) {
142
+ console.error(`Unknown flow: ${flowKey}\nOptions: ${Object.keys(FLOWS).join(', ')}`);
143
+ process.exit(1);
144
+ }
145
+ if (!fs.existsSync(SERVER_PATH)) {
146
+ console.error(`Server not found:\n ${SERVER_PATH}\nRun: npm install`);
147
+ process.exit(1);
148
+ }
149
+
150
+ console.log(`\nStarting orchestrator (soporte)...`);
151
+ console.log(` Flow: ${flowKey}`);
152
+
153
+ const client = new McpClient(SERVER_PATH);
154
+ try {
155
+ await client.initialize();
156
+ console.log(' MCP: connected ✓\n');
157
+
158
+ const runArgs = { config_path: CONFIG_PATH, task: flowDef.task };
159
+ if (flowDef.flow_id) runArgs.flow_id = flowDef.flow_id;
160
+ if (Object.keys(flowDef.payload).length > 0) runArgs.payload = flowDef.payload;
161
+
162
+ const startText = extractText(await client.callTool('orchestrator_run', runArgs));
163
+ printSection('RUN STARTED', startText);
164
+
165
+ const runIdMatch = startText.match(/runId:\s*`?([a-z0-9-]+)`?/i);
166
+ if (!runIdMatch) { console.error('\n[ERROR] Could not extract runId.'); process.exit(1); }
167
+ const runId = runIdMatch[1];
168
+
169
+ let attempts = 0, lastStatus = '';
170
+ console.log(`\nPolling (runId: ${runId})...\n`);
171
+
172
+ while (attempts < 80) {
173
+ await sleep(5000);
174
+ attempts++;
175
+
176
+ const statusText = extractText(await client.callTool('orchestrator_status', {
177
+ config_path: CONFIG_PATH, run_id: runId,
178
+ }));
179
+ const status = statusText.match(/status:\s*\*\*([^*]+)\*\*/)?.[1]
180
+ ?? statusText.match(/^status:\s*(\S+)/m)?.[1]
181
+ ?? 'unknown';
182
+
183
+ if (status !== lastStatus) {
184
+ process.stdout.write(` [${new Date().toLocaleTimeString()}] status: ${status}\n`);
185
+ lastStatus = status;
186
+ }
187
+
188
+ if (status === 'complete') { printSection('RESULT', statusText); break; }
189
+ if (status === 'failed') { printSection('ERROR', statusText); break; }
190
+
191
+ if (status === 'waiting_gate') {
192
+ printSection('GATE — APPROVAL REQUIRED', statusText);
193
+ console.log('\nAuto-approving...\n');
194
+ await sleep(2000);
195
+ const approveText = extractText(await client.callTool('orchestrator_approve', {
196
+ config_path: CONFIG_PATH, run_id: runId,
197
+ approved: true, notes: 'Auto-approved by test-flow.mjs',
198
+ }));
199
+ printSection('GATE APPROVED', approveText);
200
+ lastStatus = '';
201
+ }
202
+ }
203
+
204
+ if (attempts >= 80) console.log('\n[TIMEOUT] Check orchestrator_status manually.');
205
+ } finally {
206
+ client.close();
207
+ }
208
+ }
209
+
210
+ main().catch(err => { console.error('\n[FATAL]', err.message); process.exit(1); });