@ai-sdk/amazon-bedrock 4.0.0-beta.61 → 4.0.0-beta.62

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 CHANGED
@@ -1,5 +1,30 @@
1
1
  # @ai-sdk/amazon-bedrock
2
2
 
3
+ ## 4.0.0-beta.62
4
+
5
+ ### Patch Changes
6
+
7
+ - 88b2c7e: feat(provider/amazon-bedrock,provider/google-vertex-anthropic): add support for tool calling with structured output
8
+
9
+ Added support for combining tool calling with structured outputs in both Amazon Bedrock and Google Vertex Anthropic providers. This allows developers to use tools (like weather lookups, web search, etc.) alongside structured JSON output schemas, enabling multi-step agentic workflows with structured final outputs.
10
+
11
+ **Amazon Bedrock Changes:**
12
+
13
+ - Removed incorrect warning that prevented using tools with JSON response format
14
+ - Updated tool choice to use `{ type: 'required' }` instead of specific tool selection when using structured outputs
15
+ - Added `isJsonResponseFromTool` parameter to finish reason mapping
16
+ - JSON tool responses are correctly converted to text content and finish reason is mapped from `tool_use` to `stop`
17
+ - Added comprehensive test coverage for combining tools with structured outputs
18
+ - Added example files demonstrating the feature
19
+
20
+ **Google Vertex Anthropic Changes:**
21
+
22
+ - Inherits support from underlying Anthropic provider implementation
23
+ - Added test coverage to verify the feature works correctly
24
+ - Added example files demonstrating the feature
25
+
26
+ This brings Anthropic provider's structured output capabilities to the Amazon Bedrock and Google Vertex Anthropic providers.
27
+
3
28
  ## 4.0.0-beta.61
4
29
 
5
30
  ### Patch Changes
package/dist/index.js CHANGED
@@ -654,7 +654,7 @@ function groupIntoBlocks(prompt) {
654
654
  }
655
655
 
656
656
  // src/map-bedrock-finish-reason.ts
657
- function mapBedrockFinishReason(finishReason) {
657
+ function mapBedrockFinishReason(finishReason, isJsonResponseFromTool) {
658
658
  switch (finishReason) {
659
659
  case "stop_sequence":
660
660
  case "end_turn":
@@ -665,7 +665,7 @@ function mapBedrockFinishReason(finishReason) {
665
665
  case "guardrail_intervened":
666
666
  return "content-filter";
667
667
  case "tool_use":
668
- return "tool-calls";
668
+ return isJsonResponseFromTool ? "stop" : "tool-calls";
669
669
  default:
670
670
  return "unknown";
671
671
  }
@@ -744,14 +744,6 @@ var BedrockChatLanguageModel = class {
744
744
  details: "Only text and json response formats are supported."
745
745
  });
746
746
  }
747
- if (tools != null && (responseFormat == null ? void 0 : responseFormat.type) === "json") {
748
- if (tools.length > 0) {
749
- warnings.push({
750
- type: "other",
751
- message: "JSON response format does not support tools. The provided tools are ignored."
752
- });
753
- }
754
- }
755
747
  const jsonResponseTool = (responseFormat == null ? void 0 : responseFormat.type) === "json" && responseFormat.schema != null ? {
756
748
  type: "function",
757
749
  name: "json",
@@ -759,8 +751,8 @@ var BedrockChatLanguageModel = class {
759
751
  inputSchema: responseFormat.schema
760
752
  } : void 0;
761
753
  const { toolConfig, additionalTools, toolWarnings, betas } = await prepareTools({
762
- tools: jsonResponseTool ? [jsonResponseTool, ...tools != null ? tools : []] : tools,
763
- toolChoice: jsonResponseTool != null ? { type: "tool", toolName: jsonResponseTool.name } : toolChoice,
754
+ tools: jsonResponseTool ? [...tools != null ? tools : [], jsonResponseTool] : tools,
755
+ toolChoice: jsonResponseTool != null ? { type: "required" } : toolChoice,
764
756
  modelId: this.modelId
765
757
  });
766
758
  warnings.push(...toolWarnings);
@@ -904,11 +896,10 @@ var BedrockChatLanguageModel = class {
904
896
  fetch: this.config.fetch
905
897
  });
906
898
  const content = [];
899
+ let isJsonResponseFromTool = false;
907
900
  for (const part of response.output.message.content) {
908
901
  if (part.text) {
909
- if (!usesJsonResponseTool) {
910
- content.push({ type: "text", text: part.text });
911
- }
902
+ content.push({ type: "text", text: part.text });
912
903
  }
913
904
  if (part.reasoningContent) {
914
905
  if ("reasoningText" in part.reasoningContent) {
@@ -937,21 +928,24 @@ var BedrockChatLanguageModel = class {
937
928
  }
938
929
  }
939
930
  if (part.toolUse) {
940
- content.push(
941
- // when a json response tool is used, the tool call becomes the text:
942
- usesJsonResponseTool ? {
931
+ const isJsonResponseTool = usesJsonResponseTool && part.toolUse.name === "json";
932
+ if (isJsonResponseTool) {
933
+ isJsonResponseFromTool = true;
934
+ content.push({
943
935
  type: "text",
944
936
  text: JSON.stringify(part.toolUse.input)
945
- } : {
937
+ });
938
+ } else {
939
+ content.push({
946
940
  type: "tool-call",
947
941
  toolCallId: (_c = (_b = part.toolUse) == null ? void 0 : _b.toolUseId) != null ? _c : this.config.generateId(),
948
942
  toolName: (_e = (_d = part.toolUse) == null ? void 0 : _d.name) != null ? _e : `tool-${this.config.generateId()}`,
949
943
  input: JSON.stringify((_g = (_f = part.toolUse) == null ? void 0 : _f.input) != null ? _g : "")
950
- }
951
- );
944
+ });
945
+ }
952
946
  }
953
947
  }
954
- const providerMetadata = response.trace || response.usage || usesJsonResponseTool ? {
948
+ const providerMetadata = response.trace || response.usage || isJsonResponseFromTool ? {
955
949
  bedrock: {
956
950
  ...response.trace && typeof response.trace === "object" ? { trace: response.trace } : {},
957
951
  ...((_h = response.usage) == null ? void 0 : _h.cacheWriteInputTokens) != null && {
@@ -959,13 +953,14 @@ var BedrockChatLanguageModel = class {
959
953
  cacheWriteInputTokens: response.usage.cacheWriteInputTokens
960
954
  }
961
955
  },
962
- ...usesJsonResponseTool && { isJsonResponseFromTool: true }
956
+ ...isJsonResponseFromTool && { isJsonResponseFromTool: true }
963
957
  }
964
958
  } : void 0;
965
959
  return {
966
960
  content,
967
961
  finishReason: mapBedrockFinishReason(
968
- response.stopReason
962
+ response.stopReason,
963
+ isJsonResponseFromTool
969
964
  ),
970
965
  usage: {
971
966
  inputTokens: (_i = response.usage) == null ? void 0 : _i.inputTokens,
@@ -1007,6 +1002,7 @@ var BedrockChatLanguageModel = class {
1007
1002
  totalTokens: void 0
1008
1003
  };
1009
1004
  let providerMetadata = void 0;
1005
+ let isJsonResponseFromTool = false;
1010
1006
  const contentBlocks = {};
1011
1007
  return {
1012
1008
  stream: response.pipeThrough(
@@ -1046,7 +1042,8 @@ var BedrockChatLanguageModel = class {
1046
1042
  }
1047
1043
  if (value.messageStop) {
1048
1044
  finishReason = mapBedrockFinishReason(
1049
- value.messageStop.stopReason
1045
+ value.messageStop.stopReason,
1046
+ isJsonResponseFromTool
1050
1047
  );
1051
1048
  }
1052
1049
  if (value.metadata) {
@@ -1062,14 +1059,11 @@ var BedrockChatLanguageModel = class {
1062
1059
  const trace = value.metadata.trace ? {
1063
1060
  trace: value.metadata.trace
1064
1061
  } : void 0;
1065
- if (cacheUsage || trace || usesJsonResponseTool) {
1062
+ if (cacheUsage || trace) {
1066
1063
  providerMetadata = {
1067
1064
  bedrock: {
1068
1065
  ...cacheUsage,
1069
- ...trace,
1070
- ...usesJsonResponseTool && {
1071
- isJsonResponseFromTool: true
1072
- }
1066
+ ...trace
1073
1067
  }
1074
1068
  };
1075
1069
  }
@@ -1086,20 +1080,16 @@ var BedrockChatLanguageModel = class {
1086
1080
  const blockIndex = value.contentBlockDelta.contentBlockIndex || 0;
1087
1081
  if (contentBlocks[blockIndex] == null) {
1088
1082
  contentBlocks[blockIndex] = { type: "text" };
1089
- if (!usesJsonResponseTool) {
1090
- controller.enqueue({
1091
- type: "text-start",
1092
- id: String(blockIndex)
1093
- });
1094
- }
1095
- }
1096
- if (!usesJsonResponseTool) {
1097
1083
  controller.enqueue({
1098
- type: "text-delta",
1099
- id: String(blockIndex),
1100
- delta: value.contentBlockDelta.delta.text
1084
+ type: "text-start",
1085
+ id: String(blockIndex)
1101
1086
  });
1102
1087
  }
1088
+ controller.enqueue({
1089
+ type: "text-delta",
1090
+ id: String(blockIndex),
1091
+ delta: value.contentBlockDelta.delta.text
1092
+ });
1103
1093
  }
1104
1094
  if (((_n = value.contentBlockStop) == null ? void 0 : _n.contentBlockIndex) != null) {
1105
1095
  const blockIndex = value.contentBlockStop.contentBlockIndex;
@@ -1111,14 +1101,13 @@ var BedrockChatLanguageModel = class {
1111
1101
  id: String(blockIndex)
1112
1102
  });
1113
1103
  } else if (contentBlock.type === "text") {
1114
- if (!usesJsonResponseTool) {
1115
- controller.enqueue({
1116
- type: "text-end",
1117
- id: String(blockIndex)
1118
- });
1119
- }
1104
+ controller.enqueue({
1105
+ type: "text-end",
1106
+ id: String(blockIndex)
1107
+ });
1120
1108
  } else if (contentBlock.type === "tool-call") {
1121
- if (usesJsonResponseTool) {
1109
+ if (contentBlock.isJsonResponseTool) {
1110
+ isJsonResponseFromTool = true;
1122
1111
  controller.enqueue({
1123
1112
  type: "text-start",
1124
1113
  id: String(blockIndex)
@@ -1192,13 +1181,15 @@ var BedrockChatLanguageModel = class {
1192
1181
  if (((_p = contentBlockStart == null ? void 0 : contentBlockStart.start) == null ? void 0 : _p.toolUse) != null) {
1193
1182
  const toolUse = contentBlockStart.start.toolUse;
1194
1183
  const blockIndex = contentBlockStart.contentBlockIndex;
1184
+ const isJsonResponseTool = usesJsonResponseTool && toolUse.name === "json";
1195
1185
  contentBlocks[blockIndex] = {
1196
1186
  type: "tool-call",
1197
1187
  toolCallId: toolUse.toolUseId,
1198
1188
  toolName: toolUse.name,
1199
- jsonText: ""
1189
+ jsonText: "",
1190
+ isJsonResponseTool
1200
1191
  };
1201
- if (!usesJsonResponseTool) {
1192
+ if (!isJsonResponseTool) {
1202
1193
  controller.enqueue({
1203
1194
  type: "tool-input-start",
1204
1195
  id: toolUse.toolUseId,
@@ -1212,7 +1203,7 @@ var BedrockChatLanguageModel = class {
1212
1203
  const contentBlock = contentBlocks[blockIndex];
1213
1204
  if ((contentBlock == null ? void 0 : contentBlock.type) === "tool-call") {
1214
1205
  const delta = (_q = contentBlockDelta.delta.toolUse.input) != null ? _q : "";
1215
- if (!usesJsonResponseTool) {
1206
+ if (!contentBlock.isJsonResponseTool) {
1216
1207
  controller.enqueue({
1217
1208
  type: "tool-input-delta",
1218
1209
  id: contentBlock.toolCallId,
@@ -1224,6 +1215,20 @@ var BedrockChatLanguageModel = class {
1224
1215
  }
1225
1216
  },
1226
1217
  flush(controller) {
1218
+ if (isJsonResponseFromTool) {
1219
+ if (providerMetadata) {
1220
+ providerMetadata.bedrock = {
1221
+ ...providerMetadata.bedrock,
1222
+ isJsonResponseFromTool: true
1223
+ };
1224
+ } else {
1225
+ providerMetadata = {
1226
+ bedrock: {
1227
+ isJsonResponseFromTool: true
1228
+ }
1229
+ };
1230
+ }
1231
+ }
1227
1232
  controller.enqueue({
1228
1233
  type: "finish",
1229
1234
  finishReason,
@@ -1531,7 +1536,7 @@ var import_provider_utils7 = require("@ai-sdk/provider-utils");
1531
1536
  var import_aws4fetch = require("aws4fetch");
1532
1537
 
1533
1538
  // src/version.ts
1534
- var VERSION = true ? "4.0.0-beta.61" : "0.0.0-test";
1539
+ var VERSION = true ? "4.0.0-beta.62" : "0.0.0-test";
1535
1540
 
1536
1541
  // src/bedrock-sigv4-fetch.ts
1537
1542
  function createSigV4FetchFunction(getCredentials, fetch = globalThis.fetch) {