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.
70 lines
No EOL
1.4 KiB
Go
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
|
|
} |