ソースを参照

chore: remove unused sandbox tools

Sandbox tools were originally built for running tools inside isolated
environments, but tool execution has since been centralized into toolhub
(server-side Tool_Agent), making the local sandbox wrapper dead code.

- Delete agent/tools/builtin/sandbox.py (4 @tool functions, ~420 lines)
- Remove sandbox imports and __all__ entries in builtin/__init__.py
- Clean up commented-out sandbox references in core/runner.py
Talegorithm 3 日 前
コミット
ca3df81806
3 ファイル変更1 行追加431 行削除
  1. 0 7
      agent/core/runner.py
  2. 1 6
      agent/tools/builtin/__init__.py
  3. 0 418
      agent/tools/builtin/sandbox.py

+ 0 - 7
agent/core/runner.py

@@ -179,13 +179,6 @@ BUILTIN_TOOLS = [
     # "knowledge_batch_update",
     # "knowledge_list",
     # "knowledge_slim",
-    
-
-    # 沙箱工具
-    # "sandbox_create_environment",
-    # "sandbox_run_shell",
-    # "sandbox_rebuild_with_ports",
-    # "sandbox_destroy_environment",
 
     # 浏览器工具
     "browser_get_live_url",

+ 1 - 6
agent/tools/builtin/__init__.py

@@ -16,8 +16,7 @@ from agent.tools.builtin.bash import bash_command
 from agent.tools.builtin.skill import skill, list_skills
 from agent.tools.builtin.subagent import agent, evaluate
 from agent.tools.builtin.search import search_posts, get_search_suggestions
-from agent.tools.builtin.sandbox import (sandbox_create_environment, sandbox_run_shell,
-                                         sandbox_rebuild_with_ports,sandbox_destroy_environment)
+# sandbox 工具已废弃(2026-04):原本是给"运行工具"场景准备的,但工具已被抽到 toolhub 单独处理
 from agent.tools.builtin.knowledge import(knowledge_search,knowledge_save,knowledge_list,knowledge_update,knowledge_batch_update,knowledge_slim)
 from agent.tools.builtin.librarian import ask_knowledge, upload_knowledge
 from agent.tools.builtin.context import get_current_context
@@ -57,10 +56,6 @@ __all__ = [
     "search_posts",
     "select_post",
     "get_search_suggestions",
-    "sandbox_create_environment",
-    "sandbox_run_shell",
-    "sandbox_rebuild_with_ports",
-    "sandbox_destroy_environment",
     # 上下文工具
     "get_current_context",
     # ToolHub 远程工具库

+ 0 - 418
agent/tools/builtin/sandbox.py

@@ -1,418 +0,0 @@
-"""
-Sandbox Tools (Async)
-通过 HTTP 异步调用沙盒管理服务的客户端库。
-"""
-
-import json
-import httpx
-from typing import Optional, List, Dict, Any
-
-from agent.tools import tool, ToolResult, ToolContext
-
-
-# 服务地址,可根据实际部署情况修改
-# SANDBOX_SERVER_URL = "http://192.168.100.20:9998"
-SANDBOX_SERVER_URL = "http://61.48.133.26:9998"
-
-# 默认超时时间(秒)
-DEFAULT_TIMEOUT = 300.0
-
-
-@tool(
-    hidden_params=["context"],
-    display={
-        "zh": {
-            "name": "创建沙盒环境",
-            "params": {
-                "image": "Docker 镜像",
-                "mem_limit": "内存限制",
-                "nano_cpus": "CPU 限制",
-                "ports": "端口列表",
-                "use_gpu": "启用 GPU",
-                "gpu_count": "GPU 数量"
-            }
-        },
-        "en": {
-            "name": "Create Sandbox",
-            "params": {
-                "image": "Docker image",
-                "mem_limit": "Memory limit",
-                "nano_cpus": "CPU limit",
-                "ports": "Port list",
-                "use_gpu": "Enable GPU",
-                "gpu_count": "GPU count"
-            }
-        }
-    }
-)
-async def sandbox_create_environment(
-    image: str = "agent-sandbox:latest",
-    mem_limit: str = "512m",
-    nano_cpus: int = 500000000,
-    ports: Optional[List[int]] = None,
-    use_gpu: bool = False,
-    gpu_count: int = -1,
-    server_url: str = None,
-    timeout: float = DEFAULT_TIMEOUT,
-    context: Optional[ToolContext] = None,
-) -> ToolResult:
-    """
-    创建一个隔离的 Docker 开发环境。
-
-    Args:
-        image: Docker 镜像名称,默认为 "agent-sandbox:latest"。
-               可以使用其他镜像如 "python:3.12-slim", "node:18-slim" 等。
-        mem_limit: 容器最大内存限制,默认为 "512m"。
-        nano_cpus: 容器最大 CPU 限制(纳秒),默认为 500000000(0.5 CPU)。
-        ports: 需要映射的端口列表,如 [8080, 3000]。
-        use_gpu: 是否启用 GPU 支持,默认为 False。需要宿主机安装 nvidia-container-toolkit。
-        gpu_count: 使用的 GPU 数量,-1 表示使用所有可用 GPU,默认为 -1。
-        server_url: 服务地址,默认使用全局配置 SANDBOX_SERVER_URL。
-        timeout: 请求超时时间(秒),默认 300 秒。
-        context: 工具上下文
-
-    Returns:
-        ToolResult: 包含沙盒创建结果
-    """
-    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
-
-    try:
-        async with httpx.AsyncClient(timeout=timeout) as client:
-            response = await client.post(url, json=payload)
-            response.raise_for_status()
-            data = response.json()
-
-        sandbox_id = data.get("sandbox_id", "")
-        port_mapping = data.get("port_mapping", {})
-        access_urls = data.get("access_urls", [])
-
-        output_parts = [f"沙盒 ID: {sandbox_id}"]
-        if port_mapping:
-            output_parts.append(f"端口映射: {json.dumps(port_mapping)}")
-        if access_urls:
-            output_parts.append(f"访问地址: {', '.join(access_urls)}")
-
-        return ToolResult(
-            title="沙盒环境创建成功",
-            output="\n".join(output_parts),
-            metadata=data
-        )
-    except httpx.HTTPStatusError as e:
-        return ToolResult(
-            title="沙盒创建失败",
-            output=f"HTTP 错误: {e.response.status_code}",
-            error=str(e)
-        )
-    except httpx.RequestError as e:
-        return ToolResult(
-            title="沙盒创建失败",
-            output=f"网络请求失败: {str(e)}",
-            error=str(e)
-        )
-
-
-@tool(
-    hidden_params=["context"],
-    display={
-        "zh": {
-            "name": "执行沙盒命令",
-            "params": {
-                "sandbox_id": "沙盒 ID",
-                "command": "Shell 命令",
-                "is_background": "后台执行",
-                "timeout": "超时时间"
-            }
-        },
-        "en": {
-            "name": "Run Shell in Sandbox",
-            "params": {
-                "sandbox_id": "Sandbox ID",
-                "command": "Shell command",
-                "is_background": "Run in background",
-                "timeout": "Timeout"
-            }
-        }
-    }
-)
-async def sandbox_run_shell(
-    sandbox_id: str,
-    command: str,
-    is_background: bool = False,
-    timeout: int = 120,
-    server_url: str = None,
-    request_timeout: float = DEFAULT_TIMEOUT,
-    context: Optional[ToolContext] = None,
-) -> ToolResult:
-    """
-    在指定的沙盒中执行 Shell 命令。
-
-    Args:
-        sandbox_id: 沙盒 ID,由 create_environment 返回。
-        command: 要执行的 Shell 命令,如 "pip install flask" 或 "python app.py"。
-        is_background: 是否后台执行,默认为 False。
-            - False:前台执行,等待命令完成并返回输出
-            - True:后台执行,适合启动长期运行的服务
-        timeout: 前台命令的超时时间(秒),默认 120 秒。后台命令不受此限制。
-        server_url: 服务地址,默认使用全局配置 SANDBOX_SERVER_URL。
-        request_timeout: HTTP 请求超时时间(秒),默认 300 秒。
-        context: 工具上下文
-
-    Returns:
-        ToolResult: 命令执行结果
-    """
-    url = f"{server_url or SANDBOX_SERVER_URL}/api/run_shell"
-    payload = {
-        "sandbox_id": sandbox_id,
-        "command": command,
-        "is_background": is_background,
-        "timeout": timeout
-    }
-
-    try:
-        async with httpx.AsyncClient(timeout=request_timeout) as client:
-            response = await client.post(url, json=payload)
-            response.raise_for_status()
-            data = response.json()
-
-        if is_background:
-            status = data.get("status", "")
-            message = data.get("message", "")
-            log_file = data.get("log_file", "")
-            output = f"状态: {status}\n消息: {message}"
-            if log_file:
-                output += f"\n日志文件: {log_file}"
-            return ToolResult(
-                title=f"后台命令已启动: {command[:50]}",
-                output=output,
-                metadata=data
-            )
-        else:
-            exit_code = data.get("exit_code", -1)
-            stdout = data.get("stdout", "")
-            stderr = data.get("stderr", "")
-
-            output_parts = []
-            if stdout:
-                output_parts.append(stdout)
-            if stderr:
-                if output_parts:
-                    output_parts.append("\n--- stderr ---")
-                output_parts.append(stderr)
-            if not output_parts:
-                output_parts.append("(命令无输出)")
-
-            success = exit_code == 0
-            title = f"命令: {command[:50]}"
-            if not success:
-                title += f" (exit code: {exit_code})"
-
-            return ToolResult(
-                title=title,
-                output="\n".join(output_parts),
-                metadata=data,
-                error=None if success else f"Command failed with exit code {exit_code}"
-            )
-    except httpx.HTTPStatusError as e:
-        return ToolResult(
-            title="命令执行失败",
-            output=f"HTTP 错误: {e.response.status_code}",
-            error=str(e)
-        )
-    except httpx.RequestError as e:
-        return ToolResult(
-            title="命令执行失败",
-            output=f"网络请求失败: {str(e)}",
-            error=str(e)
-        )
-
-
-@tool(
-    hidden_params=["context"],
-    display={
-        "zh": {
-            "name": "重建沙盒端口",
-            "params": {
-                "sandbox_id": "沙盒 ID",
-                "ports": "端口列表",
-                "mem_limit": "内存限制",
-                "nano_cpus": "CPU 限制",
-                "use_gpu": "启用 GPU",
-                "gpu_count": "GPU 数量"
-            }
-        },
-        "en": {
-            "name": "Rebuild Sandbox Ports",
-            "params": {
-                "sandbox_id": "Sandbox ID",
-                "ports": "Port list",
-                "mem_limit": "Memory limit",
-                "nano_cpus": "CPU limit",
-                "use_gpu": "Enable GPU",
-                "gpu_count": "GPU count"
-            }
-        }
-    }
-)
-async def sandbox_rebuild_with_ports(
-    sandbox_id: str,
-    ports: List[int],
-    mem_limit: str = "1g",
-    nano_cpus: int = 1000000000,
-    use_gpu: bool = False,
-    gpu_count: int = -1,
-    server_url: str = None,
-    timeout: float = DEFAULT_TIMEOUT,
-    context: Optional[ToolContext] = None,
-) -> ToolResult:
-    """
-    重建沙盒并应用新的端口映射。
-
-    使用场景:先创建沙盒克隆项目,阅读 README 后才知道需要暴露哪些端口,
-    此时调用此函数重建沙盒,应用正确的端口映射。
-
-    注意:重建后会返回新的 sandbox_id,后续操作需要使用新 ID。
-    容器内的所有文件(克隆的代码、安装的依赖等)都会保留。
-
-    Args:
-        sandbox_id: 当前沙盒 ID。
-        ports: 需要映射的端口列表,如 [8080, 3306, 6379]。
-        mem_limit: 容器最大内存限制,默认为 "1g"。
-        nano_cpus: 容器最大 CPU 限制(纳秒),默认为 1000000000(1 CPU)。
-        use_gpu: 是否启用 GPU 支持,默认为 False。需要宿主机安装 nvidia-container-toolkit。
-        gpu_count: 使用的 GPU 数量,-1 表示使用所有可用 GPU,默认为 -1。
-        server_url: 服务地址,默认使用全局配置 SANDBOX_SERVER_URL。
-        timeout: 请求超时时间(秒),默认 300 秒。
-        context: 工具上下文
-
-    Returns:
-        ToolResult: 重建结果
-    """
-    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
-    }
-
-    try:
-        async with httpx.AsyncClient(timeout=timeout) as client:
-            response = await client.post(url, json=payload)
-            response.raise_for_status()
-            data = response.json()
-
-        old_id = data.get("old_sandbox_id", "")
-        new_id = data.get("new_sandbox_id", "")
-        port_mapping = data.get("port_mapping", {})
-        access_urls = data.get("access_urls", [])
-
-        output_parts = [
-            f"旧沙盒 ID: {old_id} (已销毁)",
-            f"新沙盒 ID: {new_id}"
-        ]
-        if port_mapping:
-            output_parts.append(f"端口映射: {json.dumps(port_mapping)}")
-        if access_urls:
-            output_parts.append(f"访问地址: {', '.join(access_urls)}")
-
-        return ToolResult(
-            title="沙盒重建成功",
-            output="\n".join(output_parts),
-            metadata=data
-        )
-    except httpx.HTTPStatusError as e:
-        return ToolResult(
-            title="沙盒重建失败",
-            output=f"HTTP 错误: {e.response.status_code}",
-            error=str(e)
-        )
-    except httpx.RequestError as e:
-        return ToolResult(
-            title="沙盒重建失败",
-            output=f"网络请求失败: {str(e)}",
-            error=str(e)
-        )
-
-
-@tool(
-    requires_confirmation=True,
-    display={
-        "zh": {
-            "name": "销毁沙盒环境",
-            "params": {
-                "sandbox_id": "沙盒 ID"
-            }
-        },
-        "en": {
-            "name": "Destroy Sandbox",
-            "params": {
-                "sandbox_id": "Sandbox ID"
-            }
-        }
-    }
-)
-async def sandbox_destroy_environment(
-    sandbox_id: str,
-    server_url: str = None,
-    timeout: float = DEFAULT_TIMEOUT,
-    context: Optional[ToolContext] = None,
-) -> ToolResult:
-    """
-    销毁沙盒环境,释放资源。
-
-    Args:
-        sandbox_id: 沙盒 ID。
-        server_url: 服务地址,默认使用全局配置 SANDBOX_SERVER_URL。
-        timeout: 请求超时时间(秒),默认 300 秒。
-        context: 工具上下文
-
-    Returns:
-        ToolResult: 销毁结果
-    """
-    url = f"{server_url or SANDBOX_SERVER_URL}/api/destroy_environment"
-    payload = {
-        "sandbox_id": sandbox_id
-    }
-
-    try:
-        async with httpx.AsyncClient(timeout=timeout) as client:
-            response = await client.post(url, json=payload)
-            response.raise_for_status()
-            data = response.json()
-
-        status = data.get("status", "")
-        message = data.get("message", "")
-        removed_tools = data.get("removed_tools", [])
-
-        output_parts = [f"状态: {status}", f"消息: {message}"]
-        if removed_tools:
-            output_parts.append(f"已移除的工具: {', '.join(removed_tools)}")
-
-        return ToolResult(
-            title="沙盒环境已销毁",
-            output="\n".join(output_parts),
-            metadata=data
-        )
-    except httpx.HTTPStatusError as e:
-        return ToolResult(
-            title="沙盒销毁失败",
-            output=f"HTTP 错误: {e.response.status_code}",
-            error=str(e)
-        )
-    except httpx.RequestError as e:
-        return ToolResult(
-            title="沙盒销毁失败",
-            output=f"网络请求失败: {str(e)}",
-            error=str(e)
-        )