@ai-sdk/amazon-bedrock 4.0.24 → 4.0.26
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 +16 -0
- package/dist/anthropic/index.js +1 -1
- package/dist/anthropic/index.mjs +1 -1
- package/dist/index.js +1 -1
- package/dist/index.mjs +1 -1
- package/docs/08-amazon-bedrock.mdx +1453 -0
- package/package.json +11 -6
- package/src/__fixtures__/bedrock-json-only-text-first.1.chunks.txt +7 -0
- package/src/__fixtures__/bedrock-json-other-tool.1.chunks.txt +6 -0
- package/src/__fixtures__/bedrock-json-other-tool.1.json +24 -0
- package/src/__fixtures__/bedrock-json-tool-text-then-weather-then-json.1.chunks.txt +12 -0
- package/src/__fixtures__/bedrock-json-tool-with-answer.1.json +29 -0
- package/src/__fixtures__/bedrock-json-tool.1.chunks.txt +4 -0
- package/src/__fixtures__/bedrock-json-tool.1.json +35 -0
- package/src/__fixtures__/bedrock-json-tool.2.chunks.txt +6 -0
- package/src/__fixtures__/bedrock-json-tool.2.json +28 -0
- package/src/__fixtures__/bedrock-json-tool.3.chunks.txt +7 -0
- package/src/__fixtures__/bedrock-json-tool.3.json +36 -0
- package/src/__fixtures__/bedrock-json-with-tool.1.chunks.txt +9 -0
- package/src/__fixtures__/bedrock-json-with-tool.1.json +41 -0
- package/src/__fixtures__/bedrock-json-with-tools.1.chunks.txt +12 -0
- package/src/__fixtures__/bedrock-json-with-tools.1.json +50 -0
- package/src/__fixtures__/bedrock-tool-call.1.chunks.txt +6 -0
- package/src/__fixtures__/bedrock-tool-call.1.json +24 -0
- package/src/__fixtures__/bedrock-tool-no-args.chunks.txt +8 -0
- package/src/__fixtures__/bedrock-tool-no-args.json +25 -0
- package/src/anthropic/bedrock-anthropic-fetch.test.ts +344 -0
- package/src/anthropic/bedrock-anthropic-fetch.ts +62 -0
- package/src/anthropic/bedrock-anthropic-options.ts +28 -0
- package/src/anthropic/bedrock-anthropic-provider.test.ts +456 -0
- package/src/anthropic/bedrock-anthropic-provider.ts +357 -0
- package/src/anthropic/index.ts +9 -0
- package/src/bedrock-api-types.ts +195 -0
- package/src/bedrock-chat-language-model.test.ts +4569 -0
- package/src/bedrock-chat-language-model.ts +1019 -0
- package/src/bedrock-chat-options.ts +114 -0
- package/src/bedrock-embedding-model.test.ts +148 -0
- package/src/bedrock-embedding-model.ts +104 -0
- package/src/bedrock-embedding-options.ts +24 -0
- package/src/bedrock-error.ts +6 -0
- package/src/bedrock-event-stream-decoder.ts +59 -0
- package/src/bedrock-event-stream-response-handler.test.ts +233 -0
- package/src/bedrock-event-stream-response-handler.ts +57 -0
- package/src/bedrock-image-model.test.ts +866 -0
- package/src/bedrock-image-model.ts +297 -0
- package/src/bedrock-image-settings.ts +6 -0
- package/src/bedrock-prepare-tools.ts +190 -0
- package/src/bedrock-provider.test.ts +457 -0
- package/src/bedrock-provider.ts +351 -0
- package/src/bedrock-sigv4-fetch.test.ts +675 -0
- package/src/bedrock-sigv4-fetch.ts +138 -0
- package/src/convert-bedrock-usage.test.ts +207 -0
- package/src/convert-bedrock-usage.ts +50 -0
- package/src/convert-to-bedrock-chat-messages.test.ts +1175 -0
- package/src/convert-to-bedrock-chat-messages.ts +452 -0
- package/src/index.ts +10 -0
- package/src/inject-fetch-headers.test.ts +135 -0
- package/src/inject-fetch-headers.ts +32 -0
- package/src/map-bedrock-finish-reason.ts +22 -0
- package/src/normalize-tool-call-id.test.ts +72 -0
- package/src/normalize-tool-call-id.ts +36 -0
- package/src/reranking/__fixtures__/bedrock-reranking.1.json +12 -0
- package/src/reranking/bedrock-reranking-api.ts +44 -0
- package/src/reranking/bedrock-reranking-model.test.ts +299 -0
- package/src/reranking/bedrock-reranking-model.ts +115 -0
- package/src/reranking/bedrock-reranking-options.ts +36 -0
- package/src/version.ts +6 -0
|
@@ -0,0 +1,1019 @@
|
|
|
1
|
+
import {
|
|
2
|
+
JSONObject,
|
|
3
|
+
LanguageModelV3,
|
|
4
|
+
LanguageModelV3CallOptions,
|
|
5
|
+
LanguageModelV3Content,
|
|
6
|
+
LanguageModelV3FinishReason,
|
|
7
|
+
LanguageModelV3FunctionTool,
|
|
8
|
+
LanguageModelV3GenerateResult,
|
|
9
|
+
LanguageModelV3Reasoning,
|
|
10
|
+
LanguageModelV3StreamPart,
|
|
11
|
+
LanguageModelV3StreamResult,
|
|
12
|
+
SharedV3ProviderMetadata,
|
|
13
|
+
SharedV3Warning,
|
|
14
|
+
} from '@ai-sdk/provider';
|
|
15
|
+
import {
|
|
16
|
+
FetchFunction,
|
|
17
|
+
ParseResult,
|
|
18
|
+
Resolvable,
|
|
19
|
+
combineHeaders,
|
|
20
|
+
createJsonErrorResponseHandler,
|
|
21
|
+
createJsonResponseHandler,
|
|
22
|
+
parseProviderOptions,
|
|
23
|
+
postJsonToApi,
|
|
24
|
+
resolve,
|
|
25
|
+
} from '@ai-sdk/provider-utils';
|
|
26
|
+
import { z } from 'zod/v4';
|
|
27
|
+
import {
|
|
28
|
+
BEDROCK_STOP_REASONS,
|
|
29
|
+
BedrockConverseInput,
|
|
30
|
+
BedrockStopReason,
|
|
31
|
+
} from './bedrock-api-types';
|
|
32
|
+
import {
|
|
33
|
+
BedrockChatModelId,
|
|
34
|
+
bedrockProviderOptions,
|
|
35
|
+
} from './bedrock-chat-options';
|
|
36
|
+
import { BedrockErrorSchema } from './bedrock-error';
|
|
37
|
+
import { createBedrockEventStreamResponseHandler } from './bedrock-event-stream-response-handler';
|
|
38
|
+
import { prepareTools } from './bedrock-prepare-tools';
|
|
39
|
+
import { BedrockUsage, convertBedrockUsage } from './convert-bedrock-usage';
|
|
40
|
+
import { convertToBedrockChatMessages } from './convert-to-bedrock-chat-messages';
|
|
41
|
+
import { mapBedrockFinishReason } from './map-bedrock-finish-reason';
|
|
42
|
+
import { isMistralModel, normalizeToolCallId } from './normalize-tool-call-id';
|
|
43
|
+
|
|
44
|
+
type BedrockChatConfig = {
|
|
45
|
+
baseUrl: () => string;
|
|
46
|
+
headers: Resolvable<Record<string, string | undefined>>;
|
|
47
|
+
fetch?: FetchFunction;
|
|
48
|
+
generateId: () => string;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
export class BedrockChatLanguageModel implements LanguageModelV3 {
|
|
52
|
+
readonly specificationVersion = 'v3';
|
|
53
|
+
readonly provider = 'amazon-bedrock';
|
|
54
|
+
|
|
55
|
+
constructor(
|
|
56
|
+
readonly modelId: BedrockChatModelId,
|
|
57
|
+
private readonly config: BedrockChatConfig,
|
|
58
|
+
) {}
|
|
59
|
+
|
|
60
|
+
private async getArgs({
|
|
61
|
+
prompt,
|
|
62
|
+
maxOutputTokens,
|
|
63
|
+
temperature,
|
|
64
|
+
topP,
|
|
65
|
+
topK,
|
|
66
|
+
frequencyPenalty,
|
|
67
|
+
presencePenalty,
|
|
68
|
+
stopSequences,
|
|
69
|
+
responseFormat,
|
|
70
|
+
seed,
|
|
71
|
+
tools,
|
|
72
|
+
toolChoice,
|
|
73
|
+
providerOptions,
|
|
74
|
+
}: LanguageModelV3CallOptions): Promise<{
|
|
75
|
+
command: BedrockConverseInput;
|
|
76
|
+
warnings: SharedV3Warning[];
|
|
77
|
+
usesJsonResponseTool: boolean;
|
|
78
|
+
betas: Set<string>;
|
|
79
|
+
}> {
|
|
80
|
+
// Parse provider options
|
|
81
|
+
const bedrockOptions =
|
|
82
|
+
(await parseProviderOptions({
|
|
83
|
+
provider: 'bedrock',
|
|
84
|
+
providerOptions,
|
|
85
|
+
schema: bedrockProviderOptions,
|
|
86
|
+
})) ?? {};
|
|
87
|
+
|
|
88
|
+
const warnings: SharedV3Warning[] = [];
|
|
89
|
+
|
|
90
|
+
if (frequencyPenalty != null) {
|
|
91
|
+
warnings.push({
|
|
92
|
+
type: 'unsupported',
|
|
93
|
+
feature: 'frequencyPenalty',
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (presencePenalty != null) {
|
|
98
|
+
warnings.push({
|
|
99
|
+
type: 'unsupported',
|
|
100
|
+
feature: 'presencePenalty',
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (seed != null) {
|
|
105
|
+
warnings.push({
|
|
106
|
+
type: 'unsupported',
|
|
107
|
+
feature: 'seed',
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (temperature != null && temperature > 1) {
|
|
112
|
+
warnings.push({
|
|
113
|
+
type: 'unsupported',
|
|
114
|
+
feature: 'temperature',
|
|
115
|
+
details: `${temperature} exceeds bedrock maximum of 1.0. clamped to 1.0`,
|
|
116
|
+
});
|
|
117
|
+
temperature = 1;
|
|
118
|
+
} else if (temperature != null && temperature < 0) {
|
|
119
|
+
warnings.push({
|
|
120
|
+
type: 'unsupported',
|
|
121
|
+
feature: 'temperature',
|
|
122
|
+
details: `${temperature} is below bedrock minimum of 0. clamped to 0`,
|
|
123
|
+
});
|
|
124
|
+
temperature = 0;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (
|
|
128
|
+
responseFormat != null &&
|
|
129
|
+
responseFormat.type !== 'text' &&
|
|
130
|
+
responseFormat.type !== 'json'
|
|
131
|
+
) {
|
|
132
|
+
warnings.push({
|
|
133
|
+
type: 'unsupported',
|
|
134
|
+
feature: 'responseFormat',
|
|
135
|
+
details: 'Only text and json response formats are supported.',
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const jsonResponseTool: LanguageModelV3FunctionTool | undefined =
|
|
140
|
+
responseFormat?.type === 'json' && responseFormat.schema != null
|
|
141
|
+
? {
|
|
142
|
+
type: 'function',
|
|
143
|
+
name: 'json',
|
|
144
|
+
description: 'Respond with a JSON object.',
|
|
145
|
+
inputSchema: responseFormat.schema,
|
|
146
|
+
}
|
|
147
|
+
: undefined;
|
|
148
|
+
|
|
149
|
+
const { toolConfig, additionalTools, toolWarnings, betas } =
|
|
150
|
+
await prepareTools({
|
|
151
|
+
tools: jsonResponseTool ? [...(tools ?? []), jsonResponseTool] : tools,
|
|
152
|
+
toolChoice:
|
|
153
|
+
jsonResponseTool != null ? { type: 'required' } : toolChoice,
|
|
154
|
+
modelId: this.modelId,
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
warnings.push(...toolWarnings);
|
|
158
|
+
|
|
159
|
+
if (additionalTools) {
|
|
160
|
+
bedrockOptions.additionalModelRequestFields = {
|
|
161
|
+
...bedrockOptions.additionalModelRequestFields,
|
|
162
|
+
...additionalTools,
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
if (betas.size > 0 || bedrockOptions.anthropicBeta) {
|
|
167
|
+
const existingBetas = bedrockOptions.anthropicBeta ?? [];
|
|
168
|
+
const mergedBetas =
|
|
169
|
+
betas.size > 0
|
|
170
|
+
? [...existingBetas, ...Array.from(betas)]
|
|
171
|
+
: existingBetas;
|
|
172
|
+
|
|
173
|
+
bedrockOptions.additionalModelRequestFields = {
|
|
174
|
+
...bedrockOptions.additionalModelRequestFields,
|
|
175
|
+
anthropic_beta: mergedBetas,
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
const isAnthropicModel = this.modelId.includes('anthropic');
|
|
180
|
+
const isThinkingRequested =
|
|
181
|
+
bedrockOptions.reasoningConfig?.type === 'enabled';
|
|
182
|
+
const thinkingBudget = bedrockOptions.reasoningConfig?.budgetTokens;
|
|
183
|
+
const isAnthropicThinkingEnabled = isAnthropicModel && isThinkingRequested;
|
|
184
|
+
|
|
185
|
+
const inferenceConfig = {
|
|
186
|
+
...(maxOutputTokens != null && { maxTokens: maxOutputTokens }),
|
|
187
|
+
...(temperature != null && { temperature }),
|
|
188
|
+
...(topP != null && { topP }),
|
|
189
|
+
...(topK != null && { topK }),
|
|
190
|
+
...(stopSequences != null && { stopSequences }),
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
if (isAnthropicThinkingEnabled && thinkingBudget != null) {
|
|
194
|
+
if (inferenceConfig.maxTokens != null) {
|
|
195
|
+
inferenceConfig.maxTokens += thinkingBudget;
|
|
196
|
+
} else {
|
|
197
|
+
inferenceConfig.maxTokens = thinkingBudget + 4096; // Default + thinking budget maxTokens = 4096, TODO update default in v5
|
|
198
|
+
}
|
|
199
|
+
// Add them to additional model request fields
|
|
200
|
+
// Add thinking config to additionalModelRequestFields
|
|
201
|
+
bedrockOptions.additionalModelRequestFields = {
|
|
202
|
+
...bedrockOptions.additionalModelRequestFields,
|
|
203
|
+
thinking: {
|
|
204
|
+
type: bedrockOptions.reasoningConfig?.type,
|
|
205
|
+
budget_tokens: thinkingBudget,
|
|
206
|
+
},
|
|
207
|
+
};
|
|
208
|
+
} else if (!isAnthropicModel && thinkingBudget != null) {
|
|
209
|
+
warnings.push({
|
|
210
|
+
type: 'unsupported',
|
|
211
|
+
feature: 'budgetTokens',
|
|
212
|
+
details:
|
|
213
|
+
'budgetTokens applies only to Anthropic models on Bedrock and will be ignored for this model.',
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
const maxReasoningEffort =
|
|
218
|
+
bedrockOptions.reasoningConfig?.maxReasoningEffort;
|
|
219
|
+
const isOpenAIModel = this.modelId.startsWith('openai.');
|
|
220
|
+
|
|
221
|
+
if (maxReasoningEffort != null && !isAnthropicModel) {
|
|
222
|
+
if (isOpenAIModel) {
|
|
223
|
+
// OpenAI models on Bedrock expect `reasoning_effort` as a flat value
|
|
224
|
+
bedrockOptions.additionalModelRequestFields = {
|
|
225
|
+
...bedrockOptions.additionalModelRequestFields,
|
|
226
|
+
reasoning_effort: maxReasoningEffort,
|
|
227
|
+
};
|
|
228
|
+
} else {
|
|
229
|
+
// other models (such as Nova 2) use reasoningConfig format
|
|
230
|
+
bedrockOptions.additionalModelRequestFields = {
|
|
231
|
+
...bedrockOptions.additionalModelRequestFields,
|
|
232
|
+
reasoningConfig: {
|
|
233
|
+
...(bedrockOptions.reasoningConfig?.type != null && {
|
|
234
|
+
type: bedrockOptions.reasoningConfig.type,
|
|
235
|
+
}),
|
|
236
|
+
maxReasoningEffort,
|
|
237
|
+
},
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
} else if (maxReasoningEffort != null && isAnthropicModel) {
|
|
241
|
+
warnings.push({
|
|
242
|
+
type: 'unsupported',
|
|
243
|
+
feature: 'maxReasoningEffort',
|
|
244
|
+
details:
|
|
245
|
+
'maxReasoningEffort applies only to Amazon Nova models on Bedrock and will be ignored for this model.',
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
if (isAnthropicThinkingEnabled && inferenceConfig.temperature != null) {
|
|
250
|
+
delete inferenceConfig.temperature;
|
|
251
|
+
warnings.push({
|
|
252
|
+
type: 'unsupported',
|
|
253
|
+
feature: 'temperature',
|
|
254
|
+
details: 'temperature is not supported when thinking is enabled',
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
if (isAnthropicThinkingEnabled && inferenceConfig.topP != null) {
|
|
259
|
+
delete inferenceConfig.topP;
|
|
260
|
+
warnings.push({
|
|
261
|
+
type: 'unsupported',
|
|
262
|
+
feature: 'topP',
|
|
263
|
+
details: 'topP is not supported when thinking is enabled',
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
if (isAnthropicThinkingEnabled && inferenceConfig.topK != null) {
|
|
268
|
+
delete inferenceConfig.topK;
|
|
269
|
+
warnings.push({
|
|
270
|
+
type: 'unsupported',
|
|
271
|
+
feature: 'topK',
|
|
272
|
+
details: 'topK is not supported when thinking is enabled',
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// Filter tool content from prompt when no tools are available
|
|
277
|
+
const hasAnyTools = (toolConfig.tools?.length ?? 0) > 0 || additionalTools;
|
|
278
|
+
let filteredPrompt = prompt;
|
|
279
|
+
|
|
280
|
+
if (!hasAnyTools) {
|
|
281
|
+
const hasToolContent = prompt.some(
|
|
282
|
+
message =>
|
|
283
|
+
'content' in message &&
|
|
284
|
+
Array.isArray(message.content) &&
|
|
285
|
+
message.content.some(
|
|
286
|
+
part => part.type === 'tool-call' || part.type === 'tool-result',
|
|
287
|
+
),
|
|
288
|
+
);
|
|
289
|
+
|
|
290
|
+
if (hasToolContent) {
|
|
291
|
+
filteredPrompt = prompt
|
|
292
|
+
.map(message =>
|
|
293
|
+
message.role === 'system'
|
|
294
|
+
? message
|
|
295
|
+
: {
|
|
296
|
+
...message,
|
|
297
|
+
content: message.content.filter(
|
|
298
|
+
part =>
|
|
299
|
+
part.type !== 'tool-call' && part.type !== 'tool-result',
|
|
300
|
+
),
|
|
301
|
+
},
|
|
302
|
+
)
|
|
303
|
+
.filter(
|
|
304
|
+
message => message.role === 'system' || message.content.length > 0,
|
|
305
|
+
) as typeof prompt;
|
|
306
|
+
|
|
307
|
+
warnings.push({
|
|
308
|
+
type: 'unsupported',
|
|
309
|
+
feature: 'toolContent',
|
|
310
|
+
details:
|
|
311
|
+
'Tool calls and results removed from conversation because Bedrock does not support tool content without active tools.',
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
const isMistral = isMistralModel(this.modelId);
|
|
317
|
+
const { system, messages } = await convertToBedrockChatMessages(
|
|
318
|
+
filteredPrompt,
|
|
319
|
+
isMistral,
|
|
320
|
+
);
|
|
321
|
+
|
|
322
|
+
// Filter out reasoningConfig from providerOptions.bedrock to prevent sending it to Bedrock API
|
|
323
|
+
const {
|
|
324
|
+
reasoningConfig: _,
|
|
325
|
+
additionalModelRequestFields: __,
|
|
326
|
+
...filteredBedrockOptions
|
|
327
|
+
} = providerOptions?.bedrock || {};
|
|
328
|
+
|
|
329
|
+
const additionalModelResponseFieldPaths = isAnthropicModel
|
|
330
|
+
? ['/delta/stop_sequence']
|
|
331
|
+
: undefined;
|
|
332
|
+
|
|
333
|
+
return {
|
|
334
|
+
command: {
|
|
335
|
+
system,
|
|
336
|
+
messages,
|
|
337
|
+
additionalModelRequestFields:
|
|
338
|
+
bedrockOptions.additionalModelRequestFields,
|
|
339
|
+
...(additionalModelResponseFieldPaths && {
|
|
340
|
+
additionalModelResponseFieldPaths,
|
|
341
|
+
}),
|
|
342
|
+
...(Object.keys(inferenceConfig).length > 0 && {
|
|
343
|
+
inferenceConfig,
|
|
344
|
+
}),
|
|
345
|
+
...filteredBedrockOptions,
|
|
346
|
+
...(toolConfig.tools !== undefined && toolConfig.tools.length > 0
|
|
347
|
+
? { toolConfig }
|
|
348
|
+
: {}),
|
|
349
|
+
},
|
|
350
|
+
warnings,
|
|
351
|
+
usesJsonResponseTool: jsonResponseTool != null,
|
|
352
|
+
betas,
|
|
353
|
+
};
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
readonly supportedUrls: Record<string, RegExp[]> = {
|
|
357
|
+
// no supported urls for bedrock
|
|
358
|
+
};
|
|
359
|
+
|
|
360
|
+
private async getHeaders({
|
|
361
|
+
headers,
|
|
362
|
+
}: {
|
|
363
|
+
headers: Record<string, string | undefined> | undefined;
|
|
364
|
+
}) {
|
|
365
|
+
return combineHeaders(await resolve(this.config.headers), headers);
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
async doGenerate(
|
|
369
|
+
options: LanguageModelV3CallOptions,
|
|
370
|
+
): Promise<LanguageModelV3GenerateResult> {
|
|
371
|
+
const {
|
|
372
|
+
command: args,
|
|
373
|
+
warnings,
|
|
374
|
+
usesJsonResponseTool,
|
|
375
|
+
} = await this.getArgs(options);
|
|
376
|
+
|
|
377
|
+
const url = `${this.getUrl(this.modelId)}/converse`;
|
|
378
|
+
const { value: response, responseHeaders } = await postJsonToApi({
|
|
379
|
+
url,
|
|
380
|
+
headers: await this.getHeaders({ headers: options.headers }),
|
|
381
|
+
body: args,
|
|
382
|
+
failedResponseHandler: createJsonErrorResponseHandler({
|
|
383
|
+
errorSchema: BedrockErrorSchema,
|
|
384
|
+
errorToMessage: error => `${error.message ?? 'Unknown error'}`,
|
|
385
|
+
}),
|
|
386
|
+
successfulResponseHandler: createJsonResponseHandler(
|
|
387
|
+
BedrockResponseSchema,
|
|
388
|
+
),
|
|
389
|
+
abortSignal: options.abortSignal,
|
|
390
|
+
fetch: this.config.fetch,
|
|
391
|
+
});
|
|
392
|
+
|
|
393
|
+
const content: Array<LanguageModelV3Content> = [];
|
|
394
|
+
let isJsonResponseFromTool = false;
|
|
395
|
+
|
|
396
|
+
// map response content to content array
|
|
397
|
+
for (const part of response.output.message.content) {
|
|
398
|
+
// text
|
|
399
|
+
if (part.text) {
|
|
400
|
+
content.push({ type: 'text', text: part.text });
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
// reasoning
|
|
404
|
+
if (part.reasoningContent) {
|
|
405
|
+
if ('reasoningText' in part.reasoningContent) {
|
|
406
|
+
const reasoning: LanguageModelV3Reasoning = {
|
|
407
|
+
type: 'reasoning',
|
|
408
|
+
text: part.reasoningContent.reasoningText.text,
|
|
409
|
+
};
|
|
410
|
+
|
|
411
|
+
if (part.reasoningContent.reasoningText.signature) {
|
|
412
|
+
reasoning.providerMetadata = {
|
|
413
|
+
bedrock: {
|
|
414
|
+
signature: part.reasoningContent.reasoningText.signature,
|
|
415
|
+
} satisfies BedrockReasoningMetadata,
|
|
416
|
+
};
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
content.push(reasoning);
|
|
420
|
+
} else if ('redactedReasoning' in part.reasoningContent) {
|
|
421
|
+
content.push({
|
|
422
|
+
type: 'reasoning',
|
|
423
|
+
text: '',
|
|
424
|
+
providerMetadata: {
|
|
425
|
+
bedrock: {
|
|
426
|
+
redactedData:
|
|
427
|
+
part.reasoningContent.redactedReasoning.data ?? '',
|
|
428
|
+
} satisfies BedrockReasoningMetadata,
|
|
429
|
+
},
|
|
430
|
+
});
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
// tool calls
|
|
435
|
+
if (part.toolUse) {
|
|
436
|
+
const isJsonResponseTool =
|
|
437
|
+
usesJsonResponseTool && part.toolUse.name === 'json';
|
|
438
|
+
|
|
439
|
+
if (isJsonResponseTool) {
|
|
440
|
+
isJsonResponseFromTool = true;
|
|
441
|
+
// when a json response tool is used, the tool call becomes the text:
|
|
442
|
+
content.push({
|
|
443
|
+
type: 'text',
|
|
444
|
+
text: JSON.stringify(part.toolUse.input),
|
|
445
|
+
});
|
|
446
|
+
} else {
|
|
447
|
+
const isMistral = isMistralModel(this.modelId);
|
|
448
|
+
const rawToolCallId =
|
|
449
|
+
part.toolUse?.toolUseId ?? this.config.generateId();
|
|
450
|
+
content.push({
|
|
451
|
+
type: 'tool-call' as const,
|
|
452
|
+
toolCallId: normalizeToolCallId(rawToolCallId, isMistral),
|
|
453
|
+
toolName: part.toolUse?.name ?? `tool-${this.config.generateId()}`,
|
|
454
|
+
input: JSON.stringify(part.toolUse?.input ?? {}),
|
|
455
|
+
});
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
// provider metadata:
|
|
461
|
+
const stopSequence =
|
|
462
|
+
response.additionalModelResponseFields?.delta?.stop_sequence ?? null;
|
|
463
|
+
|
|
464
|
+
const providerMetadata =
|
|
465
|
+
response.trace || response.usage || isJsonResponseFromTool || stopSequence
|
|
466
|
+
? {
|
|
467
|
+
bedrock: {
|
|
468
|
+
...(response.trace && typeof response.trace === 'object'
|
|
469
|
+
? { trace: response.trace as JSONObject }
|
|
470
|
+
: {}),
|
|
471
|
+
...(response.usage?.cacheWriteInputTokens != null && {
|
|
472
|
+
usage: {
|
|
473
|
+
cacheWriteInputTokens: response.usage.cacheWriteInputTokens,
|
|
474
|
+
},
|
|
475
|
+
}),
|
|
476
|
+
...(isJsonResponseFromTool && { isJsonResponseFromTool: true }),
|
|
477
|
+
stopSequence,
|
|
478
|
+
},
|
|
479
|
+
}
|
|
480
|
+
: undefined;
|
|
481
|
+
|
|
482
|
+
return {
|
|
483
|
+
content,
|
|
484
|
+
finishReason: {
|
|
485
|
+
unified: mapBedrockFinishReason(
|
|
486
|
+
response.stopReason as BedrockStopReason,
|
|
487
|
+
isJsonResponseFromTool,
|
|
488
|
+
),
|
|
489
|
+
raw: response.stopReason ?? undefined,
|
|
490
|
+
},
|
|
491
|
+
usage: convertBedrockUsage(response.usage),
|
|
492
|
+
response: {
|
|
493
|
+
// TODO add id, timestamp, etc
|
|
494
|
+
headers: responseHeaders,
|
|
495
|
+
},
|
|
496
|
+
warnings,
|
|
497
|
+
...(providerMetadata && { providerMetadata }),
|
|
498
|
+
};
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
async doStream(
|
|
502
|
+
options: LanguageModelV3CallOptions,
|
|
503
|
+
): Promise<LanguageModelV3StreamResult> {
|
|
504
|
+
const {
|
|
505
|
+
command: args,
|
|
506
|
+
warnings,
|
|
507
|
+
usesJsonResponseTool,
|
|
508
|
+
} = await this.getArgs(options);
|
|
509
|
+
const isMistral = isMistralModel(this.modelId);
|
|
510
|
+
const url = `${this.getUrl(this.modelId)}/converse-stream`;
|
|
511
|
+
|
|
512
|
+
const { value: response, responseHeaders } = await postJsonToApi({
|
|
513
|
+
url,
|
|
514
|
+
headers: await this.getHeaders({ headers: options.headers }),
|
|
515
|
+
body: args,
|
|
516
|
+
failedResponseHandler: createJsonErrorResponseHandler({
|
|
517
|
+
errorSchema: BedrockErrorSchema,
|
|
518
|
+
errorToMessage: error => `${error.type}: ${error.message}`,
|
|
519
|
+
}),
|
|
520
|
+
successfulResponseHandler:
|
|
521
|
+
createBedrockEventStreamResponseHandler(BedrockStreamSchema),
|
|
522
|
+
abortSignal: options.abortSignal,
|
|
523
|
+
fetch: this.config.fetch,
|
|
524
|
+
});
|
|
525
|
+
|
|
526
|
+
let finishReason: LanguageModelV3FinishReason = {
|
|
527
|
+
unified: 'other',
|
|
528
|
+
raw: undefined,
|
|
529
|
+
};
|
|
530
|
+
let usage: BedrockUsage | undefined = undefined;
|
|
531
|
+
let providerMetadata: SharedV3ProviderMetadata | undefined = undefined;
|
|
532
|
+
let isJsonResponseFromTool = false;
|
|
533
|
+
let stopSequence: string | null = null;
|
|
534
|
+
|
|
535
|
+
const contentBlocks: Record<
|
|
536
|
+
number,
|
|
537
|
+
| {
|
|
538
|
+
type: 'tool-call';
|
|
539
|
+
toolCallId: string;
|
|
540
|
+
toolName: string;
|
|
541
|
+
jsonText: string;
|
|
542
|
+
isJsonResponseTool?: boolean;
|
|
543
|
+
}
|
|
544
|
+
| { type: 'text' | 'reasoning' }
|
|
545
|
+
> = {};
|
|
546
|
+
|
|
547
|
+
return {
|
|
548
|
+
stream: response.pipeThrough(
|
|
549
|
+
new TransformStream<
|
|
550
|
+
ParseResult<z.infer<typeof BedrockStreamSchema>>,
|
|
551
|
+
LanguageModelV3StreamPart
|
|
552
|
+
>({
|
|
553
|
+
start(controller) {
|
|
554
|
+
controller.enqueue({ type: 'stream-start', warnings });
|
|
555
|
+
},
|
|
556
|
+
|
|
557
|
+
transform(chunk, controller) {
|
|
558
|
+
function enqueueError(bedrockError: Record<string, any>) {
|
|
559
|
+
finishReason = { unified: 'error', raw: undefined };
|
|
560
|
+
controller.enqueue({ type: 'error', error: bedrockError });
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
// Emit raw chunk if requested (before anything else)
|
|
564
|
+
if (options.includeRawChunks) {
|
|
565
|
+
controller.enqueue({ type: 'raw', rawValue: chunk.rawValue });
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
// handle failed chunk parsing / validation:
|
|
569
|
+
if (!chunk.success) {
|
|
570
|
+
enqueueError(chunk.error);
|
|
571
|
+
return;
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
const value = chunk.value;
|
|
575
|
+
|
|
576
|
+
// handle errors:
|
|
577
|
+
if (value.internalServerException) {
|
|
578
|
+
enqueueError(value.internalServerException);
|
|
579
|
+
return;
|
|
580
|
+
}
|
|
581
|
+
if (value.modelStreamErrorException) {
|
|
582
|
+
enqueueError(value.modelStreamErrorException);
|
|
583
|
+
return;
|
|
584
|
+
}
|
|
585
|
+
if (value.throttlingException) {
|
|
586
|
+
enqueueError(value.throttlingException);
|
|
587
|
+
return;
|
|
588
|
+
}
|
|
589
|
+
if (value.validationException) {
|
|
590
|
+
enqueueError(value.validationException);
|
|
591
|
+
return;
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
if (value.messageStop) {
|
|
595
|
+
finishReason = {
|
|
596
|
+
unified: mapBedrockFinishReason(
|
|
597
|
+
value.messageStop.stopReason as BedrockStopReason,
|
|
598
|
+
isJsonResponseFromTool,
|
|
599
|
+
),
|
|
600
|
+
raw: value.messageStop.stopReason ?? undefined,
|
|
601
|
+
};
|
|
602
|
+
stopSequence =
|
|
603
|
+
value.messageStop.additionalModelResponseFields?.delta
|
|
604
|
+
?.stop_sequence ?? null;
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
if (value.metadata) {
|
|
608
|
+
if (value.metadata.usage) {
|
|
609
|
+
usage = value.metadata.usage;
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
const cacheUsage =
|
|
613
|
+
value.metadata.usage?.cacheWriteInputTokens != null
|
|
614
|
+
? {
|
|
615
|
+
usage: {
|
|
616
|
+
cacheWriteInputTokens:
|
|
617
|
+
value.metadata.usage.cacheWriteInputTokens,
|
|
618
|
+
},
|
|
619
|
+
}
|
|
620
|
+
: undefined;
|
|
621
|
+
|
|
622
|
+
const trace = value.metadata.trace
|
|
623
|
+
? {
|
|
624
|
+
trace: value.metadata.trace as JSONObject,
|
|
625
|
+
}
|
|
626
|
+
: undefined;
|
|
627
|
+
|
|
628
|
+
if (cacheUsage || trace) {
|
|
629
|
+
providerMetadata = {
|
|
630
|
+
bedrock: {
|
|
631
|
+
...cacheUsage,
|
|
632
|
+
...trace,
|
|
633
|
+
},
|
|
634
|
+
};
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
if (
|
|
639
|
+
value.contentBlockStart?.contentBlockIndex != null &&
|
|
640
|
+
!value.contentBlockStart?.start?.toolUse
|
|
641
|
+
) {
|
|
642
|
+
const blockIndex = value.contentBlockStart.contentBlockIndex;
|
|
643
|
+
contentBlocks[blockIndex] = { type: 'text' };
|
|
644
|
+
controller.enqueue({
|
|
645
|
+
type: 'text-start',
|
|
646
|
+
id: String(blockIndex),
|
|
647
|
+
});
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
if (
|
|
651
|
+
value.contentBlockDelta?.delta &&
|
|
652
|
+
'text' in value.contentBlockDelta.delta &&
|
|
653
|
+
value.contentBlockDelta.delta.text
|
|
654
|
+
) {
|
|
655
|
+
const blockIndex = value.contentBlockDelta.contentBlockIndex || 0;
|
|
656
|
+
|
|
657
|
+
if (contentBlocks[blockIndex] == null) {
|
|
658
|
+
contentBlocks[blockIndex] = { type: 'text' };
|
|
659
|
+
|
|
660
|
+
controller.enqueue({
|
|
661
|
+
type: 'text-start',
|
|
662
|
+
id: String(blockIndex),
|
|
663
|
+
});
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
controller.enqueue({
|
|
667
|
+
type: 'text-delta',
|
|
668
|
+
id: String(blockIndex),
|
|
669
|
+
delta: value.contentBlockDelta.delta.text,
|
|
670
|
+
});
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
if (value.contentBlockStop?.contentBlockIndex != null) {
|
|
674
|
+
const blockIndex = value.contentBlockStop.contentBlockIndex;
|
|
675
|
+
const contentBlock = contentBlocks[blockIndex];
|
|
676
|
+
|
|
677
|
+
if (contentBlock != null) {
|
|
678
|
+
if (contentBlock.type === 'reasoning') {
|
|
679
|
+
controller.enqueue({
|
|
680
|
+
type: 'reasoning-end',
|
|
681
|
+
id: String(blockIndex),
|
|
682
|
+
});
|
|
683
|
+
} else if (contentBlock.type === 'text') {
|
|
684
|
+
controller.enqueue({
|
|
685
|
+
type: 'text-end',
|
|
686
|
+
id: String(blockIndex),
|
|
687
|
+
});
|
|
688
|
+
} else if (contentBlock.type === 'tool-call') {
|
|
689
|
+
if (contentBlock.isJsonResponseTool) {
|
|
690
|
+
isJsonResponseFromTool = true;
|
|
691
|
+
// when this specific tool is the json response tool, emit the tool input as text
|
|
692
|
+
controller.enqueue({
|
|
693
|
+
type: 'text-start',
|
|
694
|
+
id: String(blockIndex),
|
|
695
|
+
});
|
|
696
|
+
controller.enqueue({
|
|
697
|
+
type: 'text-delta',
|
|
698
|
+
id: String(blockIndex),
|
|
699
|
+
delta: contentBlock.jsonText,
|
|
700
|
+
});
|
|
701
|
+
controller.enqueue({
|
|
702
|
+
type: 'text-end',
|
|
703
|
+
id: String(blockIndex),
|
|
704
|
+
});
|
|
705
|
+
} else {
|
|
706
|
+
controller.enqueue({
|
|
707
|
+
type: 'tool-input-end',
|
|
708
|
+
id: contentBlock.toolCallId,
|
|
709
|
+
});
|
|
710
|
+
controller.enqueue({
|
|
711
|
+
type: 'tool-call',
|
|
712
|
+
toolCallId: contentBlock.toolCallId,
|
|
713
|
+
toolName: contentBlock.toolName,
|
|
714
|
+
input:
|
|
715
|
+
contentBlock.jsonText === ''
|
|
716
|
+
? '{}'
|
|
717
|
+
: contentBlock.jsonText,
|
|
718
|
+
});
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
delete contentBlocks[blockIndex];
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
if (
|
|
727
|
+
value.contentBlockDelta?.delta &&
|
|
728
|
+
'reasoningContent' in value.contentBlockDelta.delta &&
|
|
729
|
+
value.contentBlockDelta.delta.reasoningContent
|
|
730
|
+
) {
|
|
731
|
+
const blockIndex = value.contentBlockDelta.contentBlockIndex || 0;
|
|
732
|
+
const reasoningContent =
|
|
733
|
+
value.contentBlockDelta.delta.reasoningContent;
|
|
734
|
+
|
|
735
|
+
if ('text' in reasoningContent && reasoningContent.text) {
|
|
736
|
+
if (contentBlocks[blockIndex] == null) {
|
|
737
|
+
contentBlocks[blockIndex] = { type: 'reasoning' };
|
|
738
|
+
controller.enqueue({
|
|
739
|
+
type: 'reasoning-start',
|
|
740
|
+
id: String(blockIndex),
|
|
741
|
+
});
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
controller.enqueue({
|
|
745
|
+
type: 'reasoning-delta',
|
|
746
|
+
id: String(blockIndex),
|
|
747
|
+
delta: reasoningContent.text,
|
|
748
|
+
});
|
|
749
|
+
} else if (
|
|
750
|
+
'signature' in reasoningContent &&
|
|
751
|
+
reasoningContent.signature
|
|
752
|
+
) {
|
|
753
|
+
controller.enqueue({
|
|
754
|
+
type: 'reasoning-delta',
|
|
755
|
+
id: String(blockIndex),
|
|
756
|
+
delta: '',
|
|
757
|
+
providerMetadata: {
|
|
758
|
+
bedrock: {
|
|
759
|
+
signature: reasoningContent.signature,
|
|
760
|
+
} satisfies BedrockReasoningMetadata,
|
|
761
|
+
},
|
|
762
|
+
});
|
|
763
|
+
} else if ('data' in reasoningContent && reasoningContent.data) {
|
|
764
|
+
controller.enqueue({
|
|
765
|
+
type: 'reasoning-delta',
|
|
766
|
+
id: String(blockIndex),
|
|
767
|
+
delta: '',
|
|
768
|
+
providerMetadata: {
|
|
769
|
+
bedrock: {
|
|
770
|
+
redactedData: reasoningContent.data,
|
|
771
|
+
} satisfies BedrockReasoningMetadata,
|
|
772
|
+
},
|
|
773
|
+
});
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
const contentBlockStart = value.contentBlockStart;
|
|
778
|
+
if (contentBlockStart?.start?.toolUse != null) {
|
|
779
|
+
const toolUse = contentBlockStart.start.toolUse;
|
|
780
|
+
const blockIndex = contentBlockStart.contentBlockIndex!;
|
|
781
|
+
const isJsonResponseTool =
|
|
782
|
+
usesJsonResponseTool && toolUse.name === 'json';
|
|
783
|
+
|
|
784
|
+
const normalizedToolCallId = normalizeToolCallId(
|
|
785
|
+
toolUse.toolUseId!,
|
|
786
|
+
isMistral,
|
|
787
|
+
);
|
|
788
|
+
contentBlocks[blockIndex] = {
|
|
789
|
+
type: 'tool-call',
|
|
790
|
+
toolCallId: normalizedToolCallId,
|
|
791
|
+
toolName: toolUse.name!,
|
|
792
|
+
jsonText: '',
|
|
793
|
+
isJsonResponseTool,
|
|
794
|
+
};
|
|
795
|
+
|
|
796
|
+
// when this specific tool is the json response tool, we don't emit tool events
|
|
797
|
+
if (!isJsonResponseTool) {
|
|
798
|
+
controller.enqueue({
|
|
799
|
+
type: 'tool-input-start',
|
|
800
|
+
id: normalizedToolCallId,
|
|
801
|
+
toolName: toolUse.name!,
|
|
802
|
+
});
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
const contentBlockDelta = value.contentBlockDelta;
|
|
807
|
+
if (
|
|
808
|
+
contentBlockDelta?.delta &&
|
|
809
|
+
'toolUse' in contentBlockDelta.delta &&
|
|
810
|
+
contentBlockDelta.delta.toolUse
|
|
811
|
+
) {
|
|
812
|
+
const blockIndex = contentBlockDelta.contentBlockIndex!;
|
|
813
|
+
const contentBlock = contentBlocks[blockIndex];
|
|
814
|
+
|
|
815
|
+
if (contentBlock?.type === 'tool-call') {
|
|
816
|
+
const delta = contentBlockDelta.delta.toolUse.input ?? '';
|
|
817
|
+
|
|
818
|
+
// when this specific tool is the json response tool, we don't emit tool events
|
|
819
|
+
if (!contentBlock.isJsonResponseTool) {
|
|
820
|
+
controller.enqueue({
|
|
821
|
+
type: 'tool-input-delta',
|
|
822
|
+
id: contentBlock.toolCallId,
|
|
823
|
+
delta: delta,
|
|
824
|
+
});
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
contentBlock.jsonText += delta;
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
},
|
|
831
|
+
flush(controller) {
|
|
832
|
+
// Update provider metadata with isJsonResponseFromTool and stopSequence if needed
|
|
833
|
+
if (isJsonResponseFromTool || stopSequence != null) {
|
|
834
|
+
if (providerMetadata) {
|
|
835
|
+
providerMetadata.bedrock = {
|
|
836
|
+
...providerMetadata.bedrock,
|
|
837
|
+
...(isJsonResponseFromTool && {
|
|
838
|
+
isJsonResponseFromTool: true,
|
|
839
|
+
}),
|
|
840
|
+
stopSequence,
|
|
841
|
+
};
|
|
842
|
+
} else {
|
|
843
|
+
providerMetadata = {
|
|
844
|
+
bedrock: {
|
|
845
|
+
...(isJsonResponseFromTool && {
|
|
846
|
+
isJsonResponseFromTool: true,
|
|
847
|
+
}),
|
|
848
|
+
stopSequence,
|
|
849
|
+
},
|
|
850
|
+
};
|
|
851
|
+
}
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
controller.enqueue({
|
|
855
|
+
type: 'finish',
|
|
856
|
+
finishReason,
|
|
857
|
+
usage: convertBedrockUsage(usage),
|
|
858
|
+
...(providerMetadata && { providerMetadata }),
|
|
859
|
+
});
|
|
860
|
+
},
|
|
861
|
+
}),
|
|
862
|
+
),
|
|
863
|
+
// TODO request?
|
|
864
|
+
response: { headers: responseHeaders },
|
|
865
|
+
};
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
private getUrl(modelId: string) {
|
|
869
|
+
const encodedModelId = encodeURIComponent(modelId);
|
|
870
|
+
return `${this.config.baseUrl()}/model/${encodedModelId}`;
|
|
871
|
+
}
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
const BedrockStopReasonSchema = z.union([
|
|
875
|
+
z.enum(BEDROCK_STOP_REASONS),
|
|
876
|
+
z.string(),
|
|
877
|
+
]);
|
|
878
|
+
|
|
879
|
+
const BedrockAdditionalModelResponseFieldsSchema = z
|
|
880
|
+
.object({
|
|
881
|
+
delta: z
|
|
882
|
+
.object({
|
|
883
|
+
stop_sequence: z.string().nullish(),
|
|
884
|
+
})
|
|
885
|
+
.nullish(),
|
|
886
|
+
})
|
|
887
|
+
.catchall(z.unknown());
|
|
888
|
+
|
|
889
|
+
const BedrockToolUseSchema = z.object({
|
|
890
|
+
toolUseId: z.string(),
|
|
891
|
+
name: z.string(),
|
|
892
|
+
input: z.unknown(),
|
|
893
|
+
});
|
|
894
|
+
|
|
895
|
+
const BedrockReasoningTextSchema = z.object({
|
|
896
|
+
signature: z.string().nullish(),
|
|
897
|
+
text: z.string(),
|
|
898
|
+
});
|
|
899
|
+
|
|
900
|
+
const BedrockRedactedReasoningSchema = z.object({
|
|
901
|
+
data: z.string(),
|
|
902
|
+
});
|
|
903
|
+
|
|
904
|
+
// limited version of the schema, focused on what is needed for the implementation
|
|
905
|
+
// this approach limits breakages when the API changes and increases efficiency
|
|
906
|
+
const BedrockResponseSchema = z.object({
|
|
907
|
+
metrics: z
|
|
908
|
+
.object({
|
|
909
|
+
latencyMs: z.number(),
|
|
910
|
+
})
|
|
911
|
+
.nullish(),
|
|
912
|
+
output: z.object({
|
|
913
|
+
message: z.object({
|
|
914
|
+
content: z.array(
|
|
915
|
+
z.object({
|
|
916
|
+
text: z.string().nullish(),
|
|
917
|
+
toolUse: BedrockToolUseSchema.nullish(),
|
|
918
|
+
reasoningContent: z
|
|
919
|
+
.union([
|
|
920
|
+
z.object({
|
|
921
|
+
reasoningText: BedrockReasoningTextSchema,
|
|
922
|
+
}),
|
|
923
|
+
z.object({
|
|
924
|
+
redactedReasoning: BedrockRedactedReasoningSchema,
|
|
925
|
+
}),
|
|
926
|
+
])
|
|
927
|
+
.nullish(),
|
|
928
|
+
}),
|
|
929
|
+
),
|
|
930
|
+
role: z.string(),
|
|
931
|
+
}),
|
|
932
|
+
}),
|
|
933
|
+
stopReason: BedrockStopReasonSchema,
|
|
934
|
+
additionalModelResponseFields:
|
|
935
|
+
BedrockAdditionalModelResponseFieldsSchema.nullish(),
|
|
936
|
+
trace: z.unknown().nullish(),
|
|
937
|
+
usage: z.object({
|
|
938
|
+
inputTokens: z.number(),
|
|
939
|
+
outputTokens: z.number(),
|
|
940
|
+
totalTokens: z.number(),
|
|
941
|
+
cacheReadInputTokens: z.number().nullish(),
|
|
942
|
+
cacheWriteInputTokens: z.number().nullish(),
|
|
943
|
+
}),
|
|
944
|
+
});
|
|
945
|
+
|
|
946
|
+
// limited version of the schema, focussed on what is needed for the implementation
|
|
947
|
+
// this approach limits breakages when the API changes and increases efficiency
|
|
948
|
+
const BedrockStreamSchema = z.object({
|
|
949
|
+
contentBlockDelta: z
|
|
950
|
+
.object({
|
|
951
|
+
contentBlockIndex: z.number(),
|
|
952
|
+
delta: z
|
|
953
|
+
.union([
|
|
954
|
+
z.object({ text: z.string() }),
|
|
955
|
+
z.object({ toolUse: z.object({ input: z.string() }) }),
|
|
956
|
+
z.object({
|
|
957
|
+
reasoningContent: z.object({ text: z.string() }),
|
|
958
|
+
}),
|
|
959
|
+
z.object({
|
|
960
|
+
reasoningContent: z.object({
|
|
961
|
+
signature: z.string(),
|
|
962
|
+
}),
|
|
963
|
+
}),
|
|
964
|
+
z.object({
|
|
965
|
+
reasoningContent: z.object({ data: z.string() }),
|
|
966
|
+
}),
|
|
967
|
+
])
|
|
968
|
+
.nullish(),
|
|
969
|
+
})
|
|
970
|
+
.nullish(),
|
|
971
|
+
contentBlockStart: z
|
|
972
|
+
.object({
|
|
973
|
+
contentBlockIndex: z.number(),
|
|
974
|
+
start: z
|
|
975
|
+
.object({
|
|
976
|
+
toolUse: BedrockToolUseSchema.nullish(),
|
|
977
|
+
})
|
|
978
|
+
.nullish(),
|
|
979
|
+
})
|
|
980
|
+
.nullish(),
|
|
981
|
+
contentBlockStop: z
|
|
982
|
+
.object({
|
|
983
|
+
contentBlockIndex: z.number(),
|
|
984
|
+
})
|
|
985
|
+
.nullish(),
|
|
986
|
+
internalServerException: z.record(z.string(), z.unknown()).nullish(),
|
|
987
|
+
messageStop: z
|
|
988
|
+
.object({
|
|
989
|
+
additionalModelResponseFields:
|
|
990
|
+
BedrockAdditionalModelResponseFieldsSchema.nullish(),
|
|
991
|
+
stopReason: BedrockStopReasonSchema,
|
|
992
|
+
})
|
|
993
|
+
.nullish(),
|
|
994
|
+
metadata: z
|
|
995
|
+
.object({
|
|
996
|
+
trace: z.unknown().nullish(),
|
|
997
|
+
usage: z
|
|
998
|
+
.object({
|
|
999
|
+
cacheReadInputTokens: z.number().nullish(),
|
|
1000
|
+
cacheWriteInputTokens: z.number().nullish(),
|
|
1001
|
+
inputTokens: z.number(),
|
|
1002
|
+
outputTokens: z.number(),
|
|
1003
|
+
})
|
|
1004
|
+
.nullish(),
|
|
1005
|
+
})
|
|
1006
|
+
.nullish(),
|
|
1007
|
+
modelStreamErrorException: z.record(z.string(), z.unknown()).nullish(),
|
|
1008
|
+
throttlingException: z.record(z.string(), z.unknown()).nullish(),
|
|
1009
|
+
validationException: z.record(z.string(), z.unknown()).nullish(),
|
|
1010
|
+
});
|
|
1011
|
+
|
|
1012
|
+
export const bedrockReasoningMetadataSchema = z.object({
|
|
1013
|
+
signature: z.string().optional(),
|
|
1014
|
+
redactedData: z.string().optional(),
|
|
1015
|
+
});
|
|
1016
|
+
|
|
1017
|
+
export type BedrockReasoningMetadata = z.infer<
|
|
1018
|
+
typeof bedrockReasoningMetadataSchema
|
|
1019
|
+
>;
|