This page has the details of the Anthropic adapter. To get a first chat working, start at Anthropic.
Got a Bearer token, not an API key? Pass it as the credential and set auth: "bearer". The adapter sends Authorization: Bearer <token> and no x-api-key header:
import { chat } from "@tanstack/ai";
import { createAnthropicChat } from "@tanstack/ai-anthropic";
const adapter = createAnthropicChat("claude-sonnet-5-5", process.env.MY_CLAUDE_TOKEN!, {
auth: "bearer",
});
const stream = chat({
adapter,
messages: [{ role: "user", content: "Hello!" }],
threadId: "thread-1",
});auth takes one of three values:
A Claude OAuth token contains sk-ant-oat. For such a token, the adapter picks "oauth", so you can leave auth out. In OAuth mode, every request also gets:
An explicit auth always wins. To send an sk-ant-oat token as a plain Bearer token, without the extras, set auth: "bearer".
Is the token in your environment? Then anthropicText finds it and picks auth for you. See Set the API key for the order of the variables:
import { chat } from "@tanstack/ai";
import { anthropicText } from "@tanstack/ai-anthropic";
// ANTHROPIC_AUTH_TOKEN=my-token in your environment
const stream = chat({
adapter: anthropicText("claude-sonnet-5-5"),
messages: [{ role: "user", content: "Hello!" }],
threadId: "thread-1",
});An auth in the config wins over the kind that the adapter picks. To call Claude models through a GitHub Copilot plan, see GitHub Copilot.
import { createAnthropicChat, type AnthropicTextConfig } from "@tanstack/ai-anthropic";
const config: Omit<AnthropicTextConfig, "apiKey"> = {
baseURL: "https://api.anthropic.com", // Optional, for custom endpoints
};
const adapter = createAnthropicChat("claude-sonnet-5-5", process.env.ANTHROPIC_API_KEY!, config);Need a header on each request, or a log of each model call? This adapter supports wrapFetch. An adapter with your own client (Claude on Vertex, or createAnthropicChatWithClient) ignores it, because the adapter cannot reach the fetch of that client.
Your gateway speaks the Anthropic protocol, but it returns thinking with no signature. By default, the adapter does not send unsigned thinking back, so the next turn loses it. Turn on allowEmptySignature:
import { anthropicText } from "@tanstack/ai-anthropic";
const gateway = anthropicText("claude-sonnet-5-5", {
baseURL: "https://gateway.example.com",
provider: "my-gateway",
allowEmptySignature: true,
});
console.log(gateway.provider); // "my-gateway"Use @tanstack/ai-anthropic/vertex when Claude must run on Vertex AI. That is the path for regional endpoints and Google Cloud credentials.
Install the Vertex SDK next to the Anthropic adapter:
npm i @tanstack/ai-anthropic @anthropic-ai/vertex-sdkpnpm add @tanstack/ai-anthropic @anthropic-ai/vertex-sdkyarn add @tanstack/ai-anthropic @anthropic-ai/vertex-sdkbun add @tanstack/ai-anthropic @anthropic-ai/vertex-sdkimport { chat } from "@tanstack/ai";
import { anthropicVertexText } from "@tanstack/ai-anthropic/vertex";
const stream = chat({
adapter: anthropicVertexText("claude-sonnet-5", {
project: "my-project",
location: "europe-west1",
}),
messages: [{ role: "user", content: "Hello!" }],
threadId: "thread-1",
});Gemini on Vertex is in @tanstack/ai-vertex.
Already have a client that speaks the Anthropic protocol? Use createAnthropicChatWithClient. The adapter only needs beta.messages.create. Message mapping, streaming, tools, media, usage, and structured output stay on the same TanStack path.
npm i @tanstack/ai-anthropic @anthropic-ai/vertex-sdkpnpm add @tanstack/ai-anthropic @anthropic-ai/vertex-sdkyarn add @tanstack/ai-anthropic @anthropic-ai/vertex-sdkbun add @tanstack/ai-anthropic @anthropic-ai/vertex-sdkimport { AnthropicVertex } from "@anthropic-ai/vertex-sdk";
import { createAnthropicChatWithClient } from "@tanstack/ai-anthropic";
const client = new AnthropicVertex({
projectId: "my-project",
region: "europe-west1",
});
const adapter = createAnthropicChatWithClient("claude-sonnet-5", client);The client must implement the Anthropic Beta Messages protocol. Model and feature support of that endpoint is your job.
The Messages API of Anthropic requires max_tokens on every request, so the adapter always sends a value.
A streamed response that stops at max_tokens ends in a RUN_ERROR with code: 'max_tokens'. Anthropic bills the tokens of that call, so this RUN_ERROR carries the usage of the call. A stream can also fail after it starts, for example when the connection drops. That RUN_ERROR carries the usage from Anthropic's first event (message_start). The input counts are complete. The output count can be lower than the real one. The onUsage middleware hook fires only for RUN_FINISHED. To count these tokens too, read usage from the RUN_ERROR chunk, in the stream or in an onChunk middleware.
One exception: structured output (chat({ outputSchema })) on models that use the non-streaming finalization path caps this default at about 21K tokens. The Anthropic SDK rejects a non-streaming request whose max_tokens can go past its 10-minute timeout. Streaming chat does not have this cap. To raise the structured output limit toward the true maximum of a model, stream the response.
chat() caches Claude prompts by default. It adds cache_control markers, at most 4, to:
Pass promptCache: 'long' for the 1-hour cache, or promptCache: 'none' to send no markers. For the key and the cost, see Prompt Caching.
To put the markers in other places, set cache_control in the metadata of a message part, a system prompt, or a tool. One marker of your own turns the automatic markers off for that request:
import { chat } from "@tanstack/ai";
import { anthropicText } from "@tanstack/ai-anthropic";
const stream = chat({
adapter: anthropicText("claude-opus-5-5"),
messages: [
{
role: "user",
content: [
{
type: "text",
content: "What is the capital of France?",
metadata: {
cache_control: {
type: "ephemeral",
},
},
},
],
},
],
threadId: "thread-1",
});On claude-opus-4-8, claude-opus-5, claude-opus-5-5, claude-fable-5, and claude-fable-5-1, a tool or a system prompt that you add between model calls goes into the conversation. The cached start of the request stays the same.
What the adapter sends on these models:
The automatic tool marker stays on the last tool of the first call, so the marked start does not move.
The channels are on by default with the API of Anthropic. A custom baseURL, a custom fetch, ANTHROPIC_BASE_URL, or your own client turns them off. Set midConversationChannels to choose:
import { anthropicText } from "@tanstack/ai-anthropic";
export const fullLists = anthropicText("claude-opus-5-5", {
midConversationChannels: false,
});
export const throughProxy = anthropicText("claude-opus-5-5", {
baseURL: "https://llm-proxy.example.com",
midConversationChannels: true,
});If that endpoint sends the request and the anthropic-beta header on to Anthropic without changes, set true. See Mid-Conversation Changes.
Anthropic has tools of its own, next to the function tools that you define. Import them from @tanstack/ai-anthropic/tools and pass them into chat({ tools: [...] }).
For the concept, a comparison table, and type gating, see Provider Tools.
Claude runs the native web search of Anthropic, with inline citations.
import { chat } from "@tanstack/ai";
import { anthropicText } from "@tanstack/ai-anthropic";
import { webSearchTool } from "@tanstack/ai-anthropic/tools";
const stream = chat({
adapter: anthropicText("claude-opus-5-5"),
messages: [{ role: "user", content: "What's new in AI this week?" }],
threadId: "thread-1",
tools: [
webSearchTool({
name: "web_search",
type: "web_search_20250305",
max_uses: 2,
}),
],
});Supported models: every registered Claude model. See Provider Tools.
Claude gets the content of one URL. If the model must read a specific page, not run a search, use it. It needs no arguments. Pass a config object to change the defaults.
import { chat } from "@tanstack/ai";
import { anthropicText } from "@tanstack/ai-anthropic";
import { webFetchTool } from "@tanstack/ai-anthropic/tools";
const stream = chat({
adapter: anthropicText("claude-sonnet-4-6"),
messages: [{ role: "user", content: "Summarise https://example.com" }],
threadId: "thread-1",
tools: [webFetchTool()],
});Supported models: Claude Sonnet 4.x and later. See Provider Tools.
Gives Claude a sandbox that runs code. Claude can run Python, look at data, and return the results inline. Pick the version string of the API revision that you want.
import { chat } from "@tanstack/ai";
import { anthropicText } from "@tanstack/ai-anthropic";
import { codeExecutionTool } from "@tanstack/ai-anthropic/tools";
const stream = chat({
adapter: anthropicText("claude-sonnet-4-6"),
messages: [{ role: "user", content: "Plot a histogram of [1,2,2,3,3,3]" }],
threadId: "thread-1",
tools: [
codeExecutionTool({ name: "code_execution", type: "code_execution_20250825" }),
],
});Supported models: Claude Sonnet 4.x and later. See Provider Tools.
Pass a skills array as the second argument to load skill bundles that the provider manages into the sandbox. The adapter moves them into the container.skills parameter of the API and adds the required beta headers for you.
import { chat, toServerSentEventsResponse } from "@tanstack/ai";
import { anthropicText } from "@tanstack/ai-anthropic";
import { codeExecutionTool } from "@tanstack/ai-anthropic/tools";
export async function POST(request: Request) {
const { messages, threadId } = await request.json();
const stream = chat({
adapter: anthropicText("claude-sonnet-4-5"),
messages,
threadId,
tools: [
codeExecutionTool(
{ type: "code_execution_20250825", name: "code_execution" },
{
skills: [{ type: "anthropic", skill_id: "pptx", version: "latest" }],
},
),
],
});
return toServerSentEventsResponse(stream);
}For the skill shape, the limits, the scope, and the OpenAI equivalent, see Provider Skills.
Claude can look at a screen and use the mouse and the keyboard. Your app runs each action and sends back a screenshot. createComputerUse from @tanstack/ai-computer-use does this on a Playwright browser or an E2B desktop. Each thread gets its own machine:
import { chat } from "@tanstack/ai";
import { anthropicText } from "@tanstack/ai-anthropic";
import { createComputerUse } from "@tanstack/ai-computer-use";
import { playwrightComputer } from "@tanstack/ai-computer-playwright";
declare const threadId: string;
const computerUse = createComputerUse({
driver: playwrightComputer({ startUrl: "https://tanstack.com" }),
});
const stream = chat({
adapter: anthropicText("claude-opus-5-5"),
messages: [{ role: "user", content: "Find the TanStack AI docs" }],
threadId,
tools: computerUse.tools,
middleware: [computerUse.middleware],
interrupts: [computerUse.interrupt],
});The adapter sends the computer tool to Claude as the newest native computer tool that your model takes.
computerUseTool from @tanstack/ai-anthropic/tools is the native tool with no execute. Use it when your app runs the actions itself. Pick the version that your model takes:
| Version | Models |
|---|---|
| computer_toolset_20260801 | Claude Opus 5.5, Sonnet 5.5, Haiku 5.5, Fable 5.1, Fable 5, Opus 5, Sonnet 5, Opus 4.8 |
| computer_20251124 | Claude Fable 5.1, Fable 5, Opus 5, Sonnet 5, Opus 4.8, Opus 4.7, Opus 4.6, Sonnet 4.6, Opus 4.5 |
| computer_20250124 | Claude Sonnet 4.5, Haiku 4.5, Opus 4.1 |
import { computerUseTool } from "@tanstack/ai-anthropic/tools";
const computer = computerUseTool({ type: "computer_toolset_20260801" });The earlier versions also take a name and the screen size:
import { computerUseTool } from "@tanstack/ai-anthropic/tools";
const computer = computerUseTool({
type: "computer_20251124",
name: "computer",
display_width_px: 1280,
display_height_px: 800,
});Add an execute that runs the action and returns a result:
Claude gives coordinates in the pixels of your screenshots.
A version that your model does not take is a type error. See Provider Tools.
Gives Claude a bash shell session that stays open. Claude can run commands, install packages, or change files on the host. Pick the type string of your API revision.
import { chat } from "@tanstack/ai";
import { anthropicText } from "@tanstack/ai-anthropic";
import { bashTool } from "@tanstack/ai-anthropic/tools";
const stream = chat({
adapter: anthropicText("claude-sonnet-4-6"),
messages: [{ role: "user", content: "List all TypeScript files in src/" }],
threadId: "thread-1",
tools: [bashTool({ name: "bash", type: "bash_20250124" })],
});Supported models: Claude Sonnet 3.5 and later. See Provider Tools.
Gives Claude a text editor to view and change files, with the str_replace, create, view, and undo_edit commands. Pick the type string of the API revision that you use.
import { chat } from "@tanstack/ai";
import { anthropicText } from "@tanstack/ai-anthropic";
import { textEditorTool } from "@tanstack/ai-anthropic/tools";
const stream = chat({
adapter: anthropicText("claude-sonnet-4-6"),
messages: [{ role: "user", content: "Fix the bug in src/index.ts" }],
threadId: "thread-1",
tools: [
textEditorTool({ type: "text_editor_20250124", name: "str_replace_editor" }),
],
});Supported models: Claude Sonnet 3.5 and later. See Provider Tools.
Claude stores and reads facts across turns with the managed memory service of Anthropic. Call it with no arguments to use the default configuration.
import { chat } from "@tanstack/ai";
import { anthropicText } from "@tanstack/ai-anthropic";
import { memoryTool } from "@tanstack/ai-anthropic/tools";
const stream = chat({
adapter: anthropicText("claude-sonnet-4-6"),
messages: [{ role: "user", content: "Remember that I prefer metric units" }],
threadId: "thread-1",
tools: [memoryTool()],
});Supported models: Claude Sonnet 4.x and later. See Provider Tools.
Makes a tool with an inline schema, without toolDefinition(). If you need full control of the schema shape, or want to add cache_control, use it. customTool returns a plain Tool, so every chat model accepts it.
import { chat } from "@tanstack/ai";
import { anthropicText } from "@tanstack/ai-anthropic";
import { customTool } from "@tanstack/ai-anthropic/tools";
import { z } from "zod";
const stream = chat({
adapter: anthropicText("claude-sonnet-4-6"),
messages: [{ role: "user", content: "Look up user 42" }],
threadId: "thread-1",
tools: [
customTool(
"lookup_user",
"Look up a user by ID and return their profile",
z.object({ userId: z.number() }),
),
],
});Supported models: all current Claude models. See Provider Tools.
Each factory pair has the same shape. The short factory (anthropicText, anthropicSummarize) reads the credential from the environment. The create* factory takes an explicit credential and never reads one from the environment. Both take model as the first argument.
Creates an Anthropic chat adapter.
adapter.inputModalities lists the input kinds of the selected model. It is undefined for a model that this package does not know. See Check what a model accepts.
Creates an Anthropic chat adapter on Vertex. Import it from @tanstack/ai-anthropic/vertex.
Creates an Anthropic chat adapter with a client that you give.
Creates an Anthropic summarization adapter.
Creates a Files API adapter. See Files API.