@ai-sdk/anthropic
Version:
The **[Anthropic provider](https://ai-sdk.dev/providers/ai-sdk-providers/anthropic)** for the [AI SDK](https://ai-sdk.dev/docs) contains language model support for the [Anthropic Messages API](https://docs.anthropic.com/claude/reference/messages_post).
405 lines (384 loc) • 13.6 kB
text/typescript
import {
LanguageModelV3CallOptions,
SharedV3Warning,
UnsupportedFunctionalityError,
} from '@ai-sdk/provider';
import { AnthropicTool, AnthropicToolChoice } from './anthropic-messages-api';
import { CacheControlValidator } from './get-cache-control';
import { textEditor_20250728ArgsSchema } from './tool/text-editor_20250728';
import { webSearch_20260209ArgsSchema } from './tool/web-search_20260209';
import { webSearch_20250305ArgsSchema } from './tool/web-search_20250305';
import { webFetch_20260209ArgsSchema } from './tool/web-fetch-20260209';
import { webFetch_20250910ArgsSchema } from './tool/web-fetch-20250910';
import { validateTypes } from '@ai-sdk/provider-utils';
export interface AnthropicToolOptions {
deferLoading?: boolean;
allowedCallers?: Array<
'direct' | 'code_execution_20250825' | 'code_execution_20260120'
>;
eagerInputStreaming?: boolean;
}
export async function prepareTools({
tools,
toolChoice,
disableParallelToolUse,
cacheControlValidator,
supportsStructuredOutput,
}: {
tools: LanguageModelV3CallOptions['tools'];
toolChoice: LanguageModelV3CallOptions['toolChoice'] | undefined;
disableParallelToolUse?: boolean;
cacheControlValidator?: CacheControlValidator;
/**
* Whether the model supports structured output.
*/
supportsStructuredOutput: boolean;
}): Promise<{
tools: Array<AnthropicTool> | undefined;
toolChoice: AnthropicToolChoice | undefined;
toolWarnings: SharedV3Warning[];
betas: Set<string>;
}> {
// when the tools array is empty, change it to undefined to prevent errors:
tools = tools?.length ? tools : undefined;
const toolWarnings: SharedV3Warning[] = [];
const betas = new Set<string>();
const validator = cacheControlValidator || new CacheControlValidator();
if (tools == null) {
return { tools: undefined, toolChoice: undefined, toolWarnings, betas };
}
const anthropicTools: AnthropicTool[] = [];
for (const tool of tools) {
switch (tool.type) {
case 'function': {
const cacheControl = validator.getCacheControl(tool.providerOptions, {
type: 'tool definition',
canCache: true,
});
// Read Anthropic-specific provider options
const anthropicOptions = tool.providerOptions?.anthropic as
| AnthropicToolOptions
| undefined;
// eager_input_streaming is only supported on custom (function) tools
const eagerInputStreaming = anthropicOptions?.eagerInputStreaming;
const deferLoading = anthropicOptions?.deferLoading;
const allowedCallers = anthropicOptions?.allowedCallers;
anthropicTools.push({
name: tool.name,
description: tool.description,
input_schema: tool.inputSchema,
cache_control: cacheControl,
...(eagerInputStreaming ? { eager_input_streaming: true } : {}),
...(supportsStructuredOutput === true && tool.strict != null
? { strict: tool.strict }
: {}),
...(deferLoading != null ? { defer_loading: deferLoading } : {}),
...(allowedCallers != null
? { allowed_callers: allowedCallers }
: {}),
...(tool.inputExamples != null
? {
input_examples: tool.inputExamples.map(
example => example.input,
),
}
: {}),
});
if (supportsStructuredOutput === true) {
betas.add('structured-outputs-2025-11-13');
}
if (tool.inputExamples != null || allowedCallers != null) {
betas.add('advanced-tool-use-2025-11-20');
}
break;
}
case 'provider': {
// Note: Provider-defined tools don't currently support providerOptions in the SDK,
// so cache_control cannot be set on them. The Anthropic API supports caching all tools,
// but the SDK would need to be updated to expose providerOptions on provider-defined tools.
switch (tool.id) {
case 'anthropic.code_execution_20250522': {
betas.add('code-execution-2025-05-22');
anthropicTools.push({
type: 'code_execution_20250522',
name: 'code_execution',
cache_control: undefined,
});
break;
}
case 'anthropic.code_execution_20250825': {
betas.add('code-execution-2025-08-25');
anthropicTools.push({
type: 'code_execution_20250825',
name: 'code_execution',
});
break;
}
case 'anthropic.code_execution_20260120': {
anthropicTools.push({
type: 'code_execution_20260120',
name: 'code_execution',
});
break;
}
case 'anthropic.computer_20250124': {
betas.add('computer-use-2025-01-24');
anthropicTools.push({
name: 'computer',
type: 'computer_20250124',
display_width_px: tool.args.displayWidthPx as number,
display_height_px: tool.args.displayHeightPx as number,
display_number: tool.args.displayNumber as number,
cache_control: undefined,
});
break;
}
case 'anthropic.computer_20251124': {
betas.add('computer-use-2025-11-24');
anthropicTools.push({
name: 'computer',
type: 'computer_20251124',
display_width_px: tool.args.displayWidthPx as number,
display_height_px: tool.args.displayHeightPx as number,
display_number: tool.args.displayNumber as number,
enable_zoom: tool.args.enableZoom as boolean,
cache_control: undefined,
});
break;
}
case 'anthropic.computer_20241022': {
betas.add('computer-use-2024-10-22');
anthropicTools.push({
name: 'computer',
type: 'computer_20241022',
display_width_px: tool.args.displayWidthPx as number,
display_height_px: tool.args.displayHeightPx as number,
display_number: tool.args.displayNumber as number,
cache_control: undefined,
});
break;
}
case 'anthropic.text_editor_20250124': {
betas.add('computer-use-2025-01-24');
anthropicTools.push({
name: 'str_replace_editor',
type: 'text_editor_20250124',
cache_control: undefined,
});
break;
}
case 'anthropic.text_editor_20241022': {
betas.add('computer-use-2024-10-22');
anthropicTools.push({
name: 'str_replace_editor',
type: 'text_editor_20241022',
cache_control: undefined,
});
break;
}
case 'anthropic.text_editor_20250429': {
betas.add('computer-use-2025-01-24');
anthropicTools.push({
name: 'str_replace_based_edit_tool',
type: 'text_editor_20250429',
cache_control: undefined,
});
break;
}
case 'anthropic.text_editor_20250728': {
const args = await validateTypes({
value: tool.args,
schema: textEditor_20250728ArgsSchema,
});
anthropicTools.push({
name: 'str_replace_based_edit_tool',
type: 'text_editor_20250728',
max_characters: args.maxCharacters,
cache_control: undefined,
});
break;
}
case 'anthropic.bash_20250124': {
betas.add('computer-use-2025-01-24');
anthropicTools.push({
name: 'bash',
type: 'bash_20250124',
cache_control: undefined,
});
break;
}
case 'anthropic.bash_20241022': {
betas.add('computer-use-2024-10-22');
anthropicTools.push({
name: 'bash',
type: 'bash_20241022',
cache_control: undefined,
});
break;
}
case 'anthropic.memory_20250818': {
betas.add('context-management-2025-06-27');
anthropicTools.push({
name: 'memory',
type: 'memory_20250818',
});
break;
}
case 'anthropic.web_fetch_20250910': {
betas.add('web-fetch-2025-09-10');
const args = await validateTypes({
value: tool.args,
schema: webFetch_20250910ArgsSchema,
});
anthropicTools.push({
type: 'web_fetch_20250910',
name: 'web_fetch',
max_uses: args.maxUses,
allowed_domains: args.allowedDomains,
blocked_domains: args.blockedDomains,
citations: args.citations,
max_content_tokens: args.maxContentTokens,
cache_control: undefined,
});
break;
}
case 'anthropic.web_fetch_20260209': {
betas.add('code-execution-web-tools-2026-02-09');
const args = await validateTypes({
value: tool.args,
schema: webFetch_20260209ArgsSchema,
});
anthropicTools.push({
type: 'web_fetch_20260209',
name: 'web_fetch',
max_uses: args.maxUses,
allowed_domains: args.allowedDomains,
blocked_domains: args.blockedDomains,
citations: args.citations,
max_content_tokens: args.maxContentTokens,
cache_control: undefined,
});
break;
}
case 'anthropic.web_search_20250305': {
const args = await validateTypes({
value: tool.args,
schema: webSearch_20250305ArgsSchema,
});
anthropicTools.push({
type: 'web_search_20250305',
name: 'web_search',
max_uses: args.maxUses,
allowed_domains: args.allowedDomains,
blocked_domains: args.blockedDomains,
user_location: args.userLocation,
cache_control: undefined,
});
break;
}
case 'anthropic.web_search_20260209': {
betas.add('code-execution-web-tools-2026-02-09');
const args = await validateTypes({
value: tool.args,
schema: webSearch_20260209ArgsSchema,
});
anthropicTools.push({
type: 'web_search_20260209',
name: 'web_search',
max_uses: args.maxUses,
allowed_domains: args.allowedDomains,
blocked_domains: args.blockedDomains,
user_location: args.userLocation,
cache_control: undefined,
});
break;
}
case 'anthropic.tool_search_regex_20251119': {
betas.add('advanced-tool-use-2025-11-20');
anthropicTools.push({
type: 'tool_search_tool_regex_20251119',
name: 'tool_search_tool_regex',
});
break;
}
case 'anthropic.tool_search_bm25_20251119': {
betas.add('advanced-tool-use-2025-11-20');
anthropicTools.push({
type: 'tool_search_tool_bm25_20251119',
name: 'tool_search_tool_bm25',
});
break;
}
default: {
toolWarnings.push({
type: 'unsupported',
feature: `provider-defined tool ${tool.id}`,
});
break;
}
}
break;
}
default: {
toolWarnings.push({
type: 'unsupported',
feature: `tool ${tool}`,
});
break;
}
}
}
if (toolChoice == null) {
return {
tools: anthropicTools,
toolChoice: disableParallelToolUse
? { type: 'auto', disable_parallel_tool_use: disableParallelToolUse }
: undefined,
toolWarnings,
betas,
};
}
const type = toolChoice.type;
switch (type) {
case 'auto':
return {
tools: anthropicTools,
toolChoice: {
type: 'auto',
disable_parallel_tool_use: disableParallelToolUse,
},
toolWarnings,
betas,
};
case 'required':
return {
tools: anthropicTools,
toolChoice: {
type: 'any',
disable_parallel_tool_use: disableParallelToolUse,
},
toolWarnings,
betas,
};
case 'none':
// Anthropic does not support 'none' tool choice, so we remove the tools:
return { tools: undefined, toolChoice: undefined, toolWarnings, betas };
case 'tool':
return {
tools: anthropicTools,
toolChoice: {
type: 'tool',
name: toolChoice.toolName,
disable_parallel_tool_use: disableParallelToolUse,
},
toolWarnings,
betas,
};
default: {
const _exhaustiveCheck: never = type;
throw new UnsupportedFunctionalityError({
functionality: `tool choice type: ${_exhaustiveCheck}`,
});
}
}
}