@core-ai/anthropic 0.12.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.
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import Anthropic from '@anthropic-ai/sdk';
2
- import { ChatModel } from '@core-ai/core-ai';
2
+ import { ChatModel, ModelCapabilities } from '@core-ai/core-ai';
3
3
  import { z } from 'zod';
4
4
 
5
5
  type AnthropicProviderOptions$1 = {
@@ -18,6 +18,9 @@ type AnthropicReasoningMetadata = {
18
18
  redactedData?: string;
19
19
  };
20
20
 
21
+ type AnthropicModelCapabilities = ModelCapabilities;
22
+ declare function getAnthropicModelCapabilities(modelId: string): AnthropicModelCapabilities;
23
+
21
24
  declare const anthropicCacheControlSchema: z.ZodObject<{
22
25
  type: z.ZodLiteral<"ephemeral">;
23
26
  ttl: z.ZodOptional<z.ZodEnum<{
@@ -60,4 +63,4 @@ declare const anthropicProviderOptionsSchema: z.ZodObject<{
60
63
  }, z.core.$strict>;
61
64
  type AnthropicProviderOptions = AnthropicGenerateProviderOptions;
62
65
 
63
- export { type AnthropicCacheControl, type AnthropicGenerateProviderOptions, type AnthropicProviderOptions as AnthropicModelProviderOptions, type AnthropicProvider, type AnthropicProviderOptions$1 as AnthropicProviderOptions, type AnthropicReasoningMetadata, anthropicCacheControlSchema, anthropicGenerateProviderOptionsSchema, anthropicProviderOptionsSchema, createAnthropic };
66
+ export { type AnthropicCacheControl, type AnthropicGenerateProviderOptions, type AnthropicModelCapabilities, type AnthropicProviderOptions as AnthropicModelProviderOptions, type AnthropicProvider, type AnthropicProviderOptions$1 as AnthropicProviderOptions, type AnthropicReasoningMetadata, anthropicCacheControlSchema, anthropicGenerateProviderOptionsSchema, anthropicProviderOptionsSchema, createAnthropic, getAnthropicModelCapabilities };
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,
@@ -23,70 +24,67 @@ import {
23
24
  } from "@core-ai/core-ai";
24
25
 
25
26
  // src/model-capabilities.ts
26
- import { stripModelDateSuffix } from "@core-ai/core-ai";
27
- var DEFAULT_CAPABILITIES = {
28
- reasoning: {
29
- thinkingMode: "adaptive",
30
- supportsMaxEffort: false
31
- }
32
- };
33
- var ADAPTIVE_MAX_EFFORT_CAPABILITIES = {
34
- reasoning: {
35
- thinkingMode: "adaptive",
36
- supportsMaxEffort: true
37
- }
38
- };
39
- var MODEL_CAPABILITIES = {
40
- "claude-fable-5": ADAPTIVE_MAX_EFFORT_CAPABILITIES,
41
- "claude-mythos-5": ADAPTIVE_MAX_EFFORT_CAPABILITIES,
42
- "claude-mythos-preview": ADAPTIVE_MAX_EFFORT_CAPABILITIES,
43
- "claude-opus-4-8": ADAPTIVE_MAX_EFFORT_CAPABILITIES,
44
- "claude-opus-4-7": ADAPTIVE_MAX_EFFORT_CAPABILITIES,
45
- "claude-opus-4-6": ADAPTIVE_MAX_EFFORT_CAPABILITIES,
46
- "claude-sonnet-4-6": ADAPTIVE_MAX_EFFORT_CAPABILITIES,
47
- "claude-opus-4-5": {
48
- reasoning: {
49
- thinkingMode: "manual",
50
- supportsMaxEffort: false
51
- }
52
- },
53
- "claude-sonnet-4-5": {
54
- reasoning: {
55
- thinkingMode: "manual",
56
- supportsMaxEffort: false
57
- }
58
- },
59
- "claude-opus-4-1": {
60
- reasoning: {
61
- thinkingMode: "manual",
62
- supportsMaxEffort: false
63
- }
64
- },
65
- "claude-opus-4": {
66
- reasoning: {
67
- thinkingMode: "manual",
68
- supportsMaxEffort: false
69
- }
70
- },
71
- "claude-sonnet-4": {
72
- reasoning: {
73
- thinkingMode: "manual",
74
- supportsMaxEffort: false
75
- }
76
- },
77
- "claude-haiku-4-5": {
78
- reasoning: {
79
- thinkingMode: "manual",
80
- supportsMaxEffort: false
81
- }
82
- },
83
- "claude-sonnet-3-7": {
27
+ import {
28
+ stripModelDateSuffix
29
+ } from "@core-ai/core-ai";
30
+ var STANDARD_EFFORTS = [
31
+ "minimal",
32
+ "low",
33
+ "medium",
34
+ "high"
35
+ ];
36
+ var MAX_EFFORTS = [
37
+ "minimal",
38
+ "low",
39
+ "medium",
40
+ "high",
41
+ "max"
42
+ ];
43
+ function createCapabilities(supportedEfforts) {
44
+ return {
84
45
  reasoning: {
85
- thinkingMode: "manual",
86
- supportsMaxEffort: false
46
+ supported: true,
47
+ supportedEfforts,
48
+ restrictsSamplingParams: true
87
49
  }
88
- }
89
- };
50
+ };
51
+ }
52
+ var STANDARD_CAPABILITIES = createCapabilities(STANDARD_EFFORTS);
53
+ var MAX_EFFORT_CAPABILITIES = createCapabilities(MAX_EFFORTS);
54
+ var ADAPTIVE_MAX_EFFORT_MODELS = /* @__PURE__ */ new Set([
55
+ "claude-fable-5",
56
+ "claude-mythos-5",
57
+ "claude-mythos-preview",
58
+ "claude-opus-4-8",
59
+ "claude-opus-4-7",
60
+ "claude-opus-4-6",
61
+ "claude-sonnet-5",
62
+ "claude-sonnet-4-6"
63
+ ]);
64
+ var MANUAL_THINKING_MODELS = /* @__PURE__ */ new Set([
65
+ "claude-opus-4-5",
66
+ "claude-sonnet-4-5",
67
+ "claude-opus-4-1",
68
+ "claude-opus-4",
69
+ "claude-sonnet-4",
70
+ "claude-haiku-4-5",
71
+ "claude-sonnet-3-7"
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
+ ]);
90
88
  var ANTHROPIC_ADAPTIVE_EFFORT_MAP = {
91
89
  minimal: "low",
92
90
  low: "low",
@@ -101,20 +99,35 @@ var ANTHROPIC_MANUAL_BUDGET_MAP = {
101
99
  max: 65536
102
100
  };
103
101
  function getAnthropicModelCapabilities(modelId) {
104
- const normalizedModelId = normalizeModelId(modelId);
105
- return MODEL_CAPABILITIES[normalizedModelId] ?? DEFAULT_CAPABILITIES;
102
+ if (supportsAnthropicMaxEffort(modelId) || getAnthropicThinkingMode(modelId) === "manual") {
103
+ return MAX_EFFORT_CAPABILITIES;
104
+ }
105
+ return STANDARD_CAPABILITIES;
106
106
  }
107
107
  function normalizeModelId(modelId) {
108
108
  return stripModelDateSuffix(modelId);
109
109
  }
110
+ function getAnthropicThinkingMode(modelId) {
111
+ return MANUAL_THINKING_MODELS.has(normalizeModelId(modelId)) ? "manual" : "adaptive";
112
+ }
113
+ function supportsAnthropicMaxEffort(modelId) {
114
+ return ADAPTIVE_MAX_EFFORT_MODELS.has(normalizeModelId(modelId));
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
+ }
110
122
  function toAnthropicAdaptiveEffort(effort, supportsMaxEffort) {
111
123
  if (effort === "max") {
112
124
  return supportsMaxEffort ? "max" : "high";
113
125
  }
114
126
  return ANTHROPIC_ADAPTIVE_EFFORT_MAP[effort];
115
127
  }
116
- function toAnthropicManualBudget(effort) {
117
- 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);
118
131
  }
119
132
 
120
133
  // src/provider-options.ts
@@ -208,18 +221,17 @@ function convertMessages(messages) {
208
221
  });
209
222
  continue;
210
223
  }
211
- if (part.text.length === 0) {
224
+ if (typeof signature === "string") {
225
+ contentBlocks.push({
226
+ type: "thinking",
227
+ thinking: part.text,
228
+ signature
229
+ });
212
230
  continue;
213
231
  }
214
- if (typeof signature !== "string") {
232
+ if (part.text.length > 0) {
215
233
  contentBlocks.push({ type: "text", text: part.text });
216
- continue;
217
234
  }
218
- contentBlocks.push({
219
- type: "thinking",
220
- thinking: part.text,
221
- signature
222
- });
223
235
  }
224
236
  convertedMessages.push({
225
237
  role: "assistant",
@@ -405,13 +417,23 @@ function createStreamRequest(modelId, defaultMaxTokens, options) {
405
417
  return mapAnthropicProviderOptionsToRequest(baseRequest, anthropicOptions);
406
418
  }
407
419
  function createRequestBase(modelId, defaultMaxTokens, options, anthropicOptions) {
408
- validateAnthropicReasoningConfig(modelId, options, anthropicOptions);
420
+ const maxTokens = options.maxTokens ?? defaultMaxTokens;
421
+ validateAnthropicReasoningConfig(
422
+ modelId,
423
+ maxTokens,
424
+ options,
425
+ anthropicOptions
426
+ );
409
427
  const converted = convertMessages(options.messages);
410
- const reasoningFields = mapReasoningToRequestFields(modelId, options);
428
+ const reasoningFields = mapReasoningToRequestFields(
429
+ modelId,
430
+ maxTokens,
431
+ options
432
+ );
411
433
  return {
412
434
  model: modelId,
413
435
  messages: converted.messages,
414
- max_tokens: options.maxTokens ?? defaultMaxTokens,
436
+ max_tokens: maxTokens,
415
437
  ...converted.system ? { system: converted.system } : {},
416
438
  ...options.tools && Object.keys(options.tools).length > 0 ? { tools: convertTools(options.tools) } : {},
417
439
  ...options.toolChoice ? { tool_choice: convertToolChoice(options.toolChoice) } : {},
@@ -425,11 +447,40 @@ function mapSamplingToRequestFields(options) {
425
447
  ...options.topP !== void 0 ? { top_p: options.topP } : {}
426
448
  };
427
449
  }
428
- 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
+ }
429
473
  if (!options.reasoning) {
430
474
  return;
431
475
  }
432
- 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)) {
433
484
  throw new ValidationError(
434
485
  `Anthropic model "${modelId}" does not support temperature when reasoning is enabled`,
435
486
  void 0,
@@ -458,31 +509,48 @@ function validateAnthropicReasoningConfig(modelId, options, anthropicOptions) {
458
509
  );
459
510
  }
460
511
  }
461
- function mapReasoningToRequestFields(modelId, options) {
512
+ function mapReasoningToRequestFields(modelId, maxTokens, options) {
462
513
  if (!options.reasoning) {
463
514
  return {};
464
515
  }
516
+ const thinkingMode = getAnthropicThinkingMode(modelId);
465
517
  const capabilities = getAnthropicModelCapabilities(modelId);
518
+ const effort = clampReasoningEffort(
519
+ options.reasoning.effort,
520
+ capabilities.reasoning.supportedEfforts
521
+ );
466
522
  const baseFields = {};
467
- if (options.tools && Object.keys(options.tools).length > 0) {
468
- baseFields["betas"] = ["interleaved-thinking-2025-05-14"];
469
- }
470
- if (capabilities.reasoning.thinkingMode === "adaptive") {
471
- baseFields["thinking"] = { type: "adaptive" };
523
+ if (thinkingMode === "adaptive") {
524
+ baseFields["thinking"] = {
525
+ type: "adaptive",
526
+ display: "summarized"
527
+ };
472
528
  baseFields["output_config"] = {
473
529
  effort: toAnthropicAdaptiveEffort(
474
- options.reasoning.effort,
475
- capabilities.reasoning.supportsMaxEffort
530
+ effort,
531
+ supportsAnthropicMaxEffort(modelId)
476
532
  )
477
533
  };
478
534
  return baseFields;
479
535
  }
480
536
  baseFields["thinking"] = {
481
537
  type: "enabled",
482
- budget_tokens: toAnthropicManualBudget(options.reasoning.effort)
538
+ budget_tokens: toAnthropicManualBudget(effort, maxTokens),
539
+ display: "summarized"
483
540
  };
484
541
  return baseFields;
485
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
+ }
486
554
  function mapAnthropicProviderOptionsToRequest(baseRequest, providerOptions) {
487
555
  if (!providerOptions) {
488
556
  return baseRequest;
@@ -494,17 +562,12 @@ function mapAnthropicProviderOptionsToRequest(baseRequest, providerOptions) {
494
562
  ...baseOutputConfig,
495
563
  ...providerOptions.outputConfig ?? {}
496
564
  };
497
- const mergedBetas = [
498
- ...asStringArray(baseRequest.betas),
499
- ...providerOptions.betas ?? []
500
- ];
501
565
  const mergedRequest = {
502
566
  ...baseRequest,
503
567
  ...providerOptions.cacheControl ? { cache_control: providerOptions.cacheControl } : {},
504
568
  ...providerOptions.topK !== void 0 ? { top_k: providerOptions.topK } : {},
505
569
  ...providerOptions.stopSequences ? { stop_sequences: providerOptions.stopSequences } : {},
506
- ...Object.keys(mergedOutputConfig).length > 0 ? { output_config: mergedOutputConfig } : {},
507
- ...mergedBetas.length > 0 ? { betas: uniqueStrings(mergedBetas) } : {}
570
+ ...Object.keys(mergedOutputConfig).length > 0 ? { output_config: mergedOutputConfig } : {}
508
571
  };
509
572
  return mergedRequest;
510
573
  }
@@ -573,7 +636,7 @@ function mapGenerateResponse(response) {
573
636
  cacheReadTokens,
574
637
  cacheWriteTokens
575
638
  },
576
- outputTokenDetails: {}
639
+ outputTokenDetails: mapAnthropicOutputTokenDetails(response.usage)
577
640
  }
578
641
  };
579
642
  }
@@ -604,7 +667,9 @@ async function* transformStream(stream) {
604
667
  cacheReadTokens,
605
668
  cacheWriteTokens
606
669
  },
607
- outputTokenDetails: {}
670
+ outputTokenDetails: mapAnthropicOutputTokenDetails(
671
+ event.message.usage
672
+ )
608
673
  };
609
674
  continue;
610
675
  }
@@ -713,7 +778,10 @@ async function* transformStream(stream) {
713
778
  cacheReadTokens,
714
779
  cacheWriteTokens
715
780
  },
716
- outputTokenDetails: {}
781
+ outputTokenDetails: {
782
+ ...usage.outputTokenDetails,
783
+ ...mapAnthropicOutputTokenDetails(event.usage)
784
+ }
717
785
  };
718
786
  continue;
719
787
  }
@@ -739,11 +807,10 @@ function mapStopReason(reason) {
739
807
  }
740
808
  return "unknown";
741
809
  }
742
- function asStringArray(value) {
743
- if (!Array.isArray(value)) {
744
- return [];
745
- }
746
- 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 } : {};
747
814
  }
748
815
  function uniqueStrings(values) {
749
816
  return [...new Set(values)];
@@ -786,9 +853,14 @@ function wrapError(error) {
786
853
  // src/chat-model.ts
787
854
  function createAnthropicChatModel(client, modelId, defaultMaxTokens) {
788
855
  const provider = "anthropic";
789
- async function callAnthropicMessagesApi(request, signal) {
856
+ async function callAnthropicMessagesApi(request, betas, signal) {
790
857
  try {
791
858
  return await client.messages.create(request, {
859
+ ...betas.length > 0 ? {
860
+ headers: {
861
+ "anthropic-beta": betas.join(",")
862
+ }
863
+ } : {},
792
864
  signal
793
865
  });
794
866
  } catch (error) {
@@ -801,14 +873,18 @@ function createAnthropicChatModel(client, modelId, defaultMaxTokens) {
801
873
  defaultMaxTokens,
802
874
  options
803
875
  );
804
- const response = await callAnthropicMessagesApi(request, options.signal);
876
+ const response = await callAnthropicMessagesApi(request, getAnthropicRequestBetas(modelId, options), options.signal);
805
877
  return mapGenerateResponse(response);
806
878
  }
807
879
  async function streamChat(options) {
808
880
  const request = createStreamRequest(modelId, defaultMaxTokens, options);
809
881
  return createChatStream(
810
882
  async () => transformStream(
811
- await callAnthropicMessagesApi(request, options.signal)
883
+ await callAnthropicMessagesApi(
884
+ request,
885
+ getAnthropicRequestBetas(modelId, options),
886
+ options.signal
887
+ )
812
888
  ),
813
889
  { signal: options.signal }
814
890
  );
@@ -816,6 +892,7 @@ function createAnthropicChatModel(client, modelId, defaultMaxTokens) {
816
892
  return {
817
893
  provider,
818
894
  modelId,
895
+ capabilities: getAnthropicModelCapabilities(modelId),
819
896
  generate: generateChat,
820
897
  stream: streamChat,
821
898
  async generateObject(options) {
@@ -981,5 +1058,6 @@ export {
981
1058
  anthropicCacheControlSchema,
982
1059
  anthropicGenerateProviderOptionsSchema,
983
1060
  anthropicProviderOptionsSchema,
984
- createAnthropic
1061
+ createAnthropic,
1062
+ getAnthropicModelCapabilities
985
1063
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@core-ai/anthropic",
3
- "version": "0.12.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.12.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"