Tools
The AI SDK provides first-party tools for agents and applications. Each tool
includes its input schema, model-facing description, and
execution logic, ready to use with generateText, streamText, or ToolLoopAgent.
These tools work with any model that supports function calling.
Install tools from their individual @ai-sdk/tool-* packages.
For defining your own tools and configuring tool execution, see Tools and Tool Calling.
Bash Tool
experimental_createBashTool lets agents run Bash commands to search, analyze, and transform files.
Supply an Experimental_SandboxSession to choose where commands run. Use
@ai-sdk/sandbox-just-bash for an in-memory environment,
@ai-sdk/sandbox-vercel for Vercel Sandbox, or your own implementation.
The tool has no direct dependency on either runtime.
Installation
Install the tool and the sandbox adapter you want to use. The following examples use just-bash:
pnpmnpmyarnbun
pnpm add ai @ai-sdk/tool-bash @ai-sdk/sandbox-just-bashnpm install ai @ai-sdk/tool-bash @ai-sdk/sandbox-just-bashyarn add ai @ai-sdk/tool-bash @ai-sdk/sandbox-just-bashbun add ai @ai-sdk/tool-bash @ai-sdk/sandbox-just-bashRequires Node.js 22.13 or newer.
Usage
import { createJustBashNetworkSandboxSession } from '@ai-sdk/sandbox-just-bash';
import { experimental_createBashTool as createBashTool } from '@ai-sdk/tool-bash';
import { generateText, isStepCount } from 'ai';
const session = await createJustBashNetworkSandboxSession();
try {
const sandbox = session.restricted();
await sandbox.writeTextFile({
path: 'notes.txt',
content: 'Apples: 10\nPears: 20\n',
});
const bash = await createBashTool({ sandbox });
const result = await generateText({
model, // Your configured model with function calling support.
tools: { bash },
stopWhen: isStepCount(5),
prompt: 'Read notes.txt and write a summary to summary.txt.',
});
console.log(result.text);
console.log(await sandbox.readTextFile({ path: 'summary.txt' }));
} finally {
await session.destroy();
}Vercel Sandbox
Install @ai-sdk/sandbox-vercel and @vercel/sandbox to use an existing native
Vercel Sandbox. Wrap it with the adapter before passing it to the tool:
import { createVercelSandboxSessionFromNativeSandbox } from '@ai-sdk/sandbox-vercel';
import { experimental_createBashTool as createBashTool } from '@ai-sdk/tool-bash';
import { Sandbox } from '@vercel/sandbox';
const nativeSandbox = await Sandbox.create();
try {
const sandbox = createVercelSandboxSessionFromNativeSandbox(nativeSandbox);
await sandbox.writeTextFile({
path: 'notes.txt',
content: 'Hello from Vercel Sandbox',
});
const bash = await createBashTool({ sandbox });
// Use bash with generateText, streamText, or ToolLoopAgent here.
} finally {
await nativeSandbox.stop();
}You can also create a managed session with
createVercelNetworkSandboxSession() from @ai-sdk/sandbox-vercel and pass
session.restricted(). For an existing native just-bash Sandbox, use
createJustBashSandboxSessionFromNativeSandbox() from @ai-sdk/sandbox-just-bash.
Raw runtime instances need their respective adapters; a custom
Experimental_SandboxSession can be passed directly.
Options
experimental_createBashTool() requires an options object:
sandbox(Experimental_SandboxSession): Session for command execution and file operations.workingDirectory?(string): Absolute starting directory for each command, created if needed. When omitted, uses the sandbox's default directory.maxOutputLength?(number): Positive integer limiting characters retained from each output stream before a truncation notice. Defaults to30000.timeout?(number): Timeout per command execution, in milliseconds (integer from1to2147483647). No tool-level timeout by default.
The model calls the tool with { command: string } and receives
{ stdout, stderr, exitCode }. Nonzero exit codes are returned so the model can
inspect failures and recover. AI SDK cancellation is forwarded to the session.
Output truncation happens after execution and does not limit execution memory or
duration.
Command timeout
Set timeout to cancel commands that run longer than the configured duration:
const bash = await createBashTool({
sandbox,
timeout: 10_000,
});Each command gets a fresh timeout starting when its execution begins. This does
not include tool initialization or time waiting for model output or approval.
The timeout is combined with the caller's abort signal; either can cancel the
command. The sandbox must honor cancellation. Its result or error is passed
through; for example, just-bash returns exit code 124 when a running command is
cancelled. SDK and sandbox timeouts still apply when this option is omitted.
Files and lifecycle
Commands use the sandbox's default working directory unless workingDirectory
is provided. Without an override, creating the tool runs no setup commands.
Seed files through sandbox.writeTextFile({ path, content }) before running the
tool. With an explicit working directory, use absolute paths to write files there.
The sandbox controls which files commands can access. Available programs, network access, shell state, and persistence depend on the supplied sandbox. Its description is included in the tool's instructions.
Tools using the same session share files. Creating a tool does not reset existing files or create a new sandbox. Use separate sessions for independent workflows. The caller creates, reconnects, and destroys the sandbox.
experimental_createBashTool() returns the tool directly, ready to use as tools: { bash }.
Use the supplied sandbox's readTextFile({ path }) to read generated text files;
it returns null if the file is missing. Relative read paths depend on the
sandbox adapter; just-bash resolves them against its default directory. With an
explicit working directory, use absolute paths to read files from that directory.
The same session provides other file operations.
Web Fetch Tool
experimental_createWebFetchTool lets agents read web pages and documents by URL.
Installation
pnpmnpmyarnbun
pnpm add ai @ai-sdk/tool-web-fetchnpm install ai @ai-sdk/tool-web-fetchyarn add ai @ai-sdk/tool-web-fetchbun add ai @ai-sdk/tool-web-fetchRequires Node.js 22.13 or newer.
Usage
import { experimental_createWebFetchTool as createWebFetchTool } from '@ai-sdk/tool-web-fetch';
import { generateText, isStepCount } from 'ai';
const result = await generateText({
model, // Your configured model with function calling support.
tools: { webFetch: createWebFetchTool() },
stopWhen: isStepCount(5),
prompt: 'Summarize https://ai-sdk.dev/docs/introduction.',
});Options
experimental_createWebFetchTool() accepts an optional options object:
allowedDomains?(string[]): Only fetch from these domains and their subdomains, e.g.['example.com']. List a subdomain such asdocs.example.comto allow only that subdomain. Also applies to redirects. Cannot be combined withblockedDomains.blockedDomains?(string[]): Never fetch from these domains or their subdomains. Also applies to redirects.requireUrlInUserMessage?(boolean): Only fetch URLs that appear in user messages. URLs in instructions, system messages, assistant messages, and tool results are not included. Defaults tofalse.maxLength?(number): Maximum characters returned per call. Longer content can be read withoffset. Defaults to50000.maxBytes?(number): Maximum response size in bytes. Defaults to 10 MiB.timeout?(number): Timeout in milliseconds for fetching each URL, including redirects. Defaults to30000.fetch?(FetchFunction): Custom fetch implementation, for example to route requests through a proxy. It must validate resolved addresses itself.defuddleOptions?(DefuddleOptions): Options for the defuddle HTML content extractor, such ascontentSelector.
The model calls the tool with { url: string, offset?: number } and receives
one of the following results:
{ type: 'document', url, finalUrl, contentType, title?, content, offset, totalLength, nextOffset? }for HTML and text.{ type: 'error', url, errorCode, message, statusCode? }when fetching fails.
Errors are returned so the model can recover, for example by trying another URL. The model receives documents as text with the URL, title, and content type, followed by the content. AI SDK cancellation aborts the request.
experimental_createWebFetchTool() returns the tool directly, ready to use as tools: { webFetch }.
Content handling
Requests prefer markdown using the Accept: text/markdown header, which many
documentation sites support. Otherwise, HTML pages are converted to markdown
with defuddle, which removes navigation,
footers, and other boilerplate. Text formats such as plain text, JSON, XML, and
CSV are returned as is. PDFs, images, audio, video, and other binary formats
are not supported.
JavaScript is not executed. Pages that render their content in the browser may return little or no content, in which case the model is told that the page may require JavaScript.
The extractor sometimes selects the wrong part of a page. If you fetch pages
with a known structure, set defuddleOptions.contentSelector to choose the main
content element:
const webFetch = createWebFetchTool({
defuddleOptions: { contentSelector: 'article' },
});Content longer than maxLength is truncated. The model is told to call the tool
again with offset to continue reading. Converted documents are cached for a
few minutes per tool instance, so reading at an offset does not fetch the page
again.
Security
The tool makes GET requests without cookies or credentials, and rejects URLs
that contain credentials. Each request and redirect is validated against
private and reserved addresses such as localhost and cloud metadata
endpoints. On Node.js, resolved DNS addresses are validated at connect time to
prevent DNS rebinding. On other runtimes, only the URL is validated, so restrict
network egress at the platform level. A custom fetch must provide equivalent
validation. See Secure URL Fetching.
Fetched content is untrusted and can contain prompt injections. When an agent
has access to private data, a model could also be instructed to send that data
to another site, for example in a URL query string. Restrict fetching with
allowedDomains, enable requireUrlInUserMessage so only URLs from user
messages can be fetched, or require tool approval.
requireUrlInUserMessage ignores URLs in tool results because the model can
place arbitrary text there, for example through tool inputs that are reflected
in outputs. As a result, the model cannot follow links from search results or
fetched pages in this mode.