feat: log de auditoría técnica por agente
Nueva tabla umind_eventos_log + tab "Auditoría" en el panel: errores y eventos que hasta ahora solo se podían ver pidiendo los logs del servidor (fallos al llamar al AI, respuestas sin texto usable, tools/webhooks que fallan, tokens de correo que no se pueden refrescar, firmas de WhatsApp inválidas, errores procesando mensajes de Telegram/WhatsApp) quedan registrados por agente, visibles directo en el panel con el JSON crudo expandible para diagnosticar sin acceso al servidor. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
5febbd24d5
commit
997e3cc790
@@ -59,12 +59,14 @@ func umindTools(agenteID uint) []agentTool {
|
||||
herramientas, err := models.GetUmindHerramientasActivas(agenteID)
|
||||
if err != nil {
|
||||
log.Printf("[UMIND] Error leyendo tools custom del agente %d: %v", agenteID, err)
|
||||
models.RegistrarEventoUmind(agenteID, "error", "tool", "Error leyendo tools custom", err.Error())
|
||||
return tools
|
||||
}
|
||||
for _, h := range herramientas {
|
||||
params, err := models.ParametrosFromJSON(h.ParametrosJSON)
|
||||
if err != nil {
|
||||
log.Printf("[UMIND] Tool %q del agente %d tiene parametros_json inválido, se omite: %v", h.Nombre, agenteID, err)
|
||||
models.RegistrarEventoUmind(agenteID, "warn", "tool", fmt.Sprintf("Tool %q tiene parametros_json inválido, se omitió", h.Nombre), err.Error())
|
||||
continue
|
||||
}
|
||||
props := map[string]agentToolParam{}
|
||||
@@ -168,12 +170,14 @@ func executeUmindTool(agenteID uint, name string, args map[string]interface{}) s
|
||||
authValor, err = DescifrarSecretoUmind(herramienta.AuthHeaderValorEnc)
|
||||
if err != nil {
|
||||
log.Printf("[UMIND] Error descifrando credencial de tool %q: %v", name, err)
|
||||
models.RegistrarEventoUmind(agenteID, "error", "tool", fmt.Sprintf("Error descifrando credencial de la tool %q", name), err.Error())
|
||||
return `{"error": "la tool no está configurada correctamente"}`
|
||||
}
|
||||
}
|
||||
resultado, err := LlamarHerramientaWebhook(herramienta.URL, herramienta.AuthHeaderNombre, authValor, args)
|
||||
if err != nil {
|
||||
log.Printf("[UMIND] Error llamando tool %q del agente %d: %v", name, agenteID, err)
|
||||
models.RegistrarEventoUmind(agenteID, "error", "tool", fmt.Sprintf("Error llamando la tool %q", name), err.Error())
|
||||
return fmt.Sprintf(`{"error": %q}`, "no se pudo completar la acción, intenta de nuevo")
|
||||
}
|
||||
return resultado
|
||||
@@ -189,6 +193,7 @@ func executeUmindEmailTool(agenteID uint, name string, args map[string]interface
|
||||
}
|
||||
if err := RefrescarSiVence(conexion); err != nil {
|
||||
log.Printf("[UMIND] Error refrescando token OAuth (conexión %d): %v", conexion.ID, err)
|
||||
models.RegistrarEventoUmind(agenteID, "error", "email", "Error refrescando el token de la cuenta de correo conectada", err.Error())
|
||||
return `{"error": "no se pudo usar la cuenta de correo conectada, intenta más tarde"}`
|
||||
}
|
||||
|
||||
@@ -208,6 +213,7 @@ func executeUmindEmailTool(agenteID uint, name string, args map[string]interface
|
||||
}
|
||||
if envErr != nil {
|
||||
log.Printf("[UMIND] Error enviando correo (agente %d): %v", agenteID, envErr)
|
||||
models.RegistrarEventoUmind(agenteID, "error", "email", "Error enviando correo", envErr.Error())
|
||||
return `{"error": "no se pudo enviar el correo"}`
|
||||
}
|
||||
return `{"ok": true}`
|
||||
@@ -223,6 +229,7 @@ func executeUmindEmailTool(agenteID uint, name string, args map[string]interface
|
||||
}
|
||||
if lecErr != nil {
|
||||
log.Printf("[UMIND] Error leyendo bandeja (agente %d): %v", agenteID, lecErr)
|
||||
models.RegistrarEventoUmind(agenteID, "error", "email", "Error leyendo la bandeja de correo", lecErr.Error())
|
||||
return `{"error": "no se pudo leer la bandeja"}`
|
||||
}
|
||||
b, _ := json.Marshal(map[string]interface{}{"resultados": resultados})
|
||||
@@ -279,6 +286,7 @@ func ProcessWidgetMessage(agente *models.UmindAgente, sessionID, userText string
|
||||
aiMsg, err := callAI(&ai, messages, tools)
|
||||
if err != nil {
|
||||
log.Printf("[UMIND] Error llamando AI (agente %d) round %d: %v", agente.ID, round, err)
|
||||
models.RegistrarEventoUmind(agente.ID, "error", "ai", fmt.Sprintf("Error contactando el AI (ronda %d)", round), err.Error())
|
||||
return "", fmt.Errorf("error al contactar el sistema de IA")
|
||||
}
|
||||
|
||||
@@ -293,6 +301,7 @@ func ProcessWidgetMessage(agente *models.UmindAgente, sessionID, userText string
|
||||
// "dame más detalle" sin ninguna pista de qué pasó. Con .Raw (ver
|
||||
// agentMessage.UnmarshalJSON) queda el JSON crudo para diagnosticar.
|
||||
log.Printf("[UMIND] Respuesta del AI sin texto usable (agente %d) round %d: %s", agente.ID, round, string(aiMsg.Raw))
|
||||
models.RegistrarEventoUmind(agente.ID, "warn", "ai", fmt.Sprintf("El AI respondió sin texto usable (ronda %d)", round), string(aiMsg.Raw))
|
||||
}
|
||||
finalResponse = content
|
||||
if strings.TrimSpace(content) != "" {
|
||||
@@ -317,6 +326,7 @@ func ProcessWidgetMessage(agente *models.UmindAgente, sessionID, userText string
|
||||
|
||||
if finalResponse == "" {
|
||||
log.Printf("[UMIND] Agente %d: se agotaron las rondas de tool-calling sin una respuesta final", agente.ID)
|
||||
models.RegistrarEventoUmind(agente.ID, "warn", "ai", "Se agotaron las rondas de tool-calling sin una respuesta final", "")
|
||||
finalResponse = "Un momento, por favor — dame un poco más de detalle sobre lo que necesitas."
|
||||
}
|
||||
return finalResponse, nil
|
||||
|
||||
Reference in New Issue
Block a user