base_agent/tools/code_executor.py

61 lines
2.6 KiB
Python
Raw Normal View History

2026-02-28 08:21:35 +00:00
# ════════════════════════════════════════════════════════════════
2026-03-09 05:37:29 +00:00
# tools/code_executor.py
2026-02-28 08:21:35 +00:00
# ════════════════════════════════════════════════════════════════
2026-03-09 05:37:29 +00:00
"""沙箱代码执行工具(从配置读取 timeout / sandbox"""
2026-02-28 08:21:35 +00:00
import io
import contextlib
import time
from tools.base_tool import BaseTool, ToolResult
2026-03-09 05:37:29 +00:00
from config.settings import settings
2026-02-28 08:21:35 +00:00
class CodeExecutorTool(BaseTool):
name = "code_executor"
description = "在沙箱环境中执行 Python 代码片段,返回标准输出"
parameters = {
2026-03-09 05:37:29 +00:00
"code": {"type": "string", "description": "要执行的 Python 代码"},
"timeout": {"type": "integer", "description": "超时时间(秒)"},
2026-02-28 08:21:35 +00:00
}
_SAFE_BUILTINS = {
"print": print, "range": range, "len": len,
"int": int, "float": float, "str": str, "list": list,
"dict": dict, "tuple": tuple, "set": set, "bool": bool,
"abs": abs, "max": max, "min": min, "sum": sum,
"enumerate": enumerate, "zip": zip, "map": map,
"sorted": sorted, "reversed": reversed,
}
2026-03-09 05:37:29 +00:00
def __init__(self):
super().__init__()
2026-03-09 06:10:07 +00:00
cfg = settings.tools['code_executor']
self._timeout = cfg['timeout']
self._sandbox = cfg['sandbox']
2026-03-09 05:37:29 +00:00
self.logger.debug(
f"⚙️ CodeExecutor timeout={self._timeout}s, sandbox={self._sandbox}"
)
def execute(self, code: str, timeout: int | None = None, **_) -> ToolResult:
timeout = timeout or self._timeout
2026-02-28 08:21:35 +00:00
stdout_buf = io.StringIO()
2026-03-09 05:37:29 +00:00
start = time.perf_counter()
exec_globals = (
{"__builtins__": self._SAFE_BUILTINS}
if self._sandbox
else {"__builtins__": __builtins__}
)
2026-02-28 08:21:35 +00:00
try:
with contextlib.redirect_stdout(stdout_buf):
2026-03-09 05:37:29 +00:00
exec(compile(code, "<agent_sandbox>", "exec"), exec_globals) # noqa: S102
elapsed = (time.perf_counter() - start) * 1000
2026-02-28 08:21:35 +00:00
output = stdout_buf.getvalue() or "(无输出)"
return ToolResult(
success=True,
2026-03-09 05:37:29 +00:00
output=f"执行成功 ({elapsed:.1f}ms) [sandbox={self._sandbox}]:\n{output}",
metadata={"elapsed_ms": elapsed, "sandbox": self._sandbox},
2026-02-28 08:21:35 +00:00
)
except Exception as exc:
2026-03-09 05:37:29 +00:00
return ToolResult(success=False, output=f"执行错误: {type(exc).__name__}: {exc}")