From 2f92481654681368cfdcd179ecf2e9ce1402a20a Mon Sep 17 00:00:00 2001 From: juliette_sivan Date: Thu, 19 Dec 2024 12:45:24 +0100 Subject: [PATCH 1/2] add linkup --- .../provider/builtin/linkup/assets/icon.png | Bin 0 -> 32966 bytes .../tools/provider/builtin/linkup/linkup.py | 22 ++++++++ .../tools/provider/builtin/linkup/linkup.yml | 53 ++++++++++++++++++ .../builtin/linkup/tools/linkup_tool.py | 36 ++++++++++++ 4 files changed, 111 insertions(+) create mode 100644 api/core/tools/provider/builtin/linkup/assets/icon.png create mode 100644 api/core/tools/provider/builtin/linkup/linkup.py create mode 100644 api/core/tools/provider/builtin/linkup/linkup.yml create mode 100644 api/core/tools/provider/builtin/linkup/tools/linkup_tool.py diff --git a/api/core/tools/provider/builtin/linkup/assets/icon.png b/api/core/tools/provider/builtin/linkup/assets/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..4848d4c6b19b1da998326dbd6a3efdf3671a48a3 GIT binary patch literal 32966 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 literal 0 HcmV?d00001 diff --git a/api/core/tools/provider/builtin/linkup/linkup.py b/api/core/tools/provider/builtin/linkup/linkup.py new file mode 100644 index 00000000000000..6b533644680133 --- /dev/null +++ b/api/core/tools/provider/builtin/linkup/linkup.py @@ -0,0 +1,22 @@ +import requests +from core.tools.errors import ToolProviderCredentialValidationError +from core.tools.provider.builtin_tool_provider import BuiltinToolProviderController +from linkup import LinkupClient + +class LinkupProvider(BuiltinToolProviderController): + def _validate_credentials(self, credentials: dict) -> None: + try: + if "api_key" not in credentials or not credentials.get("api_key"): + raise ToolProviderCredentialValidationError("Linkup API key is required.") + + api_key = credentials.get("api_key") + client = LinkupClient(api_key=api_key) + try: + response = client.search(query="test") + if not response or response.get("error"): + raise ToolProviderCredentialValidationError("Invalid Linkup API key.") + except Exception as e: + raise ToolProviderCredentialValidationError(f"Linkup API key validation failed: {str(e)}") + + except Exception as e: + raise ToolProviderCredentialValidationError(str(e)) diff --git a/api/core/tools/provider/builtin/linkup/linkup.yml b/api/core/tools/provider/builtin/linkup/linkup.yml new file mode 100644 index 00000000000000..63788215d72bef --- /dev/null +++ b/api/core/tools/provider/builtin/linkup/linkup.yml @@ -0,0 +1,53 @@ +identity: + author: Juliette Sivan + name: linkup + label: + en_US: Linkup Search Tool + zh_Hans: Linkup 搜索工具 + description: + en_US: Search engine optimized for agents to seamlessly and fairly retrieve data from the web and beyond. + zh_Hans: 针对代理进行了优化的搜索引擎,可以无缝、公平地从网络及其他地方检索数据 + icon: icon.png + tags: + - search + - api + +dependencies: + - linkup_sdk + +commands: + - name: search + label: + en_US: Search + zh_Hans: 搜索 + description: + en_US: Perform a search using the Linkup API. + zh_Hans: 使用 Linkup API 进行搜索。 + parameters: + - name: query + type: string + required: true + label: + en_US: Query + zh_Hans: 查询 + description: + en_US: The search query string. + zh_Hans: 查询字符串。 + - name: depth + type: string + required: false + label: + en_US: Search Depth + zh_Hans: 搜索深度 + description: + en_US: The search depth (e.g., basic, standard). + zh_Hans: 搜索深度(例如:基础、标准)。 + - name: output_type + type: string + required: false + label: + en_US: Output Type + zh_Hans: 输出类型 + description: + en_US: The desired type of output (e.g., searchResults). + zh_Hans: 所需的输出类型(例如:searchResults)。 diff --git a/api/core/tools/provider/builtin/linkup/tools/linkup_tool.py b/api/core/tools/provider/builtin/linkup/tools/linkup_tool.py new file mode 100644 index 00000000000000..eb9bba39f060a6 --- /dev/null +++ b/api/core/tools/provider/builtin/linkup/tools/linkup_tool.py @@ -0,0 +1,36 @@ +from linkup import LinkupClient +from pydantic import PrivateAttr + +class LinkupSearchTool: + name: str = "Linkup Search Tool" + description: str = "Performs an API call to Linkup to retrieve contextual information." + _client: LinkupClient = PrivateAttr() + + def __init__(self, api_key: str): + """ + Initialize the tool with an API key. + """ + self._client = LinkupClient(api_key=api_key) + + def _run(self, query: str, depth: str = "standard", output_type: str = "searchResults") -> dict: + """ + Executes a search using the Linkup API. + + :param query: The query to search for. + :param depth: Search depth (default is "standard"). + :param output_type: Desired result type (default is "searchResults"). + :return: A dictionary containing the results or an error message. + """ + try: + response = self._client.search( + query=query, + depth=depth, + output_type=output_type + ) + results = [ + {"name": result.name, "url": result.url, "content": result.content} + for result in response.results + ] + return {"success": True, "results": results} + except Exception as e: + return {"success": False, "error": str(e)} From cb52d718a5f7fd757729c755837bb91c6a429e63 Mon Sep 17 00:00:00 2001 From: juliette_sivan Date: Fri, 10 Jan 2025 10:14:10 +0000 Subject: [PATCH 2/2] add linkup tool --- .../tools/provider/builtin/linkup/linkup.py | 1 - .../builtin/linkup/tools/linkup_tool.py | 42 ++++++++++++++----- 2 files changed, 31 insertions(+), 12 deletions(-) diff --git a/api/core/tools/provider/builtin/linkup/linkup.py b/api/core/tools/provider/builtin/linkup/linkup.py index 6b533644680133..3f1e212cfa407c 100644 --- a/api/core/tools/provider/builtin/linkup/linkup.py +++ b/api/core/tools/provider/builtin/linkup/linkup.py @@ -1,4 +1,3 @@ -import requests from core.tools.errors import ToolProviderCredentialValidationError from core.tools.provider.builtin_tool_provider import BuiltinToolProviderController from linkup import LinkupClient diff --git a/api/core/tools/provider/builtin/linkup/tools/linkup_tool.py b/api/core/tools/provider/builtin/linkup/tools/linkup_tool.py index eb9bba39f060a6..40a072923f2de4 100644 --- a/api/core/tools/provider/builtin/linkup/tools/linkup_tool.py +++ b/api/core/tools/provider/builtin/linkup/tools/linkup_tool.py @@ -12,25 +12,45 @@ def __init__(self, api_key: str): """ self._client = LinkupClient(api_key=api_key) - def _run(self, query: str, depth: str = "standard", output_type: str = "searchResults") -> dict: + def _run(self, query: str, depth: str, output_type: str, structured_output_schema: dict = None) -> dict: """ Executes a search using the Linkup API. :param query: The query to search for. :param depth: Search depth (default is "standard"). :param output_type: Desired result type (default is "searchResults"). + :param structured_output_schema: JSON schema for structured output (only used if output_type is "structured"). :return: A dictionary containing the results or an error message. """ try: - response = self._client.search( - query=query, - depth=depth, - output_type=output_type - ) - results = [ - {"name": result.name, "url": result.url, "content": result.content} - for result in response.results - ] - return {"success": True, "results": results} + if output_type == "structured" and structured_output_schema: + response = self._client.search( + query=query, + depth=depth, + output_type=output_type, + structured_output_schema=structured_output_schema + ) + else: + response = self._client.search( + query=query, + depth=depth, + output_type=output_type + ) + if output_type == "sourcedAnswer": + return { + "success": True, + "answer": response.answer, + "sources": response.sources + } + elif output_type == "searchResults": + results = [ + {"name": result.name, "url": result.url, "content": result.content} + for result in response.results + ] + return {"success": True, "results": results} + elif output_type == "structured": + return {"success": True, "structured_data": response} + else: + return {"success": False, "error": "Invalid output_type provided."} except Exception as e: return {"success": False, "error": str(e)}