Skip to content

Commit ff854a2

Browse files
vercel-ai-sdk[bot]grant0417claudefelixarntz
authored
Backport: fix(amazon-bedrock): add tool search beta for Anthropic (#13951)
This is an automated backport of #13900 to the release-v6.0 branch. FYI @grant0417 Co-authored-by: Grant G <grant0417@users.noreply.github.com> Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Co-authored-by: Felix Arntz <felix.arntz@vercel.com>
1 parent 58c95db commit ff854a2

File tree

7 files changed

+399
-0
lines changed

7 files changed

+399
-0
lines changed

.changeset/friendly-paws-think.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@ai-sdk/amazon-bedrock": patch
3+
---
4+
5+
fix(provider/amazon-bedrock): add tool search beta for Anthropic
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import { bedrockAnthropic } from '@ai-sdk/amazon-bedrock/anthropic';
2+
import { generateText, tool, stepCountIs } from 'ai';
3+
import 'dotenv/config';
4+
import { z } from 'zod';
5+
import { run } from '../../lib/run';
6+
7+
run(async () => {
8+
const result = await generateText({
9+
model: bedrockAnthropic('us.anthropic.claude-sonnet-4-5-20250929-v1:0'),
10+
prompt: 'What is the weather in San Francisco?',
11+
stopWhen: stepCountIs(10),
12+
onStepFinish: step => {
13+
console.log(`\n=== Step Response ===`);
14+
console.dir(step.response.body, { depth: Infinity });
15+
},
16+
tools: {
17+
toolSearch: bedrockAnthropic.tools.toolSearchBm25_20251119(),
18+
19+
get_weather: tool({
20+
description: 'Get the current weather at a specific location',
21+
inputSchema: z.object({
22+
location: z
23+
.string()
24+
.describe('The city and state, e.g. San Francisco, CA'),
25+
unit: z
26+
.enum(['celsius', 'fahrenheit'])
27+
.optional()
28+
.describe('Temperature unit'),
29+
}),
30+
execute: async ({ location, unit = 'fahrenheit' }) => ({
31+
location,
32+
temperature: unit === 'celsius' ? 18 : 64,
33+
condition: 'Partly cloudy',
34+
humidity: 65,
35+
}),
36+
providerOptions: {
37+
anthropic: { deferLoading: true },
38+
},
39+
}),
40+
41+
search_files: tool({
42+
description: 'Search through files in the workspace',
43+
inputSchema: z.object({
44+
query: z.string().describe('The search query'),
45+
file_types: z
46+
.array(z.string())
47+
.optional()
48+
.describe('Filter by file types'),
49+
}),
50+
execute: async ({ query }) => ({
51+
results: [`Found 3 files matching "${query}"`],
52+
}),
53+
providerOptions: {
54+
anthropic: { deferLoading: true },
55+
},
56+
}),
57+
58+
send_email: tool({
59+
description: 'Send an email to a recipient',
60+
inputSchema: z.object({
61+
to: z.string().describe('Recipient email address'),
62+
subject: z.string().describe('Email subject'),
63+
body: z.string().describe('Email body content'),
64+
}),
65+
execute: async ({ to, subject }) => ({
66+
success: true,
67+
message: `Email sent to ${to} with subject: ${subject}`,
68+
}),
69+
providerOptions: {
70+
anthropic: { deferLoading: true },
71+
},
72+
}),
73+
},
74+
});
75+
76+
console.log('\n=== Final Result ===');
77+
console.log('Text:', result.text);
78+
});
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import { bedrockAnthropic } from '@ai-sdk/amazon-bedrock/anthropic';
2+
import { generateText, tool, stepCountIs } from 'ai';
3+
import 'dotenv/config';
4+
import { z } from 'zod';
5+
import { run } from '../../lib/run';
6+
7+
run(async () => {
8+
const result = await generateText({
9+
model: bedrockAnthropic('us.anthropic.claude-sonnet-4-5-20250929-v1:0'),
10+
prompt: 'Find out weather data in SF',
11+
stopWhen: stepCountIs(10),
12+
onStepFinish: step => {
13+
console.log(`\n=== Step Response ===`);
14+
console.dir(step.response.body, { depth: Infinity });
15+
},
16+
tools: {
17+
toolSearch: bedrockAnthropic.tools.toolSearchRegex_20251119(),
18+
19+
get_temp_data: tool({
20+
description: 'For a location',
21+
inputSchema: z.object({
22+
location: z
23+
.string()
24+
.describe('The city and state, e.g. San Francisco, CA'),
25+
unit: z
26+
.enum(['celsius', 'fahrenheit'])
27+
.optional()
28+
.describe('Temperature unit'),
29+
}),
30+
execute: async ({ location, unit = 'fahrenheit' }) => ({
31+
location,
32+
temperature: unit === 'celsius' ? 18 : 64,
33+
condition: 'Partly cloudy',
34+
humidity: 65,
35+
}),
36+
providerOptions: {
37+
anthropic: { deferLoading: true },
38+
},
39+
}),
40+
41+
search_files: tool({
42+
description: 'Search through files in the workspace',
43+
inputSchema: z.object({
44+
query: z.string().describe('The search query'),
45+
file_types: z
46+
.array(z.string())
47+
.optional()
48+
.describe('Filter by file types'),
49+
}),
50+
execute: async ({ query }) => ({
51+
results: [`Found 3 files matching "${query}"`],
52+
}),
53+
providerOptions: {
54+
anthropic: { deferLoading: true },
55+
},
56+
}),
57+
58+
send_email: tool({
59+
description: 'Send an email to a recipient',
60+
inputSchema: z.object({
61+
to: z.string().describe('Recipient email address'),
62+
subject: z.string().describe('Email subject'),
63+
body: z.string().describe('Email body content'),
64+
}),
65+
execute: async ({ to, subject }) => ({
66+
success: true,
67+
message: `Email sent to ${to} with subject: ${subject}`,
68+
}),
69+
providerOptions: {
70+
anthropic: { deferLoading: true },
71+
},
72+
}),
73+
},
74+
});
75+
76+
console.log('\n=== Final Result ===');
77+
console.log('Text:', result.text);
78+
});
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
import { bedrockAnthropic } from '@ai-sdk/amazon-bedrock/anthropic';
2+
import { streamText, tool, stepCountIs } from 'ai';
3+
import 'dotenv/config';
4+
import { z } from 'zod';
5+
import { run } from '../../lib/run';
6+
7+
run(async () => {
8+
const result = streamText({
9+
model: bedrockAnthropic('us.anthropic.claude-sonnet-4-5-20250929-v1:0'),
10+
prompt: 'What is the weather in San Francisco?',
11+
stopWhen: stepCountIs(10),
12+
tools: {
13+
toolSearch: bedrockAnthropic.tools.toolSearchBm25_20251119(),
14+
15+
get_weather: tool({
16+
description: 'Get the current weather at a specific location',
17+
inputSchema: z.object({
18+
location: z
19+
.string()
20+
.describe('The city and state, e.g. San Francisco, CA'),
21+
unit: z
22+
.enum(['celsius', 'fahrenheit'])
23+
.optional()
24+
.describe('Temperature unit'),
25+
}),
26+
execute: async ({ location, unit = 'fahrenheit' }) => ({
27+
location,
28+
temperature: unit === 'celsius' ? 18 : 64,
29+
condition: 'Partly cloudy',
30+
humidity: 65,
31+
}),
32+
providerOptions: {
33+
anthropic: { deferLoading: true },
34+
},
35+
}),
36+
37+
search_files: tool({
38+
description: 'Search through files in the workspace',
39+
inputSchema: z.object({
40+
query: z.string().describe('The search query'),
41+
file_types: z
42+
.array(z.string())
43+
.optional()
44+
.describe('Filter by file types'),
45+
}),
46+
execute: async ({ query }) => ({
47+
results: [`Found 3 files matching "${query}"`],
48+
}),
49+
providerOptions: {
50+
anthropic: { deferLoading: true },
51+
},
52+
}),
53+
54+
send_email: tool({
55+
description: 'Send an email to a recipient',
56+
inputSchema: z.object({
57+
to: z.string().describe('Recipient email address'),
58+
subject: z.string().describe('Email subject'),
59+
body: z.string().describe('Email body content'),
60+
}),
61+
execute: async ({ to, subject }) => ({
62+
success: true,
63+
message: `Email sent to ${to} with subject: ${subject}`,
64+
}),
65+
providerOptions: {
66+
anthropic: { deferLoading: true },
67+
},
68+
}),
69+
},
70+
});
71+
72+
for await (const chunk of result.fullStream) {
73+
switch (chunk.type) {
74+
case 'text-delta': {
75+
process.stdout.write(chunk.text);
76+
break;
77+
}
78+
79+
case 'tool-call': {
80+
console.log(
81+
`\n\x1b[32m\x1b[1mTool call:\x1b[22m ${chunk.toolName}\x1b[0m`,
82+
);
83+
console.log(JSON.stringify(chunk.input, null, 2));
84+
break;
85+
}
86+
87+
case 'tool-result': {
88+
console.log(
89+
`\x1b[32m\x1b[1mTool result:\x1b[22m ${chunk.toolName}\x1b[0m`,
90+
);
91+
console.log(JSON.stringify(chunk.output, null, 2));
92+
break;
93+
}
94+
95+
case 'error':
96+
console.error('Error:', chunk.error);
97+
break;
98+
}
99+
}
100+
101+
console.log('\n');
102+
});
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
import { bedrockAnthropic } from '@ai-sdk/amazon-bedrock/anthropic';
2+
import { streamText, tool, stepCountIs } from 'ai';
3+
import 'dotenv/config';
4+
import { z } from 'zod';
5+
import { run } from '../../lib/run';
6+
7+
run(async () => {
8+
const result = streamText({
9+
model: bedrockAnthropic('us.anthropic.claude-sonnet-4-5-20250929-v1:0'),
10+
prompt: 'Find out weather data in SF',
11+
stopWhen: stepCountIs(10),
12+
tools: {
13+
toolSearch: bedrockAnthropic.tools.toolSearchRegex_20251119(),
14+
15+
get_temp_data: tool({
16+
description: 'Get the current weather at a specific location',
17+
inputSchema: z.object({
18+
location: z
19+
.string()
20+
.describe('The city and state, e.g. San Francisco, CA'),
21+
unit: z
22+
.enum(['celsius', 'fahrenheit'])
23+
.optional()
24+
.describe('Temperature unit'),
25+
}),
26+
execute: async ({ location, unit = 'fahrenheit' }) => ({
27+
location,
28+
temperature: unit === 'celsius' ? 18 : 64,
29+
condition: 'Partly cloudy',
30+
humidity: 65,
31+
}),
32+
providerOptions: {
33+
anthropic: { deferLoading: true },
34+
},
35+
}),
36+
37+
search_files: tool({
38+
description: 'Search through files in the workspace',
39+
inputSchema: z.object({
40+
query: z.string().describe('The search query'),
41+
file_types: z
42+
.array(z.string())
43+
.optional()
44+
.describe('Filter by file types'),
45+
}),
46+
execute: async ({ query }) => ({
47+
results: [`Found 3 files matching "${query}"`],
48+
}),
49+
providerOptions: {
50+
anthropic: { deferLoading: true },
51+
},
52+
}),
53+
54+
send_email: tool({
55+
description: 'Send an email to a recipient',
56+
inputSchema: z.object({
57+
to: z.string().describe('Recipient email address'),
58+
subject: z.string().describe('Email subject'),
59+
body: z.string().describe('Email body content'),
60+
}),
61+
execute: async ({ to, subject }) => ({
62+
success: true,
63+
message: `Email sent to ${to} with subject: ${subject}`,
64+
}),
65+
providerOptions: {
66+
anthropic: { deferLoading: true },
67+
},
68+
}),
69+
},
70+
});
71+
72+
for await (const chunk of result.fullStream) {
73+
switch (chunk.type) {
74+
case 'text-delta': {
75+
process.stdout.write(chunk.text);
76+
break;
77+
}
78+
79+
case 'tool-call': {
80+
console.log(
81+
`\n\x1b[32m\x1b[1mTool call:\x1b[22m ${chunk.toolName}\x1b[0m`,
82+
);
83+
console.log(JSON.stringify(chunk.input, null, 2));
84+
break;
85+
}
86+
87+
case 'tool-result': {
88+
console.log(
89+
`\x1b[32m\x1b[1mTool result:\x1b[22m ${chunk.toolName}\x1b[0m`,
90+
);
91+
console.log(JSON.stringify(chunk.output, null, 2));
92+
break;
93+
}
94+
95+
case 'error':
96+
console.error('Error:', chunk.error);
97+
break;
98+
}
99+
}
100+
101+
console.log('\n');
102+
});

0 commit comments

Comments
 (0)