@ai-sdk/anthropic 2.0.110 → 2.0.112

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.
@@ -1531,6 +1531,8 @@ import {
1531
1531
  UnsupportedFunctionalityError as UnsupportedFunctionalityError2
1532
1532
  } from "@ai-sdk/provider";
1533
1533
  import {
1534
+ stringifyWithBigIntAndCycles,
1535
+ secureJsonParse,
1534
1536
  convertToBase64,
1535
1537
  parseProviderOptions,
1536
1538
  validateTypes as validateTypes2
@@ -1955,7 +1957,7 @@ async function convertToAnthropicMessagesPrompt({
1955
1957
  case "json":
1956
1958
  case "error-json":
1957
1959
  default:
1958
- contentValue = JSON.stringify(output.value);
1960
+ contentValue = stringifyWithBigIntAndCycles(output.value);
1959
1961
  break;
1960
1962
  }
1961
1963
  const toolsetName = getAnthropicToolsetName({
@@ -2129,7 +2131,7 @@ async function convertToAnthropicMessagesPrompt({
2129
2131
  type: "tool_use",
2130
2132
  id: part.toolCallId,
2131
2133
  name: part.toolName,
2132
- input: part.input,
2134
+ input: parseToolCallInput(part.input),
2133
2135
  cache_control: cacheControl
2134
2136
  });
2135
2137
  break;
@@ -2364,6 +2366,18 @@ function getAnthropicToolsetName({
2364
2366
  const fromMetadata = (_a = providerOptions == null ? void 0 : providerOptions.anthropic) == null ? void 0 : _a.toolsetName;
2365
2367
  return typeof fromMetadata === "string" ? fromMetadata : void 0;
2366
2368
  }
2369
+ function parseToolCallInput(input) {
2370
+ if (typeof input === "string") {
2371
+ try {
2372
+ const parsed = secureJsonParse(input);
2373
+ if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) {
2374
+ return parsed;
2375
+ }
2376
+ } catch (e) {
2377
+ }
2378
+ }
2379
+ return input;
2380
+ }
2367
2381
 
2368
2382
  // src/map-anthropic-stop-reason.ts
2369
2383
  function mapAnthropicStopReason({
@@ -2534,6 +2548,187 @@ function isPlainObject(value) {
2534
2548
  return typeof value === "object" && value !== null && !Array.isArray(value);
2535
2549
  }
2536
2550
 
2551
+ // src/has-circular-schema-reference.ts
2552
+ var SCHEMA_MAP_KEYWORDS = /* @__PURE__ */ new Set([
2553
+ "dependentSchemas",
2554
+ "patternProperties",
2555
+ "properties"
2556
+ ]);
2557
+ var DATA_KEYWORDS = /* @__PURE__ */ new Set(["const", "default", "enum", "examples"]);
2558
+ function hasCircularSchemaReference(schema) {
2559
+ const visiting = /* @__PURE__ */ new Set();
2560
+ const visited = /* @__PURE__ */ new Set();
2561
+ const visit = (pointer) => {
2562
+ if (visiting.has(pointer)) {
2563
+ return true;
2564
+ }
2565
+ if (visited.has(pointer)) {
2566
+ return false;
2567
+ }
2568
+ const target = resolveSchemaPointer(schema, pointer);
2569
+ if (target === void 0) {
2570
+ return false;
2571
+ }
2572
+ visiting.add(pointer);
2573
+ const isCircular = collectLocalRefs(target).some(visit);
2574
+ visiting.delete(pointer);
2575
+ visited.add(pointer);
2576
+ return isCircular;
2577
+ };
2578
+ return visit("#");
2579
+ }
2580
+ function collectLocalRefs(node, refs = []) {
2581
+ if (Array.isArray(node)) {
2582
+ for (const item of node) {
2583
+ collectLocalRefs(item, refs);
2584
+ }
2585
+ return refs;
2586
+ }
2587
+ if (!isRecord(node)) {
2588
+ return refs;
2589
+ }
2590
+ for (const [key, value] of Object.entries(node)) {
2591
+ if (key === "$ref") {
2592
+ if (typeof value === "string" && value.startsWith("#")) {
2593
+ refs.push(value);
2594
+ }
2595
+ } else if (SCHEMA_MAP_KEYWORDS.has(key) && isRecord(value)) {
2596
+ for (const subschema of Object.values(value)) {
2597
+ collectLocalRefs(subschema, refs);
2598
+ }
2599
+ } else if (
2600
+ // definitions are only reached through a `$ref`:
2601
+ key !== "$defs" && key !== "definitions" && !DATA_KEYWORDS.has(key)
2602
+ ) {
2603
+ collectLocalRefs(value, refs);
2604
+ }
2605
+ }
2606
+ return refs;
2607
+ }
2608
+ function resolveSchemaPointer(schema, pointer) {
2609
+ if (pointer === "#") {
2610
+ return schema;
2611
+ }
2612
+ if (!pointer.startsWith("#/")) {
2613
+ return void 0;
2614
+ }
2615
+ let decodedPointer;
2616
+ try {
2617
+ decodedPointer = decodeURIComponent(pointer.slice(2));
2618
+ } catch (e) {
2619
+ return void 0;
2620
+ }
2621
+ let current = schema;
2622
+ for (const rawSegment of decodedPointer.split("/")) {
2623
+ const segment = rawSegment.replace(/~1/g, "/").replace(/~0/g, "~");
2624
+ if (Array.isArray(current)) {
2625
+ current = current[Number(segment)];
2626
+ } else if (isRecord(current)) {
2627
+ current = current[segment];
2628
+ } else {
2629
+ return void 0;
2630
+ }
2631
+ }
2632
+ return current;
2633
+ }
2634
+ function isRecord(value) {
2635
+ return typeof value === "object" && value !== null && !Array.isArray(value);
2636
+ }
2637
+
2638
+ // src/supports-native-structured-output-schema.ts
2639
+ var MAX_OPTIONAL_PROPERTIES = 10;
2640
+ var SUBSCHEMA_KEYWORDS = [
2641
+ "additionalProperties",
2642
+ "contains",
2643
+ "else",
2644
+ "if",
2645
+ "items",
2646
+ "not",
2647
+ "then"
2648
+ ];
2649
+ var SUBSCHEMA_LIST_KEYWORDS = ["allOf", "anyOf", "oneOf", "prefixItems"];
2650
+ var SUBSCHEMA_MAP_KEYWORDS = [
2651
+ "dependentSchemas",
2652
+ "patternProperties",
2653
+ "properties"
2654
+ ];
2655
+ function supportsNativeStructuredOutputSchema(schema) {
2656
+ if (schema.$ref != null || hasCircularSchemaReference(schema)) {
2657
+ return false;
2658
+ }
2659
+ const { optionalProperties, hasOpenObject } = getSchemaStats(
2660
+ schema,
2661
+ schema,
2662
+ /* @__PURE__ */ new Map()
2663
+ );
2664
+ return !hasOpenObject && optionalProperties <= MAX_OPTIONAL_PROPERTIES;
2665
+ }
2666
+ function getSchemaStats(node, root, refStats) {
2667
+ const stats = { optionalProperties: 0, hasOpenObject: false };
2668
+ if (!isRecord(node)) {
2669
+ return stats;
2670
+ }
2671
+ const add = (child) => {
2672
+ const childStats = getSchemaStats(child, root, refStats);
2673
+ stats.optionalProperties += childStats.optionalProperties;
2674
+ stats.hasOpenObject || (stats.hasOpenObject = childStats.hasOpenObject);
2675
+ };
2676
+ if (typeof node.$ref === "string" && node.$ref.startsWith("#")) {
2677
+ let resolved = refStats.get(node.$ref);
2678
+ if (resolved == null) {
2679
+ resolved = getSchemaStats(
2680
+ resolveSchemaPointer(root, node.$ref),
2681
+ root,
2682
+ refStats
2683
+ );
2684
+ refStats.set(node.$ref, resolved);
2685
+ }
2686
+ stats.optionalProperties += resolved.optionalProperties;
2687
+ stats.hasOpenObject || (stats.hasOpenObject = resolved.hasOpenObject);
2688
+ }
2689
+ if (isOpenObject(node)) {
2690
+ stats.hasOpenObject = true;
2691
+ }
2692
+ if (isRecord(node.properties)) {
2693
+ const required = new Set(Array.isArray(node.required) ? node.required : []);
2694
+ stats.optionalProperties += Object.keys(node.properties).filter(
2695
+ (name) => !required.has(name)
2696
+ ).length;
2697
+ }
2698
+ for (const keyword of SUBSCHEMA_KEYWORDS) {
2699
+ const value = node[keyword];
2700
+ if (Array.isArray(value)) {
2701
+ value.forEach(add);
2702
+ } else {
2703
+ add(value);
2704
+ }
2705
+ }
2706
+ for (const keyword of SUBSCHEMA_LIST_KEYWORDS) {
2707
+ const value = node[keyword];
2708
+ if (Array.isArray(value)) {
2709
+ value.forEach(add);
2710
+ }
2711
+ }
2712
+ for (const keyword of SUBSCHEMA_MAP_KEYWORDS) {
2713
+ const value = node[keyword];
2714
+ if (isRecord(value)) {
2715
+ Object.values(value).forEach(add);
2716
+ }
2717
+ }
2718
+ return stats;
2719
+ }
2720
+ function isOpenObject(node) {
2721
+ const { additionalProperties, patternProperties, properties, type } = node;
2722
+ if (additionalProperties === true || isRecord(additionalProperties)) {
2723
+ return true;
2724
+ }
2725
+ if (isRecord(patternProperties) && Object.keys(patternProperties).length > 0) {
2726
+ return true;
2727
+ }
2728
+ const isObjectType = type === "object" || Array.isArray(type) && type.includes("object");
2729
+ return isObjectType && properties == null && additionalProperties !== false;
2730
+ }
2731
+
2537
2732
  // src/anthropic-messages-language-model.ts
2538
2733
  function getAnthropicToolsetNames(tools) {
2539
2734
  const toolsetNames = {};
@@ -2591,6 +2786,31 @@ function createCitationSource(citation, citationDocuments, generateId2) {
2591
2786
  }
2592
2787
  };
2593
2788
  }
2789
+ var TEXT_OR_THINKING_BLOCK_TYPES = /* @__PURE__ */ new Set([
2790
+ "redacted_thinking",
2791
+ "text",
2792
+ "thinking"
2793
+ ]);
2794
+ function isContinuationStopReason(stopReason) {
2795
+ return stopReason === "pause_turn" || stopReason === "tool_use";
2796
+ }
2797
+ function getJsonResponseToolFallbackText(content, stopReason, jsonResponseToolName) {
2798
+ const text = /* @__PURE__ */ new Set();
2799
+ if (isContinuationStopReason(stopReason)) {
2800
+ return text;
2801
+ }
2802
+ for (const part of content) {
2803
+ if (part.type === "tool_use" && part.name === jsonResponseToolName) {
2804
+ return /* @__PURE__ */ new Set();
2805
+ }
2806
+ if (part.type === "text") {
2807
+ text.add(part);
2808
+ } else if (!TEXT_OR_THINKING_BLOCK_TYPES.has(part.type)) {
2809
+ text.clear();
2810
+ }
2811
+ }
2812
+ return text;
2813
+ }
2594
2814
  var AnthropicMessagesLanguageModel = class {
2595
2815
  constructor(modelId, config) {
2596
2816
  this.specificationVersion = "v2";
@@ -2718,9 +2938,10 @@ var AnthropicMessagesLanguageModel = class {
2718
2938
  }
2719
2939
  }
2720
2940
  const isAnthropicModel = isKnownModel || this.modelId.includes("claude-");
2941
+ const supportsResponseSchema = (responseFormat == null ? void 0 : responseFormat.type) !== "json" || responseFormat.schema == null || supportsNativeStructuredOutputSchema(responseFormat.schema);
2721
2942
  const structureOutputMode = (_a = anthropicOptions == null ? void 0 : anthropicOptions.structuredOutputMode) != null ? _a : this.modelId.includes("claude-fable-5-1") || this.modelId.includes("claude-opus-5-5") || this.modelId.includes("claude-sonnet-5-5") ? "auto" : "jsonTool";
2722
- let useStructuredOutput = structureOutputMode === "outputFormat" || structureOutputMode === "auto" && supportsStructuredOutput;
2723
- if (!useStructuredOutput && rejectsForcedToolUse && supportsStructuredOutput && (responseFormat == null ? void 0 : responseFormat.type) === "json" && responseFormat.schema != null) {
2943
+ let useStructuredOutput = structureOutputMode === "outputFormat" || structureOutputMode === "auto" && supportsStructuredOutput && supportsResponseSchema;
2944
+ if (!useStructuredOutput && rejectsForcedToolUse && supportsStructuredOutput && (responseFormat == null ? void 0 : responseFormat.type) === "json" && responseFormat.schema != null && supportsResponseSchema) {
2724
2945
  warnings.push({
2725
2946
  type: "unsupported-setting",
2726
2947
  setting: "providerOptions.anthropic.structuredOutputMode",
@@ -3029,8 +3250,13 @@ var AnthropicMessagesLanguageModel = class {
3029
3250
  betas: toolsBetas
3030
3251
  } = await prepareTools(
3031
3252
  jsonResponseTool != null ? {
3032
- tools: [...tools != null ? tools : [], jsonResponseTool],
3033
- toolChoice: tools != null && tools.length > 0 ? { type: "required" } : { type: "tool", toolName: jsonResponseTool.name },
3253
+ tools: [
3254
+ ...(tools != null ? tools : []).filter(
3255
+ (tool) => (toolChoice == null ? void 0 : toolChoice.type) !== "none" && ((toolChoice == null ? void 0 : toolChoice.type) !== "tool" || tool.name === toolChoice.toolName)
3256
+ ),
3257
+ jsonResponseTool
3258
+ ],
3259
+ toolChoice: rejectsForcedToolUse ? { type: "auto" } : tools != null && tools.length > 0 ? { type: "required" } : { type: "tool", toolName: jsonResponseTool.name },
3034
3260
  disableParallelToolUse: true,
3035
3261
  cacheControlValidator,
3036
3262
  rejectsForcedToolUse
@@ -3136,10 +3362,15 @@ var AnthropicMessagesLanguageModel = class {
3136
3362
  });
3137
3363
  const content = [];
3138
3364
  let isJsonResponseFromTool = false;
3365
+ const jsonResponseToolFallbackText = jsonResponseToolName != null ? getJsonResponseToolFallbackText(
3366
+ response.content,
3367
+ response.stop_reason,
3368
+ jsonResponseToolName
3369
+ ) : void 0;
3139
3370
  for (const part of response.content) {
3140
3371
  switch (part.type) {
3141
3372
  case "text": {
3142
- if (jsonResponseToolName == null) {
3373
+ if (jsonResponseToolFallbackText == null || jsonResponseToolFallbackText.has(part)) {
3143
3374
  const webSearchCitations = (_a = part.citations) == null ? void 0 : _a.filter(
3144
3375
  (citation) => citation.type === "web_search_result_location"
3145
3376
  );
@@ -3518,6 +3749,16 @@ var AnthropicMessagesLanguageModel = class {
3518
3749
  let iterations = null;
3519
3750
  let contextManagement = null;
3520
3751
  let isJsonResponseFromTool = false;
3752
+ let rawStopReason;
3753
+ const heldBackText = [];
3754
+ const heldBackTextByIndex = /* @__PURE__ */ new Map();
3755
+ const createTextEnd = (id, citations) => ({
3756
+ type: "text-end",
3757
+ id,
3758
+ ...citations.length > 0 && {
3759
+ providerMetadata: { anthropic: { citations } }
3760
+ }
3761
+ });
3521
3762
  let isMessageOpen = false;
3522
3763
  let activeMessageId;
3523
3764
  let hasInvalidMessageSequence = false;
@@ -3529,7 +3770,7 @@ var AnthropicMessagesLanguageModel = class {
3529
3770
  controller.enqueue({ type: "stream-start", warnings });
3530
3771
  },
3531
3772
  transform(chunk, controller) {
3532
- var _a2, _b2, _c, _d, _e, _f, _g, _h, _i, _j, _k;
3773
+ var _a2, _b2, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l;
3533
3774
  if (hasInvalidMessageSequence) {
3534
3775
  return;
3535
3776
  }
@@ -3551,8 +3792,21 @@ var AnthropicMessagesLanguageModel = class {
3551
3792
  return;
3552
3793
  }
3553
3794
  blockType = contentBlockType;
3795
+ if (!TEXT_OR_THINKING_BLOCK_TYPES.has(contentBlockType)) {
3796
+ heldBackText.length = 0;
3797
+ }
3554
3798
  switch (contentBlockType) {
3555
3799
  case "text": {
3800
+ if (jsonResponseToolName != null) {
3801
+ const entry = {
3802
+ id: String(value.index),
3803
+ text: "",
3804
+ citations: []
3805
+ };
3806
+ heldBackText.push(entry);
3807
+ heldBackTextByIndex.set(value.index, entry);
3808
+ return;
3809
+ }
3556
3810
  contentBlocks[value.index] = {
3557
3811
  type: "text",
3558
3812
  citations: []
@@ -3888,6 +4142,8 @@ var AnthropicMessagesLanguageModel = class {
3888
4142
  switch (deltaType) {
3889
4143
  case "text_delta": {
3890
4144
  if (jsonResponseToolName != null) {
4145
+ const entry = heldBackTextByIndex.get(value.index);
4146
+ if (entry != null) entry.text += value.delta.text;
3891
4147
  return;
3892
4148
  }
3893
4149
  controller.enqueue({
@@ -3966,8 +4222,10 @@ var AnthropicMessagesLanguageModel = class {
3966
4222
  case "citations_delta": {
3967
4223
  const citation = value.delta.citation;
3968
4224
  const contentBlock = contentBlocks[value.index];
3969
- if ((contentBlock == null ? void 0 : contentBlock.type) === "text" && citation.type === "web_search_result_location") {
3970
- contentBlock.citations.push(citation);
4225
+ if (citation.type === "web_search_result_location") {
4226
+ if ((contentBlock == null ? void 0 : contentBlock.type) === "text")
4227
+ contentBlock.citations.push(citation);
4228
+ (_b2 = heldBackTextByIndex.get(value.index)) == null ? void 0 : _b2.citations.push(citation);
3971
4229
  }
3972
4230
  const source = createCitationSource(
3973
4231
  citation,
@@ -4004,16 +4262,17 @@ var AnthropicMessagesLanguageModel = class {
4004
4262
  }
4005
4263
  isMessageOpen = true;
4006
4264
  activeMessageId = value.message.id;
4265
+ heldBackTextByIndex.clear();
4007
4266
  usage.inputTokens = value.message.usage.input_tokens;
4008
- usage.cachedInputTokens = (_b2 = value.message.usage.cache_read_input_tokens) != null ? _b2 : void 0;
4267
+ usage.cachedInputTokens = (_c = value.message.usage.cache_read_input_tokens) != null ? _c : void 0;
4009
4268
  rawUsage = {
4010
4269
  ...value.message.usage
4011
4270
  };
4012
- cacheCreationInputTokens = (_c = value.message.usage.cache_creation_input_tokens) != null ? _c : null;
4271
+ cacheCreationInputTokens = (_d = value.message.usage.cache_creation_input_tokens) != null ? _d : null;
4013
4272
  controller.enqueue({
4014
4273
  type: "response-metadata",
4015
- id: (_d = value.message.id) != null ? _d : void 0,
4016
- modelId: (_e = value.message.model) != null ? _e : void 0
4274
+ id: (_e = value.message.id) != null ? _e : void 0,
4275
+ modelId: (_f = value.message.model) != null ? _f : void 0
4017
4276
  });
4018
4277
  return;
4019
4278
  }
@@ -4027,7 +4286,7 @@ var AnthropicMessagesLanguageModel = class {
4027
4286
  if (value.usage.iterations != null) {
4028
4287
  iterations = value.usage.iterations;
4029
4288
  }
4030
- const servedByFallback = (_f = value.usage.iterations) == null ? void 0 : _f.some(
4289
+ const servedByFallback = (_g = value.usage.iterations) == null ? void 0 : _g.some(
4031
4290
  (iter) => iter.type === "fallback_message"
4032
4291
  );
4033
4292
  if (value.usage.iterations && value.usage.iterations.length > 0 && !servedByFallback) {
@@ -4046,21 +4305,22 @@ var AnthropicMessagesLanguageModel = class {
4046
4305
  }
4047
4306
  usage.outputTokens = value.usage.output_tokens;
4048
4307
  }
4049
- usage.totalTokens = ((_g = usage.inputTokens) != null ? _g : 0) + ((_h = usage.outputTokens) != null ? _h : 0);
4308
+ usage.totalTokens = ((_h = usage.inputTokens) != null ? _h : 0) + ((_i = usage.outputTokens) != null ? _i : 0);
4309
+ rawStopReason = value.delta.stop_reason;
4050
4310
  finishReason = mapAnthropicStopReason({
4051
4311
  finishReason: value.delta.stop_reason,
4052
4312
  isJsonResponseFromTool
4053
4313
  });
4054
4314
  stopDetails = mapAnthropicStopDetails(value.delta.stop_details);
4055
- stopSequence = (_i = value.delta.stop_sequence) != null ? _i : null;
4315
+ stopSequence = (_j = value.delta.stop_sequence) != null ? _j : null;
4056
4316
  container = value.delta.container != null ? {
4057
4317
  expiresAt: value.delta.container.expires_at,
4058
4318
  id: value.delta.container.id,
4059
- skills: (_k = (_j = value.delta.container.skills) == null ? void 0 : _j.map((skill) => ({
4319
+ skills: (_l = (_k = value.delta.container.skills) == null ? void 0 : _k.map((skill) => ({
4060
4320
  type: skill.type,
4061
4321
  skillId: skill.skill_id,
4062
4322
  version: skill.version
4063
- }))) != null ? _k : null
4323
+ }))) != null ? _l : null
4064
4324
  } : null;
4065
4325
  if (value.context_management != null) {
4066
4326
  contextManagement = {
@@ -4098,6 +4358,15 @@ var AnthropicMessagesLanguageModel = class {
4098
4358
  case "message_stop": {
4099
4359
  isMessageOpen = false;
4100
4360
  activeMessageId = void 0;
4361
+ if (!isJsonResponseFromTool && !isContinuationStopReason(rawStopReason)) {
4362
+ for (const { id, text, citations } of heldBackText) {
4363
+ if (text.length === 0) continue;
4364
+ controller.enqueue({ type: "text-start", id });
4365
+ controller.enqueue({ type: "text-delta", id, delta: text });
4366
+ controller.enqueue(createTextEnd(id, citations));
4367
+ }
4368
+ }
4369
+ heldBackText.length = 0;
4101
4370
  controller.enqueue({
4102
4371
  type: "finish",
4103
4372
  finishReason,
@@ -4921,6 +5190,7 @@ export {
4921
5190
  anthropicTools,
4922
5191
  getModelCapabilities,
4923
5192
  prepareTools,
4924
- sanitizeJsonSchema
5193
+ sanitizeJsonSchema,
5194
+ supportsNativeStructuredOutputSchema
4925
5195
  };
4926
5196
  //# sourceMappingURL=index.mjs.map