package builtin // ToolSearch 工具 -- 搜索并发现延迟加载的工具. // // 当工具数量较多时,非核心工具会被延迟加载. // 模型通过 ToolSearch 搜索匹配的工具,发现后自动激活. // // 特性: // - ConcurrencySafe: true,ReadOnly: true // - 搜索范围包括工具名称,描述和搜索提示词 // - 搜索到的工具自动激活,后续调用中可直接使用 import ( "context" "encoding/json" "fmt" "strings" "git.flytoex.net/yuanwei/flyto-agent/pkg/permission" "git.flytoex.net/yuanwei/flyto-agent/pkg/tools" ) // ToolSearchTool 是工具搜索工具. type ToolSearchTool struct { deferred *tools.DeferredRegistry } // NewToolSearchTool 创建一个 ToolSearch 工具实例. // // deferred 是延迟加载注册表,用于搜索和激活延迟工具. // 如果 deferred 为 nil,搜索将返回空结果. func NewToolSearchTool(deferred *tools.DeferredRegistry) *ToolSearchTool { return &ToolSearchTool{ deferred: deferred, } } // toolSearchInput 是 ToolSearch 工具的输入参数. type toolSearchInput struct { Query string `json:"query"` } // Name 返回工具名称. func (t *ToolSearchTool) Name() string { return "ToolSearch" } // Description 返回工具描述. func (t *ToolSearchTool) Description(ctx context.Context) string { return "Searches for available tools by keyword. " + "Use this when you need a tool that is not in the current active tool list. " + "Matched tools will be automatically activated for subsequent use. " + "Returns tool names and descriptions." } // InputSchema 返回工具的 JSON Schema 输入定义. func (t *ToolSearchTool) InputSchema() json.RawMessage { return json.RawMessage(`{ "type": "object", "properties": { "query": { "type": "string", "description": "Search query to find tools (e.g., 'fetch web page', 'search files')" } }, "required": ["query"] }`) } // Metadata 返回工具元数据. func (t *ToolSearchTool) Metadata() tools.Metadata { return tools.Metadata{ ConcurrencySafe: true, ReadOnly: true, Destructive: false, SearchHint: "tool search find discover deferred", PermissionClass: permission.PermClassReadOnly, AuditOperation: "read", } } // Execute 执行工具搜索. func (t *ToolSearchTool) Execute(ctx context.Context, input json.RawMessage, progress tools.ProgressFunc) (*tools.Result, error) { var params toolSearchInput if err := json.Unmarshal(input, ¶ms); err != nil { return &tools.Result{ Output: fmt.Sprintf("error: invalid input: %v", err), IsError: true, }, nil } if params.Query == "" { return &tools.Result{ Output: "error: query is required", IsError: true, }, nil } // 如果未配置延迟注册表,返回空结果 if t.deferred == nil { return &tools.Result{ Output: "No deferred tools available. All tools are already active.", IsError: false, }, nil } // 搜索匹配的工具 matches := t.deferred.SearchTools(params.Query) if len(matches) == 0 { return &tools.Result{ Output: fmt.Sprintf("No tools found matching '%s'.", params.Query), IsError: false, }, nil } // 构建输出并激活匹配的工具 var sb strings.Builder sb.WriteString(fmt.Sprintf("Found %d tool(s) matching '%s':\n\n", len(matches), params.Query)) for _, tool := range matches { name := tool.Name() desc := tool.Description(ctx) sb.WriteString(fmt.Sprintf("- %s: %s\n", name, desc)) // 自动激活搜索到的工具 t.deferred.ActivateTool(name) } sb.WriteString("\nThese tools have been activated and are now available for use.") return &tools.Result{ Output: sb.String(), IsError: false, Data: map[string]any{ "matched_count": len(matches), "query": params.Query, }, }, nil }