fix(telegram): el monto de una factura se guardaba en cero
El bot informó "FACTURA GUARDADA EXITOSAMENTE" con $290.000 y el registro
no aparecía. Revisando el camino salieron tres cosas, y las tres explican
por qué el mensaje del bot no se podía tomar como prueba de nada.
1. Los montos se leían con getInt, que solo acepta números JSON. Si el
modelo manda el monto como texto ("290000", "$290.000") devuelve el
valor por defecto: 0. Y con decimales los truncaba. La factura quedaba
creada en cero mientras el bot informaba el monto correcto, porque el
bot repite lo que dijo el usuario, no lo que se guardó. Ahora hay un
getFloat que acepta número o texto y limpia $ , y espacios.
2. Se registraba la llamada a la herramienta pero no su resultado, así que
no había forma de saber si guardó o devolvió error. Ahora se registra
también el resultado: es la única fuente confiable de qué pasó, porque
el mensaje del bot lo escribe el modelo.
3. El prompt no prohibía informar éxito sin haberlo verificado. Ahora se
le exige no decir que guardó algo si la herramienta devolvió error, y
confirmar con los valores que devolvió la herramienta y no con los que
dijo el usuario.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
0100986a46
commit
e9cb8107eb
@@ -10,6 +10,7 @@ import (
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -453,6 +454,29 @@ func runTool(chatID int64, name string, a map[string]interface{}) (interface{},
|
||||
}
|
||||
return def
|
||||
}
|
||||
// Los montos van por acá y no por getInt: getInt trunca los decimales y
|
||||
// devuelve 0 si el modelo manda el número como texto ("290000"), que es un
|
||||
// formato que sí usa. El resultado era una factura guardada en 0 mientras
|
||||
// el bot informaba el monto correcto, porque el bot repite lo que dijo el
|
||||
// usuario, no lo que se guardó.
|
||||
getFloat := func(key string, def float64) float64 {
|
||||
v, ok := a[key]
|
||||
if !ok {
|
||||
return def
|
||||
}
|
||||
switch x := v.(type) {
|
||||
case float64:
|
||||
return x
|
||||
case int:
|
||||
return float64(x)
|
||||
case string:
|
||||
limpio := strings.NewReplacer("$", "", ",", "", " ", "", "COP", "").Replace(x)
|
||||
if f, err := strconv.ParseFloat(limpio, 64); err == nil {
|
||||
return f
|
||||
}
|
||||
}
|
||||
return def
|
||||
}
|
||||
getStr := func(key string) string {
|
||||
if v, ok := a[key]; ok {
|
||||
if s, ok := v.(string); ok {
|
||||
@@ -652,7 +676,7 @@ func runTool(chatID int64, name string, a map[string]interface{}) (interface{},
|
||||
ClienteID: clienteID,
|
||||
Numero: getStr("numero"),
|
||||
Descripcion: getStr("descripcion"),
|
||||
Monto: float64(getInt("monto", 0)),
|
||||
Monto: getFloat("monto", 0),
|
||||
Estado: "pendiente",
|
||||
FechaEmision: time.Now(),
|
||||
Visible: true,
|
||||
@@ -676,7 +700,7 @@ func runTool(chatID int64, name string, a map[string]interface{}) (interface{},
|
||||
return map[string]interface{}{"ok": true, "factura_id": f.ID}, nil
|
||||
|
||||
case "adjuntar_factura_compra":
|
||||
cp, err := AdjuntarFacturaCompra(chatID, getStr("proveedor"), getStr("descripcion"), float64(getInt("monto", 0)))
|
||||
cp, err := AdjuntarFacturaCompra(chatID, getStr("proveedor"), getStr("descripcion"), getFloat("monto", 0))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -828,7 +852,7 @@ func runTool(chatID int64, name string, a map[string]interface{}) (interface{},
|
||||
t := &models.Transaccion{
|
||||
Tipo: getStr("tipo"),
|
||||
Descripcion: getStr("descripcion"),
|
||||
Valor: float64(getInt("valor", 0)),
|
||||
Valor: getFloat("valor", 0),
|
||||
Notas: getStr("notas"),
|
||||
}
|
||||
if err := models.CreateTransaccion(t); err != nil {
|
||||
@@ -851,7 +875,7 @@ func runTool(chatID int64, name string, a map[string]interface{}) (interface{},
|
||||
cc, doc, err := CrearCuentaCobroConDocumento(
|
||||
uint(getInt("cliente_id", 0)),
|
||||
getStr("descripcion"),
|
||||
float64(getInt("valor", 0)),
|
||||
getFloat("valor", 0),
|
||||
nil,
|
||||
getStr("notas"),
|
||||
"telegram",
|
||||
@@ -1567,6 +1591,14 @@ Tienes acceso total al sistema mediante herramientas. Puedes:
|
||||
- Monitorear servidores y URLs
|
||||
|
||||
COMPORTAMIENTO:
|
||||
- NUNCA digas que guardaste, creaste, actualizaste o borraste algo si la
|
||||
herramienta no te devolvió un resultado exitoso. Si devolvió {"error": ...},
|
||||
decí exactamente qué falló y qué hace falta para reintentar. Un "guardado
|
||||
exitosamente" sobre algo que no se guardó es peor que un error: la persona
|
||||
se entera días después, cuando el registro no aparece.
|
||||
- Al confirmar que guardaste algo, informá los valores que devolvió la
|
||||
herramienta (por ejemplo el id), no los que te dijo el usuario: son los que
|
||||
realmente quedaron en el sistema.
|
||||
- Responde siempre en español, de forma clara y concisa
|
||||
- Usa las herramientas para obtener datos reales antes de responder
|
||||
- Cuando el usuario pida una acción (deploy, renovar, crear), hazla directamente sin pedir confirmación salvo que sea destructiva
|
||||
@@ -1724,6 +1756,10 @@ Comandos: /reset · /instancias · /ayuda`, nil
|
||||
|
||||
log.Printf("[AGENT] Ejecutando tool: %s args: %s", tc.Function.Name, tc.Function.Arguments)
|
||||
toolResult := executeAgentTool(chatID, tc.Function.Name, toolArgs)
|
||||
// El resultado también se registra: el modelo puede decir que
|
||||
// guardó algo aunque la herramienta haya devuelto un error, así que
|
||||
// el log es la única fuente confiable de qué pasó de verdad.
|
||||
log.Printf("[AGENT] Resultado de %s: %s", tc.Function.Name, recortar(toolResult, 500))
|
||||
|
||||
// Agregar resultado al contexto (solo en memoria, no en BD)
|
||||
messages = append(messages, agentMessage{
|
||||
@@ -1740,3 +1776,12 @@ Comandos: /reset · /instancias · /ayuda`, nil
|
||||
}
|
||||
return finalResponse, nil
|
||||
}
|
||||
|
||||
// recortar limita lo que se escribe al log: un resultado de tool puede traer
|
||||
// listados enteros y no vale la pena volcarlos completos.
|
||||
func recortar(s string, n int) string {
|
||||
if len(s) <= n {
|
||||
return s
|
||||
}
|
||||
return s[:n] + "…"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user