DriptoBhattacharyya's picture
Gemini vision (solves chess), solver plain-text fallback, pandas in python_repl
0c9c31a
Raw
History Blame Contribute Delete
3.19 kB
"""A restricted Python REPL for exact arithmetic, string, and date work."""
from __future__ import annotations
import contextlib
import io
import math
from langchain_core.tools import tool
# A small, deliberately limited set of safe builtins/modules.
_SAFE_BUILTINS = {
"abs": abs, "all": all, "any": any, "bin": bin, "bool": bool, "chr": chr,
"dict": dict, "divmod": divmod, "enumerate": enumerate, "filter": filter,
"float": float, "hex": hex, "int": int, "len": len, "list": list, "map": map,
"max": max, "min": min, "oct": oct, "ord": ord, "pow": pow, "range": range,
"reversed": reversed, "round": round, "set": set, "sorted": sorted, "str": str,
"sum": sum, "tuple": tuple, "zip": zip, "print": print,
}
@tool
def python_repl(code: str) -> str:
"""Execute a short Python snippet and return its stdout (and `result` if set).
Use for exact arithmetic, string manipulation, sorting, and date math. ALWAYS use
this for numeric work instead of computing in your head. ``math``, ``statistics``,
``datetime``, ``re``, ``itertools``, ``collections`` and ``pd`` (pandas) are
available -- e.g. read a spreadsheet with ``pd.read_excel(path)``. Assign to a
variable named ``result`` to return a value.
Args:
code: Python source to execute.
"""
import collections
import datetime
import itertools
import re
import statistics
env = {
"__builtins__": _SAFE_BUILTINS,
"math": math,
"statistics": statistics,
"datetime": datetime,
"re": re,
"itertools": itertools,
"collections": collections,
}
# Preload pandas as `pd` so spreadsheet math is exact, e.g.
# df = pd.read_excel(path); result = df[["Burgers","Fries"]].sum().sum()
try:
import pandas as pd
env["pd"] = pd
except Exception: # noqa: BLE001
pass
buf = io.StringIO()
try:
with contextlib.redirect_stdout(buf):
exec(code, env) # noqa: S102 - sandboxed builtins, internal use only
except Exception as exc: # noqa: BLE001
return f"Error: {exc}\nOutput so far:\n{buf.getvalue()}"
out = buf.getvalue()
if "result" in env:
out += ("\n" if out else "") + f"result = {env['result']!r}"
return out or "(no output)"
@tool
def run_python_file(path: str) -> str:
"""Execute a downloaded .py file in a subprocess and return its stdout.
Use for questions asking for the output of an attached Python script.
Args:
path: Local path to the .py file (e.g. from download_task_file).
"""
import subprocess
import sys
try:
proc = subprocess.run(
[sys.executable, path],
capture_output=True,
text=True,
timeout=30,
)
except subprocess.TimeoutExpired:
return "Execution timed out after 30s."
except Exception as exc: # noqa: BLE001
return f"Could not run file: {exc}"
out = (proc.stdout or "").strip()
err = (proc.stderr or "").strip()
result = f"STDOUT:\n{out}"
if err:
result += f"\nSTDERR:\n{err[:2000]}"
return result or "(no output)"