Spaces:
Running
Running
| """Code-execution sandbox so the agent can compute, not just talk. | |
| LLMs are unreliable at arithmetic (scaling a recipe to 6 people, lentil | |
| hydration ratios, salt as a % of water weight, brew ratios, simmer timing). | |
| Instead of trusting the model's mental math, we let it WRITE Python and run it | |
| in a sandbox, then read back the real numbers. This is the "Best Use of Modal" | |
| angle: agent-generated code runs in a `modal.Sandbox`. | |
| Three backends via SANDBOX_BACKEND: | |
| - modal : run in a `modal.Sandbox` (the Space; needs Modal creds) — safe for | |
| untrusted, model-written code. | |
| - local : run in a local subprocess with a timeout (dev only; NOT sandboxed — | |
| only run code you trust / scripted-mode tests). | |
| - mock : echo back without executing (pure UI flows). | |
| """ | |
| import os | |
| import subprocess | |
| import sys | |
| import textwrap | |
| SANDBOX_BACKEND = os.environ.get("SANDBOX_BACKEND", "local") | |
| SANDBOX_TIMEOUT = int(os.environ.get("SANDBOX_TIMEOUT", "20")) | |
| MODAL_SANDBOX_APP = os.environ.get("MODAL_SANDBOX_APP", "epicurean-sandbox") | |
| def _run_local(code: str, timeout: int) -> dict: | |
| try: | |
| proc = subprocess.run( | |
| [sys.executable, "-I", "-c", code], # -I: isolated, no env/site influence | |
| capture_output=True, text=True, timeout=timeout, | |
| ) | |
| return {"ok": proc.returncode == 0, "stdout": proc.stdout, | |
| "stderr": proc.stderr, "backend": "local"} | |
| except subprocess.TimeoutExpired: | |
| return {"ok": False, "stdout": "", "stderr": f"timed out after {timeout}s", | |
| "backend": "local"} | |
| def _run_modal(code: str, timeout: int) -> dict: | |
| import modal | |
| app = modal.App.lookup(MODAL_SANDBOX_APP, create_if_missing=True) | |
| sb = modal.Sandbox.create(app=app, timeout=max(timeout + 10, 60)) | |
| try: | |
| proc = sb.exec("python", "-c", code, timeout=timeout) | |
| stdout, stderr = proc.stdout.read(), proc.stderr.read() | |
| proc.wait() | |
| return {"ok": proc.returncode == 0, "stdout": stdout, | |
| "stderr": stderr, "backend": "modal"} | |
| finally: | |
| sb.terminate() | |
| def run_code(code: str, timeout: int | None = None) -> dict: | |
| """Execute Python `code`, return {ok, stdout, stderr, backend}. Never raises.""" | |
| code = textwrap.dedent(code).strip() | |
| timeout = timeout or SANDBOX_TIMEOUT | |
| if not code: | |
| return {"ok": False, "stdout": "", "stderr": "empty code", "backend": "none"} | |
| try: | |
| if SANDBOX_BACKEND == "mock": | |
| return {"ok": True, "stdout": "(mock sandbox — code not executed)", | |
| "stderr": "", "backend": "mock"} | |
| if SANDBOX_BACKEND == "modal": | |
| return _run_modal(code, timeout) | |
| return _run_local(code, timeout) | |
| except Exception as exc: # backend misconfig shouldn't crash the agent | |
| return {"ok": False, "stdout": "", | |
| "stderr": f"{type(exc).__name__}: {exc}", "backend": SANDBOX_BACKEND} | |
| if __name__ == "__main__": | |
| # Smoke test: python sandbox.py | |
| r = run_code("servings=4\nprint('water_ml =', servings*75*3)") | |
| print(r) | |