You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
In this guide we'll add a **code interpreter** tool to a Vercel AI SDK chat app. When a user asks a question that needs computation — math, data analysis, statistics — the model writes code and sends it to a fresh `EphemeralBox` to run. The sandbox is isolated, disposable, and auto-expires when the session ends.
6
+
7
+
---
8
+
9
+
## 1. Installation
10
+
11
+
```bash
12
+
npm install @upstash/box @ai-sdk/anthropic @ai-sdk/react ai zod
13
+
```
14
+
15
+
Get a Box API key from the [Upstash Console](https://console.upstash.com/box) and add your environment variables:
16
+
17
+
```bash title=".env.local"
18
+
UPSTASH_BOX_API_KEY=box_xxxxxxxxxxxxxxxxxxxxxxxx
19
+
ANTHROPIC_API_KEY=sk-ant-xxxxxxxxxxxxxxxxxxxx
20
+
```
21
+
22
+
---
23
+
24
+
## 2. Create the API route
25
+
26
+
Each time the model decides to run code, the tool spins up a fresh `EphemeralBox`, executes the snippet, and deletes the box immediately after. Nothing persists between tool calls.
Start your Next.js app and ask anything that needs real computation:
178
+
179
+
> *"What is the square root of 144 plus 25 factorial?"*
180
+
181
+
The model writes a Python snippet, the `executeSandboxCode` tool fires, a fresh `EphemeralBox` boots, the code runs, and the result streams back — all within a single response turn.
182
+
183
+
```
184
+
executeSandboxCode ✓
185
+
186
+
Square root of 144: 12.0
187
+
25 factorial: 15511210043330985984000000
188
+
Sum: 1.5511210043330986e+25
189
+
```
190
+
191
+
Every tool call gets its own isolated box, so a crash in one never affects the others. The `timeout: 10_000` on `exec.code` cuts off the HTTP call after 10 seconds — without it, an infinite loop would hang until the backend times out or the `ttl` deletes the box. Raise the timeout for long-running scripts, but always set one.
In this guide we'll add a **code interpreter** tool to a Vercel AI SDK chat app. When a user asks a question that needs computation — math, data analysis, statistics — the model writes code and sends it to a fresh `EphemeralBox` to run. The sandbox is isolated, disposable, and auto-expires when the session ends.
710
+
711
+
***
712
+
713
+
## 1. Installation
714
+
715
+
```bash
716
+
npm install @upstash/box @ai-sdk/anthropic @ai-sdk/react ai zod
717
+
```
718
+
719
+
Get a Box API key from the [Upstash Console](https://console.upstash.com/box) and add your environment variables:
720
+
721
+
```bash title=".env.local"
722
+
UPSTASH_BOX_API_KEY=box_xxxxxxxxxxxxxxxxxxxxxxxx
723
+
ANTHROPIC_API_KEY=sk-ant-xxxxxxxxxxxxxxxxxxxx
724
+
```
725
+
726
+
***
727
+
728
+
## 2. Create the API route
729
+
730
+
Each time the model decides to run code, the tool spins up a fresh `EphemeralBox`, executes the snippet, and deletes the box immediately after. Nothing persists between tool calls.
731
+
732
+
```typescript title="app/api/chat/route.ts"
733
+
import { streamText, tool, convertToModelMessages, stepCountIs } from "ai";
734
+
import { anthropic } from "@ai-sdk/anthropic";
735
+
import { EphemeralBox } from "@upstash/box";
736
+
import { z } from "zod";
737
+
738
+
export async function POST(req: Request) {
739
+
const { messages } = await req.json();
740
+
741
+
const result = streamText({
742
+
model: anthropic("claude-sonnet-4-6"),
743
+
system:
744
+
"You are a helpful assistant with access to a secure code sandbox. " +
745
+
"When the user asks for computation, data analysis, or math — write and run code " +
746
+
"instead of estimating. Prefer Python for numerical work, JavaScript for JSON or string processing.",
747
+
messages: await convertToModelMessages(messages),
748
+
stopWhen: stepCountIs(10),
749
+
tools: {
750
+
executeSandboxCode: tool({
751
+
description:
752
+
"Run Python or JavaScript code in a secure, isolated sandbox. " +
753
+
"Use this for any math, data processing, or computation.",
754
+
inputSchema: z.object({
755
+
lang: z.enum(["python", "js"]).describe("Language to run"),
756
+
code: z.string().describe("The code to execute"),
757
+
}),
758
+
execute: async ({ lang, code, env }) => {
759
+
const box = await EphemeralBox.create({
760
+
apiKey: process.env.UPSTASH_BOX_API_KEY,
761
+
runtime: lang === "python" ? "python" : "node",
762
+
ttl: 120,
763
+
});
764
+
765
+
try {
766
+
const run = await box.exec.code({ lang, code, timeout: 10_000 });
767
+
return {
768
+
success: run.exitCode === 0,
769
+
output: run.result,
770
+
};
771
+
} finally {
772
+
await box.delete();
773
+
}
774
+
},
775
+
}),
776
+
},
777
+
});
778
+
779
+
return result.toUIMessageStreamResponse();
780
+
}
781
+
```
782
+
783
+
<Note>
784
+
`ttl: 120` means the box auto-deletes after 2 minutes even if the `finally` block is skipped. For longer-running scripts, increase this value.
785
+
</Note>
786
+
787
+
***
788
+
789
+
## 3. Add a simple UI
790
+
791
+
Wire up a simple chat UI with `useChat` from the AI SDK. This UI also will display tool calls so that we can test the functionality.
792
+
793
+
```typescript title="app/page.tsx"
794
+
"use client";
795
+
796
+
import { useState } from "react";
797
+
import { useChat } from "@ai-sdk/react";
798
+
799
+
export default function Page() {
800
+
const { messages, sendMessage, status } = useChat();
Start your Next.js app and ask anything that needs real computation:
882
+
883
+
> *"What is the square root of 144 plus 25 factorial?"*
884
+
885
+
The model writes a Python snippet, the `executeSandboxCode` tool fires, a fresh `EphemeralBox` boots, the code runs, and the result streams back — all within a single response turn.
886
+
887
+
```
888
+
executeSandboxCode ✓
889
+
890
+
Square root of 144: 12.0
891
+
25 factorial: 15511210043330985984000000
892
+
Sum: 1.5511210043330986e+25
893
+
```
894
+
895
+
Every tool call gets its own isolated box, so a crash in one never affects the others. The `timeout: 10_000` on `exec.code` cuts off the HTTP call after 10 seconds — without it, an infinite loop would hang until the backend times out or the `ttl` deletes the box. Raise the timeout for long-running scripts, but always set one.
0 commit comments