@ai-sdk/anthropic 2.0.98 → 2.0.100

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.
@@ -687,7 +687,7 @@ var anthropicProviderOptions = z3.object({
687
687
  * Determines how structured outputs are generated.
688
688
  *
689
689
  * - `outputFormat`: Use the `output_format` parameter to specify the structured output format.
690
- * - `jsonTool`: Use a special 'json' tool to specify the structured output format (default).
690
+ * - `jsonTool`: Use a special JSON response tool to specify the structured output format (default).
691
691
  * - `auto`: Use 'outputFormat' when supported, otherwise use 'jsonTool'.
692
692
  */
693
693
  structuredOutputMode: z3.enum(["outputFormat", "jsonTool", "auto"]).optional(),
@@ -2005,7 +2005,10 @@ async function convertToAnthropicMessagesPrompt({
2005
2005
  }
2006
2006
  }
2007
2007
  }
2008
- messages.push({ role: "assistant", content: anthropicContent });
2008
+ messages.push({
2009
+ role: "assistant",
2010
+ content: moveToolUseBlocksToEnd(anthropicContent)
2011
+ });
2009
2012
  break;
2010
2013
  }
2011
2014
  default: {
@@ -2065,6 +2068,27 @@ function groupIntoBlocks(prompt) {
2065
2068
  }
2066
2069
  return blocks;
2067
2070
  }
2071
+ function moveToolUseBlocksToEnd(content) {
2072
+ const result = [];
2073
+ let segment = [];
2074
+ function flushSegment() {
2075
+ result.push(
2076
+ ...segment.filter((part) => part.type !== "tool_use"),
2077
+ ...segment.filter((part) => part.type === "tool_use")
2078
+ );
2079
+ segment = [];
2080
+ }
2081
+ for (const part of content) {
2082
+ if (part.type === "thinking" || part.type === "redacted_thinking") {
2083
+ flushSegment();
2084
+ result.push(part);
2085
+ } else {
2086
+ segment.push(part);
2087
+ }
2088
+ }
2089
+ flushSegment();
2090
+ return result;
2091
+ }
2068
2092
 
2069
2093
  // src/map-anthropic-stop-reason.ts
2070
2094
  function mapAnthropicStopReason({
@@ -2236,6 +2260,15 @@ function isPlainObject(value) {
2236
2260
  }
2237
2261
 
2238
2262
  // src/anthropic-messages-language-model.ts
2263
+ function getJsonResponseToolName(tools) {
2264
+ const toolNames = new Set(tools == null ? void 0 : tools.map((tool) => tool.name));
2265
+ let name = "json";
2266
+ let suffix = 1;
2267
+ while (toolNames.has(name)) {
2268
+ name = `json_${suffix++}`;
2269
+ }
2270
+ return name;
2271
+ }
2239
2272
  function createCitationSource(citation, citationDocuments, generateId2) {
2240
2273
  var _a;
2241
2274
  if (citation.type !== "page_location" && citation.type !== "char_location") {
@@ -2341,12 +2374,6 @@ var AnthropicMessagesLanguageModel = class {
2341
2374
  setting: "responseFormat",
2342
2375
  details: "JSON response format requires a schema. The response format is ignored."
2343
2376
  });
2344
- } else if (tools != null) {
2345
- warnings.push({
2346
- type: "unsupported-setting",
2347
- setting: "tools",
2348
- details: "JSON response format does not support tools. The provided tools are ignored."
2349
- });
2350
2377
  }
2351
2378
  }
2352
2379
  const anthropicOptions = await parseProviderOptions2({
@@ -2396,9 +2423,10 @@ var AnthropicMessagesLanguageModel = class {
2396
2423
  const isAnthropicModel = isKnownModel || this.modelId.includes("claude-");
2397
2424
  const structureOutputMode = (_a = anthropicOptions == null ? void 0 : anthropicOptions.structuredOutputMode) != null ? _a : "jsonTool";
2398
2425
  const useStructuredOutput = structureOutputMode === "outputFormat" || structureOutputMode === "auto" && supportsStructuredOutput;
2426
+ const jsonResponseToolName = getJsonResponseToolName(tools);
2399
2427
  const jsonResponseTool = (responseFormat == null ? void 0 : responseFormat.type) === "json" && responseFormat.schema != null && !useStructuredOutput ? {
2400
2428
  type: "function",
2401
- name: "json",
2429
+ name: jsonResponseToolName,
2402
2430
  description: "Respond with a JSON object.",
2403
2431
  inputSchema: responseFormat.schema
2404
2432
  } : void 0;
@@ -2641,8 +2669,8 @@ var AnthropicMessagesLanguageModel = class {
2641
2669
  betas: toolsBetas
2642
2670
  } = await prepareTools(
2643
2671
  jsonResponseTool != null ? {
2644
- tools: [jsonResponseTool],
2645
- toolChoice: { type: "tool", toolName: jsonResponseTool.name },
2672
+ tools: [...tools != null ? tools : [], jsonResponseTool],
2673
+ toolChoice: tools != null && tools.length > 0 ? { type: "required" } : { type: "tool", toolName: jsonResponseTool.name },
2646
2674
  disableParallelToolUse: true,
2647
2675
  cacheControlValidator
2648
2676
  } : {
@@ -2666,7 +2694,7 @@ var AnthropicMessagesLanguageModel = class {
2666
2694
  ...userSuppliedBetas,
2667
2695
  ...(_i = anthropicOptions == null ? void 0 : anthropicOptions.anthropicBeta) != null ? _i : []
2668
2696
  ]),
2669
- usesJsonResponseTool: jsonResponseTool != null
2697
+ jsonResponseToolName: jsonResponseTool != null ? jsonResponseToolName : void 0
2670
2698
  };
2671
2699
  }
2672
2700
  async getHeaders({
@@ -2724,7 +2752,7 @@ var AnthropicMessagesLanguageModel = class {
2724
2752
  }
2725
2753
  async doGenerate(options) {
2726
2754
  var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
2727
- const { args, warnings, betas, usesJsonResponseTool } = await this.getArgs({
2755
+ const { args, warnings, betas, jsonResponseToolName } = await this.getArgs({
2728
2756
  ...options,
2729
2757
  userSuppliedBetas: await this.getBetasFromHeaders(options.headers)
2730
2758
  });
@@ -2745,10 +2773,11 @@ var AnthropicMessagesLanguageModel = class {
2745
2773
  fetch: this.config.fetch
2746
2774
  });
2747
2775
  const content = [];
2776
+ let isJsonResponseFromTool = false;
2748
2777
  for (const part of response.content) {
2749
2778
  switch (part.type) {
2750
2779
  case "text": {
2751
- if (!usesJsonResponseTool) {
2780
+ if (jsonResponseToolName == null) {
2752
2781
  const webSearchCitations = (_a = part.citations) == null ? void 0 : _a.filter(
2753
2782
  (citation) => citation.type === "web_search_result_location"
2754
2783
  );
@@ -2815,18 +2844,21 @@ var AnthropicMessagesLanguageModel = class {
2815
2844
  break;
2816
2845
  }
2817
2846
  case "tool_use": {
2818
- content.push(
2819
- // when a json response tool is used, the tool call becomes the text:
2820
- usesJsonResponseTool ? {
2847
+ const isJsonResponseTool = part.name === jsonResponseToolName;
2848
+ if (isJsonResponseTool) {
2849
+ isJsonResponseFromTool = true;
2850
+ content.push({
2821
2851
  type: "text",
2822
2852
  text: JSON.stringify(part.input)
2823
- } : {
2853
+ });
2854
+ } else {
2855
+ content.push({
2824
2856
  type: "tool-call",
2825
2857
  toolCallId: part.id,
2826
2858
  toolName: part.name,
2827
2859
  input: JSON.stringify(part.input)
2828
- }
2829
- );
2860
+ });
2861
+ }
2830
2862
  break;
2831
2863
  }
2832
2864
  case "server_tool_use": {
@@ -3008,7 +3040,7 @@ var AnthropicMessagesLanguageModel = class {
3008
3040
  content,
3009
3041
  finishReason: mapAnthropicStopReason({
3010
3042
  finishReason: response.stop_reason,
3011
- isJsonResponseFromTool: usesJsonResponseTool
3043
+ isJsonResponseFromTool
3012
3044
  }),
3013
3045
  usage: {
3014
3046
  inputTokens,
@@ -3076,7 +3108,7 @@ var AnthropicMessagesLanguageModel = class {
3076
3108
  }
3077
3109
  async doStream(options) {
3078
3110
  var _a, _b;
3079
- const { args, warnings, betas, usesJsonResponseTool } = await this.getArgs({
3111
+ const { args, warnings, betas, jsonResponseToolName } = await this.getArgs({
3080
3112
  ...options,
3081
3113
  userSuppliedBetas: await this.getBetasFromHeaders(options.headers)
3082
3114
  });
@@ -3108,6 +3140,7 @@ var AnthropicMessagesLanguageModel = class {
3108
3140
  let container = null;
3109
3141
  let iterations = null;
3110
3142
  let contextManagement = null;
3143
+ let isJsonResponseFromTool = false;
3111
3144
  let isMessageOpen = false;
3112
3145
  let activeMessageId;
3113
3146
  let hasInvalidMessageSequence = false;
@@ -3191,20 +3224,31 @@ var AnthropicMessagesLanguageModel = class {
3191
3224
  return;
3192
3225
  }
3193
3226
  case "tool_use": {
3194
- contentBlocks[value.index] = usesJsonResponseTool ? { type: "text", citations: [] } : {
3195
- type: "tool-call",
3196
- toolCallId: value.content_block.id,
3197
- toolName: value.content_block.name,
3198
- input: "",
3199
- firstDelta: true
3200
- };
3201
- controller.enqueue(
3202
- usesJsonResponseTool ? { type: "text-start", id: String(value.index) } : {
3227
+ const isJsonResponseTool = value.content_block.name === jsonResponseToolName;
3228
+ if (isJsonResponseTool) {
3229
+ isJsonResponseFromTool = true;
3230
+ contentBlocks[value.index] = {
3231
+ type: "text",
3232
+ citations: []
3233
+ };
3234
+ controller.enqueue({
3235
+ type: "text-start",
3236
+ id: String(value.index)
3237
+ });
3238
+ } else {
3239
+ contentBlocks[value.index] = {
3240
+ type: "tool-call",
3241
+ toolCallId: value.content_block.id,
3242
+ toolName: value.content_block.name,
3243
+ input: "",
3244
+ firstDelta: true
3245
+ };
3246
+ controller.enqueue({
3203
3247
  type: "tool-input-start",
3204
3248
  id: value.content_block.id,
3205
3249
  toolName: value.content_block.name
3206
- }
3207
- );
3250
+ });
3251
+ }
3208
3252
  return;
3209
3253
  }
3210
3254
  case "server_tool_use": {
@@ -3400,22 +3444,21 @@ var AnthropicMessagesLanguageModel = class {
3400
3444
  });
3401
3445
  break;
3402
3446
  }
3403
- case "tool-call":
3404
- if (!usesJsonResponseTool) {
3405
- controller.enqueue({
3406
- type: "tool-input-end",
3407
- id: contentBlock.toolCallId
3408
- });
3409
- const toolName = contentBlock.toolName === "text_editor_code_execution" || contentBlock.toolName === "bash_code_execution" ? "code_execution" : contentBlock.toolName;
3410
- controller.enqueue({
3411
- type: "tool-call",
3412
- toolCallId: contentBlock.toolCallId,
3413
- toolName,
3414
- input: contentBlock.input === "" ? "{}" : contentBlock.input,
3415
- providerExecuted: contentBlock.providerExecuted
3416
- });
3417
- }
3447
+ case "tool-call": {
3448
+ controller.enqueue({
3449
+ type: "tool-input-end",
3450
+ id: contentBlock.toolCallId
3451
+ });
3452
+ const toolName = contentBlock.toolName === "text_editor_code_execution" || contentBlock.toolName === "bash_code_execution" ? "code_execution" : contentBlock.toolName;
3453
+ controller.enqueue({
3454
+ type: "tool-call",
3455
+ toolCallId: contentBlock.toolCallId,
3456
+ toolName,
3457
+ input: contentBlock.input === "" ? "{}" : contentBlock.input,
3458
+ providerExecuted: contentBlock.providerExecuted
3459
+ });
3418
3460
  break;
3461
+ }
3419
3462
  }
3420
3463
  delete contentBlocks[value.index];
3421
3464
  }
@@ -3426,7 +3469,7 @@ var AnthropicMessagesLanguageModel = class {
3426
3469
  const deltaType = value.delta.type;
3427
3470
  switch (deltaType) {
3428
3471
  case "text_delta": {
3429
- if (usesJsonResponseTool) {
3472
+ if (jsonResponseToolName != null) {
3430
3473
  return;
3431
3474
  }
3432
3475
  controller.enqueue({
@@ -3475,10 +3518,7 @@ var AnthropicMessagesLanguageModel = class {
3475
3518
  if (delta.length === 0) {
3476
3519
  return;
3477
3520
  }
3478
- if (usesJsonResponseTool) {
3479
- if ((contentBlock == null ? void 0 : contentBlock.type) !== "text") {
3480
- return;
3481
- }
3521
+ if ((contentBlock == null ? void 0 : contentBlock.type) === "text") {
3482
3522
  controller.enqueue({
3483
3523
  type: "text-delta",
3484
3524
  id: String(value.index),
@@ -3587,7 +3627,7 @@ var AnthropicMessagesLanguageModel = class {
3587
3627
  usage.totalTokens = ((_g = usage.inputTokens) != null ? _g : 0) + ((_h = usage.outputTokens) != null ? _h : 0);
3588
3628
  finishReason = mapAnthropicStopReason({
3589
3629
  finishReason: value.delta.stop_reason,
3590
- isJsonResponseFromTool: usesJsonResponseTool
3630
+ isJsonResponseFromTool
3591
3631
  });
3592
3632
  stopDetails = mapAnthropicStopDetails(value.delta.stop_details);
3593
3633
  stopSequence = (_i = value.delta.stop_sequence) != null ? _i : null;