diff --git a/config/config.example.json b/config/config.example.json index e8c6b3d3f..6628cdf19 100644 --- a/config/config.example.json +++ b/config/config.example.json @@ -203,6 +203,15 @@ } }, "tools": { + "core": { + "enable_web_fetch": true, + "enable_message": true, + "enable_spawn": true + }, + "hardware": { + "enable_i2c": false, + "enable_spi": false + }, "web": { "brave": { "enabled": false, @@ -223,10 +232,19 @@ "exec_timeout_minutes": 5 }, "exec": { + "enabled": true, "enable_deny_patterns": false, "custom_deny_patterns": [] }, + "filesystem": { + "enable_read": true, + "enable_write": true, + "enable_list": true, + "enable_edit": true, + "enable_append": true + }, "skills": { + "enabled": true, "registries": { "clawhub": { "enabled": true, diff --git a/pkg/agent/instance.go b/pkg/agent/instance.go index c6a54c7d2..3773325e2 100644 --- a/pkg/agent/instance.go +++ b/pkg/agent/instance.go @@ -48,12 +48,24 @@ func NewAgentInstance( restrict := defaults.RestrictToWorkspace toolsRegistry := tools.NewToolRegistry() - toolsRegistry.Register(tools.NewReadFileTool(workspace, restrict)) - toolsRegistry.Register(tools.NewWriteFileTool(workspace, restrict)) - toolsRegistry.Register(tools.NewListDirTool(workspace, restrict)) - toolsRegistry.Register(tools.NewExecToolWithConfig(workspace, restrict, cfg)) - toolsRegistry.Register(tools.NewEditFileTool(workspace, restrict)) - toolsRegistry.Register(tools.NewAppendFileTool(workspace, restrict)) + if cfg.Tools.Filesystem.EnableRead { + toolsRegistry.Register(tools.NewReadFileTool(workspace, restrict)) + } + if cfg.Tools.Filesystem.EnableWrite { + toolsRegistry.Register(tools.NewWriteFileTool(workspace, restrict)) + } + if cfg.Tools.Filesystem.EnableList { + toolsRegistry.Register(tools.NewListDirTool(workspace, restrict)) + } + if cfg.Tools.Filesystem.EnableEdit { + toolsRegistry.Register(tools.NewEditFileTool(workspace, restrict)) + } + if cfg.Tools.Filesystem.EnableAppend { + toolsRegistry.Register(tools.NewAppendFileTool(workspace, restrict)) + } + if cfg.Tools.Exec.Enabled { + toolsRegistry.Register(tools.NewExecToolWithConfig(workspace, restrict, cfg)) + } sessionsDir := filepath.Join(workspace, "sessions") sessionsManager := session.NewSessionManager(sessionsDir) diff --git a/pkg/agent/loop.go b/pkg/agent/loop.go index 9a2bb1198..bca2e2bff 100644 --- a/pkg/agent/loop.go +++ b/pkg/agent/loop.go @@ -109,45 +109,57 @@ func registerSharedTools( }); searchTool != nil { agent.Tools.Register(searchTool) } - agent.Tools.Register(tools.NewWebFetchTool(50000)) + if cfg.Tools.Core.EnableWebFetch { + agent.Tools.Register(tools.NewWebFetchTool(50000)) + } // Hardware tools (I2C, SPI) - Linux only, returns error on other platforms - agent.Tools.Register(tools.NewI2CTool()) - agent.Tools.Register(tools.NewSPITool()) + if cfg.Tools.Hardware.EnableI2C { + agent.Tools.Register(tools.NewI2CTool()) + } + if cfg.Tools.Hardware.EnableSPI { + agent.Tools.Register(tools.NewSPITool()) + } // Message tool - messageTool := tools.NewMessageTool() - messageTool.SetSendCallback(func(channel, chatID, content string) error { - msgBus.PublishOutbound(bus.OutboundMessage{ - Channel: channel, - ChatID: chatID, - Content: content, + if cfg.Tools.Core.EnableMessage { + messageTool := tools.NewMessageTool() + messageTool.SetSendCallback(func(channel, chatID, content string) error { + msgBus.PublishOutbound(bus.OutboundMessage{ + Channel: channel, + ChatID: chatID, + Content: content, + }) + return nil }) - return nil - }) - agent.Tools.Register(messageTool) + agent.Tools.Register(messageTool) + } // Skill discovery and installation tools - registryMgr := skills.NewRegistryManagerFromConfig(skills.RegistryConfig{ - MaxConcurrentSearches: cfg.Tools.Skills.MaxConcurrentSearches, - ClawHub: skills.ClawHubConfig(cfg.Tools.Skills.Registries.ClawHub), - }) - searchCache := skills.NewSearchCache( - cfg.Tools.Skills.SearchCache.MaxSize, - time.Duration(cfg.Tools.Skills.SearchCache.TTLSeconds)*time.Second, - ) - agent.Tools.Register(tools.NewFindSkillsTool(registryMgr, searchCache)) - agent.Tools.Register(tools.NewInstallSkillTool(registryMgr, agent.Workspace)) + if cfg.Tools.Skills.Enabled { + registryMgr := skills.NewRegistryManagerFromConfig(skills.RegistryConfig{ + MaxConcurrentSearches: cfg.Tools.Skills.MaxConcurrentSearches, + ClawHub: skills.ClawHubConfig(cfg.Tools.Skills.Registries.ClawHub), + }) + searchCache := skills.NewSearchCache( + cfg.Tools.Skills.SearchCache.MaxSize, + time.Duration(cfg.Tools.Skills.SearchCache.TTLSeconds)*time.Second, + ) + agent.Tools.Register(tools.NewFindSkillsTool(registryMgr, searchCache)) + agent.Tools.Register(tools.NewInstallSkillTool(registryMgr, agent.Workspace)) + } // Spawn tool with allowlist checker - subagentManager := tools.NewSubagentManager(provider, agent.Model, agent.Workspace, msgBus) - subagentManager.SetLLMOptions(agent.MaxTokens, agent.Temperature) - spawnTool := tools.NewSpawnTool(subagentManager) - currentAgentID := agentID - spawnTool.SetAllowlistChecker(func(targetAgentID string) bool { - return registry.CanSpawnSubagent(currentAgentID, targetAgentID) - }) - agent.Tools.Register(spawnTool) + if cfg.Tools.Core.EnableSpawn { + subagentManager := tools.NewSubagentManager(provider, agent.Model, agent.Workspace, msgBus) + subagentManager.SetLLMOptions(agent.MaxTokens, agent.Temperature) + spawnTool := tools.NewSpawnTool(subagentManager) + currentAgentID := agentID + spawnTool.SetAllowlistChecker(func(targetAgentID string) bool { + return registry.CanSpawnSubagent(currentAgentID, targetAgentID) + }) + agent.Tools.Register(spawnTool) + } // Update context builder with the complete tools registry agent.ContextBuilder.SetToolsRegistry(agent.Tools) diff --git a/pkg/config/config.go b/pkg/config/config.go index 85135c820..db4ae1e65 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -456,22 +456,47 @@ type WebToolsConfig struct { } type CronToolsConfig struct { - ExecTimeoutMinutes int `json:"exec_timeout_minutes" env:"PICOCLAW_TOOLS_CRON_EXEC_TIMEOUT_MINUTES"` // 0 means no timeout + Enabled bool `json:"enabled" env:"PICOCLAW_TOOLS_CRON_ENABLED"` + ExecTimeoutMinutes int `json:"exec_timeout_minutes" env:"PICOCLAW_TOOLS_CRON_EXEC_TIMEOUT_MINUTES"` // 0 means no timeout +} + +type HardwareToolsConfig struct { + EnableI2C bool `json:"enable_i2c" env:"PICOCLAW_TOOLS_HW_ENABLE_I2C"` + EnableSPI bool `json:"enable_spi" env:"PICOCLAW_TOOLS_HW_ENABLE_SPI"` +} + +type CoreToolsConfig struct { + EnableWebFetch bool `json:"enable_web_fetch" env:"PICOCLAW_TOOLS_CORE_ENABLE_WEB_FETCH"` + EnableMessage bool `json:"enable_message" env:"PICOCLAW_TOOLS_CORE_ENABLE_MESSAGE"` + EnableSpawn bool `json:"enable_spawn" env:"PICOCLAW_TOOLS_CORE_ENABLE_SPAWN"` +} + +type FilesystemConfig struct { + EnableRead bool `json:"enable_read" env:"PICOCLAW_TOOLS_FS_ENABLE_READ"` + EnableWrite bool `json:"enable_write" env:"PICOCLAW_TOOLS_FS_ENABLE_WRITE"` + EnableList bool `json:"enable_list" env:"PICOCLAW_TOOLS_FS_ENABLE_LIST"` + EnableEdit bool `json:"enable_edit" env:"PICOCLAW_TOOLS_FS_ENABLE_EDIT"` + EnableAppend bool `json:"enable_append" env:"PICOCLAW_TOOLS_FS_ENABLE_APPEND"` } type ExecConfig struct { + Enabled bool `json:"enabled" env:"PICOCLAW_TOOLS_EXEC_ENABLED"` EnableDenyPatterns bool `json:"enable_deny_patterns" env:"PICOCLAW_TOOLS_EXEC_ENABLE_DENY_PATTERNS"` CustomDenyPatterns []string `json:"custom_deny_patterns" env:"PICOCLAW_TOOLS_EXEC_CUSTOM_DENY_PATTERNS"` } type ToolsConfig struct { - Web WebToolsConfig `json:"web"` - Cron CronToolsConfig `json:"cron"` - Exec ExecConfig `json:"exec"` - Skills SkillsToolsConfig `json:"skills"` + Web WebToolsConfig `json:"web"` + Cron CronToolsConfig `json:"cron"` + Exec ExecConfig `json:"exec"` + Skills SkillsToolsConfig `json:"skills"` + Filesystem FilesystemConfig `json:"filesystem"` + Hardware HardwareToolsConfig `json:"hardware"` + Core CoreToolsConfig `json:"core"` } type SkillsToolsConfig struct { + Enabled bool `json:"enabled" env:"PICOCLAW_TOOLS_SKILLS_ENABLED"` Registries SkillsRegistriesConfig `json:"registries"` MaxConcurrentSearches int `json:"max_concurrent_searches" env:"PICOCLAW_SKILLS_MAX_CONCURRENT_SEARCHES"` SearchCache SearchCacheConfig `json:"search_cache"` diff --git a/pkg/config/defaults.go b/pkg/config/defaults.go index b96ee4d89..912ce8407 100644 --- a/pkg/config/defaults.go +++ b/pkg/config/defaults.go @@ -276,6 +276,15 @@ func DefaultConfig() *Config { Port: 18790, }, Tools: ToolsConfig{ + Core: CoreToolsConfig{ + EnableWebFetch: true, + EnableMessage: true, + EnableSpawn: true, + }, + Hardware: HardwareToolsConfig{ + EnableI2C: true, + EnableSPI: true, + }, Web: WebToolsConfig{ Brave: BraveConfig{ Enabled: false, @@ -296,9 +305,18 @@ func DefaultConfig() *Config { ExecTimeoutMinutes: 5, }, Exec: ExecConfig{ + Enabled: true, EnableDenyPatterns: true, }, + Filesystem: FilesystemConfig{ + EnableRead: true, + EnableWrite: true, + EnableList: true, + EnableEdit: true, + EnableAppend: true, + }, Skills: SkillsToolsConfig{ + Enabled: true, Registries: SkillsRegistriesConfig{ ClawHub: ClawHubRegistryConfig{ Enabled: true,