@core-ai/anthropic 0.15.0 → 0.17.0

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 +174 -22
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -2,18 +2,181 @@
2
2
  import Anthropic from "@anthropic-ai/sdk";
3
3
 
4
4
  // src/chat-adapter.ts
5
- import { APIError, APIUserAbortError } from "@anthropic-ai/sdk";
6
5
  import {
7
- AbortedError,
8
6
  asObject,
9
7
  clampReasoningEffort,
10
8
  getProviderMetadata,
11
- ProviderError,
12
9
  ValidationError,
13
10
  safeParseJsonObject,
14
11
  zodSchemaToJsonSchema
15
12
  } from "@core-ai/core-ai";
16
13
 
14
+ // src/anthropic-error.ts
15
+ import { APIError, APIUserAbortError } from "@anthropic-ai/sdk";
16
+ import {
17
+ AbortedError,
18
+ ContextLengthExceededError,
19
+ ModelOverloadedError,
20
+ ProviderError,
21
+ RateLimitError,
22
+ ServiceUnavailableError,
23
+ asRecord,
24
+ getErrorMessage,
25
+ getHttpStatusCode,
26
+ getRetryAfterSecondsFromError,
27
+ getString,
28
+ isAbortErrorByName,
29
+ isRateLimitStatus,
30
+ isTransientUnavailableStatus
31
+ } from "@core-ai/core-ai";
32
+ var OVERLOAD_MESSAGE_ELIGIBLE_STATUS_CODES = /* @__PURE__ */ new Set([
33
+ 500,
34
+ 502,
35
+ 503,
36
+ 504,
37
+ 529
38
+ ]);
39
+ function wrapAnthropicError(error, provider = "anthropic") {
40
+ if (isAnthropicAbortError(error)) {
41
+ return new AbortedError(error, provider);
42
+ }
43
+ const message = getErrorMessage(error);
44
+ const statusCode = error instanceof APIError ? error.status : getHttpStatusCode(error, ["status"]);
45
+ const providerMessage = getAnthropicErrorMessage(error);
46
+ const errorType = getAnthropicErrorType(error);
47
+ const options = { statusCode, cause: error };
48
+ const contextLength = getContextLengthDetails(providerMessage, errorType);
49
+ if (contextLength) {
50
+ return new ContextLengthExceededError(message, provider, {
51
+ ...options,
52
+ ...contextLength
53
+ });
54
+ }
55
+ if (isAnthropicOverloaded(errorType, providerMessage, message, statusCode)) {
56
+ return new ModelOverloadedError(message, provider, options);
57
+ }
58
+ if (isAnthropicRateLimit(error, statusCode, errorType)) {
59
+ return new RateLimitError(message, provider, {
60
+ ...options,
61
+ retryAfterSeconds: getRetryAfterSecondsFromError(error)
62
+ });
63
+ }
64
+ if (isUnavailableStatus(error) || isTransientUnavailableStatus(statusCode)) {
65
+ return new ServiceUnavailableError(message, provider, options);
66
+ }
67
+ return new ProviderError(message, provider, options);
68
+ }
69
+ function isAnthropicAbortError(error) {
70
+ return error instanceof APIUserAbortError || isAbortErrorByName(error);
71
+ }
72
+ function isAnthropicOverloaded(errorType, providerMessage, message, statusCode) {
73
+ return statusCode === 529 || errorType === "overloaded_error" || indicatesAnthropicOverload(
74
+ `${providerMessage ?? ""} ${message}`,
75
+ statusCode
76
+ );
77
+ }
78
+ function indicatesAnthropicOverload(text, statusCode) {
79
+ if (statusCode !== void 0 && !OVERLOAD_MESSAGE_ELIGIBLE_STATUS_CODES.has(statusCode)) {
80
+ return false;
81
+ }
82
+ return /\boverloaded\b/i.test(text);
83
+ }
84
+ function isAnthropicRateLimit(error, statusCode, errorType) {
85
+ return isRateLimitStatus(statusCode) || errorType === "rate_limit_error" || isResourceExhaustedError(error);
86
+ }
87
+ function getContextLengthDetails(providerMessage, errorType) {
88
+ if (errorType === "rate_limit_error" || !providerMessage) {
89
+ return void 0;
90
+ }
91
+ if (!/prompt is too long/i.test(providerMessage)) {
92
+ const inputTokensMatch = providerMessage.match(
93
+ /Input tokens exceed the context limit of (\d+)/i
94
+ );
95
+ if (inputTokensMatch?.[1]) {
96
+ return { maxTokens: parseInt(inputTokensMatch[1], 10) };
97
+ }
98
+ return void 0;
99
+ }
100
+ const withMaximum = providerMessage.match(
101
+ /prompt is too long: (\d+) tokens > (\d+) maximum/i
102
+ );
103
+ if (withMaximum) {
104
+ const actualTokens = withMaximum[1];
105
+ const maxTokens = withMaximum[2];
106
+ if (actualTokens !== void 0 && maxTokens !== void 0) {
107
+ return {
108
+ maxTokens: parseInt(maxTokens, 10),
109
+ actualTokens: parseInt(actualTokens, 10)
110
+ };
111
+ }
112
+ }
113
+ const withoutMaximum = providerMessage.match(
114
+ /prompt is too long: (\d+) tokens > (\d+)/i
115
+ );
116
+ if (withoutMaximum) {
117
+ const actualTokens = withoutMaximum[1];
118
+ const maxTokens = withoutMaximum[2];
119
+ if (actualTokens !== void 0 && maxTokens !== void 0) {
120
+ return {
121
+ maxTokens: parseInt(maxTokens, 10),
122
+ actualTokens: parseInt(actualTokens, 10)
123
+ };
124
+ }
125
+ }
126
+ return {};
127
+ }
128
+ function isResourceExhaustedError(error) {
129
+ const body = getNestedGoogleApiErrorBody(error);
130
+ if (!body) {
131
+ return false;
132
+ }
133
+ const code = typeof body.code === "number" ? body.code : Number(body.code);
134
+ return code === 429 || body.status?.toUpperCase() === "RESOURCE_EXHAUSTED";
135
+ }
136
+ function isUnavailableStatus(error) {
137
+ const body = getNestedGoogleApiErrorBody(error);
138
+ return body?.status?.toUpperCase() === "UNAVAILABLE";
139
+ }
140
+ function getNestedGoogleApiErrorBody(error) {
141
+ const record = asRecord(error);
142
+ const outer = asRecord(record?.error);
143
+ if (!outer) {
144
+ return void 0;
145
+ }
146
+ const inner = asRecord(outer.error);
147
+ if (inner && ("code" in inner || "status" in inner)) {
148
+ return inner;
149
+ }
150
+ if ("code" in outer || "status" in outer) {
151
+ return outer;
152
+ }
153
+ return void 0;
154
+ }
155
+ function getAnthropicErrorMessage(error) {
156
+ if (error instanceof APIError) {
157
+ const nested = asRecord(error.error);
158
+ return getString(nested, "message") ?? error.message;
159
+ }
160
+ const record = asRecord(error);
161
+ const outer = asRecord(record?.error);
162
+ const inner = asRecord(outer?.error);
163
+ return getString(inner, "message") ?? getString(outer, "message") ?? getString(record, "message");
164
+ }
165
+ function getAnthropicErrorType(error) {
166
+ if (error instanceof APIError) {
167
+ if (typeof error.type === "string") {
168
+ return error.type;
169
+ }
170
+ if (typeof error.error === "object" && error.error) {
171
+ return getString(asRecord(error.error), "type");
172
+ }
173
+ }
174
+ const record = asRecord(error);
175
+ const outer = asRecord(record?.error);
176
+ const inner = asRecord(outer?.error);
177
+ return getString(inner, "type") ?? getString(outer, "type");
178
+ }
179
+
17
180
  // src/model-capabilities.ts
18
181
  import {
19
182
  stripModelDateSuffix
@@ -34,9 +197,10 @@ var MAX_EFFORTS = [
34
197
  function createCapabilities(supportedEfforts) {
35
198
  return {
36
199
  reasoning: {
37
- supported: true,
200
+ mode: "optional",
38
201
  supportedEfforts,
39
- restrictsSamplingParams: true
202
+ restrictsSamplingParams: true,
203
+ supportedToolChoices: ["auto", "none"]
40
204
  }
41
205
  };
42
206
  }
@@ -477,6 +641,7 @@ function validateAnthropicReasoningConfig(modelId, maxTokens, options, anthropic
477
641
  provider
478
642
  );
479
643
  }
644
+ const capabilities = getAnthropicModelCapabilities(modelId);
480
645
  if (options.temperature !== void 0 && (!alwaysRestrictsSampling || options.temperature !== 1)) {
481
646
  throw new ValidationError(
482
647
  `Anthropic model "${modelId}" does not support temperature when reasoning is enabled`,
@@ -491,9 +656,10 @@ function validateAnthropicReasoningConfig(modelId, maxTokens, options, anthropic
491
656
  provider
492
657
  );
493
658
  }
494
- if (options.toolChoice && options.toolChoice !== "auto" && options.toolChoice !== "none") {
659
+ const toolChoiceMode = typeof options.toolChoice === "object" ? options.toolChoice.type : options.toolChoice;
660
+ if (toolChoiceMode !== void 0 && !capabilities.reasoning.supportedToolChoices.includes(toolChoiceMode)) {
495
661
  throw new ValidationError(
496
- `Anthropic model "${modelId}" only supports toolChoice "auto" or "none" when reasoning is enabled`,
662
+ `Anthropic model "${modelId}" does not support toolChoice "${toolChoiceMode}" when reasoning is enabled`,
497
663
  void 0,
498
664
  provider
499
665
  );
@@ -840,20 +1006,6 @@ function extractThinkingText(value) {
840
1006
  return typeof text === "string" ? [text] : [];
841
1007
  }).join("");
842
1008
  }
843
- function wrapError(error, provider = DEFAULT_PROVIDER_ID) {
844
- if (error instanceof APIUserAbortError || error instanceof Error && error.name === "AbortError") {
845
- return new AbortedError(error, provider);
846
- }
847
- if (error instanceof APIError) {
848
- return new ProviderError(error.message, provider, error.status, error);
849
- }
850
- return new ProviderError(
851
- error instanceof Error ? error.message : String(error),
852
- provider,
853
- void 0,
854
- error
855
- );
856
- }
857
1009
 
858
1010
  // src/chat-model.ts
859
1011
  import {
@@ -878,7 +1030,7 @@ function createAnthropicChatModel(client, modelId, modelOptions = {}) {
878
1030
  signal
879
1031
  });
880
1032
  } catch (error) {
881
- throw wrapError(error, provider);
1033
+ throw wrapAnthropicError(error, provider);
882
1034
  }
883
1035
  }
884
1036
  async function generateChat(options) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@core-ai/anthropic",
3
- "version": "0.15.0",
3
+ "version": "0.17.0",
4
4
  "description": "Anthropic provider package for @core-ai/core-ai",
5
5
  "license": "MIT",
6
6
  "author": "Omnifact (https://omnifact.ai)",
@@ -45,7 +45,7 @@
45
45
  },
46
46
  "dependencies": {
47
47
  "@anthropic-ai/sdk": "^0.110.0",
48
- "@core-ai/core-ai": "^0.15.0"
48
+ "@core-ai/core-ai": "^0.17.0"
49
49
  },
50
50
  "peerDependencies": {
51
51
  "zod": "^4.0.0"