| """ |
| 协议工具集合 |
| |
| 提供基于协议实现的工具接口: |
| - MCP Tool: 基于 fastmcp 库,用于连接和调用 MCP 服务器 |
| - A2A Tool: 基于官方 a2a 库,用于 Agent 间通信(需要安装 a2a) |
| - ANP Tool: 基于概念实现,用于服务发现和网络管理 |
| """ |
|
|
| from typing import Dict, Any, List, Optional |
| from ..base import Tool, ToolParameter |
| import os |
|
|
|
|
| |
| |
| MCP_SERVER_ENV_MAP = { |
| "server-github": ["GITHUB_PERSONAL_ACCESS_TOKEN"], |
| "server-slack": ["SLACK_BOT_TOKEN", "SLACK_TEAM_ID"], |
| "server-google-drive": ["GOOGLE_CLIENT_ID", "GOOGLE_CLIENT_SECRET", "GOOGLE_REFRESH_TOKEN"], |
| "server-postgres": ["POSTGRES_CONNECTION_STRING"], |
| "server-sqlite": [], |
| "server-filesystem": [], |
| } |
|
|
|
|
| class MCPTool(Tool): |
| """MCP (Model Context Protocol) 工具 |
| |
| 连接到 MCP 服务器并调用其提供的工具、资源和提示词。 |
| |
| 功能: |
| - 列出服务器提供的工具 |
| - 调用服务器工具 |
| - 读取服务器资源 |
| - 获取提示词模板 |
| |
| 使用示例: |
| >>> from hello_agents.tools.builtin import MCPTool |
| >>> |
| >>> # 方式1: 使用内置演示服务器 |
| >>> tool = MCPTool() # 自动创建内置服务器 |
| >>> result = tool.run({"action": "list_tools"}) |
| >>> |
| >>> # 方式2: 连接到外部 MCP 服务器 |
| >>> tool = MCPTool(server_command=["python", "examples/mcp_example.py"]) |
| >>> result = tool.run({"action": "list_tools"}) |
| >>> |
| >>> # 方式3: 使用自定义 FastMCP 服务器 |
| >>> from fastmcp import FastMCP |
| >>> server = FastMCP("MyServer") |
| >>> tool = MCPTool(server=server) |
| |
| 注意:使用 fastmcp 库,已包含在依赖中 |
| """ |
| |
| def __init__(self, |
| name: str = "mcp", |
| description: Optional[str] = None, |
| server_command: Optional[List[str]] = None, |
| server_args: Optional[List[str]] = None, |
| server: Optional[Any] = None, |
| auto_expand: bool = True, |
| env: Optional[Dict[str, str]] = None, |
| env_keys: Optional[List[str]] = None): |
| """ |
| 初始化 MCP 工具 |
| |
| Args: |
| name: 工具名称(默认为"mcp",建议为不同服务器指定不同名称) |
| description: 工具描述(可选,默认为通用描述) |
| server_command: 服务器启动命令(如 ["python", "server.py"]) |
| server_args: 服务器参数列表 |
| server: FastMCP 服务器实例(可选,用于内存传输) |
| auto_expand: 是否自动展开为独立工具(默认True) |
| env: 环境变量字典(优先级最高,直接传递给MCP服务器) |
| env_keys: 要从系统环境变量加载的key列表(优先级中等) |
| |
| 环境变量优先级(从高到低): |
| 1. 直接传递的env参数 |
| 2. env_keys指定的环境变量 |
| 3. 自动检测的环境变量(根据server_command) |
| |
| 注意:如果所有参数都为空,将创建内置演示服务器 |
| |
| 示例: |
| >>> # 方式1:直接传递环境变量(优先级最高) |
| >>> github_tool = MCPTool( |
| ... name="github", |
| ... server_command=["npx", "-y", "@modelcontextprotocol/server-github"], |
| ... env={"GITHUB_PERSONAL_ACCESS_TOKEN": "ghp_xxx"} |
| ... ) |
| >>> |
| >>> # 方式2:从.env文件加载指定的环境变量 |
| >>> github_tool = MCPTool( |
| ... name="github", |
| ... server_command=["npx", "-y", "@modelcontextprotocol/server-github"], |
| ... env_keys=["GITHUB_PERSONAL_ACCESS_TOKEN"] |
| ... ) |
| >>> |
| >>> # 方式3:自动检测(最简单,推荐) |
| >>> github_tool = MCPTool( |
| ... name="github", |
| ... server_command=["npx", "-y", "@modelcontextprotocol/server-github"] |
| ... # 自动从环境变量加载GITHUB_PERSONAL_ACCESS_TOKEN |
| ... ) |
| """ |
| self.server_command = server_command |
| self.server_args = server_args or [] |
| self.server = server |
| self._client = None |
| self._available_tools = [] |
| self.auto_expand = auto_expand |
| self.prefix = f"{name}_" if auto_expand else "" |
|
|
| |
| self.env = self._prepare_env(env, env_keys, server_command) |
|
|
| |
| if not server_command and not server: |
| self.server = self._create_builtin_server() |
|
|
| |
| self._discover_tools() |
|
|
| |
| if description is None: |
| description = self._generate_description() |
|
|
| super().__init__( |
| name=name, |
| description=description, |
| expandable=auto_expand |
| ) |
|
|
| def _prepare_env(self, |
| env: Optional[Dict[str, str]], |
| env_keys: Optional[List[str]], |
| server_command: Optional[List[str]]) -> Dict[str, str]: |
| """ |
| 准备环境变量 |
| |
| 优先级:env > env_keys > 自动检测 |
| |
| Args: |
| env: 直接传递的环境变量字典 |
| env_keys: 要从系统环境变量加载的key列表 |
| server_command: 服务器命令(用于自动检测) |
| |
| Returns: |
| 合并后的环境变量字典 |
| """ |
| result_env = {} |
|
|
| |
| if server_command: |
| |
| server_name = None |
| for part in server_command: |
| if "server-" in part: |
| |
| server_name = part.split("/")[-1] if "/" in part else part |
| break |
|
|
| |
| if server_name and server_name in MCP_SERVER_ENV_MAP: |
| auto_keys = MCP_SERVER_ENV_MAP[server_name] |
| for key in auto_keys: |
| value = os.getenv(key) |
| if value: |
| result_env[key] = value |
| print(f"🔑 自动加载环境变量: {key}") |
|
|
| |
| if env_keys: |
| for key in env_keys: |
| value = os.getenv(key) |
| if value: |
| result_env[key] = value |
| print(f"🔑 从env_keys加载环境变量: {key}") |
| else: |
| print(f"⚠️ 警告: 环境变量 {key} 未设置") |
|
|
| |
| if env: |
| result_env.update(env) |
| for key in env.keys(): |
| print(f"🔑 使用直接传递的环境变量: {key}") |
|
|
| return result_env |
|
|
| def _create_builtin_server(self): |
| """创建内置演示服务器""" |
| try: |
| from fastmcp import FastMCP |
|
|
| server = FastMCP("HelloAgents-BuiltinServer") |
|
|
| @server.tool() |
| def add(a: float, b: float) -> float: |
| """加法计算器""" |
| return a + b |
|
|
| @server.tool() |
| def subtract(a: float, b: float) -> float: |
| """减法计算器""" |
| return a - b |
|
|
| @server.tool() |
| def multiply(a: float, b: float) -> float: |
| """乘法计算器""" |
| return a * b |
|
|
| @server.tool() |
| def divide(a: float, b: float) -> float: |
| """除法计算器""" |
| if b == 0: |
| raise ValueError("除数不能为零") |
| return a / b |
|
|
| @server.tool() |
| def greet(name: str = "World") -> str: |
| """友好问候""" |
| return f"Hello, {name}! 欢迎使用 HelloAgents MCP 工具!" |
|
|
| @server.tool() |
| def get_system_info() -> dict: |
| """获取系统信息""" |
| import platform |
| import sys |
| return { |
| "platform": platform.system(), |
| "python_version": sys.version, |
| "server_name": "HelloAgents-BuiltinServer", |
| "tools_count": 6 |
| } |
|
|
| return server |
|
|
| except ImportError: |
| raise ImportError( |
| "创建内置 MCP 服务器需要 fastmcp 库。请安装: pip install fastmcp" |
| ) |
|
|
| def _discover_tools(self): |
| """发现MCP服务器提供的所有工具""" |
| try: |
| from helloAgents.protocols.mcp.client import MCPClient |
| import asyncio |
|
|
| async def discover(): |
| client_source = self.server if self.server else self.server_command |
| async with MCPClient(client_source, self.server_args, env=self.env) as client: |
| tools = await client.list_tools() |
| return tools |
|
|
| |
| try: |
| loop = asyncio.get_running_loop() |
| |
| import concurrent.futures |
| def run_in_thread(): |
| new_loop = asyncio.new_event_loop() |
| asyncio.set_event_loop(new_loop) |
| try: |
| return new_loop.run_until_complete(discover()) |
| finally: |
| new_loop.close() |
|
|
| with concurrent.futures.ThreadPoolExecutor() as executor: |
| future = executor.submit(run_in_thread) |
| self._available_tools = future.result() |
| except RuntimeError: |
| |
| self._available_tools = asyncio.run(discover()) |
|
|
| except Exception as e: |
| |
| self._available_tools = [] |
|
|
| def _generate_description(self) -> str: |
| """生成增强的工具描述""" |
| if not self._available_tools: |
| return "连接到 MCP 服务器,调用工具、读取资源和获取提示词。支持内置服务器和外部服务器。" |
|
|
| if self.auto_expand: |
| |
| return f"MCP工具服务器,包含{len(self._available_tools)}个工具。这些工具会自动展开为独立的工具供Agent使用。" |
| else: |
| |
| desc_parts = [ |
| f"MCP工具服务器,提供{len(self._available_tools)}个工具:" |
| ] |
|
|
| |
| for tool in self._available_tools: |
| tool_name = tool.get('name', 'unknown') |
| tool_desc = tool.get('description', '无描述') |
| |
| short_desc = tool_desc.split('.')[0] if tool_desc else '无描述' |
| desc_parts.append(f" • {tool_name}: {short_desc}") |
|
|
| |
| desc_parts.append("\n调用格式:返回JSON格式的参数") |
| desc_parts.append('{"action": "call_tool", "tool_name": "工具名", "arguments": {...}}') |
|
|
| |
| if self._available_tools: |
| first_tool = self._available_tools[0] |
| tool_name = first_tool.get('name', 'example') |
| desc_parts.append(f'\n示例:{{"action": "call_tool", "tool_name": "{tool_name}", "arguments": {{...}}}}') |
|
|
| return "\n".join(desc_parts) |
|
|
| def get_expanded_tools(self) -> List['Tool']: |
| """ |
| 获取展开的工具列表 |
| |
| 将MCP服务器的每个工具包装成独立的Tool对象 |
| |
| Returns: |
| Tool对象列表 |
| """ |
| if not self.auto_expand: |
| return [] |
|
|
| from .mcp_wrapper_tool import MCPWrappedTool |
|
|
| expanded_tools = [] |
| for tool_info in self._available_tools: |
| wrapped_tool = MCPWrappedTool( |
| mcp_tool=self, |
| tool_info=tool_info, |
| prefix=self.prefix |
| ) |
| expanded_tools.append(wrapped_tool) |
|
|
| return expanded_tools |
|
|
| def run(self, parameters: Dict[str, Any]) -> str: |
| """ |
| 同步可调试执行 MCP 操作(无异步、不跳断点、正常执行) |
| """ |
| print("🔥 已进入 MCPTool.run 方法") |
| print("参数:", parameters) |
|
|
| from helloAgents.protocols.mcp.client import MCPClient |
| import asyncio |
|
|
| action = parameters.get("action", "").lower() |
| if not action and "tool_name" in parameters: |
| action = "call_tool" |
| parameters["action"] = action |
|
|
| if not action: |
| return "错误:必须指定 action" |
|
|
| try: |
| |
| async def task(): |
| client_source = self.server or self.server_command |
| async with MCPClient(client_source, self.server_args, env=self.env) as client: |
| if action == "list_tools": |
| tools = await client.list_tools() |
| return "\n".join([f"- {t['name']}: {t['description']}" for t in tools]) |
| elif action == "call_tool": |
| tool_name = parameters.get("tool_name") |
| args = parameters.get("arguments", {}) |
| return await client.call_tool(tool_name, args) |
| return "不支持的操作" |
|
|
| |
| return asyncio.run(task()) |
|
|
| except Exception as e: |
| return f"MCP 执行失败:{str(e)}" |
|
|
| |
| |
| |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| |
| |
| |
| |
|
|
| |
| |
| |
| |
| |
|
|
| |
| |
| |
| |
| |
| |
| |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| |
| |
| |
| |
| |
| |
| |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| |
| |
| |
| |
| |
| |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| |
| |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| def get_parameters(self) -> List[ToolParameter]: |
| """获取工具参数定义""" |
| return [ |
| ToolParameter( |
| name="action", |
| type="string", |
| description="操作类型: list_tools, call_tool, list_resources, read_resource, list_prompts, get_prompt", |
| required=True |
| ), |
| ToolParameter( |
| name="tool_name", |
| type="string", |
| description="工具名称(call_tool 操作需要)", |
| required=False |
| ), |
| ToolParameter( |
| name="arguments", |
| type="object", |
| description="工具参数(call_tool 操作需要)", |
| required=False |
| ), |
| ToolParameter( |
| name="uri", |
| type="string", |
| description="资源 URI(read_resource 操作需要)", |
| required=False |
| ), |
| ToolParameter( |
| name="prompt_name", |
| type="string", |
| description="提示词名称(get_prompt 操作需要)", |
| required=False |
| ), |
| ToolParameter( |
| name="prompt_arguments", |
| type="object", |
| description="提示词参数(get_prompt 操作可选)", |
| required=False |
| ) |
| ] |
|
|
|
|
| class A2ATool(Tool): |
| """A2A (Agent-to-Agent Protocol) 工具 |
| |
| 连接到 A2A Agent 并进行通信。 |
| |
| 功能: |
| - 向 Agent 提问 |
| - 获取 Agent 信息 |
| - 发送自定义消息 |
| |
| 使用示例: |
| >>> from hello_agents.tools.builtin import A2ATool |
| >>> # 连接到 A2A Agent(使用默认名称) |
| >>> tool = A2ATool(agent_url="http://localhost:5000") |
| >>> # 连接到 A2A Agent(自定义名称和描述) |
| >>> tool = A2ATool( |
| ... agent_url="http://localhost:5000", |
| ... name="tech_expert", |
| ... description="技术专家,回答技术相关问题" |
| ... ) |
| >>> # 提问 |
| >>> result = tool.run({"action": "ask", "question": "计算 2+2"}) |
| >>> # 获取信息 |
| >>> result = tool.run({"action": "get_info"}) |
| |
| 注意:需要安装官方 a2a-sdk 库: pip install a2a-sdk |
| 详见文档: docs/chapter10/A2A_GUIDE.md |
| 官方仓库: https://github.com/a2aproject/a2a-python |
| """ |
| |
| def __init__(self, agent_url: str, name: str = "a2a", description: str = None): |
| """ |
| 初始化 A2A 工具 |
| |
| Args: |
| agent_url: Agent URL |
| name: 工具名称(可选,默认为 "a2a") |
| description: 工具描述(可选) |
| """ |
| if description is None: |
| description = "连接到 A2A Agent,支持提问和获取信息。需要安装官方 a2a-sdk 库。" |
|
|
| super().__init__( |
| name=name, |
| description=description |
| ) |
| self.agent_url = agent_url |
| |
| def run(self, parameters: Dict[str, Any]) -> str: |
| """ |
| 执行 A2A 操作 |
| |
| Args: |
| parameters: 包含以下参数的字典 |
| - action: 操作类型 (ask, get_info) |
| - question: 问题文本(ask 需要) |
| |
| Returns: |
| 操作结果 |
| """ |
| try: |
| from helloAgents.protocols.a2a.implementation import A2AClient, A2A_AVAILABLE |
| if not A2A_AVAILABLE: |
| return ("错误:需要安装 a2a-sdk 库\n" |
| "安装命令: pip install a2a-sdk\n" |
| "详见文档: docs/chapter10/A2A_GUIDE.md\n" |
| "官方仓库: https://github.com/a2aproject/a2a-python") |
| except ImportError: |
| return ("错误:无法导入 A2A 模块\n" |
| "安装命令: pip install a2a-sdk\n" |
| "详见文档: docs/chapter10/A2A_GUIDE.md\n" |
| "官方仓库: https://github.com/a2aproject/a2a-python") |
|
|
| action = parameters.get("action", "").lower() |
| |
| if not action: |
| return "错误:必须指定 action 参数" |
| |
| try: |
| client = A2AClient(self.agent_url) |
| |
| if action == "ask": |
| question = parameters.get("question") |
| if not question: |
| return "错误:必须指定 question 参数" |
| response = client.ask(question) |
| return f"Agent 回答:\n{response}" |
| |
| elif action == "get_info": |
| info = client.get_info() |
| result = "Agent 信息:\n" |
| for key, value in info.items(): |
| result += f"- {key}: {value}\n" |
| return result |
| |
| else: |
| return f"错误:不支持的操作 '{action}'" |
| |
| except Exception as e: |
| return f"A2A 操作失败: {str(e)}" |
| |
| def get_parameters(self) -> List[ToolParameter]: |
| """获取工具参数定义""" |
| return [ |
| ToolParameter( |
| name="action", |
| type="string", |
| description="操作类型: ask(提问), get_info(获取信息)", |
| required=True |
| ), |
| ToolParameter( |
| name="question", |
| type="string", |
| description="问题文本(ask 操作需要)", |
| required=False |
| ) |
| ] |
|
|
|
|
| class ANPTool(Tool): |
| """ANP (Agent Network Protocol) 工具 |
| |
| 提供智能体网络管理功能,包括服务发现、节点管理和消息路由。 |
| 这是一个概念性实现,用于演示 Agent 网络管理的核心理念。 |
| |
| 功能: |
| - 注册和发现服务 |
| - 添加和管理网络节点 |
| - 消息路由 |
| - 网络统计 |
| |
| 使用示例: |
| >>> from hello_agents.tools.builtin import ANPTool |
| >>> tool = ANPTool() |
| >>> # 注册服务 |
| >>> result = tool.run({ |
| ... "action": "register_service", |
| ... "service_id": "calc-1", |
| ... "service_type": "calculator", |
| ... "endpoint": "http://localhost:5001" |
| ... }) |
| >>> # 发现服务 |
| >>> result = tool.run({ |
| ... "action": "discover_services", |
| ... "service_type": "calculator" |
| ... }) |
| >>> # 添加节点 |
| >>> result = tool.run({ |
| ... "action": "add_node", |
| ... "node_id": "agent-1", |
| ... "endpoint": "http://localhost:5001" |
| ... }) |
| |
| 注意:这是概念性实现,不需要额外依赖 |
| 详见文档: docs/chapter10/ANP_CONCEPTS.md |
| """ |
| |
| def __init__(self, name: str = "anp", description: str = None, discovery=None, network=None): |
| """初始化 ANP 工具 |
| |
| Args: |
| name: 工具名称 |
| description: 工具描述 |
| discovery: 可选的 ANPDiscovery 实例,如果不提供则创建新实例 |
| network: 可选的 ANPNetwork 实例,如果不提供则创建新实例 |
| """ |
| if description is None: |
| description = "智能体网络管理工具,支持服务发现、节点管理和消息路由。概念性实现。" |
|
|
| super().__init__( |
| name=name, |
| description=description |
| ) |
| from helloAgents.protocols.anp.implementation import ANPDiscovery, ANPNetwork |
| self._discovery = discovery if discovery is not None else ANPDiscovery() |
| self._network = network if network is not None else ANPNetwork() |
| |
| def run(self, parameters: Dict[str, Any]) -> str: |
| """ |
| 执行 ANP 操作 |
| |
| Args: |
| parameters: 包含以下参数的字典 |
| - action: 操作类型 (register_service, discover_services, add_node, route_message, get_stats) |
| - service_id, service_type, endpoint: 服务信息(register_service 需要) |
| - node_id, endpoint: 节点信息(add_node 需要) |
| - from_node, to_node, message: 路由信息(route_message 需要) |
| |
| Returns: |
| 操作结果 |
| """ |
| from helloAgents.protocols.anp.implementation import ServiceInfo |
|
|
| action = parameters.get("action", "").lower() |
| |
| if not action: |
| return "错误:必须指定 action 参数" |
| |
| try: |
| if action == "register_service": |
| service_id = parameters.get("service_id") |
| service_type = parameters.get("service_type") |
| endpoint = parameters.get("endpoint") |
| metadata = parameters.get("metadata", {}) |
| |
| if not all([service_id, service_type, endpoint]): |
| return "错误:必须指定 service_id, service_type 和 endpoint 参数" |
| |
| service = ServiceInfo(service_id, service_type, endpoint, metadata) |
| self._discovery.register_service(service) |
| return f"✅ 已注册服务 '{service_id}'" |
|
|
| elif action == "unregister_service": |
| service_id = parameters.get("service_id") |
| if not service_id: |
| return "错误:必须指定 service_id 参数" |
|
|
| |
| success = self._discovery.unregister_service(service_id) |
|
|
| if success: |
| return f"✅ 已注销服务 '{service_id}'" |
| else: |
| return f"错误:服务 '{service_id}' 不存在" |
|
|
| elif action == "discover_services": |
| service_type = parameters.get("service_type") |
| services = self._discovery.discover_services(service_type) |
|
|
| if not services: |
| return "没有找到服务" |
|
|
| result = f"找到 {len(services)} 个服务:\n\n" |
| for service in services: |
| result += f"服务ID: {service.service_id}\n" |
| result += f" 名称: {service.service_name}\n" |
| result += f" 类型: {service.service_type}\n" |
| result += f" 端点: {service.endpoint}\n" |
| if service.capabilities: |
| result += f" 能力: {', '.join(service.capabilities)}\n" |
| if service.metadata: |
| result += f" 元数据: {service.metadata}\n" |
| result += "\n" |
| return result |
| |
| elif action == "add_node": |
| node_id = parameters.get("node_id") |
| endpoint = parameters.get("endpoint") |
| metadata = parameters.get("metadata", {}) |
| |
| if not all([node_id, endpoint]): |
| return "错误:必须指定 node_id 和 endpoint 参数" |
| |
| self._network.add_node(node_id, endpoint, metadata) |
| return f"✅ 已添加节点 '{node_id}'" |
| |
| elif action == "route_message": |
| from_node = parameters.get("from_node") |
| to_node = parameters.get("to_node") |
| message = parameters.get("message", {}) |
| |
| if not all([from_node, to_node]): |
| return "错误:必须指定 from_node 和 to_node 参数" |
| |
| path = self._network.route_message(from_node, to_node, message) |
| if path: |
| return f"消息路由路径: {' -> '.join(path)}" |
| else: |
| return "无法找到路由路径" |
| |
| elif action == "get_stats": |
| stats = self._network.get_network_stats() |
| result = "网络统计:\n" |
| for key, value in stats.items(): |
| result += f"- {key}: {value}\n" |
| return result |
| |
| else: |
| return f"错误:不支持的操作 '{action}'" |
| |
| except Exception as e: |
| return f"ANP 操作失败: {str(e)}" |
| |
| def get_parameters(self) -> List[ToolParameter]: |
| """获取工具参数定义""" |
| return [ |
| ToolParameter( |
| name="action", |
| type="string", |
| description="操作类型: register_service, unregister_service, discover_services, add_node, route_message, get_stats", |
| required=True |
| ), |
| ToolParameter( |
| name="service_id", |
| type="string", |
| description="服务 ID(register_service, unregister_service 需要)", |
| required=False |
| ), |
| ToolParameter( |
| name="service_type", |
| type="string", |
| description="服务类型(register_service 需要)", |
| required=False |
| ), |
| ToolParameter( |
| name="endpoint", |
| type="string", |
| description="端点地址(register_service, add_node 需要)", |
| required=False |
| ), |
| ToolParameter( |
| name="node_id", |
| type="string", |
| description="节点 ID(add_node 需要)", |
| required=False |
| ), |
| ToolParameter( |
| name="from_node", |
| type="string", |
| description="源节点 ID(route_message 需要)", |
| required=False |
| ), |
| ToolParameter( |
| name="to_node", |
| type="string", |
| description="目标节点 ID(route_message 需要)", |
| required=False |
| ), |
| ToolParameter( |
| name="message", |
| type="object", |
| description="消息内容(route_message 需要)", |
| required=False |
| ), |
| ToolParameter( |
| name="metadata", |
| type="object", |
| description="元数据(register_service, add_node 可选)", |
| required=False |
| ) |
| ] |
|
|
|
|