merge: issue/0028-decouple-launcher — auto-discovery de agentes via init()
# Conflicts: # dev/issues/README.md
This commit is contained in:
@@ -0,0 +1,109 @@
|
||||
# 0028 — Desacoplar launcher del registro estatico de agentes
|
||||
|
||||
## Objetivo
|
||||
|
||||
Eliminar la necesidad de editar `cmd/launcher/main.go` cada vez que se añade un agente. Reemplazar el `rulesRegistry` hard-coded con auto-discovery basado en la convencion de directorios.
|
||||
|
||||
## Contexto
|
||||
|
||||
- Actualmente `cmd/launcher/main.go` importa cada paquete de agente explicitamente:
|
||||
```go
|
||||
import (
|
||||
assistantagent "github.com/enmanuel/agents/agents/assistant-bot"
|
||||
asistente2agent "github.com/enmanuel/agents/agents/asistente-2"
|
||||
)
|
||||
var rulesRegistry = map[string]func() []decision.Rule{...}
|
||||
```
|
||||
- Cada agente nuevo requiere: añadir import + añadir entrada al map + recompilar
|
||||
- El script `dev-scripts/agent/new-agent.sh` ya modifica el launcher automaticamente, pero es fragil (sed sobre codigo Go)
|
||||
- Contradiccion: el launcher hace glob de `agents/*/config.yaml` para descubrir configs, pero luego necesita imports estaticos para las reglas
|
||||
|
||||
## Arquitectura
|
||||
|
||||
```
|
||||
agents/registry.go NEW → registro global de reglas (init-based)
|
||||
agents/<id>/agent.go → cada agente se auto-registra via init()
|
||||
cmd/launcher/main.go → eliminar rulesRegistry, usar agents.GetRules(id)
|
||||
```
|
||||
|
||||
### Patron pure core / impure shell
|
||||
|
||||
- `pkg/` — sin cambios
|
||||
- `shell/` — sin cambios
|
||||
- `agents/` — nuevo registry global + init() en cada agente
|
||||
- `cmd/launcher/` — simplificacion
|
||||
|
||||
## Tareas
|
||||
|
||||
### Fase 1: Crear registry de reglas
|
||||
|
||||
- [ ] **1.1** Crear `agents/registry.go` con `Register(id, rulesFn)` y `GetRules(id)`
|
||||
- [ ] **1.2** Usar sync.Mutex o sync.Map para seguridad en init()
|
||||
|
||||
### Fase 2: Migrar agentes a auto-registro
|
||||
|
||||
- [ ] **2.1** En `agents/assistant-bot/agent.go` añadir `func init() { agents.Register("assistant-bot", Rules) }`
|
||||
- [ ] **2.2** Repetir para `asistente-2` y `meteorologo`
|
||||
- [ ] **2.3** Actualizar `agents/_template/agent.go` con el patron init()
|
||||
|
||||
### Fase 3: Simplificar launcher
|
||||
|
||||
- [ ] **3.1** Eliminar imports explicitos de agentes en `cmd/launcher/main.go`
|
||||
- [ ] **3.2** Añadir blank import: `_ "github.com/enmanuel/agents/agents/assistant-bot"` (etc.)
|
||||
- [ ] **3.3** Reemplazar `rulesRegistry[id]` con `agents.GetRules(id)`
|
||||
- [ ] **3.4** Si no hay reglas registradas para un agent id, log warning y usar reglas vacias (command-only bot)
|
||||
|
||||
### Fase 4: Actualizar scripts
|
||||
|
||||
- [ ] **4.1** Simplificar `dev-scripts/agent/new-agent.sh` — ya no necesita editar el map, solo añadir blank import
|
||||
- [ ] **4.2** Actualizar `.claude/rules/create_agent.md` con el nuevo patron
|
||||
|
||||
### Fase 5: Tests
|
||||
|
||||
- [ ] **5.1** Test para `agents/registry.go` (register, get, get-missing)
|
||||
- [ ] **5.2** `go build -tags goolm ./...` compila
|
||||
- [ ] **5.3** `go test -tags goolm ./...` pasa
|
||||
|
||||
### Fase 6: Cleanup
|
||||
|
||||
- [ ] **6.1** Actualizar `CLAUDE.md` seccion sobre registro en launcher
|
||||
- [ ] **6.2** Eliminar codigo muerto del launcher
|
||||
|
||||
---
|
||||
|
||||
## Ejemplo de uso
|
||||
|
||||
Antes (crear agente):
|
||||
```go
|
||||
// cmd/launcher/main.go — editar manualmente
|
||||
import newagent "github.com/enmanuel/agents/agents/new-bot"
|
||||
var rulesRegistry = map[string]func() []decision.Rule{
|
||||
"new-bot": newagent.Rules, // añadir esta linea
|
||||
}
|
||||
```
|
||||
|
||||
Despues:
|
||||
```go
|
||||
// agents/new-bot/agent.go — auto-registro
|
||||
func init() {
|
||||
agents.Register("new-bot", Rules)
|
||||
}
|
||||
|
||||
// cmd/launcher/main.go — solo blank import
|
||||
import _ "github.com/enmanuel/agents/agents/new-bot"
|
||||
```
|
||||
|
||||
## Decisiones de diseno
|
||||
|
||||
- **init() + blank import**: patron estandar en Go (database/sql drivers, image codecs). Simple y familiar
|
||||
- **Blank imports en launcher**: siguen siendo estaticos en el codigo, pero son una linea trivial sin logica. El script de scaffolding puede añadirla sin riesgo de romper sintaxis Go
|
||||
- **No plugin system dinamico**: Go no tiene plugins portables. init() es el mecanismo idomatic
|
||||
|
||||
## Prerequisitos
|
||||
|
||||
- Ninguno (puede hacerse independiente de otros issues)
|
||||
|
||||
## Riesgos
|
||||
|
||||
- **Orden de init()**: Go garantiza init() dentro de un paquete, pero no entre paquetes. Mitigacion: el registro es un map simple, el orden no importa
|
||||
- **Olvidar blank import**: si no se añade el blank import, el agente no se registra y el launcher lo trata como command-only. Mitigacion: el script de scaffolding lo añade automaticamente
|
||||
Reference in New Issue
Block a user