-
Notifications
You must be signed in to change notification settings - Fork 3.5k
feat(anthropic): advanced tool use #10812
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 3 commits
8761de3
ad4608d
9849126
dc8fb51
f1628f3
8f1f277
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,91 @@ | ||
| import { SharedV3ProviderMetadata, SharedV3Warning } from '@ai-sdk/provider'; | ||
| import { validateTypes } from '@ai-sdk/provider-utils'; | ||
| import { | ||
| AnthropicAdvancedToolUse, | ||
| anthropicInputExamplesSchema, | ||
| anthropicProgrammaticToolCallingSchema, | ||
| AnthropicTool, | ||
| anthropicToolSearchSchema, | ||
| } from './anthropic-messages-api'; | ||
|
|
||
| /** | ||
| * Extracts and validates Anthropic advanced tool use configuration from provider metadata. | ||
| * | ||
| * This function processes provider metadata to extract tool use configuration options including | ||
| * deferred loading, allowed callers, and input examples. It supports both camelCase and snake_case | ||
| * property naming conventions for backwards compatibility. | ||
| * | ||
| * @param providerMetadata - Optional shared provider metadata containing Anthropic-specific configuration | ||
| * @returns A promise that resolves to an object containing validated advanced tool use settings: | ||
| * - `deferLoading`: Validated tool search/defer loading configuration | ||
| * - `allowedCallers`: Validated programmatic tool calling configuration | ||
| * - `inputExamples`: Validated input examples configuration | ||
| * @throws Will throw an error if any of the extracted configurations fail validation | ||
| */ | ||
|
|
||
| export async function getAnthropicAdvancedToolUseFeaturesSupport( | ||
| providerMetadata: SharedV3ProviderMetadata | undefined, | ||
| ): Promise<AnthropicAdvancedToolUse | undefined> { | ||
| const anthropic = providerMetadata?.anthropic; | ||
| const deferLoading = anthropic?.defer_loading ?? anthropic?.deferLoading; | ||
| const inputExamples = anthropic?.input_examples ?? anthropic?.inputExamples; | ||
| const allowed_callers = | ||
| anthropic?.allowed_callers ?? anthropic?.allowedCallers; | ||
|
|
||
| const [parseDeferLoading, parseAllowedCallers, parseInputExamples] = | ||
| await Promise.all([ | ||
| validateTypes({ | ||
| value: deferLoading, | ||
| schema: anthropicToolSearchSchema, | ||
| }), | ||
| validateTypes({ | ||
| value: allowed_callers, | ||
| schema: anthropicProgrammaticToolCallingSchema, | ||
| }), | ||
| validateTypes({ | ||
| value: inputExamples, | ||
| schema: anthropicInputExamplesSchema, | ||
| }), | ||
| ]); | ||
|
|
||
| let result: AnthropicAdvancedToolUse = {}; | ||
| if (parseDeferLoading !== undefined) { | ||
| result.defer_loading = parseDeferLoading; | ||
| } | ||
|
|
||
| if (parseAllowedCallers !== undefined) { | ||
| result.allowed_callers = parseAllowedCallers; | ||
| } | ||
|
|
||
| if (parseInputExamples !== undefined) { | ||
| result.input_examples = parseInputExamples; | ||
| } | ||
|
|
||
| return result; | ||
| } | ||
|
|
||
| export const handleAnthropicAdvancedToolUseFeaturesWarnings = ( | ||
| anthropicTools: AnthropicTool[], | ||
| ) => { | ||
| const toolWarnings: SharedV3Warning[] = []; | ||
|
|
||
| // Check if any tool uses defer_loading | ||
| const anyToolUsesDeferLoading = anthropicTools.some( | ||
| t => 'defer_loading' in t && t.defer_loading === true, | ||
| ); | ||
|
|
||
| const searchTool = anthropicTools.find( | ||
| t => | ||
| t.name === 'tool_search_tool_bm25' || t.name === 'tool_search_tool_regex', | ||
| ); | ||
|
|
||
| if (anyToolUsesDeferLoading && !searchTool) { | ||
| toolWarnings.push({ | ||
| type: 'unsupported', | ||
| feature: `tool`, | ||
| details: `At least one tool has defer_loading set to true, but no tool search tool (tool_search_tool_bm25 or tool_search_tool_regex) is provided. A tool search tool is required when using deferred loading.`, | ||
| }); | ||
| } | ||
|
|
||
| return toolWarnings; | ||
| }; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -9,6 +9,10 @@ import { textEditor_20250728ArgsSchema } from './tool/text-editor_20250728'; | |
| import { webSearch_20250305ArgsSchema } from './tool/web-search_20250305'; | ||
| import { webFetch_20250910ArgsSchema } from './tool/web-fetch-20250910'; | ||
| import { validateTypes } from '@ai-sdk/provider-utils'; | ||
| import { | ||
| getAnthropicAdvancedToolUseFeaturesSupport, | ||
| handleAnthropicAdvancedToolUseFeaturesWarnings, | ||
| } from './advanced-tool-use'; | ||
|
|
||
| export async function prepareTools({ | ||
| tools, | ||
|
|
@@ -47,11 +51,17 @@ export async function prepareTools({ | |
| canCache: true, | ||
| }); | ||
|
|
||
| const advancedToolFeatures = | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The View Details📝 Patch Detailsdiff --git a/packages/anthropic/src/anthropic-prepare-tools.ts b/packages/anthropic/src/anthropic-prepare-tools.ts
index ddf852bef..d5c8a47f4 100644
--- a/packages/anthropic/src/anthropic-prepare-tools.ts
+++ b/packages/anthropic/src/anthropic-prepare-tools.ts
@@ -68,6 +68,9 @@ export async function prepareTools({
input_schema: tool.inputSchema,
cache_control: cacheControl,
...advancedToolFeatures,
+ ...(supportsStructuredOutput === true && tool.strict != null
+ ? { strict: tool.strict }
+ : {}),
});
break;
}
AnalysisMissing
|
||
| await getAnthropicAdvancedToolUseFeaturesSupport( | ||
| tool.providerOptions, | ||
| ); | ||
|
|
||
| anthropicTools.push({ | ||
| name: tool.name, | ||
| description: tool.description, | ||
| input_schema: tool.inputSchema, | ||
| cache_control: cacheControl, | ||
| ...advancedToolFeatures, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. wouldn't this make all tool follow same
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. no since
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This would still be specified in provider options right, and that make it applied to all tools then. I mean how could you have mix of tools with some having defer_loading set to true and some with false
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oops sorry, providerMetadata is tool property, I missed that, this works then |
||
| }); | ||
| break; | ||
| } | ||
|
|
@@ -203,6 +213,22 @@ export async function prepareTools({ | |
| break; | ||
| } | ||
|
|
||
| case 'anthropic.tool_search_tool_regex_20251119': { | ||
| anthropicTools.push({ | ||
| type: 'tool_search_tool_regex_20251119', | ||
| name: 'tool_search_tool_regex', | ||
| }); | ||
| break; | ||
| } | ||
|
|
||
| case 'anthropic.tool_search_tool_bm25_20251119': { | ||
| anthropicTools.push({ | ||
| type: 'tool_search_tool_bm25_20251119', | ||
| name: 'tool_search_tool_bm25', | ||
| }); | ||
| break; | ||
| } | ||
|
|
||
| default: { | ||
| toolWarnings.push({ | ||
| type: 'unsupported', | ||
|
|
@@ -224,6 +250,13 @@ export async function prepareTools({ | |
| } | ||
| } | ||
|
|
||
| const advancedToolFeaturesWarnings = | ||
| handleAnthropicAdvancedToolUseFeaturesWarnings(anthropicTools); | ||
|
|
||
| if (advancedToolFeaturesWarnings.length > 0) { | ||
| toolWarnings.push(...advancedToolFeaturesWarnings); | ||
| } | ||
|
|
||
| if (toolChoice == null) { | ||
| return { | ||
| tools: anthropicTools, | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| import { | ||
| createProviderToolFactory, | ||
| lazySchema, | ||
| zodSchema, | ||
| } from '@ai-sdk/provider-utils'; | ||
| import { z } from 'zod/v4'; | ||
|
|
||
| const toolSearchToolBm25_20251119ArgsSchema = lazySchema(() => | ||
| zodSchema(z.object({})), | ||
| ); | ||
|
|
||
| export const toolSearchToolBm25_20251119 = createProviderToolFactory<{}, {}>({ | ||
| id: 'anthropic.tool_search_tool_bm25_20251119', | ||
| inputSchema: toolSearchToolBm25_20251119ArgsSchema, | ||
| }); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| import { | ||
| createProviderToolFactory, | ||
| lazySchema, | ||
| zodSchema, | ||
| } from '@ai-sdk/provider-utils'; | ||
| import { z } from 'zod/v4'; | ||
|
|
||
| const toolSearchToolRegex_20251119ArgsSchema = lazySchema(() => | ||
| zodSchema(z.object({})), | ||
| ); | ||
|
|
||
| export const toolSearchToolRegex_20251119 = createProviderToolFactory<{}, {}>({ | ||
| id: 'anthropic.tool_search_tool_regex_20251119', | ||
| inputSchema: toolSearchToolRegex_20251119ArgsSchema, | ||
| }); |
Uh oh!
There was an error while loading. Please reload this page.