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>
This commit is contained in:
co-authored by
Claude Opus 5
parent
af71b66bb8
commit
5086087e1b
@@ -1040,3 +1040,51 @@ func ActualizarUmindDocumentoHandler(c *fiber.Ctx) error {
|
||||
func GetPlantillasRubroHandler(c *fiber.Ctx) error {
|
||||
return c.JSON(fiber.Map{"items": services.ResumenPlantillasRubro()})
|
||||
}
|
||||
|
||||
// DuplicarUmindAgenteHandler copia un agente configurado a otro tenant (o al
|
||||
// mismo), con su conocimiento y sus herramientas. Es lo que permite usar un
|
||||
// agente que ya funciona como plantilla del siguiente.
|
||||
// POST /umind/agentes/:id/duplicar {tenant_id, nombre}
|
||||
func DuplicarUmindAgenteHandler(c *fiber.Ctx) error {
|
||||
id, err := strconv.ParseUint(c.Params("id"), 10, 64)
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "id inválido"})
|
||||
}
|
||||
// Acceso al origen: sin esto un cliente podría copiarse el agente de otro.
|
||||
if _, err := accesoAgente(c, uint(id)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var req struct {
|
||||
TenantID uint `json:"tenant_id"`
|
||||
Nombre string `json:"nombre"`
|
||||
}
|
||||
if err := c.BodyParser(&req); err != nil {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "body inválido"})
|
||||
}
|
||||
|
||||
destino := req.TenantID
|
||||
if destino == 0 {
|
||||
origen, err := models.GetUmindAgenteByID(uint(id))
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusNotFound).JSON(fiber.Map{"error": "agente no encontrado"})
|
||||
}
|
||||
destino = origen.TenantID
|
||||
}
|
||||
// Y acceso al destino: copiar es crear, y crear en un tenant ajeno tampoco.
|
||||
if err := accesoTenant(c, destino); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := verificarCupoAgentes(c, destino); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
copia, err := services.DuplicarAgente(uint(id), destino, strings.TrimSpace(req.Nombre))
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": err.Error()})
|
||||
}
|
||||
return c.Status(fiber.StatusCreated).JSON(fiber.Map{
|
||||
"ok": true, "id": copia.ID, "site_key": copia.SiteKey,
|
||||
"aviso": "El conocimiento se está copiando en segundo plano. Los canales y las claves de las herramientas no se copian: hay que configurarlos en la copia.",
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user