"""파이썬 코드 실행 도구. GAIA에 "attached Python code"의 출력을 묻는 질문(예: f918266a)이 등장. 첨부 파일은 텍스트로 받지만 출력을 알려면 실제 실행이 필요. smolagents의 자체 코드 sandbox로 처리할 수도 있지만 명시 도구로 분리하면 (a) LLM이 의도를 명확히 표현 (b) stdout 캡처를 단순화한다. 안전: 첨부된 코드를 직접 실행하므로 신뢰되지 않은 입력에 노출. GAIA 채점 컨텍스트 한정으로 사용. 실서비스에는 sandbox 강화 필요. """ import os import subprocess import sys import tempfile from smolagents import tool @tool def exec_python_code(code: str) -> str: """Execute Python source code and return its captured stdout. Use this when the question asks for the output of a piece of attached or referenced Python code (e.g., "What is the final numeric output of the code?"). Pass the code body verbatim. Captures both stdout and stderr; returns up to ~12k characters. Args: code: The Python source code to execute. """ if len(code) > 50000: return "exec_python_code error: code is too large to execute safely" try: with tempfile.TemporaryDirectory(prefix="gaia_exec_") as tmpdir: script_path = os.path.join(tmpdir, "snippet.py") with open(script_path, "w", encoding="utf-8") as f: f.write(code) result = subprocess.run( [sys.executable, "-I", script_path], cwd=tmpdir, capture_output=True, text=True, timeout=8, ) out = (result.stdout or "") + (result.stderr or "") if result.returncode != 0: out = f"exec_python_code exited with status {result.returncode}\n{out}" except subprocess.TimeoutExpired as e: partial = ((e.stdout or "") + (e.stderr or ""))[:4000] return f"exec_python_code error: TimeoutExpired after 8s\n--- partial output ---\n{partial}" except Exception as e: return ( f"exec_python_code error: {type(e).__name__}: {e}\n" f"--- partial output ---\n" ) if len(out) > 12000: out = out[:12000] + "\n...[truncated]" return out or "(no stdout output)"