@core-ai/anthropic 0.2.1 → 0.4.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/README.md +1 -1
- package/dist/index.js +291 -59
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -17,7 +17,7 @@ import { generate } from '@core-ai/core-ai';
|
|
|
17
17
|
import { createAnthropic } from '@core-ai/anthropic';
|
|
18
18
|
|
|
19
19
|
const anthropic = createAnthropic({ apiKey: process.env.ANTHROPIC_API_KEY });
|
|
20
|
-
const model = anthropic.chatModel('claude-
|
|
20
|
+
const model = anthropic.chatModel('claude-haiku-4-5');
|
|
21
21
|
|
|
22
22
|
const result = await generate({
|
|
23
23
|
model,
|
package/dist/index.js
CHANGED
|
@@ -2,12 +2,28 @@
|
|
|
2
2
|
import Anthropic from "@anthropic-ai/sdk";
|
|
3
3
|
|
|
4
4
|
// src/chat-model.ts
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
StructuredOutputNoObjectGeneratedError,
|
|
7
|
+
StructuredOutputParseError,
|
|
8
|
+
StructuredOutputValidationError,
|
|
9
|
+
createObjectStreamResult,
|
|
10
|
+
createStreamResult
|
|
11
|
+
} from "@core-ai/core-ai";
|
|
6
12
|
|
|
7
13
|
// src/chat-adapter.ts
|
|
8
14
|
import { APIError } from "@anthropic-ai/sdk";
|
|
9
15
|
import { zodToJsonSchema } from "zod-to-json-schema";
|
|
10
16
|
import { ProviderError } from "@core-ai/core-ai";
|
|
17
|
+
var UNSUPPORTED_ANTHROPIC_SCHEMA_KEYWORDS = /* @__PURE__ */ new Set([
|
|
18
|
+
"minimum",
|
|
19
|
+
"maximum",
|
|
20
|
+
"exclusiveMinimum",
|
|
21
|
+
"exclusiveMaximum",
|
|
22
|
+
"multipleOf",
|
|
23
|
+
"minLength",
|
|
24
|
+
"maxLength",
|
|
25
|
+
"maxItems"
|
|
26
|
+
]);
|
|
11
27
|
function convertMessages(messages) {
|
|
12
28
|
const systemParts = [];
|
|
13
29
|
const convertedMessages = [];
|
|
@@ -115,12 +131,12 @@ function convertUserContentPart(part) {
|
|
|
115
131
|
}
|
|
116
132
|
function convertTools(tools) {
|
|
117
133
|
return Object.values(tools).map((tool) => {
|
|
118
|
-
const schema =
|
|
119
|
-
const { $schema: _schema, ...inputSchema } = schema;
|
|
134
|
+
const schema = toAnthropicJsonSchema(tool.parameters);
|
|
120
135
|
return {
|
|
121
136
|
name: tool.name,
|
|
122
137
|
description: tool.description,
|
|
123
|
-
input_schema:
|
|
138
|
+
input_schema: schema,
|
|
139
|
+
strict: true
|
|
124
140
|
};
|
|
125
141
|
});
|
|
126
142
|
}
|
|
@@ -139,35 +155,90 @@ function convertToolChoice(choice) {
|
|
|
139
155
|
name: choice.toolName
|
|
140
156
|
};
|
|
141
157
|
}
|
|
158
|
+
function createStructuredOutputOptions(options) {
|
|
159
|
+
const schema = toAnthropicJsonSchema(options.schema);
|
|
160
|
+
const schemaDescription = options.schemaDescription?.trim();
|
|
161
|
+
if (schemaDescription && schemaDescription.length > 0) {
|
|
162
|
+
schema.description = schemaDescription;
|
|
163
|
+
}
|
|
164
|
+
return {
|
|
165
|
+
messages: options.messages,
|
|
166
|
+
config: options.config,
|
|
167
|
+
providerOptions: {
|
|
168
|
+
...options.providerOptions ?? {},
|
|
169
|
+
output_config: {
|
|
170
|
+
format: {
|
|
171
|
+
type: "json_schema",
|
|
172
|
+
schema
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
},
|
|
176
|
+
signal: options.signal
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
function toAnthropicJsonSchema(schema) {
|
|
180
|
+
const rawSchema = zodToJsonSchema(schema);
|
|
181
|
+
return normalizeAnthropicJsonSchema(rawSchema);
|
|
182
|
+
}
|
|
183
|
+
function normalizeAnthropicJsonSchema(value) {
|
|
184
|
+
const normalized = normalizeAnthropicJsonValue(value);
|
|
185
|
+
return isJsonObject(normalized) ? normalized : {};
|
|
186
|
+
}
|
|
187
|
+
function normalizeAnthropicJsonValue(value) {
|
|
188
|
+
if (Array.isArray(value)) {
|
|
189
|
+
return value.map(normalizeAnthropicJsonValue);
|
|
190
|
+
}
|
|
191
|
+
if (!isJsonObject(value)) {
|
|
192
|
+
return value;
|
|
193
|
+
}
|
|
194
|
+
const normalized = {};
|
|
195
|
+
for (const [key, child] of Object.entries(value)) {
|
|
196
|
+
if (key === "$schema" || UNSUPPORTED_ANTHROPIC_SCHEMA_KEYWORDS.has(key) || key === "minItems" && typeof child === "number" && child > 1) {
|
|
197
|
+
continue;
|
|
198
|
+
}
|
|
199
|
+
normalized[key] = normalizeAnthropicJsonValue(child);
|
|
200
|
+
}
|
|
201
|
+
if (isObjectSchema(normalized)) {
|
|
202
|
+
normalized.additionalProperties = false;
|
|
203
|
+
}
|
|
204
|
+
return normalized;
|
|
205
|
+
}
|
|
206
|
+
function isObjectSchema(value) {
|
|
207
|
+
return value.type === "object" || Object.hasOwn(value, "properties") || Object.hasOwn(value, "required");
|
|
208
|
+
}
|
|
209
|
+
function isJsonObject(value) {
|
|
210
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
211
|
+
}
|
|
142
212
|
function createGenerateRequest(modelId, defaultMaxTokens, options) {
|
|
143
|
-
const converted = convertMessages(options.messages);
|
|
144
213
|
return {
|
|
145
|
-
|
|
146
|
-
messages: converted.messages,
|
|
147
|
-
max_tokens: options.config?.maxTokens ?? defaultMaxTokens,
|
|
148
|
-
...converted.system ? { system: converted.system } : {},
|
|
149
|
-
...options.tools && Object.keys(options.tools).length > 0 ? { tools: convertTools(options.tools) } : {},
|
|
150
|
-
...options.toolChoice ? { tool_choice: convertToolChoice(options.toolChoice) } : {},
|
|
151
|
-
...options.config?.temperature !== void 0 ? { temperature: options.config.temperature } : {},
|
|
152
|
-
...options.config?.topP !== void 0 ? { top_p: options.config.topP } : {},
|
|
153
|
-
...options.config?.stopSequences ? { stop_sequences: options.config.stopSequences } : {},
|
|
214
|
+
...createRequestBase(modelId, defaultMaxTokens, options),
|
|
154
215
|
...options.providerOptions
|
|
155
216
|
};
|
|
156
217
|
}
|
|
157
218
|
function createStreamRequest(modelId, defaultMaxTokens, options) {
|
|
219
|
+
return {
|
|
220
|
+
...createRequestBase(modelId, defaultMaxTokens, options),
|
|
221
|
+
stream: true,
|
|
222
|
+
...options.providerOptions
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
function createRequestBase(modelId, defaultMaxTokens, options) {
|
|
158
226
|
const converted = convertMessages(options.messages);
|
|
159
227
|
return {
|
|
160
228
|
model: modelId,
|
|
161
229
|
messages: converted.messages,
|
|
162
|
-
stream: true,
|
|
163
230
|
max_tokens: options.config?.maxTokens ?? defaultMaxTokens,
|
|
164
231
|
...converted.system ? { system: converted.system } : {},
|
|
165
232
|
...options.tools && Object.keys(options.tools).length > 0 ? { tools: convertTools(options.tools) } : {},
|
|
166
233
|
...options.toolChoice ? { tool_choice: convertToolChoice(options.toolChoice) } : {},
|
|
167
|
-
...options.config
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
234
|
+
...mapConfigToRequestFields(options.config)
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
function mapConfigToRequestFields(config) {
|
|
238
|
+
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 } : {}
|
|
171
242
|
};
|
|
172
243
|
}
|
|
173
244
|
function mapGenerateResponse(response) {
|
|
@@ -186,15 +257,23 @@ function mapGenerateResponse(response) {
|
|
|
186
257
|
});
|
|
187
258
|
}
|
|
188
259
|
}
|
|
260
|
+
const cacheReadTokens = response.usage.cache_read_input_tokens ?? 0;
|
|
261
|
+
const cacheWriteTokens = response.usage.cache_creation_input_tokens ?? 0;
|
|
262
|
+
const inputTokens = response.usage.input_tokens + cacheReadTokens + cacheWriteTokens;
|
|
189
263
|
return {
|
|
190
264
|
content: content.length > 0 ? content : null,
|
|
191
265
|
toolCalls,
|
|
192
266
|
finishReason: mapStopReason(response.stop_reason),
|
|
193
267
|
usage: {
|
|
194
|
-
inputTokens
|
|
268
|
+
inputTokens,
|
|
195
269
|
outputTokens: response.usage.output_tokens,
|
|
196
|
-
|
|
197
|
-
|
|
270
|
+
inputTokenDetails: {
|
|
271
|
+
cacheReadTokens,
|
|
272
|
+
cacheWriteTokens
|
|
273
|
+
},
|
|
274
|
+
outputTokenDetails: {
|
|
275
|
+
reasoningTokens: 0
|
|
276
|
+
}
|
|
198
277
|
}
|
|
199
278
|
};
|
|
200
279
|
}
|
|
@@ -203,25 +282,38 @@ async function* transformStream(stream) {
|
|
|
203
282
|
let usage = {
|
|
204
283
|
inputTokens: 0,
|
|
205
284
|
outputTokens: 0,
|
|
206
|
-
|
|
207
|
-
|
|
285
|
+
inputTokenDetails: {
|
|
286
|
+
cacheReadTokens: 0,
|
|
287
|
+
cacheWriteTokens: 0
|
|
288
|
+
},
|
|
289
|
+
outputTokenDetails: {
|
|
290
|
+
reasoningTokens: 0
|
|
291
|
+
}
|
|
208
292
|
};
|
|
209
293
|
const toolBuffers = /* @__PURE__ */ new Map();
|
|
210
294
|
const emittedToolCalls = /* @__PURE__ */ new Set();
|
|
211
295
|
for await (const event of stream) {
|
|
212
296
|
if (event.type === "message_start") {
|
|
297
|
+
const cacheReadTokens = event.message.usage.cache_read_input_tokens ?? 0;
|
|
298
|
+
const cacheWriteTokens = event.message.usage.cache_creation_input_tokens ?? 0;
|
|
299
|
+
const inputTokens = event.message.usage.input_tokens + cacheReadTokens + cacheWriteTokens;
|
|
213
300
|
usage = {
|
|
214
|
-
inputTokens
|
|
301
|
+
inputTokens,
|
|
215
302
|
outputTokens: event.message.usage.output_tokens,
|
|
216
|
-
|
|
217
|
-
|
|
303
|
+
inputTokenDetails: {
|
|
304
|
+
cacheReadTokens,
|
|
305
|
+
cacheWriteTokens
|
|
306
|
+
},
|
|
307
|
+
outputTokenDetails: {
|
|
308
|
+
reasoningTokens: 0
|
|
309
|
+
}
|
|
218
310
|
};
|
|
219
311
|
continue;
|
|
220
312
|
}
|
|
221
313
|
if (event.type === "content_block_start") {
|
|
222
314
|
if (event.content_block.type === "tool_use") {
|
|
223
315
|
const block = event.content_block;
|
|
224
|
-
const initialArguments = block.input && typeof block.input === "object" ? JSON.stringify(block.input) : "";
|
|
316
|
+
const initialArguments = block.input && typeof block.input === "object" ? Object.keys(block.input).length > 0 ? JSON.stringify(block.input) : "" : "";
|
|
225
317
|
toolBuffers.set(event.index, {
|
|
226
318
|
id: block.id,
|
|
227
319
|
name: block.name,
|
|
@@ -275,11 +367,19 @@ async function* transformStream(stream) {
|
|
|
275
367
|
}
|
|
276
368
|
if (event.type === "message_delta") {
|
|
277
369
|
finishReason = mapStopReason(event.delta.stop_reason);
|
|
370
|
+
const nonCachedInputTokens = event.usage.input_tokens ?? usage.inputTokens - usage.inputTokenDetails.cacheReadTokens - usage.inputTokenDetails.cacheWriteTokens;
|
|
371
|
+
const cacheReadTokens = event.usage.cache_read_input_tokens ?? usage.inputTokenDetails.cacheReadTokens;
|
|
372
|
+
const cacheWriteTokens = event.usage.cache_creation_input_tokens ?? usage.inputTokenDetails.cacheWriteTokens;
|
|
278
373
|
usage = {
|
|
279
|
-
inputTokens:
|
|
374
|
+
inputTokens: nonCachedInputTokens + cacheReadTokens + cacheWriteTokens,
|
|
280
375
|
outputTokens: event.usage.output_tokens,
|
|
281
|
-
|
|
282
|
-
|
|
376
|
+
inputTokenDetails: {
|
|
377
|
+
cacheReadTokens,
|
|
378
|
+
cacheWriteTokens
|
|
379
|
+
},
|
|
380
|
+
outputTokenDetails: {
|
|
381
|
+
reasoningTokens: 0
|
|
382
|
+
}
|
|
283
383
|
};
|
|
284
384
|
continue;
|
|
285
385
|
}
|
|
@@ -321,7 +421,12 @@ function asObject(value) {
|
|
|
321
421
|
}
|
|
322
422
|
function wrapError(error) {
|
|
323
423
|
if (error instanceof APIError) {
|
|
324
|
-
return new ProviderError(
|
|
424
|
+
return new ProviderError(
|
|
425
|
+
error.message,
|
|
426
|
+
"anthropic",
|
|
427
|
+
error.status,
|
|
428
|
+
error
|
|
429
|
+
);
|
|
325
430
|
}
|
|
326
431
|
return new ProviderError(
|
|
327
432
|
error instanceof Error ? error.message : String(error),
|
|
@@ -333,39 +438,166 @@ function wrapError(error) {
|
|
|
333
438
|
|
|
334
439
|
// src/chat-model.ts
|
|
335
440
|
function createAnthropicChatModel(client, modelId, defaultMaxTokens) {
|
|
441
|
+
const provider = "anthropic";
|
|
442
|
+
async function callAnthropicMessagesApi(request) {
|
|
443
|
+
try {
|
|
444
|
+
return await client.messages.create(request);
|
|
445
|
+
} catch (error) {
|
|
446
|
+
throw wrapError(error);
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
async function generateChat(options) {
|
|
450
|
+
const request = createGenerateRequest(modelId, defaultMaxTokens, options);
|
|
451
|
+
const response = await callAnthropicMessagesApi(request);
|
|
452
|
+
return mapGenerateResponse(response);
|
|
453
|
+
}
|
|
454
|
+
async function streamChat(options) {
|
|
455
|
+
const request = createStreamRequest(modelId, defaultMaxTokens, options);
|
|
456
|
+
const stream = await callAnthropicMessagesApi(request);
|
|
457
|
+
return createStreamResult(transformStream(stream));
|
|
458
|
+
}
|
|
336
459
|
return {
|
|
337
|
-
provider
|
|
460
|
+
provider,
|
|
338
461
|
modelId,
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
}
|
|
462
|
+
generate: generateChat,
|
|
463
|
+
stream: streamChat,
|
|
464
|
+
async generateObject(options) {
|
|
465
|
+
const structuredOptions = createStructuredOutputOptions(options);
|
|
466
|
+
const result = await generateChat(structuredOptions);
|
|
467
|
+
const object = extractStructuredObject(result, options.schema, provider);
|
|
468
|
+
return {
|
|
469
|
+
object,
|
|
470
|
+
finishReason: result.finishReason,
|
|
471
|
+
usage: result.usage
|
|
472
|
+
};
|
|
351
473
|
},
|
|
352
|
-
async
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
return createStreamResult(transformStream(stream));
|
|
363
|
-
} catch (error) {
|
|
364
|
-
throw wrapError(error);
|
|
365
|
-
}
|
|
474
|
+
async streamObject(options) {
|
|
475
|
+
const structuredOptions = createStructuredOutputOptions(options);
|
|
476
|
+
const stream = await streamChat(structuredOptions);
|
|
477
|
+
return createObjectStreamResult(
|
|
478
|
+
transformStructuredOutputStream(
|
|
479
|
+
stream,
|
|
480
|
+
options.schema,
|
|
481
|
+
provider
|
|
482
|
+
)
|
|
483
|
+
);
|
|
366
484
|
}
|
|
367
485
|
};
|
|
368
486
|
}
|
|
487
|
+
function extractStructuredObject(result, schema, provider) {
|
|
488
|
+
const rawOutput = requireStructuredOutputPayload(
|
|
489
|
+
result.finishReason,
|
|
490
|
+
result.content?.trim(),
|
|
491
|
+
provider,
|
|
492
|
+
"model did not emit a structured object payload"
|
|
493
|
+
);
|
|
494
|
+
return parseAndValidateStructuredObject(schema, rawOutput, provider);
|
|
495
|
+
}
|
|
496
|
+
async function* transformStructuredOutputStream(stream, schema, provider) {
|
|
497
|
+
let contentBuffer = "";
|
|
498
|
+
for await (const event of stream) {
|
|
499
|
+
if (event.type === "content-delta") {
|
|
500
|
+
contentBuffer += event.text;
|
|
501
|
+
yield {
|
|
502
|
+
type: "object-delta",
|
|
503
|
+
text: event.text
|
|
504
|
+
};
|
|
505
|
+
continue;
|
|
506
|
+
}
|
|
507
|
+
if (event.type === "tool-call-delta") {
|
|
508
|
+
contentBuffer += event.argumentsDelta;
|
|
509
|
+
yield {
|
|
510
|
+
type: "object-delta",
|
|
511
|
+
text: event.argumentsDelta
|
|
512
|
+
};
|
|
513
|
+
continue;
|
|
514
|
+
}
|
|
515
|
+
if (event.type === "finish") {
|
|
516
|
+
const rawOutput = requireStructuredOutputPayload(
|
|
517
|
+
event.finishReason,
|
|
518
|
+
contentBuffer.trim(),
|
|
519
|
+
provider,
|
|
520
|
+
"structured output stream ended without an object payload"
|
|
521
|
+
);
|
|
522
|
+
const validatedObject = parseAndValidateStructuredObject(
|
|
523
|
+
schema,
|
|
524
|
+
rawOutput,
|
|
525
|
+
provider
|
|
526
|
+
);
|
|
527
|
+
yield {
|
|
528
|
+
type: "object",
|
|
529
|
+
object: validatedObject
|
|
530
|
+
};
|
|
531
|
+
yield {
|
|
532
|
+
type: "finish",
|
|
533
|
+
finishReason: event.finishReason,
|
|
534
|
+
usage: event.usage
|
|
535
|
+
};
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
function requireStructuredOutputPayload(finishReason, rawOutput, provider, noPayloadMessage) {
|
|
540
|
+
if (finishReason === "content-filter") {
|
|
541
|
+
throw new StructuredOutputNoObjectGeneratedError(
|
|
542
|
+
"model refused to produce a structured output",
|
|
543
|
+
provider,
|
|
544
|
+
{
|
|
545
|
+
rawOutput
|
|
546
|
+
}
|
|
547
|
+
);
|
|
548
|
+
}
|
|
549
|
+
if (finishReason === "length") {
|
|
550
|
+
throw new StructuredOutputNoObjectGeneratedError(
|
|
551
|
+
"structured output was truncated because max tokens were reached",
|
|
552
|
+
provider,
|
|
553
|
+
{
|
|
554
|
+
rawOutput
|
|
555
|
+
}
|
|
556
|
+
);
|
|
557
|
+
}
|
|
558
|
+
if (!rawOutput || rawOutput.length === 0) {
|
|
559
|
+
throw new StructuredOutputNoObjectGeneratedError(noPayloadMessage, provider);
|
|
560
|
+
}
|
|
561
|
+
return rawOutput;
|
|
562
|
+
}
|
|
563
|
+
function parseAndValidateStructuredObject(schema, rawOutput, provider) {
|
|
564
|
+
const parsedOutput = parseJson(rawOutput, provider);
|
|
565
|
+
return validateStructuredObject(schema, parsedOutput, provider, rawOutput);
|
|
566
|
+
}
|
|
567
|
+
function parseJson(rawOutput, provider) {
|
|
568
|
+
try {
|
|
569
|
+
return JSON.parse(rawOutput);
|
|
570
|
+
} catch (error) {
|
|
571
|
+
throw new StructuredOutputParseError(
|
|
572
|
+
"failed to parse structured output as JSON",
|
|
573
|
+
provider,
|
|
574
|
+
{
|
|
575
|
+
rawOutput,
|
|
576
|
+
cause: error
|
|
577
|
+
}
|
|
578
|
+
);
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
function validateStructuredObject(schema, value, provider, rawOutput) {
|
|
582
|
+
const parsed = schema.safeParse(value);
|
|
583
|
+
if (parsed.success) {
|
|
584
|
+
return parsed.data;
|
|
585
|
+
}
|
|
586
|
+
throw new StructuredOutputValidationError(
|
|
587
|
+
"structured output does not match schema",
|
|
588
|
+
provider,
|
|
589
|
+
formatZodIssues(parsed.error.issues),
|
|
590
|
+
{
|
|
591
|
+
rawOutput
|
|
592
|
+
}
|
|
593
|
+
);
|
|
594
|
+
}
|
|
595
|
+
function formatZodIssues(issues) {
|
|
596
|
+
return issues.map((issue) => {
|
|
597
|
+
const path = issue.path.length > 0 ? issue.path.map((segment) => String(segment)).join(".") : "<root>";
|
|
598
|
+
return `${path}: ${issue.message}`;
|
|
599
|
+
});
|
|
600
|
+
}
|
|
369
601
|
|
|
370
602
|
// src/provider.ts
|
|
371
603
|
function createAnthropic(options = {}) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@core-ai/anthropic",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Anthropic provider package for @core-ai/core-ai",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Omnifact (https://omnifact.ai)",
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"test:watch": "vitest"
|
|
44
44
|
},
|
|
45
45
|
"dependencies": {
|
|
46
|
-
"@core-ai/core-ai": "^0.
|
|
46
|
+
"@core-ai/core-ai": "^0.4.0",
|
|
47
47
|
"@anthropic-ai/sdk": "^0.78.0",
|
|
48
48
|
"zod-to-json-schema": "^3.25.1"
|
|
49
49
|
},
|