@ai-sdk/amazon-bedrock 5.0.0-beta.8 → 5.0.0-beta.85

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.
Files changed (56) hide show
  1. package/CHANGELOG.md +669 -4
  2. package/README.md +2 -0
  3. package/dist/anthropic/index.d.ts +10 -10
  4. package/dist/anthropic/index.js +151 -117
  5. package/dist/anthropic/index.js.map +1 -1
  6. package/dist/index.d.ts +36 -23
  7. package/dist/index.js +881 -604
  8. package/dist/index.js.map +1 -1
  9. package/dist/mantle/index.cjs +253 -0
  10. package/dist/mantle/index.cjs.map +1 -0
  11. package/dist/mantle/index.d.cts +99 -0
  12. package/dist/mantle/index.d.ts +99 -0
  13. package/dist/mantle/index.js +240 -0
  14. package/dist/mantle/index.js.map +1 -0
  15. package/docs/08-amazon-bedrock.mdx +310 -84
  16. package/mantle/index.d.ts +1 -0
  17. package/package.json +27 -20
  18. package/src/amazon-bedrock-api-types.ts +228 -0
  19. package/src/{bedrock-chat-options.ts → amazon-bedrock-chat-language-model-options.ts} +27 -8
  20. package/src/{bedrock-chat-language-model.ts → amazon-bedrock-chat-language-model.ts} +350 -180
  21. package/src/{bedrock-embedding-options.ts → amazon-bedrock-embedding-model-options.ts} +1 -1
  22. package/src/{bedrock-embedding-model.ts → amazon-bedrock-embedding-model.ts} +61 -29
  23. package/src/{bedrock-error.ts → amazon-bedrock-error.ts} +1 -1
  24. package/src/{bedrock-event-stream-decoder.ts → amazon-bedrock-event-stream-decoder.ts} +1 -1
  25. package/src/{bedrock-event-stream-response-handler.ts → amazon-bedrock-event-stream-response-handler.ts} +6 -6
  26. package/src/{bedrock-image-model.ts → amazon-bedrock-image-model.ts} +62 -38
  27. package/src/amazon-bedrock-image-settings.ts +9 -0
  28. package/src/{bedrock-prepare-tools.ts → amazon-bedrock-prepare-tools.ts} +22 -18
  29. package/src/{bedrock-provider.ts → amazon-bedrock-provider.ts} +53 -46
  30. package/src/amazon-bedrock-reasoning-metadata.ts +10 -0
  31. package/src/{bedrock-sigv4-fetch.ts → amazon-bedrock-sigv4-fetch.ts} +17 -9
  32. package/src/anthropic/amazon-bedrock-anthropic-fetch.ts +104 -0
  33. package/src/anthropic/{bedrock-anthropic-options.ts → amazon-bedrock-anthropic-options.ts} +7 -1
  34. package/src/anthropic/{bedrock-anthropic-provider.ts → amazon-bedrock-anthropic-provider.ts} +40 -24
  35. package/src/anthropic/index.ts +19 -7
  36. package/src/{convert-bedrock-usage.ts → convert-amazon-bedrock-usage.ts} +4 -4
  37. package/src/convert-to-amazon-bedrock-chat-messages.ts +556 -0
  38. package/src/index.ts +15 -8
  39. package/src/inject-fetch-headers.ts +1 -1
  40. package/src/mantle/bedrock-mantle-options.ts +15 -0
  41. package/src/mantle/bedrock-mantle-provider.ts +283 -0
  42. package/src/mantle/index.ts +6 -0
  43. package/src/{map-bedrock-finish-reason.ts → map-amazon-bedrock-finish-reason.ts} +4 -4
  44. package/src/reranking/{bedrock-reranking-api.ts → amazon-bedrock-reranking-api.ts} +3 -3
  45. package/src/reranking/{bedrock-reranking-options.ts → amazon-bedrock-reranking-model-options.ts} +1 -1
  46. package/src/reranking/{bedrock-reranking-model.ts → amazon-bedrock-reranking-model.ts} +32 -25
  47. package/dist/anthropic/index.d.mts +0 -91
  48. package/dist/anthropic/index.mjs +0 -397
  49. package/dist/anthropic/index.mjs.map +0 -1
  50. package/dist/index.d.mts +0 -194
  51. package/dist/index.mjs +0 -2329
  52. package/dist/index.mjs.map +0 -1
  53. package/src/anthropic/bedrock-anthropic-fetch.ts +0 -68
  54. package/src/bedrock-api-types.ts +0 -216
  55. package/src/bedrock-image-settings.ts +0 -6
  56. package/src/convert-to-bedrock-chat-messages.ts +0 -468
@@ -1,216 +0,0 @@
1
- import { JSONObject } from '@ai-sdk/provider';
2
-
3
- export interface BedrockConverseInput {
4
- system?: BedrockSystemMessages;
5
- messages: BedrockMessages;
6
- toolConfig?: BedrockToolConfiguration;
7
- inferenceConfig?: {
8
- maxOutputTokens?: number;
9
- temperature?: number;
10
- topP?: number;
11
- topK?: number;
12
- stopSequences?: string[];
13
- };
14
- additionalModelRequestFields?: Record<string, unknown>;
15
- additionalModelResponseFieldPaths?: string[];
16
- guardrailConfig?:
17
- | BedrockGuardrailConfiguration
18
- | BedrockGuardrailStreamConfiguration
19
- | undefined;
20
- }
21
-
22
- export type BedrockSystemMessages = Array<BedrockSystemContentBlock>;
23
-
24
- export type BedrockMessages = Array<
25
- BedrockAssistantMessage | BedrockUserMessage
26
- >;
27
-
28
- export interface BedrockAssistantMessage {
29
- role: 'assistant';
30
- content: Array<BedrockContentBlock>;
31
- }
32
-
33
- export interface BedrockUserMessage {
34
- role: 'user';
35
- content: Array<BedrockContentBlock>;
36
- }
37
-
38
- /**
39
- * Cache TTL options for Bedrock prompt caching.
40
- * @see https://docs.aws.amazon.com/bedrock/latest/userguide/prompt-caching.html
41
- *
42
- * - '5m': 5-minute TTL (default, supported by all models)
43
- * - '1h': 1-hour TTL (supported by Claude Opus 4.5, Claude Haiku 4.5, Claude Sonnet 4.5)
44
- */
45
- export type BedrockCacheTTL = '5m' | '1h';
46
-
47
- export type BedrockCachePoint = {
48
- cachePoint: { type: 'default'; ttl?: BedrockCacheTTL };
49
- };
50
-
51
- /**
52
- * Creates a cache point with an optional TTL.
53
- * @param ttl - Cache TTL ('5m' or '1h'). If not provided, uses the default 5-minute TTL.
54
- */
55
- export function createBedrockCachePoint(
56
- ttl?: BedrockCacheTTL,
57
- ): BedrockCachePoint {
58
- return {
59
- cachePoint: { type: 'default', ttl },
60
- };
61
- }
62
-
63
- export type BedrockSystemContentBlock = { text: string } | BedrockCachePoint;
64
-
65
- export interface BedrockGuardrailConfiguration {
66
- guardrails?: Array<{
67
- name: string;
68
- description?: string;
69
- parameters?: Record<string, unknown>;
70
- }>;
71
- }
72
-
73
- export type BedrockGuardrailStreamConfiguration = BedrockGuardrailConfiguration;
74
-
75
- export interface BedrockToolInputSchema {
76
- json: Record<string, unknown>;
77
- }
78
-
79
- export interface BedrockTool {
80
- toolSpec: {
81
- name: string;
82
- description?: string;
83
- strict?: boolean;
84
- inputSchema: { json: JSONObject };
85
- };
86
- }
87
-
88
- export interface BedrockToolConfiguration {
89
- tools?: Array<BedrockTool | BedrockCachePoint>;
90
- toolChoice?:
91
- | { tool: { name: string } }
92
- | { auto: {} }
93
- | { any: {} }
94
- | undefined;
95
- }
96
-
97
- export const BEDROCK_STOP_REASONS = [
98
- 'stop',
99
- 'stop_sequence',
100
- 'end_turn',
101
- 'length',
102
- 'max_tokens',
103
- 'content-filter',
104
- 'content_filtered',
105
- 'guardrail_intervened',
106
- 'tool-calls',
107
- 'tool_use',
108
- ] as const;
109
-
110
- export type BedrockStopReason = (typeof BEDROCK_STOP_REASONS)[number];
111
-
112
- /**
113
- * @see https://docs.aws.amazon.com/bedrock/latest/APIReference/API_runtime_ImageBlock.html
114
- */
115
- export const BEDROCK_IMAGE_MIME_TYPES = {
116
- 'image/jpeg': 'jpeg',
117
- 'image/png': 'png',
118
- 'image/gif': 'gif',
119
- 'image/webp': 'webp',
120
- } as const;
121
- type BedrockImageFormats = typeof BEDROCK_IMAGE_MIME_TYPES;
122
- export type BedrockImageFormat = BedrockImageFormats[keyof BedrockImageFormats];
123
- export type BedrockImageMimeType = keyof BedrockImageFormats;
124
-
125
- /**
126
- * @see https://docs.aws.amazon.com/bedrock/latest/APIReference/API_runtime_DocumentBlock.html
127
- */
128
- export const BEDROCK_DOCUMENT_MIME_TYPES = {
129
- 'application/pdf': 'pdf',
130
- 'text/csv': 'csv',
131
- 'application/msword': 'doc',
132
- 'application/vnd.openxmlformats-officedocument.wordprocessingml.document':
133
- 'docx',
134
- 'application/vnd.ms-excel': 'xls',
135
- 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': 'xlsx',
136
- 'text/html': 'html',
137
- 'text/plain': 'txt',
138
- 'text/markdown': 'md',
139
- } as const;
140
- type BedrockDocumentFormats = typeof BEDROCK_DOCUMENT_MIME_TYPES;
141
- export type BedrockDocumentFormat =
142
- BedrockDocumentFormats[keyof BedrockDocumentFormats];
143
- export type BedrockDocumentMimeType = keyof BedrockDocumentFormats;
144
-
145
- export interface BedrockDocumentBlock {
146
- document: {
147
- format: BedrockDocumentFormat;
148
- name: string;
149
- source: {
150
- bytes: string;
151
- };
152
- citations?: {
153
- enabled: boolean;
154
- };
155
- };
156
- }
157
-
158
- export interface BedrockGuardrailConverseContentBlock {
159
- guardContent: unknown;
160
- }
161
-
162
- export interface BedrockImageBlock {
163
- image: {
164
- format: BedrockImageFormat;
165
- source: {
166
- bytes: string;
167
- };
168
- };
169
- }
170
-
171
- export interface BedrockToolResultBlock {
172
- toolResult: {
173
- toolUseId: string;
174
- content: Array<BedrockTextBlock | BedrockImageBlock>;
175
- };
176
- }
177
-
178
- export interface BedrockToolUseBlock {
179
- toolUse: {
180
- toolUseId: string;
181
- name: string;
182
- input: Record<string, unknown>;
183
- };
184
- }
185
-
186
- export interface BedrockTextBlock {
187
- text: string;
188
- }
189
-
190
- export interface BedrockReasoningContentBlock {
191
- reasoningContent: {
192
- reasoningText: {
193
- text: string;
194
- signature?: string;
195
- };
196
- };
197
- }
198
-
199
- export interface BedrockRedactedReasoningContentBlock {
200
- reasoningContent: {
201
- redactedReasoning: {
202
- data: string;
203
- };
204
- };
205
- }
206
-
207
- export type BedrockContentBlock =
208
- | BedrockDocumentBlock
209
- | BedrockGuardrailConverseContentBlock
210
- | BedrockImageBlock
211
- | BedrockTextBlock
212
- | BedrockToolResultBlock
213
- | BedrockToolUseBlock
214
- | BedrockReasoningContentBlock
215
- | BedrockRedactedReasoningContentBlock
216
- | BedrockCachePoint;
@@ -1,6 +0,0 @@
1
- export type BedrockImageModelId = 'amazon.nova-canvas-v1:0' | (string & {});
2
-
3
- // https://docs.aws.amazon.com/nova/latest/userguide/image-gen-req-resp-structure.html
4
- export const modelMaxImagesPerCall: Record<BedrockImageModelId, number> = {
5
- 'amazon.nova-canvas-v1:0': 5,
6
- };
@@ -1,468 +0,0 @@
1
- import {
2
- JSONObject,
3
- LanguageModelV4Message,
4
- LanguageModelV4Prompt,
5
- SharedV4ProviderMetadata,
6
- UnsupportedFunctionalityError,
7
- } from '@ai-sdk/provider';
8
- import {
9
- convertToBase64,
10
- parseProviderOptions,
11
- stripFileExtension,
12
- } from '@ai-sdk/provider-utils';
13
- import {
14
- BEDROCK_DOCUMENT_MIME_TYPES,
15
- BEDROCK_IMAGE_MIME_TYPES,
16
- BedrockAssistantMessage,
17
- BedrockCachePoint,
18
- BedrockDocumentFormat,
19
- BedrockDocumentMimeType,
20
- BedrockImageFormat,
21
- BedrockImageMimeType,
22
- BedrockMessages,
23
- BedrockSystemMessages,
24
- BedrockUserMessage,
25
- } from './bedrock-api-types';
26
- import { bedrockReasoningMetadataSchema } from './bedrock-chat-language-model';
27
- import { bedrockFilePartProviderOptions } from './bedrock-chat-options';
28
- import { normalizeToolCallId } from './normalize-tool-call-id';
29
-
30
- function getCachePoint(
31
- providerMetadata: SharedV4ProviderMetadata | undefined,
32
- ): BedrockCachePoint | undefined {
33
- const cachePointConfig = providerMetadata?.bedrock?.cachePoint as
34
- | BedrockCachePoint['cachePoint']
35
- | undefined;
36
-
37
- if (!cachePointConfig) {
38
- return undefined;
39
- }
40
-
41
- return { cachePoint: cachePointConfig };
42
- }
43
-
44
- async function shouldEnableCitations(
45
- providerMetadata: SharedV4ProviderMetadata | undefined,
46
- ): Promise<boolean> {
47
- const bedrockOptions = await parseProviderOptions({
48
- provider: 'bedrock',
49
- providerOptions: providerMetadata,
50
- schema: bedrockFilePartProviderOptions,
51
- });
52
-
53
- return bedrockOptions?.citations?.enabled ?? false;
54
- }
55
-
56
- export async function convertToBedrockChatMessages(
57
- prompt: LanguageModelV4Prompt,
58
- isMistral: boolean = false,
59
- ): Promise<{
60
- system: BedrockSystemMessages;
61
- messages: BedrockMessages;
62
- }> {
63
- const blocks = groupIntoBlocks(prompt);
64
-
65
- let system: BedrockSystemMessages = [];
66
- const messages: BedrockMessages = [];
67
-
68
- let documentCounter = 0;
69
- const generateDocumentName = () => `document-${++documentCounter}`;
70
-
71
- for (let i = 0; i < blocks.length; i++) {
72
- const block = blocks[i];
73
- const isLastBlock = i === blocks.length - 1;
74
- const type = block.type;
75
-
76
- switch (type) {
77
- case 'system': {
78
- if (messages.length > 0) {
79
- throw new UnsupportedFunctionalityError({
80
- functionality:
81
- 'Multiple system messages that are separated by user/assistant messages',
82
- });
83
- }
84
-
85
- for (const message of block.messages) {
86
- system.push({ text: message.content });
87
- const cachePoint = getCachePoint(message.providerOptions);
88
- if (cachePoint) {
89
- system.push(cachePoint);
90
- }
91
- }
92
- break;
93
- }
94
-
95
- case 'user': {
96
- // combines all user and tool messages in this block into a single message:
97
- const bedrockContent: BedrockUserMessage['content'] = [];
98
-
99
- for (const message of block.messages) {
100
- const { role, content, providerOptions } = message;
101
- switch (role) {
102
- case 'user': {
103
- for (let j = 0; j < content.length; j++) {
104
- const part = content[j];
105
-
106
- switch (part.type) {
107
- case 'text': {
108
- bedrockContent.push({
109
- text: part.text,
110
- });
111
- break;
112
- }
113
-
114
- case 'file': {
115
- if (part.data instanceof URL) {
116
- // The AI SDK automatically downloads files for user file parts with URLs
117
- throw new UnsupportedFunctionalityError({
118
- functionality: 'File URL data',
119
- });
120
- }
121
-
122
- if (part.mediaType.startsWith('image/')) {
123
- bedrockContent.push({
124
- image: {
125
- format: getBedrockImageFormat(part.mediaType),
126
- source: { bytes: convertToBase64(part.data) },
127
- },
128
- });
129
- } else {
130
- if (!part.mediaType) {
131
- throw new UnsupportedFunctionalityError({
132
- functionality: 'file without mime type',
133
- message:
134
- 'File mime type is required in user message part content',
135
- });
136
- }
137
-
138
- const enableCitations = await shouldEnableCitations(
139
- part.providerOptions,
140
- );
141
-
142
- bedrockContent.push({
143
- document: {
144
- format: getBedrockDocumentFormat(part.mediaType),
145
- name: part.filename
146
- ? stripFileExtension(part.filename)
147
- : generateDocumentName(),
148
- source: { bytes: convertToBase64(part.data) },
149
- ...(enableCitations && {
150
- citations: { enabled: true },
151
- }),
152
- },
153
- });
154
- }
155
-
156
- break;
157
- }
158
- }
159
- }
160
-
161
- break;
162
- }
163
- case 'tool': {
164
- for (const part of content) {
165
- if (part.type === 'tool-approval-response') {
166
- continue;
167
- }
168
- let toolResultContent;
169
-
170
- const output = part.output;
171
- switch (output.type) {
172
- case 'content': {
173
- toolResultContent = output.value.map(contentPart => {
174
- switch (contentPart.type) {
175
- case 'text':
176
- return { text: contentPart.text };
177
- case 'image-data':
178
- if (!contentPart.mediaType.startsWith('image/')) {
179
- throw new UnsupportedFunctionalityError({
180
- functionality: `media type: ${contentPart.mediaType}`,
181
- });
182
- }
183
-
184
- const format = getBedrockImageFormat(
185
- contentPart.mediaType,
186
- );
187
-
188
- return {
189
- image: {
190
- format,
191
- source: { bytes: contentPart.data },
192
- },
193
- };
194
- default: {
195
- throw new UnsupportedFunctionalityError({
196
- functionality: `unsupported tool content part type: ${contentPart.type}`,
197
- });
198
- }
199
- }
200
- });
201
- break;
202
- }
203
- case 'text':
204
- case 'error-text':
205
- toolResultContent = [{ text: output.value }];
206
- break;
207
- case 'execution-denied':
208
- toolResultContent = [
209
- { text: output.reason ?? 'Tool execution denied.' },
210
- ];
211
- break;
212
- case 'json':
213
- case 'error-json':
214
- default:
215
- toolResultContent = [
216
- { text: JSON.stringify(output.value) },
217
- ];
218
- break;
219
- }
220
-
221
- bedrockContent.push({
222
- toolResult: {
223
- toolUseId: normalizeToolCallId(part.toolCallId, isMistral),
224
- content: toolResultContent,
225
- },
226
- });
227
- }
228
-
229
- break;
230
- }
231
- default: {
232
- const _exhaustiveCheck: never = role;
233
- throw new Error(`Unsupported role: ${_exhaustiveCheck}`);
234
- }
235
- }
236
-
237
- const cachePoint = getCachePoint(providerOptions);
238
- if (cachePoint) {
239
- bedrockContent.push(cachePoint);
240
- }
241
- }
242
-
243
- messages.push({ role: 'user', content: bedrockContent });
244
-
245
- break;
246
- }
247
-
248
- case 'assistant': {
249
- // combines multiple assistant messages in this block into a single message:
250
- const bedrockContent: BedrockAssistantMessage['content'] = [];
251
-
252
- for (let j = 0; j < block.messages.length; j++) {
253
- const message = block.messages[j];
254
- const isLastMessage = j === block.messages.length - 1;
255
- const { content } = message;
256
-
257
- for (let k = 0; k < content.length; k++) {
258
- const part = content[k];
259
- const isLastContentPart = k === content.length - 1;
260
-
261
- switch (part.type) {
262
- case 'text': {
263
- // Skip empty text blocks
264
- if (!part.text.trim()) {
265
- break;
266
- }
267
-
268
- bedrockContent.push({
269
- text:
270
- // trim the last text part if it's the last message in the block
271
- // because Bedrock does not allow trailing whitespace
272
- // in pre-filled assistant responses
273
- trimIfLast(
274
- isLastBlock,
275
- isLastMessage,
276
- isLastContentPart,
277
- part.text,
278
- ),
279
- });
280
- break;
281
- }
282
-
283
- case 'reasoning': {
284
- const reasoningMetadata = await parseProviderOptions({
285
- provider: 'bedrock',
286
- providerOptions: part.providerOptions,
287
- schema: bedrockReasoningMetadataSchema,
288
- });
289
-
290
- if (reasoningMetadata != null) {
291
- if (reasoningMetadata.signature != null) {
292
- bedrockContent.push({
293
- reasoningContent: {
294
- reasoningText: {
295
- // trim the last text part if it's the last message in the block
296
- // because Bedrock does not allow trailing whitespace
297
- // in pre-filled assistant responses
298
- text: trimIfLast(
299
- isLastBlock,
300
- isLastMessage,
301
- isLastContentPart,
302
- part.text,
303
- ),
304
- signature: reasoningMetadata.signature,
305
- },
306
- },
307
- });
308
- } else if (reasoningMetadata.redactedData != null) {
309
- bedrockContent.push({
310
- reasoningContent: {
311
- redactedReasoning: {
312
- data: reasoningMetadata.redactedData,
313
- },
314
- },
315
- });
316
- }
317
- }
318
-
319
- break;
320
- }
321
-
322
- case 'tool-call': {
323
- bedrockContent.push({
324
- toolUse: {
325
- toolUseId: normalizeToolCallId(part.toolCallId, isMistral),
326
- name: part.toolName,
327
- input: part.input as JSONObject,
328
- },
329
- });
330
- break;
331
- }
332
- }
333
- }
334
- const cachePoint = getCachePoint(message.providerOptions);
335
- if (cachePoint) {
336
- bedrockContent.push(cachePoint);
337
- }
338
- }
339
-
340
- messages.push({ role: 'assistant', content: bedrockContent });
341
-
342
- break;
343
- }
344
-
345
- default: {
346
- const _exhaustiveCheck: never = type;
347
- throw new Error(`Unsupported type: ${_exhaustiveCheck}`);
348
- }
349
- }
350
- }
351
-
352
- return { system, messages };
353
- }
354
-
355
- function isBedrockImageFormat(format: string): format is BedrockImageFormat {
356
- return Object.values(BEDROCK_IMAGE_MIME_TYPES).includes(
357
- format as BedrockImageFormat,
358
- );
359
- }
360
-
361
- function getBedrockImageFormat(mimeType?: string): BedrockImageFormat {
362
- if (!mimeType) {
363
- throw new UnsupportedFunctionalityError({
364
- functionality: 'image without mime type',
365
- message: 'Image mime type is required in user message part content',
366
- });
367
- }
368
-
369
- const format = BEDROCK_IMAGE_MIME_TYPES[mimeType as BedrockImageMimeType];
370
- if (!format) {
371
- throw new UnsupportedFunctionalityError({
372
- functionality: `image mime type: ${mimeType}`,
373
- message: `Unsupported image mime type: ${mimeType}, expected one of: ${Object.keys(BEDROCK_IMAGE_MIME_TYPES).join(', ')}`,
374
- });
375
- }
376
-
377
- return format;
378
- }
379
-
380
- function getBedrockDocumentFormat(mimeType: string): BedrockDocumentFormat {
381
- const format =
382
- BEDROCK_DOCUMENT_MIME_TYPES[mimeType as BedrockDocumentMimeType];
383
- if (!format) {
384
- throw new UnsupportedFunctionalityError({
385
- functionality: `file mime type: ${mimeType}`,
386
- message: `Unsupported file mime type: ${mimeType}, expected one of: ${Object.keys(BEDROCK_DOCUMENT_MIME_TYPES).join(', ')}`,
387
- });
388
- }
389
- return format;
390
- }
391
-
392
- function trimIfLast(
393
- isLastBlock: boolean,
394
- isLastMessage: boolean,
395
- isLastContentPart: boolean,
396
- text: string,
397
- ) {
398
- return isLastBlock && isLastMessage && isLastContentPart ? text.trim() : text;
399
- }
400
-
401
- type SystemBlock = {
402
- type: 'system';
403
- messages: Array<LanguageModelV4Message & { role: 'system' }>;
404
- };
405
- type AssistantBlock = {
406
- type: 'assistant';
407
- messages: Array<LanguageModelV4Message & { role: 'assistant' }>;
408
- };
409
- type UserBlock = {
410
- type: 'user';
411
- messages: Array<LanguageModelV4Message & { role: 'user' | 'tool' }>;
412
- };
413
-
414
- function groupIntoBlocks(
415
- prompt: LanguageModelV4Prompt,
416
- ): Array<SystemBlock | AssistantBlock | UserBlock> {
417
- const blocks: Array<SystemBlock | AssistantBlock | UserBlock> = [];
418
- let currentBlock: SystemBlock | AssistantBlock | UserBlock | undefined =
419
- undefined;
420
-
421
- for (const message of prompt) {
422
- const { role } = message;
423
- switch (role) {
424
- case 'system': {
425
- if (currentBlock?.type !== 'system') {
426
- currentBlock = { type: 'system', messages: [] };
427
- blocks.push(currentBlock);
428
- }
429
-
430
- currentBlock.messages.push(message);
431
- break;
432
- }
433
- case 'assistant': {
434
- if (currentBlock?.type !== 'assistant') {
435
- currentBlock = { type: 'assistant', messages: [] };
436
- blocks.push(currentBlock);
437
- }
438
-
439
- currentBlock.messages.push(message);
440
- break;
441
- }
442
- case 'user': {
443
- if (currentBlock?.type !== 'user') {
444
- currentBlock = { type: 'user', messages: [] };
445
- blocks.push(currentBlock);
446
- }
447
-
448
- currentBlock.messages.push(message);
449
- break;
450
- }
451
- case 'tool': {
452
- if (currentBlock?.type !== 'user') {
453
- currentBlock = { type: 'user', messages: [] };
454
- blocks.push(currentBlock);
455
- }
456
-
457
- currentBlock.messages.push(message);
458
- break;
459
- }
460
- default: {
461
- const _exhaustiveCheck: never = role;
462
- throw new Error(`Unsupported role: ${_exhaustiveCheck}`);
463
- }
464
- }
465
- }
466
-
467
- return blocks;
468
- }