Skip to content
sistemo.io beta

Connect an LLM

Give a model a sandbox as a code-execution tool: it writes Python, your app runs it in an isolated microVM, you send stdout/stderr back. That is a coding agent's inner loop.

you ──prompt──▶ LLM ──tool: run_python(code)──▶ your app
                                              └── sb.run("python3 /tmp/run.py") in a microVM
                                              └── tool_result (stdout/stderr)
                                              └── LLM ──final answer──▶ you

This page is a complete script, not a sketch. Copy it, set two env vars, run it.

You need:

python3 -m venv .venv && source .venv/bin/activate
pip install sistemo anthropic          # or: pip install sistemo openai
export SISTEMO_API_KEY=sk_live_...     # dashboard → API Keys → full scope
export ANTHROPIC_API_KEY=...           # or OPENAI_API_KEY for the OpenAI section

The model will emit multiline Python. Do not stuff that into python3 -c. Write a file in the guest, then python3 /tmp/run.py.

import shlex
from sistemo import Sandbox


def run_python(sb: Sandbox, code: str) -> str:
    """Execute LLM-generated Python in the guest. Multiline and quotes survive."""
    w = sb.run(f"printf %s {shlex.quote(code)} > /tmp/run.py")
    if not w.ok:
        return w.stderr or f"write failed ({w.exit_code})"
    r = sb.run("python3 /tmp/run.py", timeout=30)
    if r.ok:
        return r.stdout
    return r.stderr or f"exit {r.exit_code}"

With Claude (Anthropic)

Save as connect_claude.py. Needs ANTHROPIC_API_KEY and SISTEMO_API_KEY.

import shlex
import anthropic
from sistemo import Sandbox


def run_python(sb: Sandbox, code: str) -> str:
    w = sb.run(f"printf %s {shlex.quote(code)} > /tmp/run.py")
    if not w.ok:
        return w.stderr or f"write failed ({w.exit_code})"
    r = sb.run("python3 /tmp/run.py", timeout=30)
    if r.ok:
        return r.stdout
    return r.stderr or f"exit {r.exit_code}"


client = anthropic.Anthropic()  # ANTHROPIC_API_KEY
tools = [{
    "name": "run_python",
    "description": "Run Python in an isolated microVM. Return stdout, or stderr on failure.",
    "input_schema": {
        "type": "object",
        "properties": {"code": {"type": "string"}},
        "required": ["code"],
    },
}]

messages = [{"role": "user", "content": "Compute the 30th Fibonacci number. Use the tool."}]

with Sandbox(stack="python") as sb:  # one VM for the whole session
    for _ in range(8):
        msg = client.messages.create(
            model="claude-sonnet-5-5",
            max_tokens=16000,
            tools=tools,
            messages=messages,
        )
        if msg.stop_reason in ("refusal", "max_tokens"):
            print(f"stopped early: {msg.stop_reason}")
            break
        if msg.stop_reason != "tool_use":
            text = "".join(getattr(b, "text", "") or "" for b in msg.content)
            print(text)
            break

        results = []
        for block in msg.content:
            if block.type == "tool_use" and block.name == "run_python":
                out = run_python(sb, block.input["code"])
                results.append({
                    "type": "tool_result",
                    "tool_use_id": block.id,
                    "content": out,
                })
        messages.append({"role": "assistant", "content": msg.content})
        messages.append({"role": "user", "content": results})
    else:
        print("stopped after 8 turns")
python3 connect_claude.py

You should see the model call run_python, the microVM print 832040, then a short final answer. Each Sandbox() bills CPU/RAM while it runs and the disk while it exists; with destroys the VM when the script ends.

With OpenAI

Save as connect_openai.py. Needs OPENAI_API_KEY and SISTEMO_API_KEY.

import json
import shlex
from openai import OpenAI
from sistemo import Sandbox


def run_python(sb: Sandbox, code: str) -> str:
    w = sb.run(f"printf %s {shlex.quote(code)} > /tmp/run.py")
    if not w.ok:
        return w.stderr or f"write failed ({w.exit_code})"
    r = sb.run("python3 /tmp/run.py", timeout=30)
    if r.ok:
        return r.stdout
    return r.stderr or f"exit {r.exit_code}"


client = OpenAI()
tools = [{
    "type": "function",
    "function": {
        "name": "run_python",
        "description": "Run Python in an isolated microVM. Return stdout, or stderr on failure.",
        "parameters": {
            "type": "object",
            "properties": {"code": {"type": "string"}},
            "required": ["code"],
        },
    },
}]
messages = [{"role": "user", "content": "What is 17 factorial? Use the tool."}]

with Sandbox(stack="python") as sb:
    for _ in range(8):
        resp = client.chat.completions.create(
            model="gpt-4o",
            tools=tools,
            messages=messages,
        )
        choice = resp.choices[0].message
        if not choice.tool_calls:
            print(choice.content)
            break
        messages.append(choice)
        for call in choice.tool_calls:
            if call.function.name != "run_python":
                continue
            code = json.loads(call.function.arguments)["code"]
            out = run_python(sb, code)
            messages.append({
                "role": "tool",
                "tool_call_id": call.id,
                "content": out,
            })
    else:
        print("stopped after 8 turns")
python3 connect_openai.py

What this is not

  • Not a Jupyter kernel. There is no run_code() — only shell run(), so we write /tmp/run.py.
  • Not a hosted agent. Your process is the loop: LLM → tool → microVM → tool_result → LLM.
  • The LLM keys are yours. Sistemo never sees ANTHROPIC_API_KEY / OPENAI_API_KEY.

Tips

  • One sandbox per session so installs and files survive across tool calls.
  • Cap timeout — models write infinite loops. Default is 30 s; raise it only when the work is actually long.
  • Return stderr — the model corrects itself if it sees the traceback.
  • with Sandbox() / try/finally + close() so a crash does not leave a billed VM.

Next: Install packages if the model needs pip first.