refactor: separar runtime.go en archivos por responsabilidad
Divide agents/runtime.go (1188 lineas) en 5 archivos especializados: - runtime.go (350 lineas): struct Agent, New(), Run(), Stop(), lifecycle - handler.go: handleEvent(), executeActions(), command routing, bus, sanitizacion - llm.go: runLLM(), tool-use loop, system prompt, initLLM(), prompt-commands - memory.go: ensureWindowLoaded(), appendToWindow(), persistMessage(), ClearWindow() - registry_build.go: buildToolRegistry(), initToolDeps(), initRateLimiter() Zero cambios en API publica. Todos los metodos siguen siendo del struct Agent, solo viven en archivos separados por responsabilidad. Funciones helper extraidas de New() para reducir su tamaño: - initCrypto(): inicializacion E2EE - initLLM(): cliente LLM con fallback - initMemoryStore(): store SQLite + window size - initToolDeps(): knowledge, MCP, skills - initRateLimiter(): rate limiting de tools Reduccion: 1188 → 350 lineas en runtime.go (70% menos).
This commit is contained in:
@@ -0,0 +1,119 @@
|
||||
package agents
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"path/filepath"
|
||||
|
||||
coretypes "github.com/enmanuel/agents/pkg/llm"
|
||||
"github.com/enmanuel/agents/pkg/memory"
|
||||
shellmem "github.com/enmanuel/agents/shell/memory"
|
||||
)
|
||||
|
||||
// ClearWindow resets the conversation window for a room and deletes persisted
|
||||
// messages from SQLite so the agent starts fresh. Implements toolmemory.WindowClearer.
|
||||
func (a *Agent) ClearWindow(roomID string) {
|
||||
a.windowsMu.Lock()
|
||||
a.windows[roomID] = memory.NewWindow(a.windowSize)
|
||||
a.windowsMu.Unlock()
|
||||
|
||||
if a.memStore != nil {
|
||||
if err := a.memStore.DeleteMessages(
|
||||
context.Background(), a.cfg.Agent.ID, &roomID,
|
||||
); err != nil {
|
||||
a.logger.Warn("failed to delete persisted messages on clear", "room", roomID, "err", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ensureWindowLoaded loads the conversation window from SQLite on first access for a room.
|
||||
func (a *Agent) ensureWindowLoaded(ctx context.Context, roomID string) {
|
||||
a.windowsMu.Lock()
|
||||
defer a.windowsMu.Unlock()
|
||||
if _, ok := a.windows[roomID]; ok {
|
||||
return
|
||||
}
|
||||
w := memory.NewWindow(a.windowSize)
|
||||
if a.memStore != nil {
|
||||
msgs, err := a.memStore.LoadMessages(ctx, a.cfg.Agent.ID, roomID, a.windowSize)
|
||||
if err != nil {
|
||||
a.logger.Warn("failed to load message history", "room", roomID, "err", err)
|
||||
} else {
|
||||
for _, m := range msgs {
|
||||
w = w.Append(coretypes.Message{Role: m.Role, Content: m.Content})
|
||||
}
|
||||
if len(msgs) > 0 {
|
||||
a.logger.Debug("loaded message history", "room", roomID, "count", len(msgs))
|
||||
}
|
||||
}
|
||||
}
|
||||
a.windows[roomID] = w
|
||||
}
|
||||
|
||||
// appendToWindow adds a message to the in-memory conversation window.
|
||||
func (a *Agent) appendToWindow(roomID string, msg coretypes.Message) {
|
||||
a.windowsMu.Lock()
|
||||
defer a.windowsMu.Unlock()
|
||||
w, ok := a.windows[roomID]
|
||||
if !ok {
|
||||
w = memory.NewWindow(a.windowSize)
|
||||
}
|
||||
a.windows[roomID] = w.Append(msg)
|
||||
}
|
||||
|
||||
// getWindowMessages returns a copy of the conversation window for a room.
|
||||
func (a *Agent) getWindowMessages(roomID string) []coretypes.Message {
|
||||
a.windowsMu.RLock()
|
||||
defer a.windowsMu.RUnlock()
|
||||
w, ok := a.windows[roomID]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
return w.ToLLMMessages()
|
||||
}
|
||||
|
||||
// persistMessage saves a message to the SQLite store (no-op if store is nil).
|
||||
func (a *Agent) persistMessage(ctx context.Context, roomID string, role coretypes.Role, content string) {
|
||||
if a.memStore == nil {
|
||||
return
|
||||
}
|
||||
if err := a.memStore.SaveMessage(ctx, memory.HistoryMessage{
|
||||
AgentID: a.cfg.Agent.ID,
|
||||
RoomID: roomID,
|
||||
Role: role,
|
||||
Content: content,
|
||||
}); err != nil {
|
||||
a.logger.Warn("failed to persist message", "room", roomID, "err", err)
|
||||
}
|
||||
}
|
||||
|
||||
// memoryInit holds the results of memory subsystem initialization.
|
||||
type memoryInit struct {
|
||||
store memory.Store
|
||||
windowSize int
|
||||
}
|
||||
|
||||
// initMemoryStore creates the memory store and resolves window size from config.
|
||||
// Returns a zero-value memoryInit if memory is disabled.
|
||||
func initMemoryStore(enabled bool, windowSizeCfg int, dbPathCfg string, dataBase string, logger *slog.Logger) (memoryInit, error) {
|
||||
if !enabled {
|
||||
return memoryInit{windowSize: defaultWindowSize}, nil
|
||||
}
|
||||
|
||||
windowSize := windowSizeCfg
|
||||
if windowSize <= 0 {
|
||||
windowSize = defaultWindowSize
|
||||
}
|
||||
|
||||
dbPath := dbPathCfg
|
||||
if dbPath == "" {
|
||||
dbPath = filepath.Join(dataBase, "memory.db")
|
||||
}
|
||||
store, err := shellmem.New(dbPath, logger)
|
||||
if err != nil {
|
||||
return memoryInit{}, fmt.Errorf("memory store: %w", err)
|
||||
}
|
||||
logger.Info("memory enabled", "window_size", windowSize, "db", dbPath)
|
||||
return memoryInit{store: store, windowSize: windowSize}, nil
|
||||
}
|
||||
Reference in New Issue
Block a user