52d5632d89
Issues planificados: - 0036: Claude Code streaming de progreso en Matrix - 0037: Agente que crea otros agentes/bots via Matrix - 0038: Webapps y dashboards embebidos en Element via widgets - 0039: Recordatorios dinámicos y crons que invocan agentes - 0040: Soporte para mensajes de voz (audio → STT) - 0041: Videollamadas con agentes via LiveKit Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
130 lines
4.4 KiB
Go
130 lines
4.4 KiB
Go
package agents
|
|
|
|
import (
|
|
"context"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/enmanuel/agents/internal/config"
|
|
"github.com/enmanuel/agents/pkg/decision"
|
|
"github.com/enmanuel/agents/tools"
|
|
|
|
"log/slog"
|
|
)
|
|
|
|
// newMetricsTestAgent creates a minimal Agent for testing the !metrics command.
|
|
// Does NOT connect to Matrix or LLM.
|
|
func newMetricsTestAgent(logDir string) *Agent {
|
|
cfg := &config.AgentConfig{
|
|
Agent: config.AgentMeta{
|
|
ID: "test-bot",
|
|
Name: "Test Bot",
|
|
},
|
|
}
|
|
return &Agent{
|
|
cfg: cfg,
|
|
logDir: logDir,
|
|
toolReg: tools.NewRegistry(slog.Default()),
|
|
logger: slog.Default(),
|
|
startTime: time.Now(),
|
|
commands: make(map[string]CommandHandler),
|
|
cmdAliases: make(map[string]string),
|
|
}
|
|
}
|
|
|
|
func TestCmdMetrics_NoLogDir(t *testing.T) {
|
|
a := newMetricsTestAgent("")
|
|
result := a.cmdMetrics(context.Background(), decision.MessageContext{})
|
|
if !strings.Contains(result, "no configurado") {
|
|
t.Errorf("expected 'no configurado' message, got: %s", result)
|
|
}
|
|
}
|
|
|
|
func TestCmdMetrics_NoLogsToday(t *testing.T) {
|
|
dir := t.TempDir()
|
|
// Create the agent subdirectory but with no log files
|
|
agentDir := filepath.Join(dir, "test-bot")
|
|
os.MkdirAll(agentDir, 0o755)
|
|
|
|
a := newMetricsTestAgent(dir)
|
|
result := a.cmdMetrics(context.Background(), decision.MessageContext{})
|
|
if !strings.Contains(result, "No hay logs") {
|
|
t.Errorf("expected 'No hay logs' message, got: %s", result)
|
|
}
|
|
}
|
|
|
|
func TestCmdMetrics_AggregatesCorrectly(t *testing.T) {
|
|
dir := t.TempDir()
|
|
agentDir := filepath.Join(dir, "test-bot")
|
|
os.MkdirAll(agentDir, 0o755)
|
|
|
|
// Create a JSONL log file for today
|
|
today := time.Now().UTC().Format("2006-01-02")
|
|
logFile := filepath.Join(agentDir, today+".jsonl")
|
|
|
|
lines := []string{
|
|
`{"time":"2026-04-09T10:00:00Z","level":"DEBUG","msg":"handling event","agent_id":"test-bot","sender":"@user:example.com"}`,
|
|
`{"time":"2026-04-09T10:00:01Z","level":"INFO","msg":"command_received","agent_id":"test-bot","command":"help"}`,
|
|
`{"time":"2026-04-09T10:00:02Z","level":"DEBUG","msg":"handling event","agent_id":"test-bot","sender":"@user2:example.com"}`,
|
|
`{"time":"2026-04-09T10:01:00Z","level":"DEBUG","msg":"LLM responded","agent_id":"test-bot","content_len":100,"duration_ms":500}`,
|
|
`{"time":"2026-04-09T10:01:01Z","level":"DEBUG","msg":"LLM responded","agent_id":"test-bot","content_len":200,"duration_ms":300,"tokens_used":150}`,
|
|
`{"time":"2026-04-09T10:02:00Z","level":"INFO","msg":"tool_exec_end","agent_id":"test-bot","tool":"current_time","duration_ms":5}`,
|
|
`{"time":"2026-04-09T10:02:01Z","level":"WARN","msg":"tool_exec_error","agent_id":"test-bot","tool":"ssh_command","err":"timeout"}`,
|
|
`{"time":"2026-04-09T10:03:00Z","level":"ERROR","msg":"something_failed","agent_id":"test-bot"}`,
|
|
}
|
|
|
|
content := strings.Join(lines, "\n") + "\n"
|
|
if err := os.WriteFile(logFile, []byte(content), 0o644); err != nil {
|
|
t.Fatalf("WriteFile: %v", err)
|
|
}
|
|
|
|
a := newMetricsTestAgent(dir)
|
|
result := a.cmdMetrics(context.Background(), decision.MessageContext{})
|
|
|
|
// Verify the output contains expected metrics
|
|
checks := map[string]string{
|
|
"messages": "| Mensajes recibidos | 2 |",
|
|
"commands": "| Comandos ejecutados | 1 |",
|
|
"llm_calls": "| Llamadas LLM | 2 |",
|
|
"llm_tokens": "| Tokens LLM (total) | 150 |",
|
|
"tool_calls": "| Llamadas a tools | 2 |",
|
|
"tool_errors": "| Errores de tools | 1 |",
|
|
"errors": "| Errores totales | 1 |",
|
|
"entries": "| Entradas de log | 8 |",
|
|
}
|
|
|
|
for name, expected := range checks {
|
|
if !strings.Contains(result, expected) {
|
|
t.Errorf("missing %s: expected %q in output:\n%s", name, expected, result)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestCmdMetrics_LLMLatencyAverage(t *testing.T) {
|
|
dir := t.TempDir()
|
|
agentDir := filepath.Join(dir, "test-bot")
|
|
os.MkdirAll(agentDir, 0o755)
|
|
|
|
today := time.Now().UTC().Format("2006-01-02")
|
|
logFile := filepath.Join(agentDir, today+".jsonl")
|
|
|
|
lines := []string{
|
|
`{"time":"2026-04-09T10:01:00Z","level":"DEBUG","msg":"LLM responded","duration_ms":400}`,
|
|
`{"time":"2026-04-09T10:01:01Z","level":"DEBUG","msg":"LLM responded","duration_ms":600}`,
|
|
}
|
|
|
|
content := strings.Join(lines, "\n") + "\n"
|
|
os.WriteFile(logFile, []byte(content), 0o644)
|
|
|
|
a := newMetricsTestAgent(dir)
|
|
result := a.cmdMetrics(context.Background(), decision.MessageContext{})
|
|
|
|
// Average of 400 and 600 = 500
|
|
if !strings.Contains(result, "| Latencia LLM (media) | 500 ms |") {
|
|
t.Errorf("expected average latency 500 ms in output:\n%s", result)
|
|
}
|
|
}
|