Skip to content

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.