feat: add support for DuckDuckGo and refactor Brave search configuration support the control with config.js

This commit is contained in:
Satyam Tiwari
2026-02-13 14:42:55 +05:30
parent fbe1152e2d
commit 2f5849b39d
5 changed files with 77 additions and 22 deletions

View File

@@ -194,9 +194,14 @@ picoclaw onboard
}, },
"tools": { "tools": {
"web": { "web": {
"search": { "brave": {
"enabled": false,
"api_key": "YOUR_BRAVE_API_KEY", "api_key": "YOUR_BRAVE_API_KEY",
"max_results": 5 "max_results": 5
},
"duckduckgo": {
"enabled": true,
"max_results": 5
} }
} }
} }
@@ -507,8 +512,14 @@ picoclaw agent -m "Hello"
}, },
"tools": { "tools": {
"web": { "web": {
"search": { "brave": {
"api_key": "BSA..." "enabled": false,
"api_key": "BSA...",
"max_results": 5
},
"duckduckgo": {
"enabled": true,
"max_results": 5
} }
} }
} }
@@ -564,9 +575,14 @@ Add the key to `~/.picoclaw/config.json` if using Brave:
{ {
"tools": { "tools": {
"web": { "web": {
"search": { "brave": {
"enabled": false,
"api_key": "YOUR_BRAVE_API_KEY", "api_key": "YOUR_BRAVE_API_KEY",
"max_results": 5 "max_results": 5
},
"duckduckgo": {
"enabled": true,
"max_results": 5
} }
} }
} }

View File

@@ -63,8 +63,15 @@ func NewAgentLoop(cfg *config.Config, msgBus *bus.MessageBus, provider providers
toolsRegistry.Register(tools.NewListDirTool(workspace, restrict)) toolsRegistry.Register(tools.NewListDirTool(workspace, restrict))
toolsRegistry.Register(tools.NewExecTool(workspace, restrict)) toolsRegistry.Register(tools.NewExecTool(workspace, restrict))
braveAPIKey := cfg.Tools.Web.Search.APIKey if searchTool := tools.NewWebSearchTool(tools.WebSearchToolOptions{
toolsRegistry.Register(tools.NewWebSearchTool(braveAPIKey, cfg.Tools.Web.Search.MaxResults)) BraveAPIKey: cfg.Tools.Web.Brave.APIKey,
BraveMaxResults: cfg.Tools.Web.Brave.MaxResults,
BraveEnabled: cfg.Tools.Web.Brave.Enabled,
DuckDuckGoMaxResults: cfg.Tools.Web.DuckDuckGo.MaxResults,
DuckDuckGoEnabled: cfg.Tools.Web.DuckDuckGo.Enabled,
}); searchTool != nil {
toolsRegistry.Register(searchTool)
}
toolsRegistry.Register(tools.NewWebFetchTool(50000)) toolsRegistry.Register(tools.NewWebFetchTool(50000))
// Register message tool // Register message tool

View File

@@ -157,13 +157,20 @@ type GatewayConfig struct {
Port int `json:"port" env:"PICOCLAW_GATEWAY_PORT"` Port int `json:"port" env:"PICOCLAW_GATEWAY_PORT"`
} }
type WebSearchConfig struct { type BraveConfig struct {
APIKey string `json:"api_key" env:"PICOCLAW_TOOLS_WEB_SEARCH_API_KEY"` Enabled bool `json:"enabled" env:"PICOCLAW_TOOLS_WEB_BRAVE_ENABLED"`
MaxResults int `json:"max_results" env:"PICOCLAW_TOOLS_WEB_SEARCH_MAX_RESULTS"` APIKey string `json:"api_key" env:"PICOCLAW_TOOLS_WEB_BRAVE_API_KEY"`
MaxResults int `json:"max_results" env:"PICOCLAW_TOOLS_WEB_BRAVE_MAX_RESULTS"`
}
type DuckDuckGoConfig struct {
Enabled bool `json:"enabled" env:"PICOCLAW_TOOLS_WEB_DUCKDUCKGO_ENABLED"`
MaxResults int `json:"max_results" env:"PICOCLAW_TOOLS_WEB_DUCKDUCKGO_MAX_RESULTS"`
} }
type WebToolsConfig struct { type WebToolsConfig struct {
Search WebSearchConfig `json:"search"` Brave BraveConfig `json:"brave"`
DuckDuckGo DuckDuckGoConfig `json:"duckduckgo"`
} }
type ToolsConfig struct { type ToolsConfig struct {
@@ -249,10 +256,15 @@ func DefaultConfig() *Config {
}, },
Tools: ToolsConfig{ Tools: ToolsConfig{
Web: WebToolsConfig{ Web: WebToolsConfig{
Search: WebSearchConfig{ Brave: BraveConfig{
Enabled: false,
APIKey: "", APIKey: "",
MaxResults: 5, MaxResults: 5,
}, },
DuckDuckGo: DuckDuckGoConfig{
Enabled: true,
MaxResults: 5,
},
}, },
}, },
} }

View File

@@ -212,12 +212,17 @@ func ConvertConfig(data map[string]interface{}) (*config.Config, []string, error
if tools, ok := getMap(data, "tools"); ok { if tools, ok := getMap(data, "tools"); ok {
if web, ok := getMap(tools, "web"); ok { if web, ok := getMap(tools, "web"); ok {
// Migrate old "search" config to "brave" if api_key is present
if search, ok := getMap(web, "search"); ok { if search, ok := getMap(web, "search"); ok {
if v, ok := getString(search, "api_key"); ok { if v, ok := getString(search, "api_key"); ok {
cfg.Tools.Web.Search.APIKey = v cfg.Tools.Web.Brave.APIKey = v
if v != "" {
cfg.Tools.Web.Brave.Enabled = true
}
} }
if v, ok := getFloat(search, "max_results"); ok { if v, ok := getFloat(search, "max_results"); ok {
cfg.Tools.Web.Search.MaxResults = int(v) cfg.Tools.Web.Brave.MaxResults = int(v)
cfg.Tools.Web.DuckDuckGo.MaxResults = int(v)
} }
} }
} }
@@ -271,8 +276,8 @@ func MergeConfig(existing, incoming *config.Config) *config.Config {
existing.Channels.MaixCam = incoming.Channels.MaixCam existing.Channels.MaixCam = incoming.Channels.MaixCam
} }
if existing.Tools.Web.Search.APIKey == "" { if existing.Tools.Web.Brave.APIKey == "" {
existing.Tools.Web.Search = incoming.Tools.Web.Search existing.Tools.Web.Brave = incoming.Tools.Web.Brave
} }
return existing return existing

View File

@@ -188,16 +188,31 @@ type WebSearchTool struct {
maxResults int maxResults int
} }
func NewWebSearchTool(apiKey string, maxResults int) *WebSearchTool { type WebSearchToolOptions struct {
if maxResults <= 0 || maxResults > 10 { BraveAPIKey string
maxResults = 5 BraveMaxResults int
} BraveEnabled bool
DuckDuckGoMaxResults int
DuckDuckGoEnabled bool
}
func NewWebSearchTool(opts WebSearchToolOptions) *WebSearchTool {
var provider SearchProvider var provider SearchProvider
if apiKey != "" { maxResults := 5
provider = &BraveSearchProvider{apiKey: apiKey}
} else { // Priority: Brave > DuckDuckGo
if opts.BraveEnabled && opts.BraveAPIKey != "" {
provider = &BraveSearchProvider{apiKey: opts.BraveAPIKey}
if opts.BraveMaxResults > 0 {
maxResults = opts.BraveMaxResults
}
} else if opts.DuckDuckGoEnabled {
provider = &DuckDuckGoSearchProvider{} provider = &DuckDuckGoSearchProvider{}
if opts.DuckDuckGoMaxResults > 0 {
maxResults = opts.DuckDuckGoMaxResults
}
} else {
return nil
} }
return &WebSearchTool{ return &WebSearchTool{