Files
agents_and_robots/dev/issues/0026-split-runtime.md
T
egutierrez acbc8ef629 chore: agregar issues 0026-0032 y worktrees a gitignore
Registra los nuevos issues pendientes en el indice y excluye
la carpeta worktrees/ del control de versiones.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 23:05:47 +00:00

3.8 KiB

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:

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