Files
agents_and_robots/dev/issues/completed/0026-split-runtime.md
T
egutierrez aba07fef60 docs: cerrar issue 0026 — split runtime.go
Mueve el issue a dev/issues/completed/ y actualiza el README.
Issue completado: runtime.go dividido en 5 archivos especializados
con tests para buildToolRegistry.
2026-04-09 00:21:42 +00:00

95 lines
3.8 KiB
Markdown

# 0026 — Refactorizar runtime.go: separar el god object
## Objetivo
Dividir `agents/runtime.go` (1,182 lineas, 25+ metodos) en archivos con responsabilidades claras. Reducir el archivo principal a lifecycle (New, Run, Stop) y delegar el resto a archivos especializados.
## Contexto
- `agents/runtime.go` concentra: lifecycle Matrix, command routing, evaluacion de reglas, invocacion LLM, loop de tool-use, gestion de memoria, carga de prompts, sanitizacion, scheduling, comunicacion inter-agente
- Funciones como `runLLM()` (131 lineas) y `handleEvent()` (100 lineas) tienen complejidad ciclomatica estimada de 10-15
- `New()` tiene 262 lineas de inicializacion secuencial para 10+ subsistemas
- El struct `Agent` tiene 25+ campos — señal de responsabilidad excesiva
- No hay tests para runtime.go, y el tamaño dificulta añadirlos
## Arquitectura
```
agents/runtime.go → solo Agent struct, New(), Run(), Stop() (~200 lineas)
agents/handler.go NEW → handleEvent(), command routing, rule evaluation
agents/llm.go NEW → runLLM(), tool-use loop, system prompt loading
agents/memory.go NEW → window management, persistence, ensureWindowLoaded()
agents/registry_build.go NEW → buildToolRegistry() y toda la logica de registro de tools
agents/commands.go → ya existe, mantener como esta
```
### Patron pure core / impure shell
- `pkg/` — sin cambios (el motor de decisiones ya esta separado)
- `shell/` — sin cambios
- `agents/` — refactoring interno, zero cambios en API publica
## Tareas
### Fase 1: Extraer handler
- [ ] **1.1** Crear `agents/handler.go` con `handleEvent()` y metodos de routing de comandos
- [ ] **1.2** Mover logica de evaluacion de reglas y fallback LLM
- [ ] **1.3** Verificar que `runtime.go` solo llama a `a.handleEvent()` como entry point
### Fase 2: Extraer LLM
- [ ] **2.1** Crear `agents/llm.go` con `runLLM()`, `expandLLMActions()`, logica de system prompt
- [ ] **2.2** Mover el loop de tool-use (iteracion + ejecucion + RBAC check)
- [ ] **2.3** Mover la carga de system prompt desde archivo
### Fase 3: Extraer memoria
- [ ] **3.1** Crear `agents/memory.go` con `ensureWindowLoaded()`, `appendToWindow()`, `persistMessage()`
- [ ] **3.2** Mover la inicializacion de memory store desde `New()`
### Fase 4: Extraer registry builder
- [ ] **4.1** Crear `agents/registry_build.go` con `buildToolRegistry()`
- [ ] **4.2** Mover todo el registro condicional de tools
### Fase 5: Tests
- [ ] **5.1** Tests unitarios para `handleEvent()` con MessageContext mock (command routing)
- [ ] **5.2** Tests unitarios para `runLLM()` con CompleteFunc mock (tool-use loop)
- [ ] **5.3** Tests para `buildToolRegistry()` con configs parciales
### Fase 6: Cleanup
- [ ] **6.1** Verificar que `runtime.go` queda < 300 lineas
- [ ] **6.2** Actualizar imports si es necesario
- [ ] **6.3** `go build -tags goolm ./...` y `go test -tags goolm ./...` pasan
---
## Ejemplo de uso
No hay cambio funcional. Antes y despues:
```go
a, err := agents.New(cfg, rules, logger) // mismo API
a.Run(ctx) // mismo comportamiento
```
Solo cambia la organizacion interna.
## Decisiones de diseno
- **Archivos por responsabilidad, no por tamaño**: cada archivo tiene una razon de existir, no es solo "partir en pedazos"
- **Zero cambios en API publica**: `New()`, `Run()`, `Stop()`, `RegisterCommand()` mantienen firma identica
- **Metodos en Agent struct**: los metodos nuevos siguen siendo metodos del mismo struct, solo viven en otro archivo
## Prerequisitos
- Ninguno
## Riesgos
- **Merge conflicts**: si hay PRs en vuelo que tocan runtime.go, el refactor generara conflictos. Mitigacion: hacerlo en una ventana sin otros cambios pendientes
- **Regresiones**: sin tests previos, los tests E2E son la unica red de seguridad. Mitigacion: correr E2E antes y despues