Skip to main content

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-bash

Requires 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 to 30000.
  • timeout? (number): Timeout per command execution, in milliseconds (integer from 1 to 2147483647). 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-fetch

Requires 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 as docs.example.com to allow only that subdomain. Also applies to redirects. Cannot be combined with blockedDomains.
  • 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 to false.
  • maxLength? (number): Maximum characters returned per call. Longer content can be read with offset. Defaults to 50000.
  • maxBytes? (number): Maximum response size in bytes. Defaults to 10 MiB.
  • timeout? (number): Timeout in milliseconds for fetching each URL, including redirects. Defaults to 30000.
  • 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 as contentSelector.

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.