feat: añadir sistema de knowledge por agente

Implementa una base de conocimiento persistente por agente siguiendo
el patrón pure core / impure shell:

- pkg/knowledge/: tipos puros (Document, Store interface)
- shell/knowledge/: FileStore con SQLite para indexación y archivos .md
- tools/knowledge.go: 4 tools LLM (search, read, write, list)
- tools/knowledge_test.go: tests unitarios de las tools
- internal/config/schema.go: nuevo KnowledgeToolCfg en ToolsCfg
- agents/runtime.go: inicialización del store y registro de tools
- agents/*/knowledge/about-me.md: documentos semilla para cada agente

Cada agente puede buscar, leer, crear y actualizar documentos de
conocimiento. Los archivos .md viven en agents/<id>/knowledge/ y se
indexan en SQLite (agents/<id>/data/knowledge.db).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-06 23:02:39 +00:00
parent 37882f1c24
commit 69607b3a65
11 changed files with 981 additions and 11 deletions
+42 -5
View File
@@ -21,6 +21,7 @@ import (
"github.com/enmanuel/agents/pkg/personality"
"github.com/enmanuel/agents/shell/bus"
"github.com/enmanuel/agents/shell/effects"
shellknowledge "github.com/enmanuel/agents/shell/knowledge"
shelllm "github.com/enmanuel/agents/shell/llm"
"github.com/enmanuel/agents/shell/matrix"
shellmem "github.com/enmanuel/agents/shell/memory"
@@ -53,6 +54,9 @@ type Agent struct {
windowSize int
roomCtx *tools.RoomContext
// Knowledge store — non-nil when knowledge is enabled
knowledgeStore *shellknowledge.FileStore
// Bus — set via SetBus() when running under the unified launcher
agentBus *bus.Bus
}
@@ -159,8 +163,27 @@ func New(cfg *config.AgentConfig, rules []decision.Rule, logger *slog.Logger) (*
logger.Info("memory enabled", "window_size", windowSize, "db", dbPath)
}
// Knowledge store
var kStore *shellknowledge.FileStore
if cfg.Tools.Knowledge.Enabled {
knowledgeDir := cfg.Tools.Knowledge.Dir
if knowledgeDir == "" {
knowledgeDir = filepath.Join("agents", cfg.Agent.ID, "knowledge")
}
knowledgeDBPath := filepath.Join("agents", cfg.Agent.ID, "data", "knowledge.db")
var kErr error
kStore, kErr = shellknowledge.New(knowledgeDir, knowledgeDBPath, logger)
if kErr != nil {
logger.Error("knowledge_store_init_failed", "err", kErr)
} else {
if syncErr := kStore.Sync(context.Background()); syncErr != nil {
logger.Error("knowledge_sync_failed", "err", syncErr)
}
}
}
// Tool registry — register tools enabled in config
toolReg := buildToolRegistry(cfg, sshExec, matrixClient, memStore, roomCtx, logger)
toolReg := buildToolRegistry(cfg, sshExec, matrixClient, memStore, kStore, roomCtx, logger)
a := &Agent{
cfg: cfg,
@@ -171,10 +194,11 @@ func New(cfg *config.AgentConfig, rules []decision.Rule, logger *slog.Logger) (*
toolReg: toolReg,
logger: logger,
cryptoStore: cryptoStore,
windows: make(map[string]memory.Window),
memStore: memStore,
windowSize: windowSize,
roomCtx: roomCtx,
windows: make(map[string]memory.Window),
memStore: memStore,
knowledgeStore: kStore,
windowSize: windowSize,
roomCtx: roomCtx,
}
// Register memory_clear_context with self as WindowClearer (after a is created)
@@ -217,6 +241,9 @@ func (a *Agent) Run(ctx context.Context) error {
if a.memStore != nil {
defer a.memStore.Close()
}
if a.knowledgeStore != nil {
defer a.knowledgeStore.Close()
}
a.logger.Info("agent starting",
"id", a.cfg.Agent.ID,
"name", a.cfg.Agent.Name,
@@ -605,6 +632,7 @@ func buildToolRegistry(
sshExec *ssh.Executor,
matrixClient *matrix.Client,
memStore memory.Store,
kStore *shellknowledge.FileStore,
roomCtx *tools.RoomContext,
logger *slog.Logger,
) *tools.Registry {
@@ -643,5 +671,14 @@ func buildToolRegistry(
logger.Debug("registered memory tools")
}
// Knowledge tools
if cfg.Tools.Knowledge.Enabled && kStore != nil {
reg.Register(tools.NewKnowledgeSearch(kStore))
reg.Register(tools.NewKnowledgeRead(kStore))
reg.Register(tools.NewKnowledgeWrite(kStore))
reg.Register(tools.NewKnowledgeList(kStore))
logger.Debug("registered knowledge tools")
}
return reg
}