Files
soft_usite/pkg/services/umind_duplicar_agente_test.go
T
Lizandro GuarnizoandClaude Opus 5 5086087e1b feat(umind): duplicar un agente para usarlo como plantilla del siguiente
El catálogo de rubros da un arranque genérico, pero el mejor punto de partida
para el segundo restaurante es el primero — el que ya tiene el conocimiento
real, el tono ajustado y las herramientas andando. Ahora se puede copiar: se
lleva conocimiento, tono, bienvenida, color, config de IA y herramientas.

Tres cosas no se copian, y es a propósito:

Los canales. Llevan las credenciales de una cuenta concreta de WhatsApp o
Telegram; copiarlas haría que dos agentes contesten por el mismo número.

Las claves de las herramientas. Son secretos de un tercero, atados a una
cuenta. La copia llega sin ellas y, si la herramienta las necesitaba, llega
desactivada — para que la falta se note al configurarla y no cuando un cliente
recibe un error.

La site_key. Es la identidad pública del widget y tiene índice único:
compartirla sería servir dos agentes distintos bajo el mismo nombre.

El conocimiento se rehace desde cero en vez de copiar los vectores. Es más
lento, pero los chunks viejos pueden venir de otro modelo de embeddings, y
mezclar vectores de modelos distintos rompe la comparación por similitud —
la búsqueda devolvería cualquier cosa.

Permisos: se verifica el acceso al agente de origen y también al tenant
destino. Copiar es crear, y crear en un tenant ajeno tampoco corresponde.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-19 18:28:15 -05:00

57 lines
1.8 KiB
Go

package services
import (
"strings"
"testing"
"github.com/sujit-baniya/fiber-boilerplate/pkg/models"
)
// Copiar una herramienta con su header de auth le daría al dueño del agente
// nuevo la credencial de un tercero que no es suya. La copia tiene que llegar
// sin el secreto — y desactivada, para que la falta se note al configurarla y
// no cuando un cliente recibe un error.
func TestLaCopiaDeHerramientaNoArrastraElSecreto(t *testing.T) {
casos := []struct {
nombre string
headerNombre string
headerValor string
activaOrigen bool
activaEsperada bool
}{
{"con auth: llega desactivada", "Authorization", "cifrado-xyz", true, false},
{"sin auth: conserva su estado", "", "", true, true},
{"sin auth y desactivada: sigue desactivada", "", "", false, false},
}
for _, c := range casos {
origen := models.UmindHerramienta{
Nombre: "consultar_stock",
AuthHeaderNombre: c.headerNombre,
AuthHeaderValorEnc: c.headerValor,
Activa: c.activaOrigen,
}
// Misma expresión que usa copiarHerramientas.
activa := origen.Activa && (origen.AuthHeaderNombre == "" || origen.AuthHeaderValorEnc == "")
if activa != c.activaEsperada {
t.Errorf("%s: activa = %v, esperaba %v", c.nombre, activa, c.activaEsperada)
}
}
}
// El nombre por defecto tiene que distinguir la copia del original: dos
// agentes con el mismo nombre en la misma lista no se pueden diferenciar.
func TestNombrePorDefectoDeLaCopia(t *testing.T) {
nombreNuevo := ""
original := "Ventas"
if nombreNuevo == "" {
nombreNuevo = original + " (copia)"
}
if nombreNuevo == original {
t.Error("la copia no puede llamarse igual que el original")
}
if !strings.Contains(nombreNuevo, original) {
t.Errorf("el nombre de la copia debería reconocerse: %q", nombreNuevo)
}
}