Ver Fonte

Merge remote-tracking branch 'refs/remotes/origin/main'

Talegorithm há 1 mês atrás
pai
commit
f1c90cfc44
2 ficheiros alterados com 108 adições e 239 exclusões
  1. 107 238
      agent/tools/builtin/sandbox.py
  2. 1 1
      examples/test_tools_baidu.py

+ 107 - 238
agent/tools/builtin/sandbox.py

@@ -12,7 +12,8 @@ from agent.tools.models import ToolResult
 
 
 
 
 # 服务地址,可根据实际部署情况修改
 # 服务地址,可根据实际部署情况修改
-SANDBOX_SERVER_URL = "http://61.48.133.26:9999"
+# SANDBOX_SERVER_URL = "http://192.168.100.20:9998"
+SANDBOX_SERVER_URL = "http://61.48.133.26:9998"
 
 
 # 默认超时时间(秒)
 # 默认超时时间(秒)
 DEFAULT_TIMEOUT = 300.0
 DEFAULT_TIMEOUT = 300.0
@@ -26,7 +27,9 @@ DEFAULT_TIMEOUT = 300.0
                 "image": "Docker 镜像",
                 "image": "Docker 镜像",
                 "mem_limit": "内存限制",
                 "mem_limit": "内存限制",
                 "nano_cpus": "CPU 限制",
                 "nano_cpus": "CPU 限制",
-                "ports": "端口列表"
+                "ports": "端口列表",
+                "use_gpu": "启用 GPU",
+                "gpu_count": "GPU 数量"
             }
             }
         },
         },
         "en": {
         "en": {
@@ -35,7 +38,9 @@ DEFAULT_TIMEOUT = 300.0
                 "image": "Docker image",
                 "image": "Docker image",
                 "mem_limit": "Memory limit",
                 "mem_limit": "Memory limit",
                 "nano_cpus": "CPU limit",
                 "nano_cpus": "CPU limit",
-                "ports": "Port list"
+                "ports": "Port list",
+                "use_gpu": "Enable GPU",
+                "gpu_count": "GPU count"
             }
             }
         }
         }
     }
     }
@@ -45,8 +50,11 @@ async def sandbox_create_environment(
     mem_limit: str = "512m",
     mem_limit: str = "512m",
     nano_cpus: int = 500000000,
     nano_cpus: int = 500000000,
     ports: Optional[List[int]] = None,
     ports: Optional[List[int]] = None,
-    uid: str = ""
-) -> ToolResult:
+    use_gpu: bool = False,
+    gpu_count: int = -1,
+    server_url: str = None,
+    timeout: float = DEFAULT_TIMEOUT
+) -> Dict[str, Any]:
     """
     """
     创建一个隔离的 Docker 开发环境。
     创建一个隔离的 Docker 开发环境。
 
 
@@ -56,47 +64,37 @@ async def sandbox_create_environment(
         mem_limit: 容器最大内存限制,默认为 "512m"。
         mem_limit: 容器最大内存限制,默认为 "512m"。
         nano_cpus: 容器最大 CPU 限制(纳秒),默认为 500000000(0.5 CPU)。
         nano_cpus: 容器最大 CPU 限制(纳秒),默认为 500000000(0.5 CPU)。
         ports: 需要映射的端口列表,如 [8080, 3000]。
         ports: 需要映射的端口列表,如 [8080, 3000]。
-        uid: 用户ID(自动注入)
+        use_gpu: 是否启用 GPU 支持,默认为 False。需要宿主机安装 nvidia-container-toolkit。
+        gpu_count: 使用的 GPU 数量,-1 表示使用所有可用 GPU,默认为 -1。
+        server_url: 服务地址,默认使用全局配置 SANDBOX_SERVER_URL。
+        timeout: 请求超时时间(秒),默认 300 秒。
 
 
     Returns:
     Returns:
-        ToolResult 包含:
+        dict: 包含以下字段
             - sandbox_id (str): 沙盒唯一标识,后续操作需要用到
             - sandbox_id (str): 沙盒唯一标识,后续操作需要用到
             - message (str): 提示信息
             - message (str): 提示信息
             - port_mapping (dict): 端口映射关系,如 {8080: 32001}
             - port_mapping (dict): 端口映射关系,如 {8080: 32001}
             - access_urls (list): 访问 URL 列表
             - access_urls (list): 访问 URL 列表
-    """
-    try:
-        url = f"{SANDBOX_SERVER_URL}/api/create_environment"
-        payload = {
-            "image": image,
-            "mem_limit": mem_limit,
-            "nano_cpus": nano_cpus
-        }
-        if ports:
-            payload["ports"] = ports
 
 
-        async with httpx.AsyncClient(timeout=DEFAULT_TIMEOUT) as client:
-            response = await client.post(url, json=payload)
-            response.raise_for_status()
-            data = response.json()
+    Raises:
+        httpx.HTTPStatusError: HTTP 请求返回错误状态码时抛出
+        httpx.RequestError: 网络请求失败时抛出
+    """
+    url = f"{server_url or SANDBOX_SERVER_URL}/api/create_environment"
+    payload = {
+        "image": image,
+        "mem_limit": mem_limit,
+        "nano_cpus": nano_cpus,
+        "use_gpu": use_gpu,
+        "gpu_count": gpu_count
+    }
+    if ports:
+        payload["ports"] = ports
 
 
-        return ToolResult(
-            title="Sandbox Created",
-            output=json.dumps(data, ensure_ascii=False, indent=2),
-            long_term_memory=f"Created sandbox: {data.get('sandbox_id', 'unknown')}"
-        )
-    except httpx.HTTPStatusError as e:
-        return ToolResult(
-            title="Create Sandbox Failed",
-            output="",
-            error=f"HTTP error {e.response.status_code}: {e.response.text}"
-        )
-    except Exception as e:
-        return ToolResult(
-            title="Create Sandbox Failed",
-            output="",
-            error=str(e)
-        )
+    async with httpx.AsyncClient(timeout=timeout) as client:
+        response = await client.post(url, json=payload)
+        response.raise_for_status()
+        return response.json()
 
 
 
 
 @tool(
 @tool(
@@ -126,8 +124,9 @@ async def sandbox_run_shell(
     command: str,
     command: str,
     is_background: bool = False,
     is_background: bool = False,
     timeout: int = 120,
     timeout: int = 120,
-    uid: str = ""
-) -> ToolResult:
+    server_url: str = None,
+    request_timeout: float = DEFAULT_TIMEOUT
+) -> Dict[str, Any]:
     """
     """
     在指定的沙盒中执行 Shell 命令。
     在指定的沙盒中执行 Shell 命令。
 
 
@@ -138,10 +137,11 @@ async def sandbox_run_shell(
             - False:前台执行,等待命令完成并返回输出
             - False:前台执行,等待命令完成并返回输出
             - True:后台执行,适合启动长期运行的服务
             - True:后台执行,适合启动长期运行的服务
         timeout: 前台命令的超时时间(秒),默认 120 秒。后台命令不受此限制。
         timeout: 前台命令的超时时间(秒),默认 120 秒。后台命令不受此限制。
-        uid: 用户ID(自动注入)
+        server_url: 服务地址,默认使用全局配置 SANDBOX_SERVER_URL。
+        request_timeout: HTTP 请求超时时间(秒),默认 300 秒。
 
 
     Returns:
     Returns:
-        ToolResult 包含
+        dict: 根据执行方式返回不同内容
             前台执行:
             前台执行:
                 - exit_code (int): 命令退出码
                 - exit_code (int): 命令退出码
                 - stdout (str): 标准输出
                 - stdout (str): 标准输出
@@ -150,38 +150,23 @@ async def sandbox_run_shell(
                 - status (str): 状态
                 - status (str): 状态
                 - message (str): 提示信息
                 - message (str): 提示信息
                 - log_file (str): 日志文件路径
                 - log_file (str): 日志文件路径
-    """
-    try:
-        url = f"{SANDBOX_SERVER_URL}/api/run_shell"
-        payload = {
-            "sandbox_id": sandbox_id,
-            "command": command,
-            "is_background": is_background,
-            "timeout": timeout
-        }
 
 
-        async with httpx.AsyncClient(timeout=DEFAULT_TIMEOUT) as client:
-            response = await client.post(url, json=payload)
-            response.raise_for_status()
-            data = response.json()
+    Raises:
+        httpx.HTTPStatusError: HTTP 请求返回错误状态码时抛出
+        httpx.RequestError: 网络请求失败时抛出
+    """
+    url = f"{server_url or SANDBOX_SERVER_URL}/api/run_shell"
+    payload = {
+        "sandbox_id": sandbox_id,
+        "command": command,
+        "is_background": is_background,
+        "timeout": timeout
+    }
 
 
-        return ToolResult(
-            title=f"Shell: {command[:50]}{'...' if len(command) > 50 else ''}",
-            output=json.dumps(data, ensure_ascii=False, indent=2),
-            long_term_memory=f"Executed in sandbox {sandbox_id}: {command[:100]}"
-        )
-    except httpx.HTTPStatusError as e:
-        return ToolResult(
-            title="Run Shell Failed",
-            output="",
-            error=f"HTTP error {e.response.status_code}: {e.response.text}"
-        )
-    except Exception as e:
-        return ToolResult(
-            title="Run Shell Failed",
-            output="",
-            error=str(e)
-        )
+    async with httpx.AsyncClient(timeout=request_timeout) as client:
+        response = await client.post(url, json=payload)
+        response.raise_for_status()
+        return response.json()
 
 
 
 
 @tool(
 @tool(
@@ -192,7 +177,9 @@ async def sandbox_run_shell(
                 "sandbox_id": "沙盒 ID",
                 "sandbox_id": "沙盒 ID",
                 "ports": "端口列表",
                 "ports": "端口列表",
                 "mem_limit": "内存限制",
                 "mem_limit": "内存限制",
-                "nano_cpus": "CPU 限制"
+                "nano_cpus": "CPU 限制",
+                "use_gpu": "启用 GPU",
+                "gpu_count": "GPU 数量"
             }
             }
         },
         },
         "en": {
         "en": {
@@ -201,7 +188,9 @@ async def sandbox_run_shell(
                 "sandbox_id": "Sandbox ID",
                 "sandbox_id": "Sandbox ID",
                 "ports": "Port list",
                 "ports": "Port list",
                 "mem_limit": "Memory limit",
                 "mem_limit": "Memory limit",
-                "nano_cpus": "CPU limit"
+                "nano_cpus": "CPU limit",
+                "use_gpu": "Enable GPU",
+                "gpu_count": "GPU count"
             }
             }
         }
         }
     }
     }
@@ -211,8 +200,11 @@ async def sandbox_rebuild_with_ports(
     ports: List[int],
     ports: List[int],
     mem_limit: str = "1g",
     mem_limit: str = "1g",
     nano_cpus: int = 1000000000,
     nano_cpus: int = 1000000000,
-    uid: str = ""
-) -> ToolResult:
+    use_gpu: bool = False,
+    gpu_count: int = -1,
+    server_url: str = None,
+    timeout: float = DEFAULT_TIMEOUT
+) -> Dict[str, Any]:
     """
     """
     重建沙盒并应用新的端口映射。
     重建沙盒并应用新的端口映射。
 
 
@@ -227,46 +219,36 @@ async def sandbox_rebuild_with_ports(
         ports: 需要映射的端口列表,如 [8080, 3306, 6379]。
         ports: 需要映射的端口列表,如 [8080, 3306, 6379]。
         mem_limit: 容器最大内存限制,默认为 "1g"。
         mem_limit: 容器最大内存限制,默认为 "1g"。
         nano_cpus: 容器最大 CPU 限制(纳秒),默认为 1000000000(1 CPU)。
         nano_cpus: 容器最大 CPU 限制(纳秒),默认为 1000000000(1 CPU)。
-        uid: 用户ID(自动注入)
+        use_gpu: 是否启用 GPU 支持,默认为 False。需要宿主机安装 nvidia-container-toolkit。
+        gpu_count: 使用的 GPU 数量,-1 表示使用所有可用 GPU,默认为 -1。
+        server_url: 服务地址,默认使用全局配置 SANDBOX_SERVER_URL。
+        timeout: 请求超时时间(秒),默认 300 秒。
 
 
     Returns:
     Returns:
-        ToolResult 包含:
+        dict: 包含以下字段
             - old_sandbox_id (str): 旧沙盒 ID(已销毁)
             - old_sandbox_id (str): 旧沙盒 ID(已销毁)
             - new_sandbox_id (str): 新沙盒 ID(后续使用这个)
             - new_sandbox_id (str): 新沙盒 ID(后续使用这个)
             - port_mapping (dict): 端口映射关系
             - port_mapping (dict): 端口映射关系
             - access_urls (list): 访问 URL 列表
             - access_urls (list): 访问 URL 列表
-    """
-    try:
-        url = f"{SANDBOX_SERVER_URL}/api/rebuild_with_ports"
-        payload = {
-            "sandbox_id": sandbox_id,
-            "ports": ports,
-            "mem_limit": mem_limit,
-            "nano_cpus": nano_cpus
-        }
 
 
-        async with httpx.AsyncClient(timeout=DEFAULT_TIMEOUT) as client:
-            response = await client.post(url, json=payload)
-            response.raise_for_status()
-            data = response.json()
+    Raises:
+        httpx.HTTPStatusError: HTTP 请求返回错误状态码时抛出
+        httpx.RequestError: 网络请求失败时抛出
+    """
+    url = f"{server_url or SANDBOX_SERVER_URL}/api/rebuild_with_ports"
+    payload = {
+        "sandbox_id": sandbox_id,
+        "ports": ports,
+        "mem_limit": mem_limit,
+        "nano_cpus": nano_cpus,
+        "use_gpu": use_gpu,
+        "gpu_count": gpu_count
+    }
 
 
-        return ToolResult(
-            title="Sandbox Rebuilt",
-            output=json.dumps(data, ensure_ascii=False, indent=2),
-            long_term_memory=f"Rebuilt sandbox {sandbox_id} -> {data.get('new_sandbox_id', 'unknown')} with ports {ports}"
-        )
-    except httpx.HTTPStatusError as e:
-        return ToolResult(
-            title="Rebuild Sandbox Failed",
-            output="",
-            error=f"HTTP error {e.response.status_code}: {e.response.text}"
-        )
-    except Exception as e:
-        return ToolResult(
-            title="Rebuild Sandbox Failed",
-            output="",
-            error=str(e)
-        )
+    async with httpx.AsyncClient(timeout=timeout) as client:
+        response = await client.post(url, json=payload)
+        response.raise_for_status()
+        return response.json()
 
 
 
 
 @tool(
 @tool(
@@ -288,146 +270,33 @@ async def sandbox_rebuild_with_ports(
 )
 )
 async def sandbox_destroy_environment(
 async def sandbox_destroy_environment(
     sandbox_id: str,
     sandbox_id: str,
-    uid: str = ""
-) -> ToolResult:
+    server_url: str = None,
+    timeout: float = DEFAULT_TIMEOUT
+) -> Dict[str, Any]:
     """
     """
     销毁沙盒环境,释放资源。
     销毁沙盒环境,释放资源。
 
 
     Args:
     Args:
         sandbox_id: 沙盒 ID。
         sandbox_id: 沙盒 ID。
-        uid: 用户ID(自动注入)
+        server_url: 服务地址,默认使用全局配置 SANDBOX_SERVER_URL。
+        timeout: 请求超时时间(秒),默认 300 秒。
 
 
     Returns:
     Returns:
-        ToolResult 包含
+        dict: 包含以下字段
             - status (str): 操作状态,如 "success"
             - status (str): 操作状态,如 "success"
             - message (str): 提示信息
             - message (str): 提示信息
             - removed_tools (list): 被移除的工具列表(如有关联的已注册工具)
             - removed_tools (list): 被移除的工具列表(如有关联的已注册工具)
-    """
-    try:
-        url = f"{SANDBOX_SERVER_URL}/api/destroy_environment"
-        payload = {
-            "sandbox_id": sandbox_id
-        }
-
-        async with httpx.AsyncClient(timeout=DEFAULT_TIMEOUT) as client:
-            response = await client.post(url, json=payload)
-            response.raise_for_status()
-            data = response.json()
-
-        return ToolResult(
-            title="Sandbox Destroyed",
-            output=json.dumps(data, ensure_ascii=False, indent=2),
-            long_term_memory=f"Destroyed sandbox: {sandbox_id}"
-        )
-    except httpx.HTTPStatusError as e:
-        return ToolResult(
-            title="Destroy Sandbox Failed",
-            output="",
-            error=f"HTTP error {e.response.status_code}: {e.response.text}"
-        )
-    except Exception as e:
-        return ToolResult(
-            title="Destroy Sandbox Failed",
-            output="",
-            error=str(e)
-        )
-
-
-@tool(
-    display={
-        "zh": {
-            "name": "注册沙盒工具",
-            "params": {
-                "tool_name": "工具名称",
-                "description": "工具描述",
-                "input_schema": "参数定义",
-                "sandbox_id": "沙盒 ID",
-                "internal_port": "内部端口",
-                "endpoint_path": "API 路径",
-                "http_method": "HTTP 方法"
-            }
-        },
-        "en": {
-            "name": "Register Sandbox Tool",
-            "params": {
-                "tool_name": "Tool name",
-                "description": "Tool description",
-                "input_schema": "Input schema",
-                "sandbox_id": "Sandbox ID",
-                "internal_port": "Internal port",
-                "endpoint_path": "API path",
-                "http_method": "HTTP method"
-            }
-        }
-    }
-)
-async def sandbox_register_tool(
-    tool_name: str,
-    description: str,
-    input_schema: Dict[str, Any],
-    sandbox_id: str,
-    internal_port: int,
-    endpoint_path: str = "/",
-    http_method: str = "POST",
-    metadata: Optional[Dict[str, Any]] = None,
-    uid: str = ""
-) -> ToolResult:
-    """
-    将部署好的服务注册为工具。
-
-    注册后,该工具会出现在统一 MCP Server 的工具列表中,可被上游服务调用。
-
-    Args:
-        tool_name: 工具唯一标识(字母开头,只能包含字母、数字、下划线),
-                   如 "rendercv_api"。
-        description: 工具描述,描述该工具的功能。
-        input_schema: JSON Schema 格式的参数定义,定义工具接收的参数。
-        sandbox_id: 服务所在的沙盒 ID。
-        internal_port: 服务在容器内的端口。
-        endpoint_path: API 路径,默认 "/"。
-        http_method: HTTP 方法,默认 "POST"。
-        metadata: 额外元数据(可选)。
-        uid: 用户ID(自动注入)
 
 
-    Returns:
-        ToolResult 包含:
-            - status (str): 操作状态,"success" 或 "error"
-            - message (str): 提示信息
-            - tool_info (dict): 工具信息(成功时)
+    Raises:
+        httpx.HTTPStatusError: HTTP 请求返回错误状态码时抛出
+        httpx.RequestError: 网络请求失败时抛出
     """
     """
-    try:
-        url = f"{SANDBOX_SERVER_URL}/api/register_tool"
-        payload = {
-            "tool_name": tool_name,
-            "description": description,
-            "input_schema": input_schema,
-            "sandbox_id": sandbox_id,
-            "internal_port": internal_port,
-            "endpoint_path": endpoint_path,
-            "http_method": http_method
-        }
-        if metadata:
-            payload["metadata"] = metadata
-
-        async with httpx.AsyncClient(timeout=DEFAULT_TIMEOUT) as client:
-            response = await client.post(url, json=payload)
-            response.raise_for_status()
-            data = response.json()
+    url = f"{server_url or SANDBOX_SERVER_URL}/api/destroy_environment"
+    payload = {
+        "sandbox_id": sandbox_id
+    }
 
 
-        return ToolResult(
-            title=f"Tool Registered: {tool_name}",
-            output=json.dumps(data, ensure_ascii=False, indent=2),
-            long_term_memory=f"Registered tool '{tool_name}' on sandbox {sandbox_id}:{internal_port}"
-        )
-    except httpx.HTTPStatusError as e:
-        return ToolResult(
-            title="Register Tool Failed",
-            output="",
-            error=f"HTTP error {e.response.status_code}: {e.response.text}"
-        )
-    except Exception as e:
-        return ToolResult(
-            title="Register Tool Failed",
-            output="",
-            error=str(e)
-        )
+    async with httpx.AsyncClient(timeout=timeout) as client:
+        response = await client.post(url, json=payload)
+        response.raise_for_status()
+        return response.json()

+ 1 - 1
examples/test_tools_baidu.py

@@ -8,7 +8,7 @@ from urllib.parse import quote
 
 
 sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
 sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
 
 
-from tools.baseClassTools import (
+from agent.tools.builtin.baseClass import (
     init_browser_session,
     init_browser_session,
     navigate_to_url,
     navigate_to_url,
     wait,
     wait,