A LangChain agent that writes Python and runs it in a disposable Tenki sandbox — the "code interpreter" pattern, with Tenki as the execution backend. One sandbox per agent session; a run_python tool the agent calls to execute code in an isolated microVM.
import { tool } from "@langchain/core/tools";
import { z } from "zod";
import { stdoutText, stderrText } from "@tenkicloud/sandbox";
export function makeCodeTool(sandbox) {
return tool(
async ({ code }) => {
const res = await sandbox.exec("python3", { args: ["-c", code] });
return `${stdoutText(res)}${stderrText(res)}`.trim() || `(exit ${res.exitCode})`;
},
{
name: "run_python",
description: "Execute Python in a sandbox and return its output.",
schema: z.object({ code: z.string() }),
},
);
}Create one sandbox, wire the tool into a LangGraph ReAct agent, ask something that needs real computation:
const agent = createReactAgent({
llm: new ChatOpenAI({ model: "gpt-4o-mini" }),
tools: [makeCodeTool(sandbox)],
});
const result = await agent.invoke({
messages: [{ role: "user", content: "What is the 20th Fibonacci number? Compute it with Python." }],
});npm install
export TENKI_AUTH_TOKEN=... # from `tenki login`
export TENKI_WORKSPACE_ID=...
export OPENAI_API_KEY=... # or swap ChatOpenAI for your provider
node agent.mjsnode verify.mjs # calls the tool directly → runs Python in Tenki → asserts the outputThis is what CI runs: it proves the Tenki integration end-to-end without a model key.
- One sandbox per session, reused across tool calls — cheaper than a sandbox per call; disposed when the agent finishes.
exec("python3", { args: ["-c", code] })passes the code as a single argument (no shell), so multi-line agent-generated code goes through without escaping issues.- Stdlib only by default — sandboxes have no outbound network unless you pass
allowOutbound: true(needed forpip install). - Built on LangChain.js v1 +
@tenkicloud/sandbox. The same tool-backed-by-a-sandbox pattern works in LangChain Python.