from __future__ import annotations import subprocess import sys from pathlib import Path class WorkspaceExecutor: """Executes model-requested actions inside the task workspace.""" def __init__(self, workspace: Path, timeout_s: int = 120) -> None: self.workspace = workspace.resolve() self.timeout_s = timeout_s self.workspace.mkdir(parents=True, exist_ok=True) def run_python(self, code: str) -> str: return self._run([sys.executable, "-c", code]) def run_shell(self, command: str) -> str: if any(token in command for token in ["../", "rm -rf /", "sudo "]): return "Blocked potentially unsafe shell command." return self._run(["bash", "-lc", command]) def _run(self, argv: list[str]) -> str: try: proc = subprocess.run( argv, cwd=self.workspace, text=True, capture_output=True, timeout=self.timeout_s, check=False, ) except subprocess.TimeoutExpired: return f"Command timed out after {self.timeout_s}s." stdout = proc.stdout.strip() stderr = proc.stderr.strip() parts = [f"exit_code={proc.returncode}"] if stdout: parts.append(f"stdout:\n{stdout}") if stderr: parts.append(f"stderr:\n{stderr}") return "\n\n".join(parts)