The code-interpreter template is the standard execution target when
your agent produces Python snippets and wants them run in isolation.
It ships the libraries LLMs commonly import — numpy, pandas,
matplotlib, plotly, scipy, scikit-learn, Pillow, SymPy, plus
jupyter and ipython — so a freshly-generated snippet doesn’t stall
on pip install every time.
Think of it as the declaw-native backing for OpenAI’s code interpreter
tool, Anthropic’s code execution tool, and similar agent primitives:
feed it a string of Python, get back stdout / stderr / exit code.
What you’ll learn
- Picking
template="code-interpreter" so the common scientific imports work cold
- Running several unrelated code snippets in the same sandbox, safely
- Letting the agent generate code and only having the SDK execute it
Prerequisites
export DECLAW_API_KEY="your-api-key"
export DECLAW_DOMAIN="your-declaw-instance.example.com:8080"
Code
In the example below we skip calling a real LLM and just iterate over
three hand-written snippets — each one stands in for whatever your
agent decides to execute next.
import textwrap
from declaw import Sandbox
# Three snippets the "agent" wants to run. In a real pipeline these
# come from the model's tool-use response; we hard-code them here so
# the example has no LLM dependency.
SNIPPETS = [
# 1. Numeric: SymPy solves a small system.
textwrap.dedent("""
from sympy import symbols, solve
x, y = symbols('x y')
eqs = [x + 2*y - 5, 3*x - y - 4]
print("solution:", solve(eqs, [x, y]))
"""),
# 2. Data shaping: pandas rollup from an in-memory CSV string.
textwrap.dedent("""
import io, pandas as pd
csv = "region,sales\\nNA,120\\nEU,80\\nAPAC,150\\nNA,60"
df = pd.read_csv(io.StringIO(csv))
print(df.groupby('region')['sales'].sum().to_dict())
"""),
# 3. Rendering: matplotlib — renders to a file, no display needed.
textwrap.dedent("""
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
plt.figure()
plt.plot([0, 1, 2, 3], [1, 4, 2, 8], marker='o')
plt.title("agent-generated chart")
plt.savefig("/tmp/chart.png", dpi=120)
print("wrote /tmp/chart.png")
"""),
]
def run_snippet(sbx: Sandbox, idx: int, code: str) -> None:
# Every snippet is written to its own file so tracebacks point
# at a real path, then executed with python3.
path = f"/tmp/snip_{idx}.py"
sbx.files.write(path, code)
r = sbx.commands.run(f"python3 {path}", timeout=30)
print(f"--- snippet {idx} (exit={r.exit_code}) ---")
if r.stdout:
print(r.stdout.rstrip())
if r.stderr and r.exit_code != 0:
print("stderr:", r.stderr.rstrip())
def main() -> None:
sbx = Sandbox.create(template="code-interpreter", timeout=180)
try:
for i, code in enumerate(SNIPPETS, start=1):
run_snippet(sbx, i, code)
# Artefacts produced by one snippet survive for the next —
# the sandbox is persistent until you kill it.
info = sbx.files.get_info("/tmp/chart.png")
print(f"\nchart.png exists: {info.size} bytes")
finally:
sbx.kill()
if __name__ == "__main__":
main()
import "dotenv/config";
import { Sandbox } from "@declaw/sdk";
const SNIPPETS = [
`from sympy import symbols, solve
x, y = symbols('x y')
eqs = [x + 2*y - 5, 3*x - y - 4]
print("solution:", solve(eqs, [x, y]))
`,
`import io, pandas as pd
csv = "region,sales\\nNA,120\\nEU,80\\nAPAC,150\\nNA,60"
df = pd.read_csv(io.StringIO(csv))
print(df.groupby('region')['sales'].sum().to_dict())
`,
`import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
plt.figure()
plt.plot([0, 1, 2, 3], [1, 4, 2, 8], marker='o')
plt.title("agent-generated chart")
plt.savefig("/tmp/chart.png", dpi=120)
print("wrote /tmp/chart.png")
`,
];
async function runSnippet(sbx: Sandbox, idx: number, code: string) {
const path = `/tmp/snip_${idx}.py`;
await sbx.files.write(path, code);
const r = await sbx.commands.run(`python3 ${path}`, { timeout: 30 });
console.log(`--- snippet ${idx} (exit=${r.exitCode}) ---`);
if (r.stdout) console.log(r.stdout.trimEnd());
if (r.stderr && r.exitCode !== 0) console.log("stderr:", r.stderr.trimEnd());
}
async function main(): Promise<void> {
const sbx = await Sandbox.create({ template: "code-interpreter", timeout: 180 });
try {
for (let i = 0; i < SNIPPETS.length; i++) {
await runSnippet(sbx, i + 1, SNIPPETS[i]);
}
const info = await sbx.files.getInfo("/tmp/chart.png");
console.log(`\nchart.png exists: ${info.size} bytes`);
} finally {
await sbx.kill();
}
}
main().catch(console.error);
Expected output
--- snippet 1 (exit=0) ---
solution: {x: 13/7, y: 11/7}
--- snippet 2 (exit=0) ---
{'APAC': 150, 'EU': 80, 'NA': 180}
--- snippet 3 (exit=0) ---
wrote /tmp/chart.png
chart.png exists: 31824 bytes
A real agent loop typically does three things per tool call: generate
the snippet with the model, pass it here for execution, then feed the
stdout / exit code back to the model. Keep the same sandbox alive
across turns so files and installed packages persist — kill it only
when the task finishes.