picoclaw/pkg/tools/registry.go
Danieldd28 52e3470e06 feat: implement swarm agents with hierarchical collaboration and vector memory
This commit introduces a multi-agent Swarm Engine to PicoClaw,
enabling complex task orchestration through autonomous collaboration and long-term
semantic memory.

Key Features:
- Actor Model Architecture: Every agent (node) runs in an isolated goroutine,
  communicating via a lightweight internal Event Bus.
- Hierarchical Delegation: Manager nodes can dynamically spawn specialized
  worker nodes (Researchers, Analysts, etc.) to perform sub-tasks in parallel.
- Hybrid Memory System: Combined SQLite for state persistence and Chromem-go
  for a persistent, cross-swarm Vector Knowledge Base.
- Progressive Summarization: Implemented an intelligent memory pruning mechanism
  that summarizes older context before truncation to preserve findings without
  exceeding token limits.
- Role-Based Access Control (RBAC): Configurable tool policies per role
  (e.g., Researchers can browse but not execute shell commands).

Performance & Scaling:
- Low Footprint: Idle memory usage is ~7-8 MB RSS.
- Efficient Scaling: During a stress test with 10 concurrent agents performing
  intensive research, memory usage peaked at only 27 MB.
- Per-Node Cost: Each active agent consumes approximately 0.6 MB to 2 MB of
  physical RAM depending on conversation length and summarization state.
- Stability: Successfully handled 10 parallel LLM requests with zero race
  conditions, showcasing the robustness of the Go-based Actor model.

Integration:
- Native CLI Support: Added /swarm spawn, /swarm list, and /swarm status commands.
- Mermaid Visualization: Support for /swarm viz <id> to generate organizational
  charts of active agent hierarchies.
- Configurable: Roles, models, and security policies are fully customizable
  via config.json.
2026-02-10 21:53:43 +07:00

70 lines
No EOL
1.4 KiB
Go

package tools
import (
"context"
"fmt"
"sync"
)
type ToolRegistry struct {
tools map[string]Tool
mu sync.RWMutex
}
func NewToolRegistry() *ToolRegistry {
return &ToolRegistry{
tools: make(map[string]Tool),
}
}
func (tr *ToolRegistry) Register(tool Tool) {
tr.mu.Lock()
defer tr.mu.Unlock()
tr.tools[tool.Name()] = tool
}
func (tr *ToolRegistry) Get(name string) (Tool, bool) {
tr.mu.RLock()
defer tr.mu.RUnlock()
tool, ok := tr.tools[name]
return tool, ok
}
func (tr *ToolRegistry) Execute(ctx context.Context, name string, args map[string]interface{}) (string, error) {
tool, ok := tr.Get(name)
if !ok {
return "", fmt.Errorf("tool not found: %s", name)
}
return tool.Execute(ctx, args)
}
func (tr *ToolRegistry) GetDefinitions() []map[string]interface{} {
tr.mu.RLock()
defer tr.mu.RUnlock()
var definitions []map[string]interface{}
for _, tool := range tr.tools {
definitions = append(definitions, map[string]interface{}{
"type": "function",
"function": map[string]interface{}{
"name": tool.Name(),
"description": tool.Description(),
"parameters": tool.Parameters(),
},
})
}
return definitions
}
// Clone creates a shallow copy of the registry
func (tr *ToolRegistry) Clone() *ToolRegistry {
tr.mu.RLock()
defer tr.mu.RUnlock()
newReg := NewToolRegistry()
for name, tool := range tr.tools {
newReg.tools[name] = tool
}
return newReg
}