File size: 2,022 Bytes
b6c100d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
"""Python code execution tool.



Runs code in a separate interpreter process via subprocess with:

  - a hard process timeout (killed on expiry),

  - no shell involvement,

  - stdout/stderr capture with truncation.

"""
from __future__ import annotations

import subprocess
import sys

from .base import Tool, ToolResult

MAX_OUTPUT_CHARS = 2000
PROCESS_TIMEOUT = 10


class CodeExecTool(Tool):
    name = "code_exec"
    description = ("Execute a short Python snippet in an isolated process and "
                   "return its stdout. Use print() to output results.")
    args_hint = '{"code": "<python source code>"}'
    timeout_seconds = PROCESS_TIMEOUT + 5  # outer guard above the process timeout

    def _run(self, code: str = "") -> ToolResult:
        if not code or not code.strip():
            return ToolResult(success=False, error="code must be a non-empty string",
                              error_type="INPUT_ERROR")
        try:
            proc = subprocess.run(
                [sys.executable, "-I", "-c", code],  # -I: isolated mode
                capture_output=True,
                text=True,
                timeout=PROCESS_TIMEOUT,
            )
        except subprocess.TimeoutExpired:
            return ToolResult(success=False,
                              error=f"code ran longer than {PROCESS_TIMEOUT}s and was killed",
                              error_type="TIMEOUT")

        stdout = (proc.stdout or "")[:MAX_OUTPUT_CHARS]
        stderr = (proc.stderr or "")[:MAX_OUTPUT_CHARS]
        if proc.returncode != 0:
            return ToolResult(success=False, error=stderr or "non-zero exit",
                              error_type="EXECUTION_ERROR")
        if not stdout.strip():
            return ToolResult(success=True,
                              data="(code ran successfully but printed nothing — "
                                   "use print() to see values)")
        return ToolResult(success=True, data=stdout)