@core-ai/anthropic 0.13.0 → 0.13.1

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 (2) hide show
  1. package/dist/index.js +125 -39
  2. package/package.json +3 -3
package/dist/index.js CHANGED
@@ -15,6 +15,7 @@ import { APIError, APIUserAbortError } from "@anthropic-ai/sdk";
15
15
  import {
16
16
  AbortedError,
17
17
  asObject,
18
+ clampReasoningEffort,
18
19
  getProviderMetadata,
19
20
  ProviderError,
20
21
  ValidationError,
@@ -69,6 +70,21 @@ var MANUAL_THINKING_MODELS = /* @__PURE__ */ new Set([
69
70
  "claude-haiku-4-5",
70
71
  "claude-sonnet-3-7"
71
72
  ]);
73
+ var MANUAL_INTERLEAVED_THINKING_MODELS = /* @__PURE__ */ new Set([
74
+ "claude-opus-4-5",
75
+ "claude-sonnet-4-5",
76
+ "claude-opus-4-1",
77
+ "claude-opus-4",
78
+ "claude-sonnet-4"
79
+ ]);
80
+ var ALWAYS_RESTRICTED_SAMPLING_MODELS = /* @__PURE__ */ new Set([
81
+ "claude-fable-5",
82
+ "claude-mythos-5",
83
+ "claude-mythos-preview",
84
+ "claude-opus-4-8",
85
+ "claude-opus-4-7",
86
+ "claude-sonnet-5"
87
+ ]);
72
88
  var ANTHROPIC_ADAPTIVE_EFFORT_MAP = {
73
89
  minimal: "low",
74
90
  low: "low",
@@ -97,14 +113,21 @@ function getAnthropicThinkingMode(modelId) {
97
113
  function supportsAnthropicMaxEffort(modelId) {
98
114
  return ADAPTIVE_MAX_EFFORT_MODELS.has(normalizeModelId(modelId));
99
115
  }
116
+ function requiresAnthropicInterleavedThinkingBeta(modelId) {
117
+ return MANUAL_INTERLEAVED_THINKING_MODELS.has(normalizeModelId(modelId));
118
+ }
119
+ function restrictsAnthropicSamplingParamsAlways(modelId) {
120
+ return ALWAYS_RESTRICTED_SAMPLING_MODELS.has(normalizeModelId(modelId));
121
+ }
100
122
  function toAnthropicAdaptiveEffort(effort, supportsMaxEffort) {
101
123
  if (effort === "max") {
102
124
  return supportsMaxEffort ? "max" : "high";
103
125
  }
104
126
  return ANTHROPIC_ADAPTIVE_EFFORT_MAP[effort];
105
127
  }
106
- function toAnthropicManualBudget(effort) {
107
- return ANTHROPIC_MANUAL_BUDGET_MAP[effort];
128
+ function toAnthropicManualBudget(effort, maxTokens) {
129
+ const targetBudget = ANTHROPIC_MANUAL_BUDGET_MAP[effort];
130
+ return maxTokens === void 0 ? targetBudget : Math.min(targetBudget, maxTokens - 1);
108
131
  }
109
132
 
110
133
  // src/provider-options.ts
@@ -198,18 +221,17 @@ function convertMessages(messages) {
198
221
  });
199
222
  continue;
200
223
  }
201
- if (part.text.length === 0) {
224
+ if (typeof signature === "string") {
225
+ contentBlocks.push({
226
+ type: "thinking",
227
+ thinking: part.text,
228
+ signature
229
+ });
202
230
  continue;
203
231
  }
204
- if (typeof signature !== "string") {
232
+ if (part.text.length > 0) {
205
233
  contentBlocks.push({ type: "text", text: part.text });
206
- continue;
207
234
  }
208
- contentBlocks.push({
209
- type: "thinking",
210
- thinking: part.text,
211
- signature
212
- });
213
235
  }
214
236
  convertedMessages.push({
215
237
  role: "assistant",
@@ -395,13 +417,23 @@ function createStreamRequest(modelId, defaultMaxTokens, options) {
395
417
  return mapAnthropicProviderOptionsToRequest(baseRequest, anthropicOptions);
396
418
  }
397
419
  function createRequestBase(modelId, defaultMaxTokens, options, anthropicOptions) {
398
- validateAnthropicReasoningConfig(modelId, options, anthropicOptions);
420
+ const maxTokens = options.maxTokens ?? defaultMaxTokens;
421
+ validateAnthropicReasoningConfig(
422
+ modelId,
423
+ maxTokens,
424
+ options,
425
+ anthropicOptions
426
+ );
399
427
  const converted = convertMessages(options.messages);
400
- const reasoningFields = mapReasoningToRequestFields(modelId, options);
428
+ const reasoningFields = mapReasoningToRequestFields(
429
+ modelId,
430
+ maxTokens,
431
+ options
432
+ );
401
433
  return {
402
434
  model: modelId,
403
435
  messages: converted.messages,
404
- max_tokens: options.maxTokens ?? defaultMaxTokens,
436
+ max_tokens: maxTokens,
405
437
  ...converted.system ? { system: converted.system } : {},
406
438
  ...options.tools && Object.keys(options.tools).length > 0 ? { tools: convertTools(options.tools) } : {},
407
439
  ...options.toolChoice ? { tool_choice: convertToolChoice(options.toolChoice) } : {},
@@ -415,11 +447,40 @@ function mapSamplingToRequestFields(options) {
415
447
  ...options.topP !== void 0 ? { top_p: options.topP } : {}
416
448
  };
417
449
  }
418
- function validateAnthropicReasoningConfig(modelId, options, anthropicOptions) {
450
+ function validateAnthropicReasoningConfig(modelId, maxTokens, options, anthropicOptions) {
451
+ const alwaysRestrictsSampling = restrictsAnthropicSamplingParamsAlways(modelId);
452
+ if (alwaysRestrictsSampling && options.temperature !== void 0 && options.temperature !== 1) {
453
+ throw new ValidationError(
454
+ `Anthropic model "${modelId}" only supports the default temperature of 1`,
455
+ void 0,
456
+ "anthropic"
457
+ );
458
+ }
459
+ if (alwaysRestrictsSampling && options.topP !== void 0 && options.topP !== 1) {
460
+ throw new ValidationError(
461
+ `Anthropic model "${modelId}" only supports the default topP of 1`,
462
+ void 0,
463
+ "anthropic"
464
+ );
465
+ }
466
+ if (alwaysRestrictsSampling && anthropicOptions?.topK !== void 0) {
467
+ throw new ValidationError(
468
+ `Anthropic model "${modelId}" does not support top_k`,
469
+ void 0,
470
+ "anthropic"
471
+ );
472
+ }
419
473
  if (!options.reasoning) {
420
474
  return;
421
475
  }
422
- if (options.temperature !== void 0) {
476
+ if (getAnthropicThinkingMode(modelId) === "manual" && maxTokens <= 1024) {
477
+ throw new ValidationError(
478
+ `Anthropic model "${modelId}" requires maxTokens greater than 1024 when reasoning is enabled`,
479
+ void 0,
480
+ "anthropic"
481
+ );
482
+ }
483
+ if (options.temperature !== void 0 && (!alwaysRestrictsSampling || options.temperature !== 1)) {
423
484
  throw new ValidationError(
424
485
  `Anthropic model "${modelId}" does not support temperature when reasoning is enabled`,
425
486
  void 0,
@@ -448,20 +509,25 @@ function validateAnthropicReasoningConfig(modelId, options, anthropicOptions) {
448
509
  );
449
510
  }
450
511
  }
451
- function mapReasoningToRequestFields(modelId, options) {
512
+ function mapReasoningToRequestFields(modelId, maxTokens, options) {
452
513
  if (!options.reasoning) {
453
514
  return {};
454
515
  }
455
516
  const thinkingMode = getAnthropicThinkingMode(modelId);
517
+ const capabilities = getAnthropicModelCapabilities(modelId);
518
+ const effort = clampReasoningEffort(
519
+ options.reasoning.effort,
520
+ capabilities.reasoning.supportedEfforts
521
+ );
456
522
  const baseFields = {};
457
- if (options.tools && Object.keys(options.tools).length > 0) {
458
- baseFields["betas"] = ["interleaved-thinking-2025-05-14"];
459
- }
460
523
  if (thinkingMode === "adaptive") {
461
- baseFields["thinking"] = { type: "adaptive" };
524
+ baseFields["thinking"] = {
525
+ type: "adaptive",
526
+ display: "summarized"
527
+ };
462
528
  baseFields["output_config"] = {
463
529
  effort: toAnthropicAdaptiveEffort(
464
- options.reasoning.effort,
530
+ effort,
465
531
  supportsAnthropicMaxEffort(modelId)
466
532
  )
467
533
  };
@@ -469,10 +535,22 @@ function mapReasoningToRequestFields(modelId, options) {
469
535
  }
470
536
  baseFields["thinking"] = {
471
537
  type: "enabled",
472
- budget_tokens: toAnthropicManualBudget(options.reasoning.effort)
538
+ budget_tokens: toAnthropicManualBudget(effort, maxTokens),
539
+ display: "summarized"
473
540
  };
474
541
  return baseFields;
475
542
  }
543
+ function getAnthropicRequestBetas(modelId, options) {
544
+ const providerOptions = parseAnthropicGenerateProviderOptions(
545
+ options.providerOptions
546
+ );
547
+ const configuredBetas = providerOptions?.betas ?? [];
548
+ const shouldEnableInterleavedThinking = options.reasoning !== void 0 && options.tools !== void 0 && Object.keys(options.tools).length > 0 && requiresAnthropicInterleavedThinkingBeta(modelId);
549
+ return uniqueStrings([
550
+ ...configuredBetas,
551
+ ...shouldEnableInterleavedThinking ? ["interleaved-thinking-2025-05-14"] : []
552
+ ]);
553
+ }
476
554
  function mapAnthropicProviderOptionsToRequest(baseRequest, providerOptions) {
477
555
  if (!providerOptions) {
478
556
  return baseRequest;
@@ -484,17 +562,12 @@ function mapAnthropicProviderOptionsToRequest(baseRequest, providerOptions) {
484
562
  ...baseOutputConfig,
485
563
  ...providerOptions.outputConfig ?? {}
486
564
  };
487
- const mergedBetas = [
488
- ...asStringArray(baseRequest.betas),
489
- ...providerOptions.betas ?? []
490
- ];
491
565
  const mergedRequest = {
492
566
  ...baseRequest,
493
567
  ...providerOptions.cacheControl ? { cache_control: providerOptions.cacheControl } : {},
494
568
  ...providerOptions.topK !== void 0 ? { top_k: providerOptions.topK } : {},
495
569
  ...providerOptions.stopSequences ? { stop_sequences: providerOptions.stopSequences } : {},
496
- ...Object.keys(mergedOutputConfig).length > 0 ? { output_config: mergedOutputConfig } : {},
497
- ...mergedBetas.length > 0 ? { betas: uniqueStrings(mergedBetas) } : {}
570
+ ...Object.keys(mergedOutputConfig).length > 0 ? { output_config: mergedOutputConfig } : {}
498
571
  };
499
572
  return mergedRequest;
500
573
  }
@@ -563,7 +636,7 @@ function mapGenerateResponse(response) {
563
636
  cacheReadTokens,
564
637
  cacheWriteTokens
565
638
  },
566
- outputTokenDetails: {}
639
+ outputTokenDetails: mapAnthropicOutputTokenDetails(response.usage)
567
640
  }
568
641
  };
569
642
  }
@@ -594,7 +667,9 @@ async function* transformStream(stream) {
594
667
  cacheReadTokens,
595
668
  cacheWriteTokens
596
669
  },
597
- outputTokenDetails: {}
670
+ outputTokenDetails: mapAnthropicOutputTokenDetails(
671
+ event.message.usage
672
+ )
598
673
  };
599
674
  continue;
600
675
  }
@@ -703,7 +778,10 @@ async function* transformStream(stream) {
703
778
  cacheReadTokens,
704
779
  cacheWriteTokens
705
780
  },
706
- outputTokenDetails: {}
781
+ outputTokenDetails: {
782
+ ...usage.outputTokenDetails,
783
+ ...mapAnthropicOutputTokenDetails(event.usage)
784
+ }
707
785
  };
708
786
  continue;
709
787
  }
@@ -729,11 +807,10 @@ function mapStopReason(reason) {
729
807
  }
730
808
  return "unknown";
731
809
  }
732
- function asStringArray(value) {
733
- if (!Array.isArray(value)) {
734
- return [];
735
- }
736
- return value.filter((item) => typeof item === "string");
810
+ function mapAnthropicOutputTokenDetails(usage) {
811
+ const outputTokenDetails = asObject(asObject(usage).output_tokens_details);
812
+ const reasoningTokens = outputTokenDetails.thinking_tokens;
813
+ return typeof reasoningTokens === "number" ? { reasoningTokens } : {};
737
814
  }
738
815
  function uniqueStrings(values) {
739
816
  return [...new Set(values)];
@@ -776,9 +853,14 @@ function wrapError(error) {
776
853
  // src/chat-model.ts
777
854
  function createAnthropicChatModel(client, modelId, defaultMaxTokens) {
778
855
  const provider = "anthropic";
779
- async function callAnthropicMessagesApi(request, signal) {
856
+ async function callAnthropicMessagesApi(request, betas, signal) {
780
857
  try {
781
858
  return await client.messages.create(request, {
859
+ ...betas.length > 0 ? {
860
+ headers: {
861
+ "anthropic-beta": betas.join(",")
862
+ }
863
+ } : {},
782
864
  signal
783
865
  });
784
866
  } catch (error) {
@@ -791,14 +873,18 @@ function createAnthropicChatModel(client, modelId, defaultMaxTokens) {
791
873
  defaultMaxTokens,
792
874
  options
793
875
  );
794
- const response = await callAnthropicMessagesApi(request, options.signal);
876
+ const response = await callAnthropicMessagesApi(request, getAnthropicRequestBetas(modelId, options), options.signal);
795
877
  return mapGenerateResponse(response);
796
878
  }
797
879
  async function streamChat(options) {
798
880
  const request = createStreamRequest(modelId, defaultMaxTokens, options);
799
881
  return createChatStream(
800
882
  async () => transformStream(
801
- await callAnthropicMessagesApi(request, options.signal)
883
+ await callAnthropicMessagesApi(
884
+ request,
885
+ getAnthropicRequestBetas(modelId, options),
886
+ options.signal
887
+ )
802
888
  ),
803
889
  { signal: options.signal }
804
890
  );
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@core-ai/anthropic",
3
- "version": "0.13.0",
3
+ "version": "0.13.1",
4
4
  "description": "Anthropic provider package for @core-ai/core-ai",
5
5
  "license": "MIT",
6
6
  "author": "Omnifact (https://omnifact.ai)",
@@ -44,8 +44,8 @@
44
44
  "test:watch": "vitest"
45
45
  },
46
46
  "dependencies": {
47
- "@core-ai/core-ai": "^0.13.0",
48
- "@anthropic-ai/sdk": "^0.78.0"
47
+ "@anthropic-ai/sdk": "^0.110.0",
48
+ "@core-ai/core-ai": "^0.13.1"
49
49
  },
50
50
  "peerDependencies": {
51
51
  "zod": "^4.0.0"