@core-ai/anthropic 0.4.0 → 0.6.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.
- package/dist/index.d.ts +49 -3
- package/dist/index.js +429 -65
- package/package.json +5 -5
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import Anthropic from '@anthropic-ai/sdk';
|
|
2
2
|
import { ChatModel } from '@core-ai/core-ai';
|
|
3
|
+
import { z } from 'zod';
|
|
3
4
|
|
|
4
|
-
type AnthropicProviderOptions = {
|
|
5
|
+
type AnthropicProviderOptions$1 = {
|
|
5
6
|
apiKey?: string;
|
|
6
7
|
baseURL?: string;
|
|
7
8
|
client?: Anthropic;
|
|
@@ -10,6 +11,51 @@ type AnthropicProviderOptions = {
|
|
|
10
11
|
type AnthropicProvider = {
|
|
11
12
|
chatModel(modelId: string): ChatModel;
|
|
12
13
|
};
|
|
13
|
-
declare function createAnthropic(options?: AnthropicProviderOptions): AnthropicProvider;
|
|
14
|
+
declare function createAnthropic(options?: AnthropicProviderOptions$1): AnthropicProvider;
|
|
14
15
|
|
|
15
|
-
|
|
16
|
+
type AnthropicReasoningMetadata = {
|
|
17
|
+
signature?: string;
|
|
18
|
+
redactedData?: string;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
declare const anthropicGenerateProviderOptionsSchema: z.ZodObject<{
|
|
22
|
+
topK: z.ZodOptional<z.ZodNumber>;
|
|
23
|
+
stopSequences: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
24
|
+
betas: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
25
|
+
outputConfig: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
26
|
+
}, "strict", z.ZodTypeAny, {
|
|
27
|
+
topK?: number | undefined;
|
|
28
|
+
stopSequences?: string[] | undefined;
|
|
29
|
+
betas?: string[] | undefined;
|
|
30
|
+
outputConfig?: Record<string, unknown> | undefined;
|
|
31
|
+
}, {
|
|
32
|
+
topK?: number | undefined;
|
|
33
|
+
stopSequences?: string[] | undefined;
|
|
34
|
+
betas?: string[] | undefined;
|
|
35
|
+
outputConfig?: Record<string, unknown> | undefined;
|
|
36
|
+
}>;
|
|
37
|
+
type AnthropicGenerateProviderOptions = z.infer<typeof anthropicGenerateProviderOptionsSchema>;
|
|
38
|
+
declare module '@core-ai/core-ai' {
|
|
39
|
+
interface GenerateProviderOptions {
|
|
40
|
+
anthropic?: AnthropicGenerateProviderOptions;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
declare const anthropicProviderOptionsSchema: z.ZodObject<{
|
|
44
|
+
topK: z.ZodOptional<z.ZodNumber>;
|
|
45
|
+
stopSequences: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
46
|
+
betas: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
47
|
+
outputConfig: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
48
|
+
}, "strict", z.ZodTypeAny, {
|
|
49
|
+
topK?: number | undefined;
|
|
50
|
+
stopSequences?: string[] | undefined;
|
|
51
|
+
betas?: string[] | undefined;
|
|
52
|
+
outputConfig?: Record<string, unknown> | undefined;
|
|
53
|
+
}, {
|
|
54
|
+
topK?: number | undefined;
|
|
55
|
+
stopSequences?: string[] | undefined;
|
|
56
|
+
betas?: string[] | undefined;
|
|
57
|
+
outputConfig?: Record<string, unknown> | undefined;
|
|
58
|
+
}>;
|
|
59
|
+
type AnthropicProviderOptions = AnthropicGenerateProviderOptions;
|
|
60
|
+
|
|
61
|
+
export { type AnthropicGenerateProviderOptions, type AnthropicProviderOptions as AnthropicModelProviderOptions, type AnthropicProvider, type AnthropicProviderOptions$1 as AnthropicProviderOptions, type AnthropicReasoningMetadata, anthropicGenerateProviderOptionsSchema, anthropicProviderOptionsSchema, createAnthropic };
|
package/dist/index.js
CHANGED
|
@@ -6,14 +6,128 @@ import {
|
|
|
6
6
|
StructuredOutputNoObjectGeneratedError,
|
|
7
7
|
StructuredOutputParseError,
|
|
8
8
|
StructuredOutputValidationError,
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
createObjectStream,
|
|
10
|
+
createChatStream
|
|
11
11
|
} from "@core-ai/core-ai";
|
|
12
12
|
|
|
13
13
|
// src/chat-adapter.ts
|
|
14
14
|
import { APIError } from "@anthropic-ai/sdk";
|
|
15
15
|
import { zodToJsonSchema } from "zod-to-json-schema";
|
|
16
|
-
import { ProviderError } from "@core-ai/core-ai";
|
|
16
|
+
import { ProviderError, getProviderMetadata } from "@core-ai/core-ai";
|
|
17
|
+
|
|
18
|
+
// src/model-capabilities.ts
|
|
19
|
+
var DEFAULT_CAPABILITIES = {
|
|
20
|
+
reasoning: {
|
|
21
|
+
thinkingMode: "adaptive",
|
|
22
|
+
supportsMaxEffort: false
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
var MODEL_CAPABILITIES = {
|
|
26
|
+
"claude-opus-4-6": {
|
|
27
|
+
reasoning: {
|
|
28
|
+
thinkingMode: "adaptive",
|
|
29
|
+
supportsMaxEffort: true
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
"claude-sonnet-4-6": {
|
|
33
|
+
reasoning: {
|
|
34
|
+
thinkingMode: "adaptive",
|
|
35
|
+
supportsMaxEffort: false
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
"claude-opus-4-5": {
|
|
39
|
+
reasoning: {
|
|
40
|
+
thinkingMode: "manual",
|
|
41
|
+
supportsMaxEffort: false
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
"claude-sonnet-4-5": {
|
|
45
|
+
reasoning: {
|
|
46
|
+
thinkingMode: "manual",
|
|
47
|
+
supportsMaxEffort: false
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
"claude-opus-4-1": {
|
|
51
|
+
reasoning: {
|
|
52
|
+
thinkingMode: "manual",
|
|
53
|
+
supportsMaxEffort: false
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
"claude-opus-4": {
|
|
57
|
+
reasoning: {
|
|
58
|
+
thinkingMode: "manual",
|
|
59
|
+
supportsMaxEffort: false
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
"claude-sonnet-4": {
|
|
63
|
+
reasoning: {
|
|
64
|
+
thinkingMode: "manual",
|
|
65
|
+
supportsMaxEffort: false
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
"claude-haiku-4-5": {
|
|
69
|
+
reasoning: {
|
|
70
|
+
thinkingMode: "manual",
|
|
71
|
+
supportsMaxEffort: false
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
"claude-sonnet-3-7": {
|
|
75
|
+
reasoning: {
|
|
76
|
+
thinkingMode: "manual",
|
|
77
|
+
supportsMaxEffort: false
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
function getAnthropicModelCapabilities(modelId) {
|
|
82
|
+
const normalizedModelId = normalizeModelId(modelId);
|
|
83
|
+
return MODEL_CAPABILITIES[normalizedModelId] ?? DEFAULT_CAPABILITIES;
|
|
84
|
+
}
|
|
85
|
+
function normalizeModelId(modelId) {
|
|
86
|
+
return modelId.replace(/-\d{8}$/, "");
|
|
87
|
+
}
|
|
88
|
+
function toAnthropicAdaptiveEffort(effort, supportsMaxEffort) {
|
|
89
|
+
if (effort === "minimal") {
|
|
90
|
+
return "low";
|
|
91
|
+
}
|
|
92
|
+
if (effort === "max") {
|
|
93
|
+
return supportsMaxEffort ? "max" : "high";
|
|
94
|
+
}
|
|
95
|
+
return effort;
|
|
96
|
+
}
|
|
97
|
+
function toAnthropicManualBudget(effort) {
|
|
98
|
+
if (effort === "minimal") {
|
|
99
|
+
return 1024;
|
|
100
|
+
}
|
|
101
|
+
if (effort === "low") {
|
|
102
|
+
return 2048;
|
|
103
|
+
}
|
|
104
|
+
if (effort === "medium") {
|
|
105
|
+
return 8192;
|
|
106
|
+
}
|
|
107
|
+
if (effort === "high") {
|
|
108
|
+
return 32768;
|
|
109
|
+
}
|
|
110
|
+
return 65536;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// src/provider-options.ts
|
|
114
|
+
import { z } from "zod";
|
|
115
|
+
var anthropicGenerateProviderOptionsSchema = z.object({
|
|
116
|
+
topK: z.number().int().optional(),
|
|
117
|
+
stopSequences: z.array(z.string()).optional(),
|
|
118
|
+
betas: z.array(z.string()).optional(),
|
|
119
|
+
outputConfig: z.record(z.string(), z.unknown()).optional()
|
|
120
|
+
}).strict();
|
|
121
|
+
function parseAnthropicGenerateProviderOptions(providerOptions) {
|
|
122
|
+
const rawOptions = providerOptions?.anthropic;
|
|
123
|
+
if (rawOptions === void 0) {
|
|
124
|
+
return void 0;
|
|
125
|
+
}
|
|
126
|
+
return anthropicGenerateProviderOptionsSchema.parse(rawOptions);
|
|
127
|
+
}
|
|
128
|
+
var anthropicProviderOptionsSchema = anthropicGenerateProviderOptionsSchema;
|
|
129
|
+
|
|
130
|
+
// src/chat-adapter.ts
|
|
17
131
|
var UNSUPPORTED_ANTHROPIC_SCHEMA_KEYWORDS = /* @__PURE__ */ new Set([
|
|
18
132
|
"minimum",
|
|
19
133
|
"maximum",
|
|
@@ -44,18 +158,55 @@ function convertMessages(messages) {
|
|
|
44
158
|
}
|
|
45
159
|
if (message.role === "assistant") {
|
|
46
160
|
const contentBlocks = [];
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
161
|
+
for (const part of message.parts) {
|
|
162
|
+
if (part.type === "text") {
|
|
163
|
+
contentBlocks.push({
|
|
164
|
+
type: "text",
|
|
165
|
+
text: part.text
|
|
166
|
+
});
|
|
167
|
+
continue;
|
|
168
|
+
}
|
|
169
|
+
if (part.type === "tool-call") {
|
|
170
|
+
contentBlocks.push({
|
|
171
|
+
type: "tool_use",
|
|
172
|
+
id: part.toolCall.id,
|
|
173
|
+
name: part.toolCall.name,
|
|
174
|
+
input: part.toolCall.arguments
|
|
175
|
+
});
|
|
176
|
+
continue;
|
|
177
|
+
}
|
|
178
|
+
const anthropicMeta = getProviderMetadata(
|
|
179
|
+
part.providerMetadata,
|
|
180
|
+
"anthropic"
|
|
181
|
+
);
|
|
182
|
+
if (anthropicMeta == null) {
|
|
183
|
+
if (part.text.length > 0) {
|
|
184
|
+
contentBlocks.push({
|
|
185
|
+
type: "text",
|
|
186
|
+
text: `<thinking>${part.text}</thinking>`
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
continue;
|
|
190
|
+
}
|
|
191
|
+
const { signature, redactedData } = anthropicMeta;
|
|
192
|
+
if (typeof redactedData === "string") {
|
|
193
|
+
contentBlocks.push({
|
|
194
|
+
type: "redacted_thinking",
|
|
195
|
+
data: redactedData
|
|
196
|
+
});
|
|
197
|
+
continue;
|
|
198
|
+
}
|
|
199
|
+
if (part.text.length === 0) {
|
|
200
|
+
continue;
|
|
201
|
+
}
|
|
202
|
+
if (typeof signature !== "string") {
|
|
203
|
+
contentBlocks.push({ type: "text", text: part.text });
|
|
204
|
+
continue;
|
|
205
|
+
}
|
|
54
206
|
contentBlocks.push({
|
|
55
|
-
type: "
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
input: toolCall.arguments
|
|
207
|
+
type: "thinking",
|
|
208
|
+
thinking: part.text,
|
|
209
|
+
signature
|
|
59
210
|
});
|
|
60
211
|
}
|
|
61
212
|
convertedMessages.push({
|
|
@@ -163,13 +314,19 @@ function createStructuredOutputOptions(options) {
|
|
|
163
314
|
}
|
|
164
315
|
return {
|
|
165
316
|
messages: options.messages,
|
|
166
|
-
|
|
317
|
+
reasoning: options.reasoning,
|
|
318
|
+
temperature: options.temperature,
|
|
319
|
+
maxTokens: options.maxTokens,
|
|
320
|
+
topP: options.topP,
|
|
167
321
|
providerOptions: {
|
|
168
322
|
...options.providerOptions ?? {},
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
323
|
+
anthropic: {
|
|
324
|
+
...options.providerOptions?.anthropic ?? {},
|
|
325
|
+
outputConfig: {
|
|
326
|
+
format: {
|
|
327
|
+
type: "json_schema",
|
|
328
|
+
schema
|
|
329
|
+
}
|
|
173
330
|
}
|
|
174
331
|
}
|
|
175
332
|
},
|
|
@@ -210,58 +367,187 @@ function isJsonObject(value) {
|
|
|
210
367
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
211
368
|
}
|
|
212
369
|
function createGenerateRequest(modelId, defaultMaxTokens, options) {
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
370
|
+
const anthropicOptions = parseAnthropicGenerateProviderOptions(
|
|
371
|
+
options.providerOptions
|
|
372
|
+
);
|
|
373
|
+
const baseRequest = createRequestBase(
|
|
374
|
+
modelId,
|
|
375
|
+
defaultMaxTokens,
|
|
376
|
+
options,
|
|
377
|
+
anthropicOptions
|
|
378
|
+
);
|
|
379
|
+
return mapAnthropicProviderOptionsToRequest(baseRequest, anthropicOptions);
|
|
217
380
|
}
|
|
218
381
|
function createStreamRequest(modelId, defaultMaxTokens, options) {
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
382
|
+
const anthropicOptions = parseAnthropicGenerateProviderOptions(
|
|
383
|
+
options.providerOptions
|
|
384
|
+
);
|
|
385
|
+
const baseRequest = {
|
|
386
|
+
...createRequestBase(
|
|
387
|
+
modelId,
|
|
388
|
+
defaultMaxTokens,
|
|
389
|
+
options,
|
|
390
|
+
anthropicOptions
|
|
391
|
+
),
|
|
392
|
+
stream: true
|
|
223
393
|
};
|
|
394
|
+
return mapAnthropicProviderOptionsToRequest(baseRequest, anthropicOptions);
|
|
224
395
|
}
|
|
225
|
-
function createRequestBase(modelId, defaultMaxTokens, options) {
|
|
396
|
+
function createRequestBase(modelId, defaultMaxTokens, options, anthropicOptions) {
|
|
397
|
+
validateAnthropicReasoningConfig(modelId, options, anthropicOptions);
|
|
226
398
|
const converted = convertMessages(options.messages);
|
|
399
|
+
const reasoningFields = mapReasoningToRequestFields(modelId, options);
|
|
227
400
|
return {
|
|
228
401
|
model: modelId,
|
|
229
402
|
messages: converted.messages,
|
|
230
|
-
max_tokens: options.
|
|
403
|
+
max_tokens: options.maxTokens ?? defaultMaxTokens,
|
|
231
404
|
...converted.system ? { system: converted.system } : {},
|
|
232
405
|
...options.tools && Object.keys(options.tools).length > 0 ? { tools: convertTools(options.tools) } : {},
|
|
233
406
|
...options.toolChoice ? { tool_choice: convertToolChoice(options.toolChoice) } : {},
|
|
234
|
-
...
|
|
407
|
+
...reasoningFields,
|
|
408
|
+
...mapSamplingToRequestFields(options)
|
|
235
409
|
};
|
|
236
410
|
}
|
|
237
|
-
function
|
|
411
|
+
function mapSamplingToRequestFields(options) {
|
|
238
412
|
return {
|
|
239
|
-
...
|
|
240
|
-
...
|
|
241
|
-
|
|
413
|
+
...options.temperature !== void 0 ? { temperature: options.temperature } : {},
|
|
414
|
+
...options.topP !== void 0 ? { top_p: options.topP } : {}
|
|
415
|
+
};
|
|
416
|
+
}
|
|
417
|
+
function validateAnthropicReasoningConfig(modelId, options, anthropicOptions) {
|
|
418
|
+
if (!options.reasoning) {
|
|
419
|
+
return;
|
|
420
|
+
}
|
|
421
|
+
if (options.temperature !== void 0) {
|
|
422
|
+
throw new ProviderError(
|
|
423
|
+
`Anthropic model "${modelId}" does not support temperature when reasoning is enabled`,
|
|
424
|
+
"anthropic"
|
|
425
|
+
);
|
|
426
|
+
}
|
|
427
|
+
if (options.topP !== void 0 && (options.topP < 0.95 || options.topP > 1)) {
|
|
428
|
+
throw new ProviderError(
|
|
429
|
+
`Anthropic model "${modelId}" requires topP between 0.95 and 1 when reasoning is enabled`,
|
|
430
|
+
"anthropic"
|
|
431
|
+
);
|
|
432
|
+
}
|
|
433
|
+
if (options.toolChoice && options.toolChoice !== "auto" && options.toolChoice !== "none") {
|
|
434
|
+
throw new ProviderError(
|
|
435
|
+
`Anthropic model "${modelId}" only supports toolChoice "auto" or "none" when reasoning is enabled`,
|
|
436
|
+
"anthropic"
|
|
437
|
+
);
|
|
438
|
+
}
|
|
439
|
+
if (anthropicOptions?.topK !== void 0) {
|
|
440
|
+
throw new ProviderError(
|
|
441
|
+
`Anthropic model "${modelId}" does not support top_k when reasoning is enabled`,
|
|
442
|
+
"anthropic"
|
|
443
|
+
);
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
function mapReasoningToRequestFields(modelId, options) {
|
|
447
|
+
if (!options.reasoning) {
|
|
448
|
+
return {};
|
|
449
|
+
}
|
|
450
|
+
const capabilities = getAnthropicModelCapabilities(modelId);
|
|
451
|
+
const baseFields = {};
|
|
452
|
+
if (options.tools && Object.keys(options.tools).length > 0) {
|
|
453
|
+
baseFields["betas"] = ["interleaved-thinking-2025-05-14"];
|
|
454
|
+
}
|
|
455
|
+
if (capabilities.reasoning.thinkingMode === "adaptive") {
|
|
456
|
+
baseFields["thinking"] = { type: "adaptive" };
|
|
457
|
+
baseFields["output_config"] = {
|
|
458
|
+
effort: toAnthropicAdaptiveEffort(
|
|
459
|
+
options.reasoning.effort,
|
|
460
|
+
capabilities.reasoning.supportsMaxEffort
|
|
461
|
+
)
|
|
462
|
+
};
|
|
463
|
+
return baseFields;
|
|
464
|
+
}
|
|
465
|
+
baseFields["thinking"] = {
|
|
466
|
+
type: "enabled",
|
|
467
|
+
budget_tokens: toAnthropicManualBudget(options.reasoning.effort)
|
|
242
468
|
};
|
|
469
|
+
return baseFields;
|
|
470
|
+
}
|
|
471
|
+
function mapAnthropicProviderOptionsToRequest(baseRequest, providerOptions) {
|
|
472
|
+
if (!providerOptions) {
|
|
473
|
+
return baseRequest;
|
|
474
|
+
}
|
|
475
|
+
const baseOutputConfig = asObject(
|
|
476
|
+
baseRequest.output_config
|
|
477
|
+
);
|
|
478
|
+
const mergedOutputConfig = {
|
|
479
|
+
...baseOutputConfig,
|
|
480
|
+
...providerOptions.outputConfig ?? {}
|
|
481
|
+
};
|
|
482
|
+
const mergedBetas = [
|
|
483
|
+
...asStringArray(baseRequest.betas),
|
|
484
|
+
...providerOptions.betas ?? []
|
|
485
|
+
];
|
|
486
|
+
const mergedRequest = {
|
|
487
|
+
...baseRequest,
|
|
488
|
+
...providerOptions.topK !== void 0 ? { top_k: providerOptions.topK } : {},
|
|
489
|
+
...providerOptions.stopSequences ? { stop_sequences: providerOptions.stopSequences } : {},
|
|
490
|
+
...Object.keys(mergedOutputConfig).length > 0 ? { output_config: mergedOutputConfig } : {},
|
|
491
|
+
...mergedBetas.length > 0 ? { betas: uniqueStrings(mergedBetas) } : {}
|
|
492
|
+
};
|
|
493
|
+
return mergedRequest;
|
|
243
494
|
}
|
|
244
495
|
function mapGenerateResponse(response) {
|
|
245
|
-
const
|
|
246
|
-
let content = "";
|
|
496
|
+
const parts = [];
|
|
247
497
|
for (const block of response.content) {
|
|
248
498
|
if (block.type === "text") {
|
|
249
|
-
|
|
499
|
+
parts.push({
|
|
500
|
+
type: "text",
|
|
501
|
+
text: block.text
|
|
502
|
+
});
|
|
250
503
|
continue;
|
|
251
504
|
}
|
|
252
505
|
if (block.type === "tool_use") {
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
506
|
+
parts.push({
|
|
507
|
+
type: "tool-call",
|
|
508
|
+
toolCall: {
|
|
509
|
+
id: block.id,
|
|
510
|
+
name: block.name,
|
|
511
|
+
arguments: asObject(block.input)
|
|
512
|
+
}
|
|
513
|
+
});
|
|
514
|
+
continue;
|
|
515
|
+
}
|
|
516
|
+
if (block.type === "thinking") {
|
|
517
|
+
const thinkingText = typeof block.thinking === "string" ? block.thinking : extractThinkingText(block.thinking);
|
|
518
|
+
const signature = typeof block.signature === "string" ? block.signature : void 0;
|
|
519
|
+
parts.push({
|
|
520
|
+
type: "reasoning",
|
|
521
|
+
text: thinkingText,
|
|
522
|
+
providerMetadata: {
|
|
523
|
+
anthropic: { ...signature ? { signature } : {} }
|
|
524
|
+
}
|
|
525
|
+
});
|
|
526
|
+
continue;
|
|
527
|
+
}
|
|
528
|
+
if (block.type === "redacted_thinking") {
|
|
529
|
+
const redactedData = typeof block.data === "string" ? block.data : void 0;
|
|
530
|
+
parts.push({
|
|
531
|
+
type: "reasoning",
|
|
532
|
+
text: "",
|
|
533
|
+
providerMetadata: {
|
|
534
|
+
anthropic: { ...redactedData ? { redactedData } : {} }
|
|
535
|
+
}
|
|
257
536
|
});
|
|
258
537
|
}
|
|
259
538
|
}
|
|
260
539
|
const cacheReadTokens = response.usage.cache_read_input_tokens ?? 0;
|
|
261
540
|
const cacheWriteTokens = response.usage.cache_creation_input_tokens ?? 0;
|
|
262
541
|
const inputTokens = response.usage.input_tokens + cacheReadTokens + cacheWriteTokens;
|
|
542
|
+
const content = parts.flatMap((part) => part.type === "text" ? [part.text] : []).join("");
|
|
543
|
+
const reasoning = parts.flatMap((part) => part.type === "reasoning" ? [part.text] : []).join("");
|
|
544
|
+
const toolCalls = parts.flatMap(
|
|
545
|
+
(part) => part.type === "tool-call" ? [part.toolCall] : []
|
|
546
|
+
);
|
|
263
547
|
return {
|
|
548
|
+
parts,
|
|
264
549
|
content: content.length > 0 ? content : null,
|
|
550
|
+
reasoning: reasoning.length > 0 ? reasoning : null,
|
|
265
551
|
toolCalls,
|
|
266
552
|
finishReason: mapStopReason(response.stop_reason),
|
|
267
553
|
usage: {
|
|
@@ -271,9 +557,7 @@ function mapGenerateResponse(response) {
|
|
|
271
557
|
cacheReadTokens,
|
|
272
558
|
cacheWriteTokens
|
|
273
559
|
},
|
|
274
|
-
outputTokenDetails: {
|
|
275
|
-
reasoningTokens: 0
|
|
276
|
-
}
|
|
560
|
+
outputTokenDetails: {}
|
|
277
561
|
}
|
|
278
562
|
};
|
|
279
563
|
}
|
|
@@ -286,12 +570,12 @@ async function* transformStream(stream) {
|
|
|
286
570
|
cacheReadTokens: 0,
|
|
287
571
|
cacheWriteTokens: 0
|
|
288
572
|
},
|
|
289
|
-
outputTokenDetails: {
|
|
290
|
-
reasoningTokens: 0
|
|
291
|
-
}
|
|
573
|
+
outputTokenDetails: {}
|
|
292
574
|
};
|
|
293
575
|
const toolBuffers = /* @__PURE__ */ new Map();
|
|
294
576
|
const emittedToolCalls = /* @__PURE__ */ new Set();
|
|
577
|
+
const contentBlockTypeByIndex = /* @__PURE__ */ new Map();
|
|
578
|
+
const reasoningSignatureByIndex = /* @__PURE__ */ new Map();
|
|
295
579
|
for await (const event of stream) {
|
|
296
580
|
if (event.type === "message_start") {
|
|
297
581
|
const cacheReadTokens = event.message.usage.cache_read_input_tokens ?? 0;
|
|
@@ -304,13 +588,18 @@ async function* transformStream(stream) {
|
|
|
304
588
|
cacheReadTokens,
|
|
305
589
|
cacheWriteTokens
|
|
306
590
|
},
|
|
307
|
-
outputTokenDetails: {
|
|
308
|
-
reasoningTokens: 0
|
|
309
|
-
}
|
|
591
|
+
outputTokenDetails: {}
|
|
310
592
|
};
|
|
311
593
|
continue;
|
|
312
594
|
}
|
|
313
595
|
if (event.type === "content_block_start") {
|
|
596
|
+
contentBlockTypeByIndex.set(event.index, event.content_block.type);
|
|
597
|
+
if (event.content_block.type === "thinking") {
|
|
598
|
+
yield {
|
|
599
|
+
type: "reasoning-start"
|
|
600
|
+
};
|
|
601
|
+
continue;
|
|
602
|
+
}
|
|
314
603
|
if (event.content_block.type === "tool_use") {
|
|
315
604
|
const block = event.content_block;
|
|
316
605
|
const initialArguments = block.input && typeof block.input === "object" ? Object.keys(block.input).length > 0 ? JSON.stringify(block.input) : "" : "";
|
|
@@ -330,11 +619,29 @@ async function* transformStream(stream) {
|
|
|
330
619
|
if (event.type === "content_block_delta") {
|
|
331
620
|
if (event.delta.type === "text_delta") {
|
|
332
621
|
yield {
|
|
333
|
-
type: "
|
|
622
|
+
type: "text-delta",
|
|
334
623
|
text: event.delta.text
|
|
335
624
|
};
|
|
336
625
|
continue;
|
|
337
626
|
}
|
|
627
|
+
if (event.delta.type === "thinking_delta") {
|
|
628
|
+
const thinkingDelta = event.delta;
|
|
629
|
+
const thinkingText = typeof thinkingDelta.thinking === "string" ? thinkingDelta.thinking : typeof thinkingDelta.text === "string" ? thinkingDelta.text : "";
|
|
630
|
+
if (thinkingText.length > 0) {
|
|
631
|
+
yield {
|
|
632
|
+
type: "reasoning-delta",
|
|
633
|
+
text: thinkingText
|
|
634
|
+
};
|
|
635
|
+
}
|
|
636
|
+
continue;
|
|
637
|
+
}
|
|
638
|
+
if (event.delta.type === "signature_delta") {
|
|
639
|
+
reasoningSignatureByIndex.set(
|
|
640
|
+
event.index,
|
|
641
|
+
event.delta.signature
|
|
642
|
+
);
|
|
643
|
+
continue;
|
|
644
|
+
}
|
|
338
645
|
if (event.delta.type === "input_json_delta") {
|
|
339
646
|
const current = toolBuffers.get(event.index);
|
|
340
647
|
if (!current) {
|
|
@@ -350,6 +657,19 @@ async function* transformStream(stream) {
|
|
|
350
657
|
continue;
|
|
351
658
|
}
|
|
352
659
|
if (event.type === "content_block_stop") {
|
|
660
|
+
if (contentBlockTypeByIndex.get(event.index) === "thinking") {
|
|
661
|
+
const signature = reasoningSignatureByIndex.get(event.index);
|
|
662
|
+
reasoningSignatureByIndex.delete(event.index);
|
|
663
|
+
contentBlockTypeByIndex.delete(event.index);
|
|
664
|
+
yield {
|
|
665
|
+
type: "reasoning-end",
|
|
666
|
+
providerMetadata: {
|
|
667
|
+
anthropic: { ...signature ? { signature } : {} }
|
|
668
|
+
}
|
|
669
|
+
};
|
|
670
|
+
continue;
|
|
671
|
+
}
|
|
672
|
+
contentBlockTypeByIndex.delete(event.index);
|
|
353
673
|
const current = toolBuffers.get(event.index);
|
|
354
674
|
if (!current || emittedToolCalls.has(event.index)) {
|
|
355
675
|
continue;
|
|
@@ -377,9 +697,7 @@ async function* transformStream(stream) {
|
|
|
377
697
|
cacheReadTokens,
|
|
378
698
|
cacheWriteTokens
|
|
379
699
|
},
|
|
380
|
-
outputTokenDetails: {
|
|
381
|
-
reasoningTokens: 0
|
|
382
|
-
}
|
|
700
|
+
outputTokenDetails: {}
|
|
383
701
|
};
|
|
384
702
|
continue;
|
|
385
703
|
}
|
|
@@ -419,6 +737,30 @@ function asObject(value) {
|
|
|
419
737
|
}
|
|
420
738
|
return {};
|
|
421
739
|
}
|
|
740
|
+
function asStringArray(value) {
|
|
741
|
+
if (!Array.isArray(value)) {
|
|
742
|
+
return [];
|
|
743
|
+
}
|
|
744
|
+
return value.filter((item) => typeof item === "string");
|
|
745
|
+
}
|
|
746
|
+
function uniqueStrings(values) {
|
|
747
|
+
return [...new Set(values)];
|
|
748
|
+
}
|
|
749
|
+
function extractThinkingText(value) {
|
|
750
|
+
if (typeof value === "string") {
|
|
751
|
+
return value;
|
|
752
|
+
}
|
|
753
|
+
if (!Array.isArray(value)) {
|
|
754
|
+
return "";
|
|
755
|
+
}
|
|
756
|
+
return value.flatMap((item) => {
|
|
757
|
+
if (!item || typeof item !== "object") {
|
|
758
|
+
return [];
|
|
759
|
+
}
|
|
760
|
+
const text = item.text;
|
|
761
|
+
return typeof text === "string" ? [text] : [];
|
|
762
|
+
}).join("");
|
|
763
|
+
}
|
|
422
764
|
function wrapError(error) {
|
|
423
765
|
if (error instanceof APIError) {
|
|
424
766
|
return new ProviderError(
|
|
@@ -439,22 +781,32 @@ function wrapError(error) {
|
|
|
439
781
|
// src/chat-model.ts
|
|
440
782
|
function createAnthropicChatModel(client, modelId, defaultMaxTokens) {
|
|
441
783
|
const provider = "anthropic";
|
|
442
|
-
async function callAnthropicMessagesApi(request) {
|
|
784
|
+
async function callAnthropicMessagesApi(request, signal) {
|
|
443
785
|
try {
|
|
444
|
-
return await client.messages.create(request
|
|
786
|
+
return await client.messages.create(request, {
|
|
787
|
+
signal
|
|
788
|
+
});
|
|
445
789
|
} catch (error) {
|
|
446
790
|
throw wrapError(error);
|
|
447
791
|
}
|
|
448
792
|
}
|
|
449
793
|
async function generateChat(options) {
|
|
450
|
-
const request = createGenerateRequest(
|
|
451
|
-
|
|
794
|
+
const request = createGenerateRequest(
|
|
795
|
+
modelId,
|
|
796
|
+
defaultMaxTokens,
|
|
797
|
+
options
|
|
798
|
+
);
|
|
799
|
+
const response = await callAnthropicMessagesApi(request, options.signal);
|
|
452
800
|
return mapGenerateResponse(response);
|
|
453
801
|
}
|
|
454
802
|
async function streamChat(options) {
|
|
455
803
|
const request = createStreamRequest(modelId, defaultMaxTokens, options);
|
|
456
|
-
|
|
457
|
-
|
|
804
|
+
return createChatStream(
|
|
805
|
+
async () => transformStream(
|
|
806
|
+
await callAnthropicMessagesApi(request, options.signal)
|
|
807
|
+
),
|
|
808
|
+
{ signal: options.signal }
|
|
809
|
+
);
|
|
458
810
|
}
|
|
459
811
|
return {
|
|
460
812
|
provider,
|
|
@@ -464,7 +816,11 @@ function createAnthropicChatModel(client, modelId, defaultMaxTokens) {
|
|
|
464
816
|
async generateObject(options) {
|
|
465
817
|
const structuredOptions = createStructuredOutputOptions(options);
|
|
466
818
|
const result = await generateChat(structuredOptions);
|
|
467
|
-
const object = extractStructuredObject(
|
|
819
|
+
const object = extractStructuredObject(
|
|
820
|
+
result,
|
|
821
|
+
options.schema,
|
|
822
|
+
provider
|
|
823
|
+
);
|
|
468
824
|
return {
|
|
469
825
|
object,
|
|
470
826
|
finishReason: result.finishReason,
|
|
@@ -474,12 +830,15 @@ function createAnthropicChatModel(client, modelId, defaultMaxTokens) {
|
|
|
474
830
|
async streamObject(options) {
|
|
475
831
|
const structuredOptions = createStructuredOutputOptions(options);
|
|
476
832
|
const stream = await streamChat(structuredOptions);
|
|
477
|
-
return
|
|
833
|
+
return createObjectStream(
|
|
478
834
|
transformStructuredOutputStream(
|
|
479
835
|
stream,
|
|
480
836
|
options.schema,
|
|
481
837
|
provider
|
|
482
|
-
)
|
|
838
|
+
),
|
|
839
|
+
{
|
|
840
|
+
signal: options.signal
|
|
841
|
+
}
|
|
483
842
|
);
|
|
484
843
|
}
|
|
485
844
|
};
|
|
@@ -496,7 +855,7 @@ function extractStructuredObject(result, schema, provider) {
|
|
|
496
855
|
async function* transformStructuredOutputStream(stream, schema, provider) {
|
|
497
856
|
let contentBuffer = "";
|
|
498
857
|
for await (const event of stream) {
|
|
499
|
-
if (event.type === "
|
|
858
|
+
if (event.type === "text-delta") {
|
|
500
859
|
contentBuffer += event.text;
|
|
501
860
|
yield {
|
|
502
861
|
type: "object-delta",
|
|
@@ -556,7 +915,10 @@ function requireStructuredOutputPayload(finishReason, rawOutput, provider, noPay
|
|
|
556
915
|
);
|
|
557
916
|
}
|
|
558
917
|
if (!rawOutput || rawOutput.length === 0) {
|
|
559
|
-
throw new StructuredOutputNoObjectGeneratedError(
|
|
918
|
+
throw new StructuredOutputNoObjectGeneratedError(
|
|
919
|
+
noPayloadMessage,
|
|
920
|
+
provider
|
|
921
|
+
);
|
|
560
922
|
}
|
|
561
923
|
return rawOutput;
|
|
562
924
|
}
|
|
@@ -611,5 +973,7 @@ function createAnthropic(options = {}) {
|
|
|
611
973
|
};
|
|
612
974
|
}
|
|
613
975
|
export {
|
|
976
|
+
anthropicGenerateProviderOptionsSchema,
|
|
977
|
+
anthropicProviderOptionsSchema,
|
|
614
978
|
createAnthropic
|
|
615
979
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@core-ai/anthropic",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "Anthropic provider package for @core-ai/core-ai",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Omnifact (https://omnifact.ai)",
|
|
@@ -38,12 +38,11 @@
|
|
|
38
38
|
"build": "tsup",
|
|
39
39
|
"lint": "eslint src/ --max-warnings 0",
|
|
40
40
|
"check-types": "tsc --noEmit",
|
|
41
|
-
"prepublishOnly": "npm run build",
|
|
42
41
|
"test": "vitest run",
|
|
43
42
|
"test:watch": "vitest"
|
|
44
43
|
},
|
|
45
44
|
"dependencies": {
|
|
46
|
-
"@core-ai/core-ai": "^0.
|
|
45
|
+
"@core-ai/core-ai": "^0.6.0",
|
|
47
46
|
"@anthropic-ai/sdk": "^0.78.0",
|
|
48
47
|
"zod-to-json-schema": "^3.25.1"
|
|
49
48
|
},
|
|
@@ -51,8 +50,9 @@
|
|
|
51
50
|
"zod": "^3.25.0 || ^4.0.0"
|
|
52
51
|
},
|
|
53
52
|
"devDependencies": {
|
|
54
|
-
"@core-ai/eslint-config": "
|
|
55
|
-
"@core-ai/
|
|
53
|
+
"@core-ai/eslint-config": "*",
|
|
54
|
+
"@core-ai/testing": "*",
|
|
55
|
+
"@core-ai/typescript-config": "*",
|
|
56
56
|
"typescript": "^5.7.3",
|
|
57
57
|
"vitest": "^3.2.4"
|
|
58
58
|
}
|