Appearance
LangGraph
A LangGraph agent that writes code needs somewhere to run it. Running it in your own process means model output executes with your privileges; an Ovrin sandbox puts it behind a boundary you control, and disposes of it afterwards.
The graph runs wherever it already runs. Only execution moves.
Setup
bash
pip install ovrin langgraph langchain-anthropic
export OVRIN_API_KEY="ovrin_..."
export ANTHROPIC_API_KEY="sk-ant-..."A sandbox as a tool
python
import ovrin
from langchain_core.tools import tool
from langchain_anthropic import ChatAnthropic
from langgraph.prebuilt import create_react_agent
client = ovrin.Client() # reads OVRIN_API_KEY
@tool
def run_python(code: str) -> str:
"""Execute Python in a fresh, isolated sandbox and return its output."""
sandbox = client.sandboxes.create(template="python", timeout=300)
try:
result = sandbox.run(f"python -c {code!r}", timeout=120)
return result.stdout or result.stderr
finally:
sandbox.kill()
agent = create_react_agent(ChatAnthropic(model="claude-sonnet-4-20250514"), [run_python])
for step in agent.stream({"messages": [("user", "What is 2**100? Compute it.")]}):
print(step)Each call gets a clean sandbox and kills it in a finally, so a failure mid-run does not leave compute billing.
Keeping state across steps
A fresh sandbox per call is the safe default. When the agent needs variables to survive between steps, hold one sandbox open and use a stateful context:
python
sandbox = client.sandboxes.create(template="code-interpreter", timeout=1800)
context_id = sandbox.run_code("import pandas as pd")["context_id"]
@tool
def run_python(code: str) -> str:
"""Execute Python; variables persist between calls."""
out = sandbox.run_code(code, context_id=context_id)
return out["stdout"] or out["error"] or ""Remember to sandbox.kill() when the graph finishes.
Related
- Code interpreter — the stateful execution model
- Google ADK — the same pattern in another framework