feat(web): rename web provider config from perplexity to grok

This commit is contained in:
root 2026-02-23 20:59:27 +08:00
parent 08a9d99cd8
commit 8c2058fc5c
6 changed files with 59 additions and 33 deletions

View file

@ -213,9 +213,11 @@
"enabled": true, "enabled": true,
"max_results": 5 "max_results": 5
}, },
"perplexity": { "grok": {
"enabled": false, "enabled": false,
"api_key": "pplx-xxx", "api_key": "xai-xxx",
"endpoint": "https://api.x.ai/v1/chat/completions",
"default_model": "grok-4",
"max_results": 5 "max_results": 5
}, },
"proxy": "" "proxy": ""

View file

@ -34,12 +34,14 @@ Web tools are used for web search and fetching.
| `enabled` | bool | true | Enable DuckDuckGo search | | `enabled` | bool | true | Enable DuckDuckGo search |
| `max_results` | int | 5 | Maximum number of results | | `max_results` | int | 5 | Maximum number of results |
### Perplexity ### Grok
| Config | Type | Default | Description | | Config | Type | Default | Description |
|--------|------|---------|-------------| |--------|------|---------|-------------|
| `enabled` | bool | false | Enable Perplexity search | | `enabled` | bool | false | Enable Grok search |
| `api_key` | string | - | Perplexity API key | | `api_key` | string | - | Grok API key |
| `endpoint` | string | `https://api.x.ai/v1/chat/completions` | Grok-compatible chat completions endpoint |
| `default_model` | string | `grok-4` | Default Grok model used by web search |
| `max_results` | int | 5 | Maximum number of results | | `max_results` | int | 5 | Maximum number of results |
## Exec Tool ## Exec Tool

View file

@ -107,9 +107,11 @@ func registerSharedTools(
TavilyEnabled: cfg.Tools.Web.Tavily.Enabled, TavilyEnabled: cfg.Tools.Web.Tavily.Enabled,
DuckDuckGoMaxResults: cfg.Tools.Web.DuckDuckGo.MaxResults, DuckDuckGoMaxResults: cfg.Tools.Web.DuckDuckGo.MaxResults,
DuckDuckGoEnabled: cfg.Tools.Web.DuckDuckGo.Enabled, DuckDuckGoEnabled: cfg.Tools.Web.DuckDuckGo.Enabled,
PerplexityAPIKey: cfg.Tools.Web.Perplexity.APIKey, GrokAPIKey: cfg.Tools.Web.Grok.APIKey,
PerplexityMaxResults: cfg.Tools.Web.Perplexity.MaxResults, GrokEndpoint: cfg.Tools.Web.Grok.Endpoint,
PerplexityEnabled: cfg.Tools.Web.Perplexity.Enabled, GrokModel: cfg.Tools.Web.Grok.DefaultModel,
GrokMaxResults: cfg.Tools.Web.Grok.MaxResults,
GrokEnabled: cfg.Tools.Web.Grok.Enabled,
Proxy: cfg.Tools.Web.Proxy, Proxy: cfg.Tools.Web.Proxy,
}); searchTool != nil { }); searchTool != nil {
agent.Tools.Register(searchTool) agent.Tools.Register(searchTool)

View file

@ -444,17 +444,19 @@ type DuckDuckGoConfig struct {
MaxResults int `json:"max_results" env:"PICOCLAW_TOOLS_WEB_DUCKDUCKGO_MAX_RESULTS"` MaxResults int `json:"max_results" env:"PICOCLAW_TOOLS_WEB_DUCKDUCKGO_MAX_RESULTS"`
} }
type PerplexityConfig struct { type GrokConfig struct {
Enabled bool `json:"enabled" env:"PICOCLAW_TOOLS_WEB_PERPLEXITY_ENABLED"` Enabled bool `json:"enabled" env:"PICOCLAW_TOOLS_WEB_GROK_ENABLED"`
APIKey string `json:"api_key" env:"PICOCLAW_TOOLS_WEB_PERPLEXITY_API_KEY"` APIKey string `json:"api_key" env:"PICOCLAW_TOOLS_WEB_GROK_API_KEY"`
MaxResults int `json:"max_results" env:"PICOCLAW_TOOLS_WEB_PERPLEXITY_MAX_RESULTS"` Endpoint string `json:"endpoint" env:"PICOCLAW_TOOLS_WEB_GROK_ENDPOINT"`
DefaultModel string `json:"default_model" env:"PICOCLAW_TOOLS_WEB_GROK_DEFAULT_MODEL"`
MaxResults int `json:"max_results" env:"PICOCLAW_TOOLS_WEB_GROK_MAX_RESULTS"`
} }
type WebToolsConfig struct { type WebToolsConfig struct {
Brave BraveConfig `json:"brave"` Brave BraveConfig `json:"brave"`
Tavily TavilyConfig `json:"tavily"` Tavily TavilyConfig `json:"tavily"`
DuckDuckGo DuckDuckGoConfig `json:"duckduckgo"` DuckDuckGo DuckDuckGoConfig `json:"duckduckgo"`
Perplexity PerplexityConfig `json:"perplexity"` Grok GrokConfig `json:"grok"`
// Proxy is an optional proxy URL for web tools (http/https/socks5/socks5h). // Proxy is an optional proxy URL for web tools (http/https/socks5/socks5h).
// For authenticated proxies, prefer HTTP_PROXY/HTTPS_PROXY env vars instead of embedding credentials in config. // For authenticated proxies, prefer HTTP_PROXY/HTTPS_PROXY env vars instead of embedding credentials in config.
Proxy string `json:"proxy,omitempty" env:"PICOCLAW_TOOLS_WEB_PROXY"` Proxy string `json:"proxy,omitempty" env:"PICOCLAW_TOOLS_WEB_PROXY"`

View file

@ -287,9 +287,11 @@ func DefaultConfig() *Config {
Enabled: true, Enabled: true,
MaxResults: 5, MaxResults: 5,
}, },
Perplexity: PerplexityConfig{ Grok: GrokConfig{
Enabled: false, Enabled: false,
APIKey: "", APIKey: "",
Endpoint: "https://api.x.ai/v1/chat/completions",
DefaultModel: "grok-4",
MaxResults: 5, MaxResults: 5,
}, },
}, },

View file

@ -319,16 +319,25 @@ func stripTags(content string) string {
return reTags.ReplaceAllString(content, "") return reTags.ReplaceAllString(content, "")
} }
type PerplexitySearchProvider struct { type GrokSearchProvider struct {
apiKey string apiKey string
endpoint string
model string
proxy string proxy string
} }
func (p *PerplexitySearchProvider) Search(ctx context.Context, query string, count int) (string, error) { func (p *GrokSearchProvider) Search(ctx context.Context, query string, count int) (string, error) {
searchURL := "https://api.perplexity.ai/chat/completions" searchURL := strings.TrimSpace(p.endpoint)
if searchURL == "" {
searchURL = "https://api.x.ai/v1/chat/completions"
}
model := strings.TrimSpace(p.model)
if model == "" {
model = "grok-4"
}
payload := map[string]any{ payload := map[string]any{
"model": "sonar", "model": model,
"messages": []map[string]string{ "messages": []map[string]string{
{ {
"role": "system", "role": "system",
@ -372,7 +381,7 @@ func (p *PerplexitySearchProvider) Search(ctx context.Context, query string, cou
} }
if resp.StatusCode != http.StatusOK { if resp.StatusCode != http.StatusOK {
return "", fmt.Errorf("Perplexity API error: %s", string(body)) return "", fmt.Errorf("Grok API error: %s", string(body))
} }
var searchResp struct { var searchResp struct {
@ -391,7 +400,7 @@ func (p *PerplexitySearchProvider) Search(ctx context.Context, query string, cou
return fmt.Sprintf("No results for: %s", query), nil return fmt.Sprintf("No results for: %s", query), nil
} }
return fmt.Sprintf("Results for: %s (via Perplexity)\n%s", query, searchResp.Choices[0].Message.Content), nil return fmt.Sprintf("Results for: %s (via Grok)\n%s", query, searchResp.Choices[0].Message.Content), nil
} }
type WebSearchTool struct { type WebSearchTool struct {
@ -409,9 +418,11 @@ type WebSearchToolOptions struct {
TavilyEnabled bool TavilyEnabled bool
DuckDuckGoMaxResults int DuckDuckGoMaxResults int
DuckDuckGoEnabled bool DuckDuckGoEnabled bool
PerplexityAPIKey string GrokAPIKey string
PerplexityMaxResults int GrokEndpoint string
PerplexityEnabled bool GrokModel string
GrokMaxResults int
GrokEnabled bool
Proxy string Proxy string
} }
@ -419,11 +430,16 @@ func NewWebSearchTool(opts WebSearchToolOptions) *WebSearchTool {
var provider SearchProvider var provider SearchProvider
maxResults := 5 maxResults := 5
// Priority: Perplexity > Brave > Tavily > DuckDuckGo // Priority: Grok > Brave > Tavily > DuckDuckGo
if opts.PerplexityEnabled && opts.PerplexityAPIKey != "" { if opts.GrokEnabled && opts.GrokAPIKey != "" {
provider = &PerplexitySearchProvider{apiKey: opts.PerplexityAPIKey, proxy: opts.Proxy} provider = &GrokSearchProvider{
if opts.PerplexityMaxResults > 0 { apiKey: opts.GrokAPIKey,
maxResults = opts.PerplexityMaxResults endpoint: opts.GrokEndpoint,
model: opts.GrokModel,
proxy: opts.Proxy,
}
if opts.GrokMaxResults > 0 {
maxResults = opts.GrokMaxResults
} }
} else if opts.BraveEnabled && opts.BraveAPIKey != "" { } else if opts.BraveEnabled && opts.BraveAPIKey != "" {
provider = &BraveSearchProvider{apiKey: opts.BraveAPIKey, proxy: opts.Proxy} provider = &BraveSearchProvider{apiKey: opts.BraveAPIKey, proxy: opts.Proxy}