a5d038913f
Mover issue a completed/ y actualizar estado en README. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
158 lines
5.6 KiB
Markdown
158 lines
5.6 KiB
Markdown
# 0030 — Separacion Robot vs Agente
|
|
|
|
## Objetivo
|
|
|
|
Crear un tipo `Robot` como runtime ligero para bots que solo responden comandos, sin LLM, reglas, memoria ni tools. Distinguir en config entre `type: robot` y `type: agent` para que el launcher sepa que runtime instanciar.
|
|
|
|
## Contexto
|
|
|
|
- Actualmente todos los bots usan el mismo `Agent` struct (1,182 lineas) con 25+ subsistemas
|
|
- Un bot de comandos simples (ej: `!deploy prod`, `!status`) no necesita LLM, memoria, knowledge, skills, sanitizacion, ni tool-use
|
|
- Si `llm.primary.provider` esta vacio, `runtime.go` loguea "running as command-only bot" pero sigue inicializando todo el subsistema
|
|
- No hay forma idiomatica de crear un bot simple sin arrastrar toda la complejidad
|
|
- Ejemplos de robots: bot de deploys, bot de health checks, bot de notificaciones, bot de CI/CD
|
|
|
|
## Arquitectura
|
|
|
|
```
|
|
agents/robot.go NEW → Robot struct (~150 lineas): Matrix + Commands
|
|
agents/robot_test.go NEW → tests del runtime minimo
|
|
agents/types.go NEW → interfaz comun Runner { Run(ctx), Stop(), RegisterCommand() }
|
|
cmd/launcher/main.go → detectar type: robot y crear Robot en vez de Agent
|
|
internal/config/schema.go → añadir campo Agent.Type ("robot" | "agent")
|
|
```
|
|
|
|
### Patron pure core / impure shell
|
|
|
|
- `pkg/` — sin cambios (el Robot no usa decision engine ni reglas)
|
|
- `shell/matrix/` — sin cambios (el Robot reutiliza el mismo cliente Matrix)
|
|
- `agents/robot.go` — impuro (tiene Matrix client), pero minimo
|
|
- `agents/runtime.go` — sin cambios (Agent sigue igual)
|
|
|
|
## Tareas
|
|
|
|
### Fase 1: Definir interfaz comun
|
|
|
|
- [ ] **1.1** Crear `agents/types.go` con interfaz `Runner`:
|
|
```go
|
|
type Runner interface {
|
|
Run(ctx context.Context) error
|
|
Stop()
|
|
RegisterCommand(spec command.Spec, handler CommandHandler)
|
|
}
|
|
```
|
|
- [ ] **1.2** Verificar que `Agent` ya satisface `Runner` (o adaptar)
|
|
|
|
### Fase 2: Implementar Robot
|
|
|
|
- [ ] **2.1** Crear `agents/robot.go` con struct `Robot`:
|
|
- `matrix *matrix.Client`
|
|
- `commands *command.Registry` (built-ins + custom)
|
|
- `logger *slog.Logger`
|
|
- `config config.AgentConfig`
|
|
- [ ] **2.2** Implementar `NewRobot(cfg, logger)` — solo inicializa Matrix + commands
|
|
- [ ] **2.3** Implementar `Run()` — sync loop que solo despacha comandos
|
|
- [ ] **2.4** Implementar `Stop()` — cierra Matrix client
|
|
- [ ] **2.5** Implementar `RegisterCommand()` — registra comando custom
|
|
- [ ] **2.6** En `handleEvent()`: si no es comando, ignorar silenciosamente (no hay LLM)
|
|
|
|
### Fase 3: Config y launcher
|
|
|
|
- [ ] **3.1** Añadir campo `Type string` a `AgentCfg` en schema.go (default: "agent")
|
|
- [ ] **3.2** En launcher: si `cfg.Agent.Type == "robot"`, crear `NewRobot()` en vez de `New()`
|
|
- [ ] **3.3** El launcher usa la interfaz `Runner` para manejar ambos tipos uniformemente
|
|
|
|
### Fase 4: Template y scaffolding
|
|
|
|
- [ ] **4.1** Crear `agents/_template_robot/` con config minimo para robots
|
|
- [ ] **4.2** Config de robot ejemplo (~20 lineas):
|
|
```yaml
|
|
agent:
|
|
id: deploy-bot
|
|
type: robot
|
|
description: "Bot de deploys"
|
|
personality:
|
|
prefix: "🤖"
|
|
matrix:
|
|
threads:
|
|
enabled: true
|
|
```
|
|
- [ ] **4.3** Actualizar `dev-scripts/agent/create-full.sh` para aceptar flag `--robot`
|
|
|
|
### Fase 5: Tests
|
|
|
|
- [ ] **5.1** Test: Robot responde a `!help` con lista de comandos
|
|
- [ ] **5.2** Test: Robot responde a `!ping` con pong
|
|
- [ ] **5.3** Test: Robot ignora mensajes normales (no es error, simplemente no responde)
|
|
- [ ] **5.4** Test: Robot con comando custom registrado lo ejecuta
|
|
- [ ] **5.5** Test: `Runner` interfaz es satisfecha por ambos `Agent` y `Robot`
|
|
|
|
### Fase 6: Documentacion
|
|
|
|
- [ ] **6.1** Actualizar `CLAUDE.md` con seccion Robot vs Agent
|
|
- [ ] **6.2** Actualizar `.claude/rules/create_agent.md` mencionando la opcion robot
|
|
- [ ] **6.3** Añadir tabla comparativa en docs
|
|
|
|
---
|
|
|
|
## Ejemplo de uso
|
|
|
|
```yaml
|
|
# agents/deploy-bot/config.yaml
|
|
agent:
|
|
id: deploy-bot
|
|
type: robot
|
|
description: "Bot de deploys con comandos directos"
|
|
|
|
personality:
|
|
prefix: "🚀"
|
|
|
|
matrix:
|
|
homeserver: ${MATRIX_HOMESERVER}
|
|
user_id: "@deploy-bot:matrix-af2f3d.organic-machine.com"
|
|
access_token_env: MATRIX_TOKEN_DEPLOY_BOT
|
|
```
|
|
|
|
```go
|
|
// agents/deploy-bot/commands.go
|
|
package deploy
|
|
|
|
func Commands() []agents.CommandEntry {
|
|
return []agents.CommandEntry{
|
|
{
|
|
Spec: command.Spec{Name: "deploy", Usage: "!deploy <env>"},
|
|
Handler: func(ctx context.Context, msg decision.MessageContext) string {
|
|
return fmt.Sprintf("Deploying to %s...", msg.Args[0])
|
|
},
|
|
},
|
|
}
|
|
}
|
|
```
|
|
|
|
Interaccion en Element:
|
|
```
|
|
Usuario: !deploy staging
|
|
Bot: 🚀 Deploying to staging...
|
|
|
|
Usuario: hola bot
|
|
Bot: (silencio — no tiene LLM)
|
|
```
|
|
|
|
## Decisiones de diseno
|
|
|
|
- **Interfaz `Runner`**: permite al launcher tratar robots y agentes uniformemente sin type switches
|
|
- **Robot NO tiene reglas**: las reglas son para routing inteligente. Un robot solo hace dispatch de comandos
|
|
- **Robot NO tiene memory/knowledge/skills**: mantener el runtime lo mas ligero posible
|
|
- **Config minimo**: un robot funcional se define en ~20 lineas de YAML
|
|
- **Silencio ante mensajes normales**: un robot no responde "no entiendo", simplemente ignora. Los comandos tienen `!help` para descubrirse
|
|
|
|
## Prerequisitos
|
|
|
|
- Ninguno (puede hacerse independiente)
|
|
- Se beneficia de 0026 (split runtime) pero no lo requiere
|
|
|
|
## Riesgos
|
|
|
|
- **Duplicacion**: Robot y Agent comparten logica de Matrix, commands, lifecycle. Mitigacion: reutilizar `shell/matrix/` y `pkg/command/` sin duplicar
|
|
- **Scope creep**: tentacion de añadir "un poquito de LLM" al Robot. Mitigacion: la linea es clara — si necesita LLM, es un Agent
|