@ai-sdk/amazon-bedrock 5.0.93 → 5.0.96
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +33 -0
- package/README.md +3 -3
- package/dist/anthropic/index.js +24 -29
- package/dist/anthropic/index.js.map +1 -1
- package/dist/index.js +223 -187
- package/dist/index.js.map +1 -1
- package/dist/mantle/index.cjs +23 -30
- package/dist/mantle/index.cjs.map +1 -1
- package/dist/mantle/index.js +23 -30
- package/dist/mantle/index.js.map +1 -1
- package/docs/08-amazon-bedrock.mdx +7 -7
- package/package.json +5 -5
- package/src/amazon-bedrock-chat-language-model.ts +29 -10
- package/src/amazon-bedrock-prepare-tools.ts +49 -12
- package/src/normalize-tool-call-id.ts +37 -4
|
@@ -27,6 +27,7 @@ export async function prepareTools({
|
|
|
27
27
|
modelFamily,
|
|
28
28
|
reasoningBudgetTokens,
|
|
29
29
|
disableParallelToolUse,
|
|
30
|
+
rejectsForcedToolUse = false,
|
|
30
31
|
}: {
|
|
31
32
|
tools: LanguageModelV4CallOptions['tools'];
|
|
32
33
|
toolChoice?: LanguageModelV4CallOptions['toolChoice'];
|
|
@@ -34,6 +35,7 @@ export async function prepareTools({
|
|
|
34
35
|
modelFamily?: AmazonBedrockChatModelSettings['modelFamily'];
|
|
35
36
|
reasoningBudgetTokens?: number;
|
|
36
37
|
disableParallelToolUse?: boolean;
|
|
38
|
+
rejectsForcedToolUse?: boolean;
|
|
37
39
|
}): Promise<{
|
|
38
40
|
toolConfig: AmazonBedrockToolConfiguration;
|
|
39
41
|
additionalTools: Record<string, unknown> | undefined;
|
|
@@ -84,13 +86,22 @@ export async function prepareTools({
|
|
|
84
86
|
modelFamily,
|
|
85
87
|
reasoningBudgetTokens,
|
|
86
88
|
});
|
|
87
|
-
const
|
|
89
|
+
const providerTools = supportedTools.filter(t => t.type === 'provider');
|
|
88
90
|
const functionTools = supportedTools.filter(t => t.type === 'function');
|
|
91
|
+
const rejectsForcedToolChoice =
|
|
92
|
+
isAnthropicModel &&
|
|
93
|
+
rejectsForcedToolUse &&
|
|
94
|
+
(toolChoice?.type === 'required' || toolChoice?.type === 'tool');
|
|
95
|
+
const providerToolsForRequest =
|
|
96
|
+
rejectsForcedToolChoice && toolChoice.type === 'tool'
|
|
97
|
+
? providerTools.filter(tool => tool.name === toolChoice.toolName)
|
|
98
|
+
: providerTools;
|
|
89
99
|
|
|
90
100
|
let additionalTools: Record<string, unknown> | undefined = undefined;
|
|
91
101
|
const amazonBedrockTools: AmazonBedrockTool[] = [];
|
|
92
102
|
|
|
93
|
-
const usingAnthropicTools =
|
|
103
|
+
const usingAnthropicTools =
|
|
104
|
+
isAnthropicModel && providerToolsForRequest.length > 0;
|
|
94
105
|
|
|
95
106
|
// Handle Anthropic provider-defined tools for Anthropic models on Bedrock
|
|
96
107
|
if (usingAnthropicTools) {
|
|
@@ -99,11 +110,12 @@ export async function prepareTools({
|
|
|
99
110
|
toolWarnings: anthropicToolWarnings,
|
|
100
111
|
betas: anthropicBetas,
|
|
101
112
|
} = await prepareAnthropicTools({
|
|
102
|
-
tools:
|
|
113
|
+
tools: providerTools,
|
|
103
114
|
toolChoice,
|
|
104
115
|
disableParallelToolUse,
|
|
105
116
|
supportsStructuredOutput: false,
|
|
106
117
|
supportsStrictTools: false,
|
|
118
|
+
rejectsForcedToolUse,
|
|
107
119
|
});
|
|
108
120
|
|
|
109
121
|
toolWarnings.push(...anthropicToolWarnings);
|
|
@@ -118,7 +130,7 @@ export async function prepareTools({
|
|
|
118
130
|
}
|
|
119
131
|
|
|
120
132
|
// Create a standard Bedrock tool representation for validation purposes
|
|
121
|
-
for (const tool of
|
|
133
|
+
for (const tool of providerToolsForRequest) {
|
|
122
134
|
const toolFactory = Object.values(anthropicTools).find(factory => {
|
|
123
135
|
const instance = (factory as (args: any) => any)({});
|
|
124
136
|
return instance.id === tool.id;
|
|
@@ -141,11 +153,34 @@ export async function prepareTools({
|
|
|
141
153
|
}
|
|
142
154
|
} else {
|
|
143
155
|
// Report unsupported provider-defined tools for non-anthropic models
|
|
144
|
-
for (const tool of
|
|
156
|
+
for (const tool of providerToolsForRequest) {
|
|
145
157
|
toolWarnings.push({ type: 'unsupported', feature: `tool ${tool.id}` });
|
|
146
158
|
}
|
|
147
159
|
}
|
|
148
160
|
|
|
161
|
+
let preparedToolChoice = toolChoice;
|
|
162
|
+
if (!usingAnthropicTools && rejectsForcedToolChoice) {
|
|
163
|
+
if (toolChoice.type === 'tool') {
|
|
164
|
+
toolWarnings.push({
|
|
165
|
+
type: 'unsupported',
|
|
166
|
+
feature: 'toolChoice',
|
|
167
|
+
details:
|
|
168
|
+
`toolChoice 'tool' is not supported by this model because it rejects forced tool use. ` +
|
|
169
|
+
`Only the '${toolChoice.toolName}' tool is sent with 'auto' tool choice. ` +
|
|
170
|
+
`Instruct the model to use the tool in the prompt and verify that a tool call was made.`,
|
|
171
|
+
});
|
|
172
|
+
} else {
|
|
173
|
+
toolWarnings.push({
|
|
174
|
+
type: 'unsupported',
|
|
175
|
+
feature: 'toolChoice',
|
|
176
|
+
details:
|
|
177
|
+
`toolChoice 'required' is not supported by this model because it rejects forced tool use. ` +
|
|
178
|
+
`Using 'auto' instead. Instruct the model to use a tool in the prompt and verify that a tool call was made.`,
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
preparedToolChoice = { type: 'auto' };
|
|
182
|
+
}
|
|
183
|
+
|
|
149
184
|
const filteredFunctionTools =
|
|
150
185
|
toolChoice?.type === 'tool'
|
|
151
186
|
? functionTools.filter(t => t.name === toolChoice.toolName)
|
|
@@ -193,16 +228,16 @@ export async function prepareTools({
|
|
|
193
228
|
!usingAnthropicTools &&
|
|
194
229
|
disableParallelToolUse &&
|
|
195
230
|
amazonBedrockTools.length > 0 &&
|
|
196
|
-
|
|
231
|
+
preparedToolChoice?.type !== 'none'
|
|
197
232
|
) {
|
|
198
233
|
additionalTools = {
|
|
199
234
|
tool_choice:
|
|
200
|
-
|
|
235
|
+
preparedToolChoice?.type === 'required'
|
|
201
236
|
? { type: 'any', disable_parallel_tool_use: true }
|
|
202
|
-
:
|
|
237
|
+
: preparedToolChoice?.type === 'tool'
|
|
203
238
|
? {
|
|
204
239
|
type: 'tool',
|
|
205
|
-
name:
|
|
240
|
+
name: preparedToolChoice.toolName,
|
|
206
241
|
disable_parallel_tool_use: true,
|
|
207
242
|
}
|
|
208
243
|
: { type: 'auto', disable_parallel_tool_use: true },
|
|
@@ -216,9 +251,9 @@ export async function prepareTools({
|
|
|
216
251
|
!usingAnthropicTools &&
|
|
217
252
|
additionalTools?.tool_choice == null &&
|
|
218
253
|
amazonBedrockTools.length > 0 &&
|
|
219
|
-
|
|
254
|
+
preparedToolChoice
|
|
220
255
|
) {
|
|
221
|
-
const type =
|
|
256
|
+
const type = preparedToolChoice.type;
|
|
222
257
|
switch (type) {
|
|
223
258
|
case 'auto':
|
|
224
259
|
amazonBedrockToolChoice = { auto: {} };
|
|
@@ -231,7 +266,9 @@ export async function prepareTools({
|
|
|
231
266
|
amazonBedrockToolChoice = undefined;
|
|
232
267
|
break;
|
|
233
268
|
case 'tool':
|
|
234
|
-
amazonBedrockToolChoice = {
|
|
269
|
+
amazonBedrockToolChoice = {
|
|
270
|
+
tool: { name: preparedToolChoice.toolName },
|
|
271
|
+
};
|
|
235
272
|
break;
|
|
236
273
|
default: {
|
|
237
274
|
const _exhaustiveCheck: never = type;
|
|
@@ -16,7 +16,7 @@ export function isMistralModel(modelId: string): boolean {
|
|
|
16
16
|
* Bedrock generates tool call IDs in formats like `tooluse_bpe71yCfRu2b5i-nKGDr5g`,
|
|
17
17
|
* which are incompatible with Mistral's requirements.
|
|
18
18
|
*
|
|
19
|
-
* This function
|
|
19
|
+
* This function hashes incompatible IDs into 9 alphanumeric characters.
|
|
20
20
|
*
|
|
21
21
|
* @param toolCallId - The original tool call ID from Bedrock
|
|
22
22
|
* @param isMistral - Whether the model is a Mistral model
|
|
@@ -30,7 +30,40 @@ export function normalizeToolCallId(
|
|
|
30
30
|
return toolCallId;
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
33
|
+
if (/^[a-zA-Z0-9]{9}$/.test(toolCallId)) {
|
|
34
|
+
return toolCallId;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return convertToBase62Hash(toolCallId);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const base62Characters =
|
|
41
|
+
'0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
|
|
42
|
+
const base62Length = BigInt(base62Characters.length);
|
|
43
|
+
const normalizedToolCallIdLength = 9;
|
|
44
|
+
const normalizedToolCallIdSpace =
|
|
45
|
+
base62Length ** BigInt(normalizedToolCallIdLength);
|
|
46
|
+
const fnvOffsetBasis64 = BigInt('14695981039346656037');
|
|
47
|
+
const fnvPrime64 = BigInt('1099511628211');
|
|
48
|
+
const fnv64BitMask = BigInt('18446744073709551615');
|
|
49
|
+
|
|
50
|
+
function convertToBase62Hash(value: string): string {
|
|
51
|
+
// FNV-1a 64-bit is deterministic across runtimes and gives the normalized ID
|
|
52
|
+
// access to the full 9-character base62 space.
|
|
53
|
+
let hash = fnvOffsetBasis64;
|
|
54
|
+
|
|
55
|
+
for (let i = 0; i < value.length; i++) {
|
|
56
|
+
hash ^= BigInt(value.charCodeAt(i));
|
|
57
|
+
hash = (hash * fnvPrime64) & fnv64BitMask;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
let base62Value = hash % normalizedToolCallIdSpace;
|
|
61
|
+
let result = '';
|
|
62
|
+
|
|
63
|
+
for (let i = 0; i < normalizedToolCallIdLength; i++) {
|
|
64
|
+
result = base62Characters[Number(base62Value % base62Length)] + result;
|
|
65
|
+
base62Value /= base62Length;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return result;
|
|
36
69
|
}
|