docs: crear issues 0036-0041 — nuevas features del sistema
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>
This commit is contained in:
@@ -0,0 +1,129 @@
|
||||
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)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user