Enhance code as comment from best friends
This commit is contained in:
parent
c3967a560d
commit
487edfa64e
4 changed files with 71 additions and 27 deletions
|
|
@ -3,7 +3,7 @@
|
||||||
"defaults": {
|
"defaults": {
|
||||||
"workspace": "~/.picoclaw/workspace",
|
"workspace": "~/.picoclaw/workspace",
|
||||||
"restrict_to_workspace": true,
|
"restrict_to_workspace": true,
|
||||||
"model": "ollama/qwen2.5:14b-instruct ",
|
"model": "",
|
||||||
"max_tokens": 8192,
|
"max_tokens": 8192,
|
||||||
"temperature": 0.7,
|
"temperature": 0.7,
|
||||||
"max_tool_iterations": 20
|
"max_tool_iterations": 20
|
||||||
|
|
@ -119,11 +119,11 @@
|
||||||
"tools": {
|
"tools": {
|
||||||
"web": {
|
"web": {
|
||||||
"search": {
|
"search": {
|
||||||
"provider": "ollama",
|
"provider": "ollama/brave/duckduckgo",
|
||||||
"api_key": "Your Ollama API Key",
|
"api_key": "Your API Key",
|
||||||
"endpoint": "https://ollama.com/api/web_search",
|
"endpoint": "https://ollama.com/api/web_search",
|
||||||
"rest_type": "POST",
|
"rest_type": "POST for ollama, GET for others",
|
||||||
"query_param": "query",
|
"query_param": "query for ollama, q for others",
|
||||||
"max_results": 5
|
"max_results": 5
|
||||||
},
|
},
|
||||||
"perplexity": {
|
"perplexity": {
|
||||||
|
|
|
||||||
|
|
@ -70,7 +70,7 @@ func NewAgentLoop(cfg *config.Config, msgBus *bus.MessageBus, provider providers
|
||||||
Param: cfg.Tools.Web.Search.QueryParam,
|
Param: cfg.Tools.Web.Search.QueryParam,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Provider: "duckduckgo",
|
Provider: "duckduckgo", //fallback to duckduckgo if not configured
|
||||||
MaxResults: 5,
|
MaxResults: 5,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -283,23 +283,6 @@ type GatewayConfig struct {
|
||||||
Port int `json:"port" env:"PICOCLAW_GATEWAY_PORT"`
|
Port int `json:"port" env:"PICOCLAW_GATEWAY_PORT"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type BraveConfig struct {
|
|
||||||
Enabled bool `json:"enabled" env:"PICOCLAW_TOOLS_WEB_BRAVE_ENABLED"`
|
|
||||||
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 OllamaConfig struct {
|
|
||||||
Enabled bool `json:"enabled" env:"PICOCLAW_TOOLS_WEB_OLLAMA_ENABLED"`
|
|
||||||
BaseURL string `json:"base_url" env:"PICOCLAW_TOOLS_WEB_OLLAMA_BASE_URL"`
|
|
||||||
MaxResults int `json:"max_results" env:"PICOCLAW_TOOLS_WEB_OLLAMA_MAX_RESULTS"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// WebSearchConfig defines a single active web search provider
|
// WebSearchConfig defines a single active web search provider
|
||||||
// Falls back to DuckDuckGo if the primary provider fails
|
// Falls back to DuckDuckGo if the primary provider fails
|
||||||
type WebSearchConfig struct {
|
type WebSearchConfig struct {
|
||||||
|
|
@ -429,7 +412,7 @@ func DefaultConfig() *Config {
|
||||||
Web: WebToolsConfig{
|
Web: WebToolsConfig{
|
||||||
Search: WebSearchConfig{
|
Search: WebSearchConfig{
|
||||||
Provider: "ollama",
|
Provider: "ollama",
|
||||||
APIKey: "77b893700a1d4c8dad9a7326be9a76d6.7pl0DA9ojPa_6UCMMZ_Sk-Cn",
|
APIKey: "",
|
||||||
Endpoint: "https://ollama.com/api/web_search",
|
Endpoint: "https://ollama.com/api/web_search",
|
||||||
RestType: "POST",
|
RestType: "POST",
|
||||||
QueryParam: "query",
|
QueryParam: "query",
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,8 @@ import (
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/sipeed/picoclaw/pkg/logger"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
@ -208,10 +210,22 @@ func (p *OllamaSearchProvider) Search(ctx context.Context, query string, count i
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
||||||
body, err := io.ReadAll(resp.Body)
|
body, err := io.ReadAll(resp.Body)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("failed to read response: %w", err)
|
return "", fmt.Errorf("failed to read response: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if resp.StatusCode != http.StatusOK {
|
||||||
|
logger.ErrorCF("tool", "Ollama web search request failed",
|
||||||
|
map[string]interface{}{
|
||||||
|
"provider": "ollama",
|
||||||
|
"status_code": resp.StatusCode,
|
||||||
|
"endpoint": p.baseURL,
|
||||||
|
"response": strings.TrimSpace(string(body)),
|
||||||
|
})
|
||||||
|
return "", fmt.Errorf("Ollama API error: %s", string(body))
|
||||||
|
}
|
||||||
|
|
||||||
// Return the raw JSON string for the agent/tool to process
|
// Return the raw JSON string for the agent/tool to process
|
||||||
return string(body), nil
|
return string(body), nil
|
||||||
}
|
}
|
||||||
|
|
@ -283,6 +297,7 @@ func (p *PerplexitySearchProvider) Search(ctx context.Context, query string, cou
|
||||||
|
|
||||||
type WebSearchTool struct {
|
type WebSearchTool struct {
|
||||||
provider SearchProvider
|
provider SearchProvider
|
||||||
|
fallback SearchProvider
|
||||||
maxResults int
|
maxResults int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -298,11 +313,12 @@ type WebSearchTool struct {
|
||||||
// opts := []WebSearchToolOptions{
|
// opts := []WebSearchToolOptions{
|
||||||
// {Provider: "brave", APIKey: "key", MaxResults: 5},
|
// {Provider: "brave", APIKey: "key", MaxResults: 5},
|
||||||
// {Provider: "ollama", BaseURL: "http://localhost:11434", MaxResults: 5},
|
// {Provider: "ollama", BaseURL: "http://localhost:11434", MaxResults: 5},
|
||||||
|
// {Provider: "perplexity", APIKey: "key", MaxResults: 5},
|
||||||
// {Provider: "duckduckgo", MaxResults: 5},
|
// {Provider: "duckduckgo", MaxResults: 5},
|
||||||
// }
|
// }
|
||||||
// tool := NewWebSearchTool(opts...)
|
// tool := NewWebSearchTool(opts...)
|
||||||
type WebSearchToolOptions struct {
|
type WebSearchToolOptions struct {
|
||||||
Provider string // "brave", "ollama", "duckduckgo"
|
Provider string // "brave", "ollama", "perplexity", "duckduckgo"
|
||||||
APIKey string // For Brave API
|
APIKey string // For Brave API
|
||||||
BaseURL string // For custom providers (e.g., Ollama)
|
BaseURL string // For custom providers (e.g., Ollama)
|
||||||
MaxResults int // Default: 5
|
MaxResults int // Default: 5
|
||||||
|
|
@ -311,8 +327,8 @@ type WebSearchToolOptions struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewWebSearchTool(opts ...WebSearchToolOptions) *WebSearchTool {
|
func NewWebSearchTool(opts ...WebSearchToolOptions) *WebSearchTool {
|
||||||
// Priority order: Brave > Ollama > DuckDuckGo
|
// Priority order: Brave > Ollama > Perplexity > DuckDuckGo
|
||||||
priorityOrder := []string{"brave", "ollama", "duckduckgo"}
|
priorityOrder := []string{"brave", "ollama", "perplexity", "duckduckgo"}
|
||||||
optMap := make(map[string]WebSearchToolOptions)
|
optMap := make(map[string]WebSearchToolOptions)
|
||||||
|
|
||||||
// Build map of enabled providers
|
// Build map of enabled providers
|
||||||
|
|
@ -344,6 +360,15 @@ func NewWebSearchTool(opts ...WebSearchToolOptions) *WebSearchTool {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var fallbackProvider SearchProvider
|
||||||
|
if selectedOpt != nil && selectedOpt.Provider != "duckduckgo" {
|
||||||
|
if ddgOpt, exists := optMap["duckduckgo"]; exists {
|
||||||
|
if p, err := createProvider(&ddgOpt); err == nil && p != nil {
|
||||||
|
fallbackProvider = p
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
maxResults := 5
|
maxResults := 5
|
||||||
if selectedOpt != nil && selectedOpt.MaxResults > 0 {
|
if selectedOpt != nil && selectedOpt.MaxResults > 0 {
|
||||||
maxResults = selectedOpt.MaxResults
|
maxResults = selectedOpt.MaxResults
|
||||||
|
|
@ -351,6 +376,7 @@ func NewWebSearchTool(opts ...WebSearchToolOptions) *WebSearchTool {
|
||||||
|
|
||||||
return &WebSearchTool{
|
return &WebSearchTool{
|
||||||
provider: provider,
|
provider: provider,
|
||||||
|
fallback: fallbackProvider,
|
||||||
maxResults: maxResults,
|
maxResults: maxResults,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -386,6 +412,12 @@ func createProvider(opt *WebSearchToolOptions) (SearchProvider, error) {
|
||||||
case "duckduckgo":
|
case "duckduckgo":
|
||||||
return &DuckDuckGoSearchProvider{}, nil
|
return &DuckDuckGoSearchProvider{}, nil
|
||||||
|
|
||||||
|
case "perplexity":
|
||||||
|
if opt.APIKey == "" {
|
||||||
|
return nil, fmt.Errorf("Perplexity API key required")
|
||||||
|
}
|
||||||
|
return &PerplexitySearchProvider{apiKey: opt.APIKey}, nil
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("unknown provider: %s", opt.Provider)
|
return nil, fmt.Errorf("unknown provider: %s", opt.Provider)
|
||||||
}
|
}
|
||||||
|
|
@ -433,6 +465,35 @@ func (t *WebSearchTool) Execute(ctx context.Context, args map[string]interface{}
|
||||||
|
|
||||||
result, err := t.provider.Search(ctx, query, count)
|
result, err := t.provider.Search(ctx, query, count)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if t.fallback != nil {
|
||||||
|
logger.WarnCF("tool", "Primary web search failed, attempting fallback",
|
||||||
|
map[string]interface{}{
|
||||||
|
"primary_error": err.Error(),
|
||||||
|
"fallback": "duckduckgo",
|
||||||
|
"query": query,
|
||||||
|
})
|
||||||
|
|
||||||
|
fallbackResult, fallbackErr := t.fallback.Search(ctx, query, count)
|
||||||
|
if fallbackErr == nil {
|
||||||
|
logger.InfoCF("tool", "Fallback web search succeeded",
|
||||||
|
map[string]interface{}{
|
||||||
|
"provider": "duckduckgo",
|
||||||
|
"query": query,
|
||||||
|
})
|
||||||
|
|
||||||
|
return &ToolResult{
|
||||||
|
ForLLM: fmt.Sprintf("Primary search provider failed: %v\nFallback provider (duckduckgo) result:\n%s", err, fallbackResult),
|
||||||
|
ForUser: fallbackResult,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.ErrorCF("tool", "Fallback web search failed",
|
||||||
|
map[string]interface{}{
|
||||||
|
"provider": "duckduckgo",
|
||||||
|
"error": fallbackErr.Error(),
|
||||||
|
"query": query,
|
||||||
|
})
|
||||||
|
}
|
||||||
return ErrorResult(fmt.Sprintf("search failed: %v", err))
|
return ErrorResult(fmt.Sprintf("search failed: %v", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue