LangChain and Vercel AI¶
Rayito as an agent tool: the model writes Python, the tool runs it in a stateful sandbox and returns the result. Two adapters of about fifty lines each, ready to copy.
When to use it¶
- Your agent uses LangChain (Python) or the Vercel AI SDK (TypeScript) and you want to give it a safe code interpreter.
- For hosts that speak MCP (Claude Code, Claude Desktop, Cursor, VS Code) you need no code: use the MCP server.
- If you want the whole agent (the model loop and its tools) to run
inside the sandbox, with the model behind the secrets gateway, you do
not need these adapters: use
sbx.agent, with OpenCode or with a deepagents (LangChain) graph.
Example¶
Each adapter creates the sandbox on the first call, reuses it (variables
survive between calls, as in a notebook) and destroys it when the process
exits. It returns to the model a JSON with text, stdout, stderr and
error.
Install: pip install rayito langchain and the provider package for
your model.
"""Un sandbox de Rayito como herramienta de LangChain, en cincuenta líneas.
Instalación: `pip install rayito langchain` (y el proveedor de tu modelo).
Entorno: `RAYITO_TEMPLATE` (nombre o ARN de la imagen), `AWS_REGION` y
`AWS_PROFILE` o las credenciales de boto3. El sandbox se crea en la primera
llamada, vive como mucho 900 s y se destruye al salir del proceso.
"""
from __future__ import annotations
import atexit
import json
from langchain.tools import tool
from rayito import Sandbox
SANDBOX_TIMEOUT_SECONDS = 900
_sandbox: Sandbox | None = None
def sandbox() -> Sandbox:
global _sandbox
if _sandbox is None:
_sandbox = Sandbox.create(timeout=SANDBOX_TIMEOUT_SECONDS)
atexit.register(_sandbox.kill)
return _sandbox
@tool
def run_python(code: str) -> str:
"""Ejecuta código Python en un sandbox aislado con estado entre llamadas
(Linux, internet, matplotlib y pandas instalados). Devuelve un JSON con
`text` (valor de la última expresión), `stdout`, `stderr` y `error`
(nombre y valor si la celda lanzó una excepción)."""
execution = sandbox().run_code(code)
error = execution.error
summary = {
"text": execution.text,
"stdout": "".join(execution.logs.stdout),
"stderr": "".join(execution.logs.stderr),
"error": None if error is None else {"name": error.name, "value": error.value},
}
return json.dumps(summary, ensure_ascii=False)
if __name__ == "__main__":
from langchain.agents import create_agent
agent = create_agent("anthropic:claude-opus-5", tools=[run_python])
print(agent.invoke({"messages": [("user", "Calcula 2**100 en Python.")]}))
Install: pnpm add rayito ai zod and the provider package for your
model.
/**
* Un sandbox de Rayito como herramienta del Vercel AI SDK, en cincuenta líneas.
*
* Instalación: `pnpm add ai zod rayito` (y el proveedor de tu modelo).
* Entorno: `RAYITO_TEMPLATE` (nombre o ARN de la imagen), `AWS_REGION` y
* `AWS_PROFILE` o las credenciales del SDK de AWS. El sandbox se crea en la
* primera llamada, vive como mucho 900 s y se destruye al salir del proceso.
*/
import { tool } from "ai";
import { Sandbox } from "rayito";
import { z } from "zod";
const SANDBOX_TIMEOUT_MS = 900_000;
let pending: Promise<Sandbox> | undefined;
function sandbox(): Promise<Sandbox> {
pending ??= Sandbox.create({ timeoutMs: SANDBOX_TIMEOUT_MS });
return pending;
}
process.on("beforeExit", () => {
void pending?.then((sbx) => sbx.kill());
});
export const runPython = tool({
description:
"Ejecuta código Python en un sandbox aislado con estado entre llamadas " +
"(Linux, internet, matplotlib y pandas instalados). Devuelve text (valor de " +
"la última expresión), stdout, stderr y error (nombre y valor si la celda " +
"lanzó una excepción).",
inputSchema: z.object({ code: z.string().describe("Código Python que ejecutar.") }),
execute: async ({ code }) => {
const execution = await (await sandbox()).runCode(code);
return {
text: execution.text ?? null,
stdout: execution.logs.stdout.join(""),
stderr: execution.logs.stderr.join(""),
error: execution.error ? { name: execution.error.name, value: execution.error.value } : null,
};
},
});
// Uso: `generateText({ model, tools: { runPython }, prompt: "Calcula 2**100 en Python." })`.
Both read the image from RAYITO_TEMPLATE and the credentials from the
standard AWS chain (AWS_PROFILE, AWS_REGION).
Step by step¶
- One sandbox per process. The first call to the tool creates the
sandbox with a
timeoutof 900 s; later calls reuse the same kernel. - Errors as data. If the model's code raises an exception, the tool
returns
errorwith its name and value instead of failing: the model can read it and correct itself. - Cleanup. The sandbox is killed when the process exits (
atexitin Python,beforeExitin Node). If the process dies abruptly, the sandbox lives until itstimeout.
Common adjustments¶
- One sandbox per conversation: keep the sandbox in the session state instead of a global variable, and kill it when the session closes.
- Latency: with a pool, the first call takes < 1 s instead of 5-6 s; each idle slot has a fixed monthly cost (Pricing).
- No internet: create the sandbox on
rayito-base-capswithallow_internet_access=False(Outbound network). - Charts: also return
execution.results[i].png(base64) if your model accepts images.
See also¶
- MCP server
- Agent in the sandbox: the agent loop running inside the sandbox
- Run code
- Security: what the model's code can do inside the sandbox