@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 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
- export { type AnthropicProvider, type AnthropicProviderOptions, createAnthropic };
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
- createObjectStreamResult,
10
- createStreamResult
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
- if (message.content) {
48
- contentBlocks.push({
49
- type: "text",
50
- text: message.content
51
- });
52
- }
53
- for (const toolCall of message.toolCalls ?? []) {
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: "tool_use",
56
- id: toolCall.id,
57
- name: toolCall.name,
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
- config: options.config,
317
+ reasoning: options.reasoning,
318
+ temperature: options.temperature,
319
+ maxTokens: options.maxTokens,
320
+ topP: options.topP,
167
321
  providerOptions: {
168
322
  ...options.providerOptions ?? {},
169
- output_config: {
170
- format: {
171
- type: "json_schema",
172
- schema
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
- return {
214
- ...createRequestBase(modelId, defaultMaxTokens, options),
215
- ...options.providerOptions
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
- return {
220
- ...createRequestBase(modelId, defaultMaxTokens, options),
221
- stream: true,
222
- ...options.providerOptions
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.config?.maxTokens ?? defaultMaxTokens,
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
- ...mapConfigToRequestFields(options.config)
407
+ ...reasoningFields,
408
+ ...mapSamplingToRequestFields(options)
235
409
  };
236
410
  }
237
- function mapConfigToRequestFields(config) {
411
+ function mapSamplingToRequestFields(options) {
238
412
  return {
239
- ...config?.temperature !== void 0 ? { temperature: config.temperature } : {},
240
- ...config?.topP !== void 0 ? { top_p: config.topP } : {},
241
- ...config?.stopSequences ? { stop_sequences: config.stopSequences } : {}
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 toolCalls = [];
246
- let content = "";
496
+ const parts = [];
247
497
  for (const block of response.content) {
248
498
  if (block.type === "text") {
249
- content += block.text;
499
+ parts.push({
500
+ type: "text",
501
+ text: block.text
502
+ });
250
503
  continue;
251
504
  }
252
505
  if (block.type === "tool_use") {
253
- toolCalls.push({
254
- id: block.id,
255
- name: block.name,
256
- arguments: asObject(block.input)
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: "content-delta",
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(modelId, defaultMaxTokens, options);
451
- const response = await callAnthropicMessagesApi(request);
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
- const stream = await callAnthropicMessagesApi(request);
457
- return createStreamResult(transformStream(stream));
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(result, options.schema, provider);
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 createObjectStreamResult(
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 === "content-delta") {
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(noPayloadMessage, provider);
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.4.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.4.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": "^0.0.0",
55
- "@core-ai/typescript-config": "^0.0.0",
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
  }