Files
agents_and_robots/README.md
T
egutierrez 98839cd8a8 feat(api): HTTP API REST+SSE para gestion remota de agentes (issue 0128)
Nuevo paquete internal/api con servidor HTTP stdlib (sin gin/echo):
- Auth Bearer via AGENTS_API_KEY con subtle.ConstantTimeCompare
- REST: GET /health (sin auth), GET/POST /agents, /agents/{id}, /{id}/{start,stop,restart,logs}
- SSE: /sse/status (broadcast diffs cada 2s) y /sse/agents/{id}/logs (tail -f)
- Pubsub in-memory (TODO: NATS cuando haya 2do cliente)
- Tail de logfiles: retroalimenta ultimos 50KB + poll 200ms para streaming

Integracion en cmd/launcher/main.go:
- Flag --api-port (0=desactivado, 8487 en produccion)
- Flag --api-key (override de AGENTS_API_KEY env var)
- Si apiPort>0 y sin clave, WARN y deshabilita en vez de fallar

Systemd unit en systemd/agents_and_robots.service:
- Restart=always (no on-failure — evita que exit limpio mate el service)
- EnvironmentFile para AGENTS_API_KEY y demas tokens
- WorkingDirectory=/home/ubuntu/CodeProyects/agents_and_robots

app.md v0.2.0:
- port: 8487, health_endpoint: /health (fix drift anterior donde era null)
- e2e_checks: build, tests, smoke_health, smoke_auth
- Documentacion Traefik+DNS pendiente humano post-merge

Tests: 12 tests unitarios en internal/api (auth, health, bus, agents, logs)
Smoke: /health 200, /agents sin auth 401, /agents con key 200 — verificado local

Co-Authored-By: fn-constructor (agent)
2026-05-22 21:19:10 +02:00

370 lines
11 KiB
Markdown

# agents_and_robots
Plataforma en Go para gestionar bots Matrix autónomos. Cada bot combina un **core puro** (personalidad, reglas de decisión, transformaciones) con un **shell impuro** (conexión Matrix, SSH, LLM, side effects), conectados a un servidor Matrix self-hosted.
> **CI/CD**: push a Gitea → webhook → deploy_server → `bash build.sh` → `systemctl restart`.
---
## Inicio rápido
```bash
# 1. Compilar todo
./build.sh
# 2. Cargar variables de entorno
source .env
# 3. Lanzar la TUI interactiva (dashboard)
./bin/dashboard
```
### Dashboard TUI
El dashboard es una interfaz de terminal interactiva (bubbletea) para gestionar los bots del servidor:
```
./bin/dashboard
```
Desde la TUI puedes:
- **Agents** — ver estado de cada agente, iniciar/detener/reiniciar/kill individual, ver logs
- **Server** — operaciones masivas: start all, stop all, restart all, kill all con resumen de estado
### Otros binarios
| Binario | Uso |
|---------|-----|
| `./bin/launcher` | Inicia uno o varios agentes como procesos |
| `./bin/agentctl` | CLI: `list`, `start`, `stop`, `remove` |
| `./bin/register` | Registra bots en Synapse via admin API |
| `./bin/dashboard` | TUI interactiva para gestión de bots |
---
## HTTP API (v0.1)
El launcher expone una API REST + SSE cuando se arranca con `--api-port <N>`.
### Arrancar con API habilitada
```bash
# Requiere AGENTS_API_KEY en .env (generar con: openssl rand -hex 32)
./bin/launcher --log-level info --api-port 8487
# Con systemd (VPS):
sudo systemctl start agents_and_robots.service
```
### Autenticacion
Todos los endpoints (excepto `/health`) requieren:
```
Authorization: Bearer <AGENTS_API_KEY>
```
Comparacion con `crypto/subtle.ConstantTimeCompare` — resistente a timing attacks.
### Endpoints REST
```bash
# Liveness (sin auth)
curl http://localhost:8487/health
# Listar agentes
curl -H "Authorization: Bearer $AGENTS_API_KEY" http://localhost:8487/agents
# Detalle + logs de un agente
curl -H "Authorization: Bearer $AGENTS_API_KEY" http://localhost:8487/agents/assistant-bot
# Control
curl -X POST -H "Authorization: Bearer $AGENTS_API_KEY" http://localhost:8487/agents/assistant-bot/stop
curl -X POST -H "Authorization: Bearer $AGENTS_API_KEY" http://localhost:8487/agents/assistant-bot/start
curl -X POST -H "Authorization: Bearer $AGENTS_API_KEY" http://localhost:8487/agents/assistant-bot/restart
# Logs snapshot
curl -H "Authorization: Bearer $AGENTS_API_KEY" "http://localhost:8487/agents/assistant-bot/logs?n=50"
```
### Endpoints SSE
```bash
# Stream de cambios de estado (stop/start) — un evento por transicion
curl -N -H "Authorization: Bearer $AGENTS_API_KEY" http://localhost:8487/sse/status
# Tail en vivo del logfile de un agente (< 1s de lag)
curl -N -H "Authorization: Bearer $AGENTS_API_KEY" http://localhost:8487/sse/agents/assistant-bot/logs
```
### En produccion (VPS)
El VPS expone la API via Traefik con TLS en `agents.organic-machine.com`.
Los pasos DNS + Traefik los configura el humano tras el merge (ver `app.md` seccion Traefik).
```bash
# Con Traefik configurado:
curl -fsS -H "Authorization: Bearer $AGENTS_API_KEY" https://agents.organic-machine.com/agents
```
---
## Principio de diseño
El proyecto usa el patrón **pure core / impure shell**:
```
Mensaje Matrix
Parse() ← puro: produce MessageContext
Evaluate() ← puro: produce []Action (solo datos, sin efectos)
Runner.Execute() ← impuro: interpreta las acciones → envía mensajes, ejecuta SSH, llama LLM
```
Nada dentro de `pkg/` tiene efectos secundarios. Todo el I/O vive en `shell/`.
---
## Estructura
```
agents_and_robots/
├── pkg/ ← PURE CORE — sin side effects
│ ├── decision/ engine de reglas: Evaluate(), Rule, Action, MatchFunc
│ ├── llm/ tipos LLM: CompleteFunc, CompletionRequest
│ ├── tools/ specs declarativas: SSHCommandSpec, HTTPCallSpec...
│ ├── message/ parse y format de mensajes
│ └── personality/ tipos de personalidad del bot
├── shell/ ← IMPURE SHELL — todo el I/O
│ ├── llm/ clientes reales: Anthropic, OpenAI/Ollama
│ ├── matrix/ cliente mautrix-go: envío, sync, listener
│ ├── ssh/ ejecución SSH real (golang.org/x/crypto/ssh)
│ ├── effects/ Runner: interpreta []Action → side effects
│ ├── bus/ mensajería inter-agente via Go channels
│ └── protocols/ MCP server/client (mark3labs/mcp-go)
├── agents/ ← definición de cada bot
│ ├── runtime.go Agent{}: ensambla core + shell
│ └── assistant/ reglas + config del assistant-bot
├── internal/config/ esquema YAML completo + loader con env vars
├── cmd/
│ ├── launcher/ inicia uno o varios agentes
│ ├── agentctl/ CLI: list, start, stop, remove
│ └── register/ registra bots en Synapse via admin API
├── dev-scripts/ scripts bash para el día a día
│ ├── server/ gestión del launcher (start, stop, restart, ps, logs, dashboard)
│ └── agent/ gestión de agentes (new, register, verify, avatar, remove, list)
├── config/ configuración global (matrix.yaml, servers.yaml)
└── .env.example plantilla de variables de entorno
```
---
## Requisitos
- Go 1.23+
- Servidor Matrix (Synapse) con acceso admin
- API key de OpenAI o Anthropic (según el bot)
---
## Setup inicial
```bash
# 1. Clonar y entrar al repo
git clone <repo-url>
cd agents_and_robots
# 2. Copiar y rellenar variables de entorno
cp .env.example .env
# Editar .env con: MATRIX_HOMESERVER, OPENAI_API_KEY, etc.
# 3. Descargar dependencias
go mod tidy
```
---
## Registrar y arrancar un bot
```bash
# Registrar el bot en el servidor Matrix (necesita MATRIX_ADMIN_TOKEN en .env)
./dev-scripts/agent/register.sh assistant-bot "Assistant"
# → imprime el token, copiarlo a .env como MATRIX_TOKEN_ASSISTANT
# Ver todos los bots y su estado
./dev-scripts/agent/list.sh
# Iniciar
./dev-scripts/server/start.sh assistant-bot
# Ver logs en vivo
./dev-scripts/server/logs.sh assistant-bot
# Detener
./dev-scripts/server/stop.sh assistant-bot
```
---
## CLI — agentctl
```bash
go run ./cmd/agentctl list # ver todos los bots
go run ./cmd/agentctl start assistant-bot # iniciar
go run ./cmd/agentctl stop # detener todos
go run ./cmd/agentctl remove assistant-bot # deshabilitar (sin borrar datos)
```
O compilando los binarios:
```bash
make build # genera bin/launcher, bin/agentctl, bin/register
./bin/agentctl list
```
---
## Crear un bot nuevo
```bash
# 1. Generar el scaffold completo
./dev-scripts/agent/new-agent.sh monitor-bot "Monitor Agent"
```
Genera:
```
agents/monitor-bot/
├── config.yaml ← configuración completa, lista para editar
├── agent.go ← reglas puras con help + LLM fallback
└── prompts/
└── system.md ← system prompt del LLM
```
El script imprime los dos pasos manuales que quedan:
```bash
# 2. Añadir al registro en cmd/launcher/main.go:
import monitoragent "github.com/enmanuel/agents/agents/monitor-bot"
var rulesRegistry = map[string]func() []decision.Rule{
"monitor-bot": monitoragent.Rules, // ← añadir aquí
...
}
# 3. Registrarlo en Matrix y arrancar
./dev-scripts/agent/register.sh monitor-bot "Monitor Agent"
# → añadir token a .env
./dev-scripts/server/start.sh monitor-bot
```
---
## Configuración de agentes
Cada `agents/<id>/config.yaml` soporta:
| Sección | Qué controla |
|---------|--------------|
| `agent` | identidad, versión, tags, enabled |
| `personality` | tono, verbosidad, idioma, emoji, templates de respuesta, comportamiento |
| `llm` | provider (anthropic/openai/ollama), modelo, fallback, rate limits, tool use |
| `tools` | SSH, HTTP, scripts, file_ops, MCP (habilitados por bot) |
| `matrix` | homeserver, user_id, rooms, filtros de mensajes, E2EE |
| `agents` | peers con los que colabora, delegación, protocolo |
| `ssh` | inventario de targets con hosts, users, jump host |
| `security` | RBAC por roles, audit log, gestión de secrets |
| `schedules` | tareas cron automáticas con acciones SSH/script |
| `observability` | logging, métricas Prometheus, health check, tracing |
| `resilience` | circuit breaker, retry, graceful shutdown, queue |
| `storage` | estado SQLite/Redis, caché, historial de conversación |
Las variables del sistema se referencian como `${NOMBRE_VAR}` y se expanden en tiempo de carga.
---
## Reglas de decisión
Las reglas de cada bot se definen como datos puros en `agents/<id>/agent.go`:
```go
func Rules() []decision.Rule {
return []decision.Rule{
{
Name: "deploy-staging",
Match: decision.And(
decision.MatchCommand("deploy"),
func(ctx decision.MessageContext) bool {
return len(ctx.Args) > 0 && ctx.Args[0] == "staging"
},
),
Actions: []decision.Action{{
Kind: decision.ActionKindSSH,
SSH: &tools.SSHCommandSpec{Target: "staging", Command: "..."},
}},
},
// catch-all: DMs y menciones van al LLM
{
Name: "llm-fallback",
Match: func(ctx decision.MessageContext) bool {
return ctx.IsDirectMsg || ctx.IsMention
},
Actions: []decision.Action{{Kind: decision.ActionKindLLM, LLM: &decision.LLMAction{}}},
},
}
}
```
Predicados disponibles: `MatchCommand`, `MatchPrefix`, `MatchMinPowerLevel`, `MatchAny`, `And`, `Or`.
Tipos de acción: `reply`, `ssh`, `http`, `script`, `file_ops`, `mcp`, `llm`, `delegate`.
---
## Bots incluidos
### assistant-bot
Asistente general con GPT-4o. Responde a DMs y menciones. Sin acceso a herramientas — solo LLM.
```
@assistant-bot:matrix-af2f3d.organic-machine.com
```
---
## Dependencias
| Librería | Versión | Uso |
|----------|---------|-----|
| `maunium.net/go/mautrix` | v0.21.1 | Cliente Matrix, sync, E2EE |
| `github.com/sashabaranov/go-openai` | v1.36.1 | OpenAI API y compatibles (Ollama) |
| `github.com/mark3labs/mcp-go` | v0.44.1 | MCP protocol server/client |
| `golang.org/x/crypto` | v0.31.0 | SSH |
| `github.com/spf13/cobra` | v1.8.1 | CLI |
| `gopkg.in/yaml.v3` | v3.0.1 | Config |
---
## Makefile
```bash
make build # compila todos los binarios en bin/
make list # agentctl list
make start # start todos (AGENT=id para uno)
make stop # stop todos (AGENT=id para uno)
make tidy # go mod tidy
make clean # elimina bin/ y run/
```