55 lines
1.5 KiB
Python
55 lines
1.5 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Monty execution helper.
|
|
|
|
This is intentionally minimal:
|
|
- No external functions
|
|
- No filesystem access
|
|
- No network
|
|
- No environment access
|
|
- Synchronous run only
|
|
|
|
If pydantic-monty is not installed, this module raises a clear error.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from dataclasses import dataclass
|
|
from typing import Any, Dict, Optional, Tuple
|
|
|
|
|
|
@dataclass
|
|
class MontyExecResult:
|
|
output: Any
|
|
stdout: str
|
|
stderr: str
|
|
|
|
|
|
def run_monty_pure(code: str, inputs: Optional[Dict[str, Any]] = None, type_check: bool = True) -> MontyExecResult:
|
|
try:
|
|
import pydantic_monty # provided by `pydantic-monty`
|
|
except Exception as e:
|
|
raise RuntimeError(
|
|
"pydantic_monty not available. Install with: pip install pydantic-monty (or uv add pydantic-monty)."
|
|
) from e
|
|
|
|
if inputs is None:
|
|
inputs = {}
|
|
|
|
# Monty captures stdout/stderr internally, but to be robust we also capture at the runner layer.
|
|
# Here we only return the Monty output; runner will wrap stdout/stderr capture.
|
|
m = pydantic_monty.Monty(
|
|
code,
|
|
inputs=list(inputs.keys()),
|
|
external_functions=[],
|
|
script_name="tool_exec.py",
|
|
type_check=type_check,
|
|
)
|
|
|
|
# Per upstream examples, Monty can run synchronously with .run(inputs={...}). :contentReference[oaicite:2]{index=2}
|
|
out = m.run(inputs=inputs)
|
|
|
|
# We return empty strings here; the runner will capture actual stdout/stderr around this call.
|
|
return MontyExecResult(output=out, stdout="", stderr="")
|
|
|