diff --git a/backend/app/utils/listen/toolkit_listen.py b/backend/app/utils/listen/toolkit_listen.py index 1f4053fe7..77079c7c5 100644 --- a/backend/app/utils/listen/toolkit_listen.py +++ b/backend/app/utils/listen/toolkit_listen.py @@ -24,7 +24,7 @@ def listen_toolkit( if iscoroutinefunction(func): # async function wrapper - @wraps(func) + @wraps(wrap) async def async_wrapper(*args, **kwargs): toolkit: AbstractToolkit = args[0] task_lock = get_task_lock(toolkit.api_task_id) @@ -93,7 +93,7 @@ def listen_toolkit( else: # sync function wrapper - @wraps(func) + @wraps(wrap) def sync_wrapper(*args, **kwargs): toolkit: AbstractToolkit = args[0] task_lock = get_task_lock(toolkit.api_task_id) diff --git a/backend/app/utils/toolkit/notion_mcp_toolkit.py b/backend/app/utils/toolkit/notion_mcp_toolkit.py index 137c48cd1..36928aa0a 100644 --- a/backend/app/utils/toolkit/notion_mcp_toolkit.py +++ b/backend/app/utils/toolkit/notion_mcp_toolkit.py @@ -1,14 +1,13 @@ import os -from typing import Any, ClassVar, Dict, List, Optional, Set -from camel.toolkits import FunctionTool, NotionMCPToolkit as BaseNotionMCPToolkit -from app.component.command import bun +from typing import Any, Dict, List +from loguru import logger +from camel.toolkits import FunctionTool from app.component.environment import env -from app.service.task import Agents from app.utils.toolkit.abstract_toolkit import AbstractToolkit from camel.toolkits.mcp_toolkit import MCPToolkit -class NotionMCPToolkit(BaseNotionMCPToolkit, AbstractToolkit): +class NotionMCPToolkit(MCPToolkit, AbstractToolkit): def __init__( self, @@ -18,25 +17,84 @@ class NotionMCPToolkit(BaseNotionMCPToolkit, AbstractToolkit): self.api_task_id = api_task_id if timeout is None: timeout = 120.0 - super().__init__(timeout) - self._mcp_toolkit = MCPToolkit( - config_dict={ - "mcpServers": { - "notionMCP": { - "command": "npx", - "args": [ - "-y", - "mcp-remote", - "https://mcp.notion.com/mcp", - ], - "env": { - "MCP_REMOTE_CONFIG_DIR": env("MCP_REMOTE_CONFIG_DIR", os.path.expanduser("~/.mcp-auth")), - }, - } - } - }, - timeout=timeout, - ) + + config_dict={ + "mcpServers": { + "notionMCP": { + "command": "npx", + "args": [ + "-y", + "mcp-remote", + "https://mcp.notion.com/mcp", + ], + "env": { + "MCP_REMOTE_CONFIG_DIR": env("MCP_REMOTE_CONFIG_DIR", os.path.expanduser("~/.mcp-auth")), + }, + } + } + } + super().__init__(config_dict=config_dict, timeout=timeout) + + def get_tools(self) -> List[FunctionTool]: + r"""Returns a list of tools provided by the NotionMCPToolkit. + + Returns: + List[FunctionTool]: List of available tools. + """ + all_tools = [] + for client in self.clients: + try: + original_build_schema = client._build_tool_schema + + def create_wrapper(orig_func): + def wrapper(mcp_tool): + return self._build_custom_tool_schema( + mcp_tool, orig_func + ) + + return wrapper + + client._build_tool_schema = create_wrapper( # type: ignore[method-assign] + original_build_schema + ) + + client_tools = client.get_tools() + all_tools.extend(client_tools) + + client._build_tool_schema = original_build_schema # type: ignore[method-assign] + + except Exception as e: + logger.error(f"Failed to get tools from client: {e}") + return all_tools + + def _build_custom_tool_schema(self, mcp_tool, original_build_schema): + r"""Build tool schema with custom modifications.""" + schema = original_build_schema(mcp_tool) + self._customize_function_parameters(schema) + return schema + + def _customize_function_parameters(self, schema: Dict[str, Any]) -> None: + r"""Customize function parameters for specific functions. + + This method allows modifying parameter descriptions or other schema + attributes for specific functions. + """ + function_info = schema.get("function", {}) + function_name = function_info.get("name", "") + parameters = function_info.get("parameters", {}) + properties = parameters.get("properties", {}) + + # Modify the notion-create-pages function to make parent optional + if function_name == "notion-create-pages": + if "parent" in properties: + # Update the parent parameter description + properties["parent"]["description"] = ( + "Optional. The parent under which the new pages will be created. " + "This can be a page (page_id), a database page (database_id), or " + "a data source/collection under a database (data_source_id). " + "If omitted, the new pages will be created as private pages at the workspace level. " + "Use data_source_id when you have a collection:// URL from the fetch tool." + ) @classmethod async def get_can_use_tools(cls, api_task_id: str) -> list[FunctionTool]: @@ -45,7 +103,7 @@ class NotionMCPToolkit(BaseNotionMCPToolkit, AbstractToolkit): try: await toolkit.connect() # Use subclass implementation that inlines upstream processing - all_tools = BaseNotionMCPToolkit.get_tools(toolkit) + all_tools = toolkit.get_tools() for item in all_tools: setattr(item, "_toolkit_name", cls.__name__) tools.append(item) diff --git a/backend/pyproject.toml b/backend/pyproject.toml index a712b0c3d..1b13bafbd 100644 --- a/backend/pyproject.toml +++ b/backend/pyproject.toml @@ -17,8 +17,9 @@ dependencies = [ "inflection>=0.5.1", "aiofiles>=24.1.0", "openai>=1.99.3,<2", - "traceroot>=0.0.4a9", + "traceroot>=0.0.5a2", "nodejs-wheel>=22.18.0", + "numpy>=1.23.0,<2.0.0", ] diff --git a/backend/uv.lock b/backend/uv.lock index 9f85ff552..14561e98b 100644 --- a/backend/uv.lock +++ b/backend/uv.lock @@ -221,6 +221,7 @@ dependencies = [ { name = "inflection" }, { name = "loguru" }, { name = "nodejs-wheel" }, + { name = "numpy" }, { name = "openai" }, { name = "pydantic-i18n" }, { name = "pydash" }, @@ -246,11 +247,12 @@ requires-dist = [ { name = "inflection", specifier = ">=0.5.1" }, { name = "loguru", specifier = ">=0.7.3" }, { name = "nodejs-wheel", specifier = ">=22.18.0" }, + { name = "numpy", specifier = ">=1.23.0,<2.0.0" }, { name = "openai", specifier = ">=1.99.3,<2" }, { name = "pydantic-i18n", specifier = ">=0.4.5" }, { name = "pydash", specifier = ">=8.0.5" }, { name = "python-dotenv", specifier = ">=1.1.0" }, - { name = "traceroot", specifier = ">=0.0.4a9" }, + { name = "traceroot", specifier = ">=0.0.5a2" }, { name = "uvicorn", extras = ["standard"], specifier = ">=0.34.2" }, ] @@ -1430,24 +1432,18 @@ wheels = [ [[package]] name = "numpy" -version = "2.2.0" +version = "1.26.4" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/47/1b/1d565e0f6e156e1522ab564176b8b29d71e13d8caf003a08768df3d5cec5/numpy-2.2.0.tar.gz", hash = "sha256:140dd80ff8981a583a60980be1a655068f8adebf7a45a06a6858c873fcdcd4a0", size = 20225497, upload-time = "2024-12-08T15:45:53.828Z" } +sdist = { url = "https://files.pythonhosted.org/packages/65/6e/09db70a523a96d25e115e71cc56a6f9031e7b8cd166c1ac8438307c14058/numpy-1.26.4.tar.gz", hash = "sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010", size = 15786129, upload-time = "2024-02-06T00:26:44.495Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c7/81/3882353e097204fe4d7a5fe026b694b0104b78f930c969faadeed1538e00/numpy-2.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1e25507d85da11ff5066269d0bd25d06e0a0f2e908415534f3e603d2a78e4ffa", size = 21212476, upload-time = "2024-12-08T15:20:47.292Z" }, - { url = "https://files.pythonhosted.org/packages/2c/64/5577dc71240272749e07fcacb47c0f29e31ba4fbd1613fefbd1aa88efc29/numpy-2.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a62eb442011776e4036af5c8b1a00b706c5bc02dc15eb5344b0c750428c94219", size = 14351441, upload-time = "2024-12-08T15:21:10.966Z" }, - { url = "https://files.pythonhosted.org/packages/c9/43/850c040481c19c1c2289203a606df1a202eeb3aa81440624bac891024f83/numpy-2.2.0-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:b606b1aaf802e6468c2608c65ff7ece53eae1a6874b3765f69b8ceb20c5fa78e", size = 5390304, upload-time = "2024-12-08T15:21:20.431Z" }, - { url = "https://files.pythonhosted.org/packages/73/96/a4c8a86300dbafc7e4f44d8986f8b64950b7f4640a2dc5c91e036afe28c6/numpy-2.2.0-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:36b2b43146f646642b425dd2027730f99bac962618ec2052932157e213a040e9", size = 6925476, upload-time = "2024-12-08T15:21:31.436Z" }, - { url = "https://files.pythonhosted.org/packages/0c/0a/22129c3107c4fb237f97876df4399a5c3a83f3d95f86e0353ae6fbbd202f/numpy-2.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7fe8f3583e0607ad4e43a954e35c1748b553bfe9fdac8635c02058023277d1b3", size = 14329997, upload-time = "2024-12-08T15:21:53.67Z" }, - { url = "https://files.pythonhosted.org/packages/4c/49/c2adeccc8a47bcd9335ec000dfcb4de34a7c34aeaa23af57cd504017e8c3/numpy-2.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:122fd2fcfafdefc889c64ad99c228d5a1f9692c3a83f56c292618a59aa60ae83", size = 16378908, upload-time = "2024-12-08T15:22:18.524Z" }, - { url = "https://files.pythonhosted.org/packages/8d/85/b65f4596748cc5468c0a978a16b3be45f6bcec78339b0fe7bce71d121d89/numpy-2.2.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3f2f5cddeaa4424a0a118924b988746db6ffa8565e5829b1841a8a3bd73eb59a", size = 15540949, upload-time = "2024-12-08T15:22:42.538Z" }, - { url = "https://files.pythonhosted.org/packages/ff/b3/3b18321c94a6a6a1d972baf1b39a6de50e65c991002c014ffbcce7e09be8/numpy-2.2.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7fe4bb0695fe986a9e4deec3b6857003b4cfe5c5e4aac0b95f6a658c14635e31", size = 18167677, upload-time = "2024-12-08T15:23:11.062Z" }, - { url = "https://files.pythonhosted.org/packages/41/f0/fa2a76e893a05764e4474f6011575c4e4ccf32af9c95bfcc8ef4b8a99f69/numpy-2.2.0-cp310-cp310-win32.whl", hash = "sha256:b30042fe92dbd79f1ba7f6898fada10bdaad1847c44f2dff9a16147e00a93661", size = 6570288, upload-time = "2024-12-08T15:23:22.863Z" }, - { url = "https://files.pythonhosted.org/packages/97/4e/0b7debcd013214db224997b0d3e39bb7b3656d37d06dfc31bb57d42d143b/numpy-2.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:54dc1d6d66f8d37843ed281773c7174f03bf7ad826523f73435deb88ba60d2d4", size = 12912730, upload-time = "2024-12-08T15:23:42.938Z" }, - { url = "https://files.pythonhosted.org/packages/f3/18/6d4e1274f221073058b621f4df8050958b7564b24b4fa25be9f1b7639274/numpy-2.2.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:e12c6c1ce84628c52d6367863773f7c8c8241be554e8b79686e91a43f1733773", size = 21043901, upload-time = "2024-12-08T15:40:09.263Z" }, - { url = "https://files.pythonhosted.org/packages/19/3e/2b20599e7ead7ae1b89a77bb34f88c5ec12e43fbb320576ed646388d2cb7/numpy-2.2.0-pp310-pypy310_pp73-macosx_14_0_x86_64.whl", hash = "sha256:b6207dc8fb3c8cb5668e885cef9ec7f70189bec4e276f0ff70d5aa078d32c88e", size = 6789122, upload-time = "2024-12-08T15:40:21.876Z" }, - { url = "https://files.pythonhosted.org/packages/c9/5a/378954132c192fafa6c3d5c160092a427c7562e5bda0cc6ad9cc37008a7a/numpy-2.2.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a50aeff71d0f97b6450d33940c7181b08be1441c6c193e678211bff11aa725e7", size = 16194018, upload-time = "2024-12-08T15:40:45.485Z" }, - { url = "https://files.pythonhosted.org/packages/67/17/209bda34fc83f3436834392f44643e66dcf3c77465f232102e7f1c7d8eae/numpy-2.2.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:df12a1f99b99f569a7c2ae59aa2d31724e8d835fc7f33e14f4792e3071d11221", size = 12819486, upload-time = "2024-12-08T15:41:05.529Z" }, + { url = "https://files.pythonhosted.org/packages/a7/94/ace0fdea5241a27d13543ee117cbc65868e82213fb31a8eb7fe9ff23f313/numpy-1.26.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9ff0f4f29c51e2803569d7a51c2304de5554655a60c5d776e35b4a41413830d0", size = 20631468, upload-time = "2024-02-05T23:48:01.194Z" }, + { url = "https://files.pythonhosted.org/packages/20/f7/b24208eba89f9d1b58c1668bc6c8c4fd472b20c45573cb767f59d49fb0f6/numpy-1.26.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2e4ee3380d6de9c9ec04745830fd9e2eccb3e6cf790d39d7b98ffd19b0dd754a", size = 13966411, upload-time = "2024-02-05T23:48:29.038Z" }, + { url = "https://files.pythonhosted.org/packages/fc/a5/4beee6488160798683eed5bdb7eead455892c3b4e1f78d79d8d3f3b084ac/numpy-1.26.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d209d8969599b27ad20994c8e41936ee0964e6da07478d6c35016bc386b66ad4", size = 14219016, upload-time = "2024-02-05T23:48:54.098Z" }, + { url = "https://files.pythonhosted.org/packages/4b/d7/ecf66c1cd12dc28b4040b15ab4d17b773b87fa9d29ca16125de01adb36cd/numpy-1.26.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ffa75af20b44f8dba823498024771d5ac50620e6915abac414251bd971b4529f", size = 18240889, upload-time = "2024-02-05T23:49:25.361Z" }, + { url = "https://files.pythonhosted.org/packages/24/03/6f229fe3187546435c4f6f89f6d26c129d4f5bed40552899fcf1f0bf9e50/numpy-1.26.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:62b8e4b1e28009ef2846b4c7852046736bab361f7aeadeb6a5b89ebec3c7055a", size = 13876746, upload-time = "2024-02-05T23:49:51.983Z" }, + { url = "https://files.pythonhosted.org/packages/39/fe/39ada9b094f01f5a35486577c848fe274e374bbf8d8f472e1423a0bbd26d/numpy-1.26.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a4abb4f9001ad2858e7ac189089c42178fcce737e4169dc61321660f1a96c7d2", size = 18078620, upload-time = "2024-02-05T23:50:22.515Z" }, + { url = "https://files.pythonhosted.org/packages/d5/ef/6ad11d51197aad206a9ad2286dc1aac6a378059e06e8cf22cd08ed4f20dc/numpy-1.26.4-cp310-cp310-win32.whl", hash = "sha256:bfe25acf8b437eb2a8b2d49d443800a5f18508cd811fea3181723922a8a82b07", size = 5972659, upload-time = "2024-02-05T23:50:35.834Z" }, + { url = "https://files.pythonhosted.org/packages/19/77/538f202862b9183f54108557bfda67e17603fc560c384559e769321c9d92/numpy-1.26.4-cp310-cp310-win_amd64.whl", hash = "sha256:b97fe8060236edf3662adfc2c633f56a08ae30560c56310562cb4f95500022d5", size = 15808905, upload-time = "2024-02-05T23:51:03.701Z" }, ] [[package]] diff --git a/src/assets/wechat_qr_1.jpg b/src/assets/wechat_qr_1.jpg index 262368de8..a3814f7f0 100644 Binary files a/src/assets/wechat_qr_1.jpg and b/src/assets/wechat_qr_1.jpg differ diff --git a/src/assets/wechat_qr_2.jpg b/src/assets/wechat_qr_2.jpg index 10dcd99ea..c560e36c9 100644 Binary files a/src/assets/wechat_qr_2.jpg and b/src/assets/wechat_qr_2.jpg differ diff --git a/src/assets/wechat_qr_3.jpg b/src/assets/wechat_qr_3.jpg index 880356cbe..d5d31392f 100644 Binary files a/src/assets/wechat_qr_3.jpg and b/src/assets/wechat_qr_3.jpg differ diff --git a/src/assets/wechat_qr_4.jpg b/src/assets/wechat_qr_4.jpg index ccf2ede66..7ac6837ff 100644 Binary files a/src/assets/wechat_qr_4.jpg and b/src/assets/wechat_qr_4.jpg differ diff --git a/src/components/AddWorker/IntegrationList.tsx b/src/components/AddWorker/IntegrationList.tsx index 027a1fbf0..8a2dc55d2 100644 --- a/src/components/AddWorker/IntegrationList.tsx +++ b/src/components/AddWorker/IntegrationList.tsx @@ -15,6 +15,7 @@ interface IntegrationItem { name: string; desc: string; env_vars: string[]; + toolkit?: string; // Add toolkit field onInstall: () => void | Promise; } @@ -316,8 +317,11 @@ export default function IntegrationList({ "Github", ].includes(item.name) ) { - if (item.env_vars.length === 0 || isInstalled) { - addOption(item, true); + if (item.env_vars.length === 0 || isInstalled) { + // Ensure toolkit field is passed and normalized for known cases + const normalizedToolkit = + item.name === "Notion" ? "notion_mcp_toolkit" : item.toolkit; + addOption({ ...item, toolkit: normalizedToolkit }, true); } else { handleInstall(item); }