From be01d95631e1371ef528798e955345cf88073f2a Mon Sep 17 00:00:00 2001 From: Lizandro Guarnizo <77708265+lizandrogd@users.noreply.github.com> Date: Sun, 23 Aug 2026 11:40:39 -0500 Subject: [PATCH] feat(studio): la puesta en marcha guiada y una bandeja de conversaciones que informa MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Dos mitades de la misma experiencia: el primer día y todos los días después. El primer día. Un agente recién creado mostraba tres avisos ámbar sueltos —"no atiende", "no sabe nada"— sin ningún orden: el dueño sabía que faltaban cosas pero no cuál iba primero. Ahora hay una guía de tres pasos (contale de tu negocio → hacele una pregunta → ponelo a atender) donde solo el siguiente paso pendiente se resalta, porque una guía donde todo grita a la vez no guía nada. Mientras falte algo, la guía reemplaza al estado — una sola voz por etapa; con los pasos hechos desaparece para siempre y el estado operativo toma su lugar. Todos los días. La bandeja de conversaciones mostraba el último mensaje de cada sesión —casi siempre la respuesta del bot, "¡Hola! ¿En qué te ayudo?" cincuenta veces— y el session_id crudo (tg:8812). Ahora cada conversación muestra lo que el visitante preguntó al abrir, que es el dato que le importa al dueño: qué le preguntan de verdad a su negocio. Con canal deducido del prefijo de la sesión (WhatsApp, Telegram, Tu web, Prueba), cantidad de mensajes, y fecha relativa. Las pruebas propias se separan detrás de un filtro: mezcladas inflan la lista y el dueño no distingue cuáles son clientes reales. El contador del estado cuenta solo las reales, por lo mismo — si arriba dice 4 y la lista muestra 3, el número parece roto. El hilo muestra la hora de cada mensaje, y el backend gana una consulta que agrupa por sesión con el primer mensaje del visitante en vez de mandar filas crudas; la vieja quedó sin usos y se fue. Co-Authored-By: Claude Opus 5 --- orchestrator/src/views/AgenteDetail.vue | 21 +++- .../src/views/agente/EstadoAgente.vue | 12 +- .../src/views/agente/PrimerosPasos.vue | 107 ++++++++++++++++ .../src/views/agente/TabConversaciones.vue | 114 +++++++++++++++--- pkg/models/umind.go | 47 +++++--- public/orchestrator/assets/index-CZn9dJyg.css | 1 + public/orchestrator/assets/index-Cd5jgLRW.css | 1 - public/orchestrator/assets/index-CxArDUWK.js | 26 ---- public/orchestrator/assets/index-NXjEScsg.js | 26 ++++ public/orchestrator/index.html | 4 +- rest/controllers/umind_admin_controller.go | 2 +- 11 files changed, 288 insertions(+), 73 deletions(-) create mode 100644 orchestrator/src/views/agente/PrimerosPasos.vue create mode 100644 public/orchestrator/assets/index-CZn9dJyg.css delete mode 100644 public/orchestrator/assets/index-Cd5jgLRW.css delete mode 100644 public/orchestrator/assets/index-CxArDUWK.js create mode 100644 public/orchestrator/assets/index-NXjEScsg.js diff --git a/orchestrator/src/views/AgenteDetail.vue b/orchestrator/src/views/AgenteDetail.vue index 38a4729..9c60a49 100644 --- a/orchestrator/src/views/AgenteDetail.vue +++ b/orchestrator/src/views/AgenteDetail.vue @@ -12,6 +12,7 @@ import TabConversaciones from './agente/TabConversaciones.vue' import TabHerramientas from './agente/TabHerramientas.vue' import TabCanales from './agente/TabCanales.vue' import EstadoAgente from './agente/EstadoAgente.vue' +import PrimerosPasos from './agente/PrimerosPasos.vue' const props = defineProps({ tenantId: { type: String, required: true }, @@ -254,6 +255,12 @@ const AVANZADO = [ ['auditoria', 'Problemas'], ] +// La guía se muestra hasta que sabe algo Y atiende en algún lado. Probar es +// deseable pero no bloquea: nadie queda preso de la guía por no haber chateado. +const configurando = computed( + () => !documentos.value.some((d) => d.estado === 'listo') || !canales.value.some((c) => c.activo), +) + const mostrarAvanzado = ref(false) // Si se entra directo a una pestaña avanzada (por la URL o desde el estado de @@ -313,10 +320,18 @@ watch( - + + const problemas = computed(() => props.eventos.filter((e) => e.nivel === 'error').length) +// Solo conversaciones de clientes: la bandeja separa las pruebas propias, y si +// este número las incluyera diría una cosa distinta que la lista de al lado. +const reales = computed(() => + props.sesiones.filter((s) => !String(s.session_id).startsWith('staff-preview')), +) + // Cada señal dice qué pasa y, cuando algo anda mal, a dónde ir a arreglarlo. const señales = computed(() => [ { @@ -63,9 +69,9 @@ const señales = computed(() => [ icono: 'grafico', // Que nadie haya escrito todavía no es un problema: es un dato. bien: true, - neutro: props.sesiones.length === 0, - texto: props.sesiones.length - ? `${props.sesiones.length} ${props.sesiones.length === 1 ? 'conversación' : 'conversaciones'}` + neutro: reales.value.length === 0, + texto: reales.value.length + ? `${reales.value.length} ${reales.value.length === 1 ? 'conversación' : 'conversaciones'}` : 'Nadie escribió todavía', destino: 'conversaciones', }, diff --git a/orchestrator/src/views/agente/PrimerosPasos.vue b/orchestrator/src/views/agente/PrimerosPasos.vue new file mode 100644 index 0000000..ef52656 --- /dev/null +++ b/orchestrator/src/views/agente/PrimerosPasos.vue @@ -0,0 +1,107 @@ + + + diff --git a/orchestrator/src/views/agente/TabConversaciones.vue b/orchestrator/src/views/agente/TabConversaciones.vue index ef0f478..883f953 100644 --- a/orchestrator/src/views/agente/TabConversaciones.vue +++ b/orchestrator/src/views/agente/TabConversaciones.vue @@ -1,8 +1,9 @@