@ai-sdk/amazon-bedrock 4.0.134 → 4.0.136

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.
@@ -35,7 +35,7 @@ var import_provider_utils = require("@ai-sdk/provider-utils");
35
35
  var import_aws4fetch = require("aws4fetch");
36
36
 
37
37
  // src/version.ts
38
- var VERSION = true ? "4.0.134" : "0.0.0-test";
38
+ var VERSION = true ? "4.0.136" : "0.0.0-test";
39
39
 
40
40
  // src/bedrock-sigv4-fetch.ts
41
41
  function createSigV4FetchFunction(getCredentials, fetch, service = "bedrock") {
@@ -23,7 +23,7 @@ import {
23
23
  import { AwsV4Signer } from "aws4fetch";
24
24
 
25
25
  // src/version.ts
26
- var VERSION = true ? "4.0.134" : "0.0.0-test";
26
+ var VERSION = true ? "4.0.136" : "0.0.0-test";
27
27
 
28
28
  // src/bedrock-sigv4-fetch.ts
29
29
  function createSigV4FetchFunction(getCredentials, fetch, service = "bedrock") {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-sdk/amazon-bedrock",
3
- "version": "4.0.134",
3
+ "version": "4.0.136",
4
4
  "license": "Apache-2.0",
5
5
  "sideEffects": false,
6
6
  "main": "./dist/index.js",
@@ -44,10 +44,10 @@
44
44
  "@smithy/eventstream-codec": "^4.0.1",
45
45
  "@smithy/util-utf8": "^4.0.0",
46
46
  "aws4fetch": "^1.0.20",
47
- "@ai-sdk/anthropic": "3.0.96",
48
- "@ai-sdk/openai": "3.0.84",
47
+ "@ai-sdk/openai": "3.0.85",
48
+ "@ai-sdk/anthropic": "3.0.97",
49
49
  "@ai-sdk/provider": "3.0.14",
50
- "@ai-sdk/provider-utils": "4.0.38"
50
+ "@ai-sdk/provider-utils": "4.0.39"
51
51
  },
52
52
  "devDependencies": {
53
53
  "@types/node": "20.17.24",
@@ -16,6 +16,7 @@ import {
16
16
  combineHeaders,
17
17
  createJsonErrorResponseHandler,
18
18
  createJsonResponseHandler,
19
+ injectJsonInstructionIntoMessages,
19
20
  parseProviderOptions,
20
21
  postJsonToApi,
21
22
  resolve,
@@ -78,6 +79,7 @@ export class BedrockChatLanguageModel implements LanguageModelV3 {
78
79
  }: LanguageModelV3CallOptions): Promise<{
79
80
  command: BedrockConverseInput;
80
81
  warnings: SharedV3Warning[];
82
+ usesJsonInstruction: boolean;
81
83
  usesJsonResponseTool: boolean;
82
84
  betas: Set<string>;
83
85
  }> {
@@ -145,16 +147,36 @@ export class BedrockChatLanguageModel implements LanguageModelV3 {
145
147
  bedrockOptions.reasoningConfig?.type === 'enabled' ||
146
148
  bedrockOptions.reasoningConfig?.type === 'adaptive';
147
149
 
150
+ const modelRejectsNativeStructuredOutput =
151
+ this.modelId.includes('claude-opus-4-7') ||
152
+ this.modelId.includes('claude-opus-4-8') ||
153
+ this.modelId.includes('claude-fable-5') ||
154
+ this.modelId.includes('claude-sonnet-5');
155
+
156
+ const modelSupportsStructuredOutput =
157
+ bedrockChatModelSupportsStructuredOutput(this.modelId);
158
+
148
159
  const useNativeStructuredOutput =
149
160
  isAnthropicModel &&
150
- isThinkingEnabled &&
161
+ !modelRejectsNativeStructuredOutput &&
162
+ (modelSupportsStructuredOutput || isThinkingEnabled) &&
151
163
  responseFormat?.type === 'json' &&
152
164
  responseFormat.schema != null;
153
165
 
166
+ const useJsonInstructionForStructuredOutput =
167
+ isAnthropicModel &&
168
+ (this.modelId.includes('claude-opus-4-7') ||
169
+ this.modelId.includes('claude-opus-4-8')) &&
170
+ responseFormat?.type === 'json' &&
171
+ responseFormat.schema != null &&
172
+ tools != null &&
173
+ tools.length > 0;
174
+
154
175
  const jsonResponseTool: LanguageModelV3FunctionTool | undefined =
155
176
  responseFormat?.type === 'json' &&
156
177
  responseFormat.schema != null &&
157
- !useNativeStructuredOutput
178
+ !useNativeStructuredOutput &&
179
+ !useJsonInstructionForStructuredOutput
158
180
  ? {
159
181
  type: 'function',
160
182
  name: 'json',
@@ -367,6 +389,15 @@ export class BedrockChatLanguageModel implements LanguageModelV3 {
367
389
  }
368
390
  }
369
391
 
392
+ if (useJsonInstructionForStructuredOutput) {
393
+ filteredPrompt = injectJsonInstructionIntoMessages({
394
+ messages: filteredPrompt,
395
+ schema: responseFormat!.schema,
396
+ schemaSuffix:
397
+ 'You MUST answer with only a JSON object that matches the JSON schema above. Do not wrap it in markdown fences or include any other text.',
398
+ });
399
+ }
400
+
370
401
  const isMistral = isMistralModel(this.modelId);
371
402
  const { system, messages } = await convertToBedrockChatMessages(
372
403
  filteredPrompt,
@@ -408,6 +439,7 @@ export class BedrockChatLanguageModel implements LanguageModelV3 {
408
439
  : {}),
409
440
  },
410
441
  warnings,
442
+ usesJsonInstruction: useJsonInstructionForStructuredOutput,
411
443
  usesJsonResponseTool: jsonResponseTool != null,
412
444
  betas,
413
445
  };
@@ -431,6 +463,7 @@ export class BedrockChatLanguageModel implements LanguageModelV3 {
431
463
  const {
432
464
  command: args,
433
465
  warnings,
466
+ usesJsonInstruction,
434
467
  usesJsonResponseTool,
435
468
  } = await this.getArgs(options);
436
469
 
@@ -452,12 +485,18 @@ export class BedrockChatLanguageModel implements LanguageModelV3 {
452
485
 
453
486
  const content: Array<LanguageModelV3Content> = [];
454
487
  let isJsonResponseFromTool = false;
488
+ const jsonObjectTextExtractor = usesJsonInstruction
489
+ ? new JsonObjectTextExtractor()
490
+ : undefined;
455
491
 
456
492
  // map response content to content array
457
493
  for (const part of response.output.message.content) {
458
494
  // text
459
495
  if (part.text != null) {
460
- content.push({ type: 'text', text: part.text });
496
+ content.push({
497
+ type: 'text',
498
+ text: jsonObjectTextExtractor?.process(part.text) ?? part.text,
499
+ });
461
500
  }
462
501
 
463
502
  // reasoning
@@ -576,6 +615,7 @@ export class BedrockChatLanguageModel implements LanguageModelV3 {
576
615
  headers: responseHeaders,
577
616
  },
578
617
  warnings,
618
+ request: { body: args },
579
619
  ...(providerMetadata && { providerMetadata }),
580
620
  };
581
621
  }
@@ -586,6 +626,7 @@ export class BedrockChatLanguageModel implements LanguageModelV3 {
586
626
  const {
587
627
  command: args,
588
628
  warnings,
629
+ usesJsonInstruction,
589
630
  usesJsonResponseTool,
590
631
  } = await this.getArgs(options);
591
632
  const modelId = this.modelId;
@@ -614,6 +655,9 @@ export class BedrockChatLanguageModel implements LanguageModelV3 {
614
655
  let providerMetadata: SharedV3ProviderMetadata | undefined = undefined;
615
656
  let isJsonResponseFromTool = false;
616
657
  let stopSequence: string | null = null;
658
+ const jsonObjectTextExtractor = usesJsonInstruction
659
+ ? new JsonObjectTextExtractor()
660
+ : undefined;
617
661
 
618
662
  const contentBlocks: Record<
619
663
  number,
@@ -773,11 +817,18 @@ export class BedrockChatLanguageModel implements LanguageModelV3 {
773
817
  });
774
818
  }
775
819
 
776
- controller.enqueue({
777
- type: 'text-delta',
778
- id: String(blockIndex),
779
- delta: value.contentBlockDelta.delta.text,
780
- });
820
+ const textDelta =
821
+ jsonObjectTextExtractor?.process(
822
+ value.contentBlockDelta.delta.text,
823
+ ) ?? value.contentBlockDelta.delta.text;
824
+
825
+ if (textDelta.length > 0) {
826
+ controller.enqueue({
827
+ type: 'text-delta',
828
+ id: String(blockIndex),
829
+ delta: textDelta,
830
+ });
831
+ }
781
832
  }
782
833
 
783
834
  if (value.contentBlockStop?.contentBlockIndex != null) {
@@ -984,7 +1035,7 @@ export class BedrockChatLanguageModel implements LanguageModelV3 {
984
1035
  },
985
1036
  }),
986
1037
  ),
987
- // TODO request?
1038
+ request: { body: args },
988
1039
  response: { headers: responseHeaders },
989
1040
  };
990
1041
  }
@@ -995,6 +1046,83 @@ export class BedrockChatLanguageModel implements LanguageModelV3 {
995
1046
  }
996
1047
  }
997
1048
 
1049
+ function bedrockChatModelSupportsStructuredOutput(modelId: string): boolean {
1050
+ return (
1051
+ modelId.includes('claude-opus-4-8') ||
1052
+ modelId.includes('claude-opus-4-7') ||
1053
+ modelId.includes('claude-fable-5') ||
1054
+ modelId.includes('claude-sonnet-5') ||
1055
+ modelId.includes('claude-sonnet-4-6') ||
1056
+ modelId.includes('claude-opus-4-6') ||
1057
+ modelId.includes('claude-sonnet-4-5') ||
1058
+ modelId.includes('claude-opus-4-5') ||
1059
+ modelId.includes('claude-haiku-4-5') ||
1060
+ modelId.includes('claude-opus-4-1')
1061
+ );
1062
+ }
1063
+
1064
+ class JsonObjectTextExtractor {
1065
+ private started = false;
1066
+ private completed = false;
1067
+ private depth = 0;
1068
+ private inString = false;
1069
+ private escaped = false;
1070
+
1071
+ process(text: string): string {
1072
+ let result = '';
1073
+
1074
+ for (const character of text) {
1075
+ if (this.completed) {
1076
+ break;
1077
+ }
1078
+
1079
+ if (!this.started) {
1080
+ if (character !== '{') {
1081
+ continue;
1082
+ }
1083
+
1084
+ this.started = true;
1085
+ this.depth = 1;
1086
+ result += character;
1087
+ continue;
1088
+ }
1089
+
1090
+ result += character;
1091
+
1092
+ if (this.escaped) {
1093
+ this.escaped = false;
1094
+ continue;
1095
+ }
1096
+
1097
+ if (character === '\\' && this.inString) {
1098
+ this.escaped = true;
1099
+ continue;
1100
+ }
1101
+
1102
+ if (character === '"') {
1103
+ this.inString = !this.inString;
1104
+ continue;
1105
+ }
1106
+
1107
+ if (this.inString) {
1108
+ continue;
1109
+ }
1110
+
1111
+ if (character === '{') {
1112
+ this.depth++;
1113
+ } else if (character === '}') {
1114
+ this.depth--;
1115
+
1116
+ if (this.depth === 0) {
1117
+ this.completed = true;
1118
+ }
1119
+ }
1120
+ }
1121
+
1122
+ return result;
1123
+ }
1124
+ }
1125
+
998
1126
  const BedrockStopReasonSchema = z.union([
999
1127
  z.enum(BEDROCK_STOP_REASONS),
1000
1128
  z.string(),