| | from typing import Any, Dict |
| | from smolagents.tools import Tool |
| | import io |
| | import contextlib |
| | import traceback |
| | import signal |
| |
|
| | class TimeoutException(Exception): |
| | pass |
| |
|
| | def timeout_handler(signum, frame): |
| | raise TimeoutException("Execution timed out.") |
| |
|
| | class PythonRunnerTool(Tool): |
| | name = "python_runner" |
| | description = "Executes Python code safely and returns stdout or errors." |
| | inputs = {'code': {'type': 'string', 'description': 'Python code to execute'}} |
| | output_type = "string" |
| |
|
| | def forward(self, code: str) -> str: |
| | stdout_buffer = io.StringIO() |
| | safe_globals = { |
| | "__builtins__": { |
| | "print": print, |
| | "range": range, |
| | "len": len, |
| | "int": int, |
| | "float": float, |
| | "str": str, |
| | "list": list, |
| | "dict": dict, |
| | "sum": sum, |
| | "min": min, |
| | "max": max, |
| | "abs": abs, |
| | } |
| | } |
| | try: |
| | signal.signal(signal.SIGALRM, timeout_handler) |
| | signal.alarm(5) |
| |
|
| | with contextlib.redirect_stdout(stdout_buffer): |
| | exec(code, safe_globals, {}) |
| |
|
| | signal.alarm(0) |
| | return stdout_buffer.getvalue() |
| |
|
| | except TimeoutException as e: |
| | return f"Error: {str(e)}" |
| |
|
| | except Exception: |
| | return traceback.format_exc() |
| |
|