@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.
Files changed (67) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/anthropic/index.js +1 -1
  3. package/dist/anthropic/index.mjs +1 -1
  4. package/dist/index.js +1 -1
  5. package/dist/index.mjs +1 -1
  6. package/docs/08-amazon-bedrock.mdx +1453 -0
  7. package/package.json +11 -6
  8. package/src/__fixtures__/bedrock-json-only-text-first.1.chunks.txt +7 -0
  9. package/src/__fixtures__/bedrock-json-other-tool.1.chunks.txt +6 -0
  10. package/src/__fixtures__/bedrock-json-other-tool.1.json +24 -0
  11. package/src/__fixtures__/bedrock-json-tool-text-then-weather-then-json.1.chunks.txt +12 -0
  12. package/src/__fixtures__/bedrock-json-tool-with-answer.1.json +29 -0
  13. package/src/__fixtures__/bedrock-json-tool.1.chunks.txt +4 -0
  14. package/src/__fixtures__/bedrock-json-tool.1.json +35 -0
  15. package/src/__fixtures__/bedrock-json-tool.2.chunks.txt +6 -0
  16. package/src/__fixtures__/bedrock-json-tool.2.json +28 -0
  17. package/src/__fixtures__/bedrock-json-tool.3.chunks.txt +7 -0
  18. package/src/__fixtures__/bedrock-json-tool.3.json +36 -0
  19. package/src/__fixtures__/bedrock-json-with-tool.1.chunks.txt +9 -0
  20. package/src/__fixtures__/bedrock-json-with-tool.1.json +41 -0
  21. package/src/__fixtures__/bedrock-json-with-tools.1.chunks.txt +12 -0
  22. package/src/__fixtures__/bedrock-json-with-tools.1.json +50 -0
  23. package/src/__fixtures__/bedrock-tool-call.1.chunks.txt +6 -0
  24. package/src/__fixtures__/bedrock-tool-call.1.json +24 -0
  25. package/src/__fixtures__/bedrock-tool-no-args.chunks.txt +8 -0
  26. package/src/__fixtures__/bedrock-tool-no-args.json +25 -0
  27. package/src/anthropic/bedrock-anthropic-fetch.test.ts +344 -0
  28. package/src/anthropic/bedrock-anthropic-fetch.ts +62 -0
  29. package/src/anthropic/bedrock-anthropic-options.ts +28 -0
  30. package/src/anthropic/bedrock-anthropic-provider.test.ts +456 -0
  31. package/src/anthropic/bedrock-anthropic-provider.ts +357 -0
  32. package/src/anthropic/index.ts +9 -0
  33. package/src/bedrock-api-types.ts +195 -0
  34. package/src/bedrock-chat-language-model.test.ts +4569 -0
  35. package/src/bedrock-chat-language-model.ts +1019 -0
  36. package/src/bedrock-chat-options.ts +114 -0
  37. package/src/bedrock-embedding-model.test.ts +148 -0
  38. package/src/bedrock-embedding-model.ts +104 -0
  39. package/src/bedrock-embedding-options.ts +24 -0
  40. package/src/bedrock-error.ts +6 -0
  41. package/src/bedrock-event-stream-decoder.ts +59 -0
  42. package/src/bedrock-event-stream-response-handler.test.ts +233 -0
  43. package/src/bedrock-event-stream-response-handler.ts +57 -0
  44. package/src/bedrock-image-model.test.ts +866 -0
  45. package/src/bedrock-image-model.ts +297 -0
  46. package/src/bedrock-image-settings.ts +6 -0
  47. package/src/bedrock-prepare-tools.ts +190 -0
  48. package/src/bedrock-provider.test.ts +457 -0
  49. package/src/bedrock-provider.ts +351 -0
  50. package/src/bedrock-sigv4-fetch.test.ts +675 -0
  51. package/src/bedrock-sigv4-fetch.ts +138 -0
  52. package/src/convert-bedrock-usage.test.ts +207 -0
  53. package/src/convert-bedrock-usage.ts +50 -0
  54. package/src/convert-to-bedrock-chat-messages.test.ts +1175 -0
  55. package/src/convert-to-bedrock-chat-messages.ts +452 -0
  56. package/src/index.ts +10 -0
  57. package/src/inject-fetch-headers.test.ts +135 -0
  58. package/src/inject-fetch-headers.ts +32 -0
  59. package/src/map-bedrock-finish-reason.ts +22 -0
  60. package/src/normalize-tool-call-id.test.ts +72 -0
  61. package/src/normalize-tool-call-id.ts +36 -0
  62. package/src/reranking/__fixtures__/bedrock-reranking.1.json +12 -0
  63. package/src/reranking/bedrock-reranking-api.ts +44 -0
  64. package/src/reranking/bedrock-reranking-model.test.ts +299 -0
  65. package/src/reranking/bedrock-reranking-model.ts +115 -0
  66. package/src/reranking/bedrock-reranking-options.ts +36 -0
  67. package/src/version.ts +6 -0
@@ -0,0 +1,457 @@
1
+ import { describe, it, expect, vi, beforeEach, Mock } from 'vitest';
2
+ import { createAmazonBedrock } from './bedrock-provider';
3
+ import { BedrockChatLanguageModel } from './bedrock-chat-language-model';
4
+ import { BedrockEmbeddingModel } from './bedrock-embedding-model';
5
+ import { BedrockImageModel } from './bedrock-image-model';
6
+ import { anthropicTools } from '@ai-sdk/anthropic/internal';
7
+
8
+ // Add type assertions for the mocked classes
9
+ const BedrockChatLanguageModelMock =
10
+ BedrockChatLanguageModel as unknown as Mock;
11
+ const BedrockEmbeddingModelMock = BedrockEmbeddingModel as unknown as Mock;
12
+ const BedrockImageModelMock = BedrockImageModel as unknown as Mock;
13
+
14
+ vi.mock('./bedrock-chat-language-model', () => ({
15
+ BedrockChatLanguageModel: vi.fn(),
16
+ }));
17
+
18
+ vi.mock('./bedrock-embedding-model', () => ({
19
+ BedrockEmbeddingModel: vi.fn(),
20
+ }));
21
+
22
+ vi.mock('./bedrock-image-model', () => ({
23
+ BedrockImageModel: vi.fn(),
24
+ }));
25
+
26
+ vi.mock('./bedrock-sigv4-fetch', () => ({
27
+ createSigV4FetchFunction: vi.fn(),
28
+ createApiKeyFetchFunction: vi.fn(),
29
+ }));
30
+
31
+ vi.mock('@ai-sdk/anthropic', async importOriginal => {
32
+ const original = await importOriginal<typeof import('@ai-sdk/anthropic')>();
33
+ return {
34
+ ...original,
35
+ anthropicTools: { mock: 'tools' },
36
+ prepareTools: vi.fn(),
37
+ };
38
+ });
39
+
40
+ vi.mock('@ai-sdk/provider-utils', async importOriginal => {
41
+ const original =
42
+ await importOriginal<typeof import('@ai-sdk/provider-utils')>();
43
+ return {
44
+ ...original,
45
+ loadSetting: vi
46
+ .fn()
47
+ .mockImplementation(({ settingValue }) => settingValue || 'us-east-1'),
48
+ loadOptionalSetting: vi
49
+ .fn()
50
+ .mockImplementation(({ settingValue }) => settingValue),
51
+ withoutTrailingSlash: vi.fn(url => url),
52
+ generateId: vi.fn().mockReturnValue('mock-id'),
53
+ createJsonErrorResponseHandler: vi.fn(),
54
+ createJsonResponseHandler: vi.fn(),
55
+ postJsonToApi: vi.fn(),
56
+ resolve: vi.fn(val => Promise.resolve(val)),
57
+ combineHeaders: vi.fn((...headers) => Object.assign({}, ...headers)),
58
+ parseProviderOptions: vi.fn(),
59
+ asSchema: vi.fn(schema => ({ jsonSchema: schema })),
60
+ };
61
+ });
62
+
63
+ vi.mock('./version', () => ({
64
+ VERSION: '0.0.0-test',
65
+ }));
66
+
67
+ // Import mocked modules to get references
68
+ import {
69
+ createSigV4FetchFunction,
70
+ createApiKeyFetchFunction,
71
+ } from './bedrock-sigv4-fetch';
72
+ import { loadOptionalSetting } from '@ai-sdk/provider-utils';
73
+
74
+ const mockCreateSigV4FetchFunction = vi.mocked(createSigV4FetchFunction);
75
+ const mockCreateApiKeyFetchFunction = vi.mocked(createApiKeyFetchFunction);
76
+ const mockLoadOptionalSetting = vi.mocked(loadOptionalSetting);
77
+
78
+ describe('AmazonBedrockProvider', () => {
79
+ beforeEach(() => {
80
+ vi.clearAllMocks();
81
+ // Reset mock implementations
82
+ mockCreateSigV4FetchFunction.mockReturnValue(vi.fn());
83
+ mockCreateApiKeyFetchFunction.mockReturnValue(vi.fn());
84
+ mockLoadOptionalSetting.mockImplementation(
85
+ ({ settingValue }) => settingValue,
86
+ );
87
+ });
88
+
89
+ describe('createAmazonBedrock', () => {
90
+ it('should create a provider instance with default options', () => {
91
+ const provider = createAmazonBedrock();
92
+ const model = provider('anthropic.claude-v2');
93
+
94
+ const constructorCall = BedrockChatLanguageModelMock.mock.calls[0];
95
+ expect(constructorCall[0]).toBe('anthropic.claude-v2');
96
+ expect(constructorCall[1].headers()).toMatchObject({});
97
+ expect(constructorCall[1].headers()['user-agent']).toContain(
98
+ 'ai-sdk/amazon-bedrock/0.0.0-test',
99
+ );
100
+ expect(constructorCall[1].baseUrl()).toBe(
101
+ 'https://bedrock-runtime.us-east-1.amazonaws.com',
102
+ );
103
+ });
104
+
105
+ it('should create a provider instance with custom options', () => {
106
+ const customHeaders = { 'custom-header': 'value' };
107
+ const options = {
108
+ region: 'eu-west-1',
109
+ baseURL: 'https://custom.url',
110
+ headers: customHeaders,
111
+ };
112
+
113
+ const provider = createAmazonBedrock(options);
114
+ provider('anthropic.claude-v2');
115
+
116
+ const constructorCall = BedrockChatLanguageModelMock.mock.calls[0];
117
+ expect(constructorCall[1].headers()).toMatchObject(customHeaders);
118
+ expect(constructorCall[1].headers()['user-agent']).toContain(
119
+ 'ai-sdk/amazon-bedrock/0.0.0-test',
120
+ );
121
+ expect(constructorCall[1].baseUrl()).toBe('https://custom.url');
122
+ });
123
+
124
+ it('should accept a credentialProvider in options', () => {
125
+ const mockCredentialProvider = vi.fn().mockResolvedValue({
126
+ accessKeyId: 'dynamic-access-key',
127
+ secretAccessKey: 'dynamic-secret-key',
128
+ sessionToken: 'dynamic-session-token',
129
+ });
130
+
131
+ const provider = createAmazonBedrock({
132
+ credentialProvider: mockCredentialProvider,
133
+ });
134
+
135
+ provider('anthropic.claude-v2');
136
+
137
+ const constructorCall = BedrockChatLanguageModelMock.mock.calls[0];
138
+ expect(constructorCall[0]).toBe('anthropic.claude-v2');
139
+ expect(constructorCall[1].headers()).toMatchObject({});
140
+ expect(constructorCall[1].headers()['user-agent']).toContain(
141
+ 'ai-sdk/amazon-bedrock/0.0.0-test',
142
+ );
143
+ expect(constructorCall[1].baseUrl()).toBe(
144
+ 'https://bedrock-runtime.us-east-1.amazonaws.com',
145
+ );
146
+ });
147
+
148
+ it('should prioritize credentialProvider over static credentials', () => {
149
+ const mockCredentialProvider = vi.fn().mockResolvedValue({
150
+ accessKeyId: 'dynamic-access-key',
151
+ secretAccessKey: 'dynamic-secret-key',
152
+ sessionToken: 'dynamic-session-token',
153
+ });
154
+
155
+ const provider = createAmazonBedrock({
156
+ accessKeyId: 'static-access-key',
157
+ secretAccessKey: 'static-secret-key',
158
+ sessionToken: 'static-session-token',
159
+ credentialProvider: mockCredentialProvider,
160
+ });
161
+
162
+ provider('anthropic.claude-v2');
163
+ const constructorCall = BedrockChatLanguageModelMock.mock.calls[0];
164
+ expect(constructorCall[0]).toBe('anthropic.claude-v2');
165
+ });
166
+
167
+ it('should pass headers to embedding model', () => {
168
+ const customHeaders = { 'custom-header': 'value' };
169
+ const provider = createAmazonBedrock({
170
+ headers: customHeaders,
171
+ });
172
+
173
+ provider.embedding('amazon.titan-embed-text-v1');
174
+
175
+ const constructorCall = BedrockEmbeddingModelMock.mock.calls[0];
176
+ expect(constructorCall[1].headers()).toMatchObject(customHeaders);
177
+ expect(constructorCall[1].headers()['user-agent']).toContain(
178
+ 'ai-sdk/amazon-bedrock/0.0.0-test',
179
+ );
180
+ });
181
+
182
+ it('should throw error when called with new keyword', () => {
183
+ const provider = createAmazonBedrock();
184
+ expect(() => {
185
+ new (provider as any)();
186
+ }).toThrow(
187
+ 'The Amazon Bedrock model function cannot be called with the new keyword.',
188
+ );
189
+ });
190
+
191
+ describe('API Key Authentication', () => {
192
+ it('should use API key when provided in options', () => {
193
+ const provider = createAmazonBedrock({
194
+ apiKey: 'test-api-key',
195
+ region: 'us-east-1',
196
+ });
197
+
198
+ // Verify that createApiKeyFetchFunction was called with the correct API key
199
+ expect(mockCreateApiKeyFetchFunction).toHaveBeenCalledWith(
200
+ 'test-api-key',
201
+ undefined, // fetch function
202
+ );
203
+ expect(mockCreateSigV4FetchFunction).not.toHaveBeenCalled();
204
+
205
+ provider('anthropic.claude-v2');
206
+
207
+ const constructorCall = BedrockChatLanguageModelMock.mock.calls[0];
208
+ expect(constructorCall[0]).toBe('anthropic.claude-v2');
209
+ expect(constructorCall[1].headers()).toMatchObject({});
210
+ expect(constructorCall[1].headers()['user-agent']).toContain(
211
+ 'ai-sdk/amazon-bedrock/',
212
+ );
213
+ expect(constructorCall[1].baseUrl()).toBe(
214
+ 'https://bedrock-runtime.us-east-1.amazonaws.com',
215
+ );
216
+ });
217
+
218
+ it('should use API key from environment variable', () => {
219
+ // Mock loadOptionalSetting to return environment variable value
220
+ mockLoadOptionalSetting.mockImplementation(
221
+ ({ settingValue, environmentVariableName }) => {
222
+ if (environmentVariableName === 'AWS_BEARER_TOKEN_BEDROCK') {
223
+ return 'env-api-key';
224
+ }
225
+ return settingValue;
226
+ },
227
+ );
228
+
229
+ const provider = createAmazonBedrock({
230
+ region: 'us-east-1',
231
+ });
232
+
233
+ // Verify that createApiKeyFetchFunction was called with the environment variable value
234
+ expect(mockCreateApiKeyFetchFunction).toHaveBeenCalledWith(
235
+ 'env-api-key',
236
+ undefined,
237
+ );
238
+ expect(mockCreateSigV4FetchFunction).not.toHaveBeenCalled();
239
+ });
240
+
241
+ it('should prioritize options.apiKey over environment variable', () => {
242
+ // Mock loadOptionalSetting to return environment variable value when no settingValue
243
+ mockLoadOptionalSetting.mockImplementation(
244
+ ({ settingValue, environmentVariableName }) => {
245
+ if (settingValue) {
246
+ return settingValue;
247
+ }
248
+ if (environmentVariableName === 'AWS_BEARER_TOKEN_BEDROCK') {
249
+ return 'env-api-key';
250
+ }
251
+ return undefined;
252
+ },
253
+ );
254
+
255
+ const provider = createAmazonBedrock({
256
+ apiKey: 'options-api-key',
257
+ region: 'us-east-1',
258
+ });
259
+
260
+ // Verify that options.apiKey takes precedence
261
+ expect(mockCreateApiKeyFetchFunction).toHaveBeenCalledWith(
262
+ 'options-api-key',
263
+ undefined,
264
+ );
265
+ expect(mockCreateSigV4FetchFunction).not.toHaveBeenCalled();
266
+ });
267
+
268
+ it('should fall back to SigV4 when no API key provided', () => {
269
+ // Mock loadOptionalSetting to return undefined (no API key)
270
+ mockLoadOptionalSetting.mockImplementation(() => undefined);
271
+
272
+ const provider = createAmazonBedrock({
273
+ region: 'us-east-1',
274
+ accessKeyId: 'test-access-key',
275
+ secretAccessKey: 'test-secret-key',
276
+ });
277
+
278
+ // Verify that SigV4 authentication is used as fallback
279
+ expect(mockCreateApiKeyFetchFunction).not.toHaveBeenCalled();
280
+ expect(mockCreateSigV4FetchFunction).toHaveBeenCalled();
281
+
282
+ provider('anthropic.claude-v2');
283
+
284
+ const constructorCall = BedrockChatLanguageModelMock.mock.calls[0];
285
+ expect(constructorCall[0]).toBe('anthropic.claude-v2');
286
+ });
287
+
288
+ it('should pass custom fetch function to API key authentication', () => {
289
+ const customFetch = vi.fn();
290
+
291
+ const provider = createAmazonBedrock({
292
+ apiKey: 'test-api-key',
293
+ region: 'us-east-1',
294
+ fetch: customFetch,
295
+ });
296
+
297
+ // Verify that custom fetch function is passed to createApiKeyFetchFunction
298
+ expect(mockCreateApiKeyFetchFunction).toHaveBeenCalledWith(
299
+ 'test-api-key',
300
+ customFetch,
301
+ );
302
+ });
303
+
304
+ it('should pass custom fetch function to SigV4 authentication', () => {
305
+ // Mock loadOptionalSetting to return undefined (no API key)
306
+ mockLoadOptionalSetting.mockImplementation(() => undefined);
307
+
308
+ const customFetch = vi.fn();
309
+
310
+ const provider = createAmazonBedrock({
311
+ region: 'us-east-1',
312
+ accessKeyId: 'test-access-key',
313
+ secretAccessKey: 'test-secret-key',
314
+ fetch: customFetch,
315
+ });
316
+
317
+ // Verify that custom fetch function is passed to createSigV4FetchFunction
318
+ expect(mockCreateSigV4FetchFunction).toHaveBeenCalledWith(
319
+ expect.any(Function), // credentials function
320
+ customFetch,
321
+ );
322
+ });
323
+
324
+ it('should work with embedding models when using API key', () => {
325
+ const provider = createAmazonBedrock({
326
+ apiKey: 'test-api-key',
327
+ region: 'us-east-1',
328
+ headers: { 'custom-header': 'value' },
329
+ });
330
+
331
+ provider.embedding('amazon.titan-embed-text-v1');
332
+
333
+ const constructorCall = BedrockEmbeddingModelMock.mock.calls[0];
334
+ expect(constructorCall[0]).toBe('amazon.titan-embed-text-v1');
335
+ expect(constructorCall[1].headers()).toMatchObject({
336
+ 'custom-header': 'value',
337
+ });
338
+ expect(constructorCall[1].headers()['user-agent']).toContain(
339
+ 'ai-sdk/amazon-bedrock/0.0.0-test',
340
+ );
341
+ expect(mockCreateApiKeyFetchFunction).toHaveBeenCalledWith(
342
+ 'test-api-key',
343
+ undefined,
344
+ );
345
+ });
346
+
347
+ it('should work with image models when using API key', () => {
348
+ const provider = createAmazonBedrock({
349
+ apiKey: 'test-api-key',
350
+ region: 'us-east-1',
351
+ headers: { 'custom-header': 'value' },
352
+ });
353
+
354
+ provider.image('amazon.titan-image-generator');
355
+
356
+ const constructorCall = BedrockImageModelMock.mock.calls[0];
357
+ expect(constructorCall[0]).toBe('amazon.titan-image-generator');
358
+ expect(constructorCall[1].headers()).toMatchObject({
359
+ 'custom-header': 'value',
360
+ });
361
+ expect(constructorCall[1].headers()['user-agent']).toContain(
362
+ 'ai-sdk/amazon-bedrock/0.0.0-test',
363
+ );
364
+ expect(mockCreateApiKeyFetchFunction).toHaveBeenCalledWith(
365
+ 'test-api-key',
366
+ undefined,
367
+ );
368
+ });
369
+
370
+ it('should maintain backward compatibility with existing SigV4 authentication', () => {
371
+ // Mock loadOptionalSetting to return undefined (no API key)
372
+ mockLoadOptionalSetting.mockImplementation(() => undefined);
373
+
374
+ const provider = createAmazonBedrock({
375
+ region: 'eu-west-1',
376
+ accessKeyId: 'test-access-key',
377
+ secretAccessKey: 'test-secret-key',
378
+ sessionToken: 'test-session-token',
379
+ });
380
+
381
+ provider('anthropic.claude-v2');
382
+
383
+ // Verify SigV4 is used when no API key is provided
384
+ expect(mockCreateSigV4FetchFunction).toHaveBeenCalled();
385
+ expect(mockCreateApiKeyFetchFunction).not.toHaveBeenCalled();
386
+
387
+ const constructorCall = BedrockChatLanguageModelMock.mock.calls[0];
388
+ expect(constructorCall[0]).toBe('anthropic.claude-v2');
389
+ expect(constructorCall[1].baseUrl()).toBe(
390
+ 'https://bedrock-runtime.eu-west-1.amazonaws.com',
391
+ );
392
+ });
393
+
394
+ it('should work with credential provider when no API key is provided', () => {
395
+ // Mock loadOptionalSetting to return undefined (no API key)
396
+ mockLoadOptionalSetting.mockImplementation(() => undefined);
397
+
398
+ const mockCredentialProvider = vi.fn().mockResolvedValue({
399
+ accessKeyId: 'dynamic-access-key',
400
+ secretAccessKey: 'dynamic-secret-key',
401
+ sessionToken: 'dynamic-session-token',
402
+ });
403
+
404
+ const provider = createAmazonBedrock({
405
+ region: 'us-east-1',
406
+ credentialProvider: mockCredentialProvider,
407
+ });
408
+
409
+ provider('anthropic.claude-v2');
410
+
411
+ // Verify SigV4 is used with credential provider when no API key
412
+ expect(mockCreateSigV4FetchFunction).toHaveBeenCalled();
413
+ expect(mockCreateApiKeyFetchFunction).not.toHaveBeenCalled();
414
+ });
415
+ });
416
+ });
417
+
418
+ describe('provider methods', () => {
419
+ it('should create an embedding model', () => {
420
+ const provider = createAmazonBedrock();
421
+ const modelId = 'amazon.titan-embed-text-v1';
422
+
423
+ const model = provider.embedding(modelId);
424
+
425
+ const constructorCall = BedrockEmbeddingModelMock.mock.calls[0];
426
+ expect(constructorCall[0]).toBe(modelId);
427
+ expect(model).toBeInstanceOf(BedrockEmbeddingModel);
428
+ });
429
+
430
+ it('should create an image model', () => {
431
+ const provider = createAmazonBedrock();
432
+ const modelId = 'amazon.titan-image-generator';
433
+
434
+ const model = provider.image(modelId);
435
+
436
+ const constructorCall = BedrockImageModelMock.mock.calls[0];
437
+ expect(constructorCall[0]).toBe(modelId);
438
+ expect(model).toBeInstanceOf(BedrockImageModel);
439
+ });
440
+
441
+ it('should create an image model via imageModel method', () => {
442
+ const provider = createAmazonBedrock();
443
+ const modelId = 'amazon.titan-image-generator';
444
+
445
+ const model = provider.imageModel(modelId);
446
+
447
+ const constructorCall = BedrockImageModelMock.mock.calls[0];
448
+ expect(constructorCall[0]).toBe(modelId);
449
+ expect(model).toBeInstanceOf(BedrockImageModel);
450
+ });
451
+
452
+ it('should expose anthropicTools', () => {
453
+ const provider = createAmazonBedrock();
454
+ expect(provider.tools).toBe(anthropicTools);
455
+ });
456
+ });
457
+ });