Custom Tools
Add AI SDK tools to Bunny Agent runs
Bunny Agent uses the standard AI SDK tool API. Keep importing streamText and
tool from ai; Bunny only provides the model provider and optional helper
tools.
Quick Start
import { bunnyHttpTool, createBunnyAgent } from "@bunny-agent/sdk";
import { streamText } from "ai";
import { z } from "zod";
const bunny = createBunnyAgent({
sandbox,
env: {
OPENAI_API_KEY: process.env.OPENAI_API_KEY!,
},
});
const result = streamText({
model: bunny("gpt-5.2"),
prompt: "Get the weather in Paris.",
tools: {
weather: bunnyHttpTool({
description: "Get current weather",
inputSchema: z.object({ city: z.string() }),
endpoint: {
url: "https://your-app.com/api/tools/weather",
headers: {
Authorization: `Bearer ${process.env.TOOL_API_TOKEN}`,
},
},
}),
},
});This keeps the call shape as standard AI SDK streamText({ tools }), while the
Bunny helper adds provider-visible runtime metadata for the sandbox runner.
Runner-Executed Tools
The pi runner can also execute provider-side tools inside the sandbox. These tools are rendered as provider-executed dynamic tool calls in AI SDK UI streams.
Bunny supports two runner-executed tool styles:
| Use case | API |
|---|---|
| The tool already exists as an HTTP API | bunnyHttpTool(...) |
| The tool implementation exists inside the sandbox filesystem | bunnySandboxTool(...) |
Use these when you want the sandbox runner, not AI SDK, to execute the tool.
Standard AI SDK tool({ execute }) callbacks are client-executed tools. AI SDK
does not pass their JavaScript execute functions through the provider
boundary, so Bunny cannot turn arbitrary host closures into pi-runner tools from
inside createBunnyAgent().
Direct HTTP Tools
If the tool already exists as an HTTP API and you want the sandbox runner to
call it directly, use bunnyHttpTool.
import { bunnyHttpTool, createBunnyAgent } from "@bunny-agent/sdk";
import { streamText } from "ai";
import { z } from "zod";
const bunny = createBunnyAgent({ sandbox });
const result = streamText({
model: bunny("gpt-5.2"),
prompt: "Get the weather in Paris.",
tools: {
weather: bunnyHttpTool({
description: "Get current weather",
inputSchema: z.object({ city: z.string() }),
endpoint: {
url: "https://your-app.com/api/tools/weather",
headers: {
Authorization: `Bearer ${process.env.TOOL_API_TOKEN}`,
},
},
}),
},
});The endpoint and headers are sent to the sandbox runner, so only use this when that credential is safe for the sandbox boundary.
Sandbox Module Tools
If the tool implementation already exists inside the sandbox filesystem, use
bunnySandboxTool.
import { bunnySandboxTool, createBunnyAgent } from "@bunny-agent/sdk";
import { streamText } from "ai";
import { z } from "zod";
const bunny = createBunnyAgent({ sandbox });
const result = streamText({
model: bunny("gpt-5.2"),
prompt: "Summarize this repository.",
tools: {
repoStats: bunnySandboxTool({
description: "Summarize repository stats",
inputSchema: z.object({ path: z.string() }),
module: "/workspace/tools/repo-stats.mjs",
exportName: "execute",
}),
},
});The runner imports the module inside the sandbox and calls the selected export.