@core-ai/core-ai 0.7.0 → 0.8.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
@@ -281,15 +281,21 @@ type GeneratedImage = {
281
281
  revisedPrompt?: string;
282
282
  };
283
283
 
284
- declare class LLMError extends Error {
284
+ declare class CoreAIError extends Error {
285
285
  readonly cause?: unknown;
286
- constructor(message: string, cause?: unknown);
286
+ readonly provider?: string;
287
+ constructor(message: string, cause?: unknown, provider?: string);
287
288
  }
288
- declare class StreamAbortedError extends LLMError {
289
- constructor(message?: string, cause?: unknown);
289
+ declare class ValidationError extends CoreAIError {
290
+ constructor(message: string, cause?: unknown, provider?: string);
290
291
  }
291
- declare class ProviderError extends LLMError {
292
- readonly provider: string;
292
+ declare class AbortedError extends CoreAIError {
293
+ constructor(cause?: unknown, provider?: string);
294
+ }
295
+ declare class StreamAbortedError extends AbortedError {
296
+ constructor(cause?: unknown, provider?: string);
297
+ }
298
+ declare class ProviderError extends CoreAIError {
293
299
  readonly statusCode?: number;
294
300
  constructor(message: string, provider: string, statusCode?: number, cause?: unknown);
295
301
  }
@@ -298,7 +304,8 @@ type StructuredOutputErrorOptions = {
298
304
  cause?: unknown;
299
305
  rawOutput?: string;
300
306
  };
301
- declare class StructuredOutputError extends ProviderError {
307
+ declare class StructuredOutputError extends CoreAIError {
308
+ readonly statusCode?: number;
302
309
  readonly rawOutput?: string;
303
310
  constructor(message: string, provider: string, options?: StructuredOutputErrorOptions);
304
311
  }
@@ -321,6 +328,11 @@ declare function defineTool(options: ToolDefinition): ToolDefinition;
321
328
  */
322
329
  declare function zodSchemaToJsonSchema(schema: z.ZodType): Record<string, unknown>;
323
330
 
331
+ declare function stripModelDateSuffix(modelId: string): string;
332
+
333
+ declare function asObject(value: unknown): Record<string, unknown>;
334
+ declare function safeParseJsonObject(json: string): Record<string, unknown>;
335
+
324
336
  type ResultToMessageOptions = {
325
337
  includeReasoning?: boolean;
326
338
  };
@@ -366,4 +378,4 @@ type GenerateImageParams = ImageGenerateOptions & {
366
378
  };
367
379
  declare function generateImage(params: GenerateImageParams): Promise<ImageGenerateResult>;
368
380
 
369
- export { type AssistantContentPart, type AssistantMessage, type AssistantTextPart, type BaseGenerateOptions, type ChatInputTokenDetails, type ChatModel, type ChatOutputTokenDetails, type ChatStream, type ChatUsage, type EmbedOptions, type EmbedProviderOptions, type EmbedResult, type EmbeddingModel, type EmbeddingUsage, type FilePart, type FinishReason, type GenerateObjectOptions, type GenerateObjectResult, type GenerateOptions, type GenerateProviderOptions, type GenerateResult, type GeneratedImage, type ImageGenerateOptions, type ImageGenerateResult, type ImageModel, type ImagePart, type ImageProviderOptions, LLMError, type Message, type ObjectStream, type ObjectStreamEvent, ProviderError, type ReasoningConfig, type ReasoningEffort, type ReasoningPart, StreamAbortedError, type StreamEvent, type StreamObjectOptions, StructuredOutputError, StructuredOutputNoObjectGeneratedError, StructuredOutputParseError, StructuredOutputValidationError, type SystemMessage, type TextPart, type ToolCall, type ToolCallPart, type ToolChoice, type ToolDefinition, type ToolResultMessage, type ToolSet, type UserContentPart, type UserMessage, assistantMessage, createChatStream, createObjectStream, defineTool, embed, generate, generateImage, generateObject, getProviderMetadata, resultToMessage, stream, streamObject, zodSchemaToJsonSchema };
381
+ export { AbortedError, type AssistantContentPart, type AssistantMessage, type AssistantTextPart, type BaseGenerateOptions, type ChatInputTokenDetails, type ChatModel, type ChatOutputTokenDetails, type ChatStream, type ChatUsage, CoreAIError, type EmbedOptions, type EmbedProviderOptions, type EmbedResult, type EmbeddingModel, type EmbeddingUsage, type FilePart, type FinishReason, type GenerateObjectOptions, type GenerateObjectResult, type GenerateOptions, type GenerateProviderOptions, type GenerateResult, type GeneratedImage, type ImageGenerateOptions, type ImageGenerateResult, type ImageModel, type ImagePart, type ImageProviderOptions, type Message, type ObjectStream, type ObjectStreamEvent, ProviderError, type ReasoningConfig, type ReasoningEffort, type ReasoningPart, StreamAbortedError, type StreamEvent, type StreamObjectOptions, StructuredOutputError, StructuredOutputNoObjectGeneratedError, StructuredOutputParseError, StructuredOutputValidationError, type SystemMessage, type TextPart, type ToolCall, type ToolCallPart, type ToolChoice, type ToolDefinition, type ToolResultMessage, type ToolSet, type UserContentPart, type UserMessage, ValidationError, asObject, assistantMessage, createChatStream, createObjectStream, defineTool, embed, generate, generateImage, generateObject, getProviderMetadata, resultToMessage, safeParseJsonObject, stream, streamObject, stripModelDateSuffix, zodSchemaToJsonSchema };
package/dist/index.js CHANGED
@@ -1,33 +1,48 @@
1
1
  // src/errors.ts
2
- var LLMError = class extends Error {
2
+ var CoreAIError = class extends Error {
3
3
  cause;
4
- constructor(message, cause) {
4
+ provider;
5
+ constructor(message, cause, provider) {
5
6
  super(message);
6
- this.name = "LLMError";
7
+ this.name = "CoreAIError";
7
8
  this.cause = cause;
9
+ this.provider = provider;
10
+ }
11
+ };
12
+ var ValidationError = class extends CoreAIError {
13
+ constructor(message, cause, provider) {
14
+ super(message, cause, provider);
15
+ this.name = "ValidationError";
8
16
  }
9
17
  };
10
- var StreamAbortedError = class extends LLMError {
11
- constructor(message = "stream aborted", cause) {
12
- super(message, cause);
18
+ var AbortedError = class extends CoreAIError {
19
+ constructor(cause, provider) {
20
+ super("operation aborted", cause, provider);
21
+ this.name = "AbortedError";
22
+ }
23
+ };
24
+ var StreamAbortedError = class extends AbortedError {
25
+ constructor(cause, provider) {
26
+ super(cause, provider);
13
27
  this.name = "StreamAbortedError";
28
+ this.message = "stream aborted";
14
29
  }
15
30
  };
16
- var ProviderError = class extends LLMError {
17
- provider;
31
+ var ProviderError = class extends CoreAIError {
18
32
  statusCode;
19
33
  constructor(message, provider, statusCode, cause) {
20
- super(message, cause);
34
+ super(message, cause, provider);
21
35
  this.name = "ProviderError";
22
- this.provider = provider;
23
36
  this.statusCode = statusCode;
24
37
  }
25
38
  };
26
- var StructuredOutputError = class extends ProviderError {
39
+ var StructuredOutputError = class extends CoreAIError {
40
+ statusCode;
27
41
  rawOutput;
28
42
  constructor(message, provider, options = {}) {
29
- super(message, provider, options.statusCode, options.cause);
43
+ super(message, options.cause, provider);
30
44
  this.name = "StructuredOutputError";
45
+ this.statusCode = options.statusCode;
31
46
  this.rawOutput = options.rawOutput;
32
47
  }
33
48
  };
@@ -65,6 +80,27 @@ function zodSchemaToJsonSchema(schema) {
65
80
  });
66
81
  }
67
82
 
83
+ // src/model-id.ts
84
+ var MODEL_DATE_SUFFIX_PATTERN = /-\d{8}$/;
85
+ function stripModelDateSuffix(modelId) {
86
+ return modelId.replace(MODEL_DATE_SUFFIX_PATTERN, "");
87
+ }
88
+
89
+ // src/provider-utils.ts
90
+ function asObject(value) {
91
+ if (value && typeof value === "object" && !Array.isArray(value)) {
92
+ return value;
93
+ }
94
+ return {};
95
+ }
96
+ function safeParseJsonObject(json) {
97
+ try {
98
+ return asObject(JSON.parse(json));
99
+ } catch {
100
+ return {};
101
+ }
102
+ }
103
+
68
104
  // src/result-to-message.ts
69
105
  function resultToMessage(result, options) {
70
106
  const includeReasoning = options?.includeReasoning ?? true;
@@ -87,19 +123,19 @@ function isEmptyText(value) {
87
123
  }
88
124
  function assertNonEmptyMessages(messages) {
89
125
  if (messages.length === 0) {
90
- throw new LLMError("messages must not be empty");
126
+ throw new ValidationError("messages must not be empty");
91
127
  }
92
128
  }
93
129
  function assertNonEmptyEmbedInput(input) {
94
130
  const isEmptyString = typeof input === "string" && isEmptyText(input);
95
131
  const isEmptyArray = Array.isArray(input) && input.length === 0;
96
132
  if (isEmptyString || isEmptyArray) {
97
- throw new LLMError("input must not be empty");
133
+ throw new ValidationError("input must not be empty");
98
134
  }
99
135
  }
100
136
  function assertNonEmptyPrompt(prompt) {
101
137
  if (isEmptyText(prompt)) {
102
- throw new LLMError("prompt must not be empty");
138
+ throw new ValidationError("prompt must not be empty");
103
139
  }
104
140
  }
105
141
 
@@ -111,26 +147,33 @@ function splitModelFromParams(params) {
111
147
  options
112
148
  };
113
149
  }
150
+ function callModelWithOptions(params, call) {
151
+ const { model, options } = splitModelFromParams(params);
152
+ return call(model, options);
153
+ }
114
154
 
115
155
  // src/generate.ts
116
156
  async function generate(params) {
117
157
  assertNonEmptyMessages(params.messages);
118
- const { model, options } = splitModelFromParams(params);
119
- return model.generate(options);
158
+ return callModelWithOptions(
159
+ params,
160
+ (model, options) => model.generate(options)
161
+ );
120
162
  }
121
163
 
122
164
  // src/generate-object.ts
123
165
  async function generateObject(params) {
124
166
  assertNonEmptyMessages(params.messages);
125
- const { model, options } = splitModelFromParams(params);
126
- return model.generateObject(options);
167
+ return callModelWithOptions(
168
+ params,
169
+ (model, options) => model.generateObject(options)
170
+ );
127
171
  }
128
172
 
129
173
  // src/stream-chat.ts
130
174
  async function stream(params) {
131
175
  assertNonEmptyMessages(params.messages);
132
- const { model, options } = splitModelFromParams(params);
133
- return model.stream(options);
176
+ return callModelWithOptions(params, (model, options) => model.stream(options));
134
177
  }
135
178
 
136
179
  // src/base-stream.ts
@@ -170,31 +213,31 @@ function createStream(options) {
170
213
  function cleanupSignalListener() {
171
214
  signal?.removeEventListener("abort", abortStream);
172
215
  }
173
- function settleCompleted(finalResult) {
216
+ function settleTerminalState(nextState) {
174
217
  if (terminalState.status !== "running") {
175
218
  return;
176
219
  }
177
- terminalState = {
178
- status: "completed",
179
- result: finalResult
180
- };
220
+ terminalState = nextState;
181
221
  cleanupSignalListener();
182
- resolveResult?.(finalResult);
222
+ if (nextState.status === "completed") {
223
+ resolveResult?.(nextState.result);
224
+ } else {
225
+ rejectResult?.(nextState.error);
226
+ }
183
227
  resolveEvents?.([...bufferedEvents]);
184
228
  notifyWaiters();
185
229
  }
230
+ function settleCompleted(finalResult) {
231
+ settleTerminalState({
232
+ status: "completed",
233
+ result: finalResult
234
+ });
235
+ }
186
236
  function settleRejected(error) {
187
- if (terminalState.status !== "running") {
188
- return;
189
- }
190
- terminalState = {
237
+ settleTerminalState({
191
238
  status: "rejected",
192
239
  error
193
- };
194
- cleanupSignalListener();
195
- rejectResult?.(error);
196
- resolveEvents?.([...bufferedEvents]);
197
- notifyWaiters();
240
+ });
198
241
  }
199
242
  function closeSourceIterator() {
200
243
  if (closeSourceIteratorPromise) {
@@ -212,7 +255,7 @@ function createStream(options) {
212
255
  if (terminalState.status !== "running") {
213
256
  return;
214
257
  }
215
- settleRejected(new StreamAbortedError("stream aborted"));
258
+ settleRejected(new StreamAbortedError());
216
259
  void closeSourceIterator();
217
260
  }
218
261
  if (signal) {
@@ -248,6 +291,12 @@ function createStream(options) {
248
291
  }
249
292
  }
250
293
  void pump();
294
+ function getDoneResult() {
295
+ return {
296
+ done: true,
297
+ value: void 0
298
+ };
299
+ }
251
300
  return {
252
301
  [Symbol.asyncIterator]() {
253
302
  let index = 0;
@@ -255,17 +304,11 @@ function createStream(options) {
255
304
  return {
256
305
  async next() {
257
306
  if (closed) {
258
- return {
259
- done: true,
260
- value: void 0
261
- };
307
+ return getDoneResult();
262
308
  }
263
309
  while (!closed && index >= bufferedEvents.length) {
264
310
  if (terminalState.status === "completed") {
265
- return {
266
- done: true,
267
- value: void 0
268
- };
311
+ return getDoneResult();
269
312
  }
270
313
  if (terminalState.status === "rejected") {
271
314
  throw terminalState.error;
@@ -273,10 +316,7 @@ function createStream(options) {
273
316
  await resolveWhenUpdated();
274
317
  }
275
318
  if (closed) {
276
- return {
277
- done: true,
278
- value: void 0
279
- };
319
+ return getDoneResult();
280
320
  }
281
321
  const value = bufferedEvents[index];
282
322
  index += 1;
@@ -288,10 +328,7 @@ function createStream(options) {
288
328
  async return() {
289
329
  closed = true;
290
330
  notifyWaiters();
291
- return {
292
- done: true,
293
- value: void 0
294
- };
331
+ return getDoneResult();
295
332
  }
296
333
  };
297
334
  },
@@ -303,8 +340,10 @@ function createStream(options) {
303
340
  // src/stream-object.ts
304
341
  async function streamObject(params) {
305
342
  assertNonEmptyMessages(params.messages);
306
- const { model, ...options } = params;
307
- return model.streamObject(options);
343
+ return callModelWithOptions(
344
+ params,
345
+ (model, options) => model.streamObject(options)
346
+ );
308
347
  }
309
348
  function createObjectStream(source, options = {}) {
310
349
  const { signal } = options;
@@ -337,7 +376,7 @@ function createObjectStream(source, options = {}) {
337
376
  },
338
377
  finalizeResult() {
339
378
  if (objectState.status !== "ready") {
340
- throw new LLMError(
379
+ throw new CoreAIError(
341
380
  "object stream completed without emitting a final object"
342
381
  );
343
382
  }
@@ -430,6 +469,31 @@ function createChatStream(source, options = {}) {
430
469
  finishReason = event.finishReason;
431
470
  usage = event.usage;
432
471
  };
472
+ const collectFinalizedData = () => {
473
+ const contentSegments = [];
474
+ const reasoningSegments = [];
475
+ const toolCalls = [];
476
+ for (const part of parts) {
477
+ if (part.type === "text") {
478
+ contentSegments.push(part.text);
479
+ continue;
480
+ }
481
+ if (part.type === "reasoning") {
482
+ reasoningSegments.push(part.text);
483
+ continue;
484
+ }
485
+ if (part.type === "tool-call") {
486
+ toolCalls.push(part.toolCall);
487
+ }
488
+ }
489
+ const content = contentSegments.join("");
490
+ const reasoning = reasoningSegments.join("");
491
+ return {
492
+ content: content.length > 0 ? content : null,
493
+ reasoning: reasoning.length > 0 ? reasoning : null,
494
+ toolCalls
495
+ };
496
+ };
433
497
  return createStream({
434
498
  source: resolvedSource,
435
499
  signal,
@@ -460,17 +524,11 @@ function createChatStream(source, options = {}) {
460
524
  finalizeResult() {
461
525
  flushText();
462
526
  flushReasoning();
463
- const content = parts.flatMap((part) => part.type === "text" ? [part.text] : []).join("");
464
- const reasoning = parts.flatMap(
465
- (part) => part.type === "reasoning" ? [part.text] : []
466
- ).join("");
467
- const toolCalls = parts.flatMap(
468
- (part) => part.type === "tool-call" ? [part.toolCall] : []
469
- );
527
+ const { content, reasoning, toolCalls } = collectFinalizedData();
470
528
  return {
471
529
  parts,
472
- content: content.length > 0 ? content : null,
473
- reasoning: reasoning.length > 0 ? reasoning : null,
530
+ content,
531
+ reasoning,
474
532
  toolCalls,
475
533
  finishReason,
476
534
  usage
@@ -487,24 +545,28 @@ function getProviderMetadata(providerMetadata, provider) {
487
545
  // src/embed.ts
488
546
  async function embed(params) {
489
547
  assertNonEmptyEmbedInput(params.input);
490
- const { model, options } = splitModelFromParams(params);
491
- return model.embed(options);
548
+ return callModelWithOptions(params, (model, options) => model.embed(options));
492
549
  }
493
550
 
494
551
  // src/generate-image.ts
495
552
  async function generateImage(params) {
496
553
  assertNonEmptyPrompt(params.prompt);
497
- const { model, options } = splitModelFromParams(params);
498
- return model.generate(options);
554
+ return callModelWithOptions(
555
+ params,
556
+ (model, options) => model.generate(options)
557
+ );
499
558
  }
500
559
  export {
501
- LLMError,
560
+ AbortedError,
561
+ CoreAIError,
502
562
  ProviderError,
503
563
  StreamAbortedError,
504
564
  StructuredOutputError,
505
565
  StructuredOutputNoObjectGeneratedError,
506
566
  StructuredOutputParseError,
507
567
  StructuredOutputValidationError,
568
+ ValidationError,
569
+ asObject,
508
570
  assistantMessage,
509
571
  createChatStream,
510
572
  createObjectStream,
@@ -515,7 +577,9 @@ export {
515
577
  generateObject,
516
578
  getProviderMetadata,
517
579
  resultToMessage,
580
+ safeParseJsonObject,
518
581
  stream,
519
582
  streamObject,
583
+ stripModelDateSuffix,
520
584
  zodSchemaToJsonSchema
521
585
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@core-ai/core-ai",
3
- "version": "0.7.0",
3
+ "version": "0.8.0",
4
4
  "description": "Type-safe LLM abstraction layer over native provider SDKs",
5
5
  "license": "MIT",
6
6
  "author": "Omnifact (https://omnifact.ai)",