@core-ai/core-ai 0.5.1 → 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/README.md +1 -0
- package/dist/index.d.ts +72 -30
- package/dist/index.js +300 -159
- package/package.json +4 -3
package/README.md
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -42,7 +42,18 @@ type AssistantTextPart = {
|
|
|
42
42
|
type ReasoningPart = {
|
|
43
43
|
type: 'reasoning';
|
|
44
44
|
text: string;
|
|
45
|
-
|
|
45
|
+
/**
|
|
46
|
+
* Provider-namespaced metadata for this reasoning block. The top-level key is
|
|
47
|
+
* the provider identifier (e.g. `'anthropic'`, `'openai'`), which also serves as
|
|
48
|
+
* the ownership discriminator: an adapter checks for the presence of its own key
|
|
49
|
+
* to detect cross-provider blocks. Cross-provider blocks are downgraded to plain
|
|
50
|
+
* text (preserving context) rather than forwarding opaque metadata that would
|
|
51
|
+
* cause an API error on the receiving provider.
|
|
52
|
+
*
|
|
53
|
+
* @example Anthropic: `{ anthropic: { signature: '...' } }`
|
|
54
|
+
* @example OpenAI: `{ openai: { encryptedContent: '...' } }`
|
|
55
|
+
*/
|
|
56
|
+
providerMetadata?: Record<string, Record<string, unknown>>;
|
|
46
57
|
};
|
|
47
58
|
type ToolCallPart = {
|
|
48
59
|
type: 'tool-call';
|
|
@@ -78,26 +89,31 @@ type ChatModel = {
|
|
|
78
89
|
readonly provider: string;
|
|
79
90
|
readonly modelId: string;
|
|
80
91
|
generate(options: GenerateOptions): Promise<GenerateResult>;
|
|
81
|
-
stream(options: GenerateOptions): Promise<
|
|
92
|
+
stream(options: GenerateOptions): Promise<ChatStream>;
|
|
82
93
|
generateObject<TSchema extends z.ZodType>(options: GenerateObjectOptions<TSchema>): Promise<GenerateObjectResult<TSchema>>;
|
|
83
|
-
streamObject<TSchema extends z.ZodType>(options: StreamObjectOptions<TSchema>): Promise<
|
|
94
|
+
streamObject<TSchema extends z.ZodType>(options: StreamObjectOptions<TSchema>): Promise<ObjectStream<TSchema>>;
|
|
84
95
|
};
|
|
85
|
-
|
|
96
|
+
interface GenerateProviderOptions {
|
|
97
|
+
[key: string]: Record<string, unknown> | undefined;
|
|
98
|
+
}
|
|
99
|
+
interface EmbedProviderOptions {
|
|
100
|
+
[key: string]: Record<string, unknown> | undefined;
|
|
101
|
+
}
|
|
102
|
+
interface ImageProviderOptions {
|
|
103
|
+
[key: string]: Record<string, unknown> | undefined;
|
|
104
|
+
}
|
|
105
|
+
type BaseGenerateOptions = {
|
|
106
|
+
messages: Message[];
|
|
86
107
|
temperature?: number;
|
|
87
108
|
maxTokens?: number;
|
|
88
109
|
topP?: number;
|
|
89
|
-
stopSequences?: string[];
|
|
90
|
-
frequencyPenalty?: number;
|
|
91
|
-
presencePenalty?: number;
|
|
92
|
-
};
|
|
93
|
-
type GenerateOptions = {
|
|
94
|
-
messages: Message[];
|
|
95
110
|
reasoning?: ReasoningConfig;
|
|
111
|
+
providerOptions?: GenerateProviderOptions;
|
|
112
|
+
signal?: AbortSignal;
|
|
113
|
+
};
|
|
114
|
+
type GenerateOptions = BaseGenerateOptions & {
|
|
96
115
|
tools?: ToolSet;
|
|
97
116
|
toolChoice?: ToolChoice;
|
|
98
|
-
config?: ModelConfig;
|
|
99
|
-
providerOptions?: Record<string, unknown>;
|
|
100
|
-
signal?: AbortSignal;
|
|
101
117
|
};
|
|
102
118
|
type GenerateResult = {
|
|
103
119
|
parts: AssistantContentPart[];
|
|
@@ -107,15 +123,10 @@ type GenerateResult = {
|
|
|
107
123
|
finishReason: FinishReason;
|
|
108
124
|
usage: ChatUsage;
|
|
109
125
|
};
|
|
110
|
-
type GenerateObjectOptions<TSchema extends z.ZodType> = {
|
|
111
|
-
messages: Message[];
|
|
126
|
+
type GenerateObjectOptions<TSchema extends z.ZodType> = BaseGenerateOptions & {
|
|
112
127
|
schema: TSchema;
|
|
113
128
|
schemaName?: string;
|
|
114
129
|
schemaDescription?: string;
|
|
115
|
-
reasoning?: ReasoningConfig;
|
|
116
|
-
config?: ModelConfig;
|
|
117
|
-
providerOptions?: Record<string, unknown>;
|
|
118
|
-
signal?: AbortSignal;
|
|
119
130
|
};
|
|
120
131
|
type StreamObjectOptions<TSchema extends z.ZodType> = GenerateObjectOptions<TSchema>;
|
|
121
132
|
type GenerateObjectResult<TSchema extends z.ZodType> = {
|
|
@@ -170,6 +181,7 @@ type StreamEvent = {
|
|
|
170
181
|
text: string;
|
|
171
182
|
} | {
|
|
172
183
|
type: 'reasoning-end';
|
|
184
|
+
providerMetadata?: Record<string, Record<string, unknown>>;
|
|
173
185
|
} | {
|
|
174
186
|
type: 'text-delta';
|
|
175
187
|
text: string;
|
|
@@ -189,8 +201,21 @@ type StreamEvent = {
|
|
|
189
201
|
finishReason: FinishReason;
|
|
190
202
|
usage: ChatUsage;
|
|
191
203
|
};
|
|
192
|
-
|
|
193
|
-
|
|
204
|
+
/**
|
|
205
|
+
* Handle for a single in-flight chat streaming operation.
|
|
206
|
+
*
|
|
207
|
+
* The handle is replayable: iterating after some or all events have already
|
|
208
|
+
* arrived replays the buffered event history before waiting for later events.
|
|
209
|
+
*
|
|
210
|
+
* `result` resolves with the aggregated final response when the operation
|
|
211
|
+
* completes successfully, and rejects on abort or upstream failure.
|
|
212
|
+
*
|
|
213
|
+
* `events` always resolves with all observed events up to the terminal point,
|
|
214
|
+
* including abort and failure cases.
|
|
215
|
+
*/
|
|
216
|
+
type ChatStream = AsyncIterable<StreamEvent> & {
|
|
217
|
+
readonly result: Promise<GenerateResult>;
|
|
218
|
+
readonly events: Promise<readonly StreamEvent[]>;
|
|
194
219
|
};
|
|
195
220
|
type ObjectStreamEvent<TSchema extends z.ZodType> = {
|
|
196
221
|
type: 'object-delta';
|
|
@@ -203,8 +228,16 @@ type ObjectStreamEvent<TSchema extends z.ZodType> = {
|
|
|
203
228
|
finishReason: FinishReason;
|
|
204
229
|
usage: ChatUsage;
|
|
205
230
|
};
|
|
206
|
-
|
|
207
|
-
|
|
231
|
+
/**
|
|
232
|
+
* Handle for a single in-flight structured object streaming operation.
|
|
233
|
+
*
|
|
234
|
+
* The lifecycle semantics mirror `ChatStream`: iteration is replayable,
|
|
235
|
+
* `result` settles independently of event consumption, and `events` resolves
|
|
236
|
+
* with the observed history.
|
|
237
|
+
*/
|
|
238
|
+
type ObjectStream<TSchema extends z.ZodType> = AsyncIterable<ObjectStreamEvent<TSchema>> & {
|
|
239
|
+
readonly result: Promise<GenerateObjectResult<TSchema>>;
|
|
240
|
+
readonly events: Promise<readonly ObjectStreamEvent<TSchema>[]>;
|
|
208
241
|
};
|
|
209
242
|
type EmbeddingModel = {
|
|
210
243
|
readonly provider: string;
|
|
@@ -214,7 +247,7 @@ type EmbeddingModel = {
|
|
|
214
247
|
type EmbedOptions = {
|
|
215
248
|
input: string | string[];
|
|
216
249
|
dimensions?: number;
|
|
217
|
-
providerOptions?:
|
|
250
|
+
providerOptions?: EmbedProviderOptions;
|
|
218
251
|
};
|
|
219
252
|
type EmbedResult = {
|
|
220
253
|
embeddings: number[][];
|
|
@@ -237,7 +270,7 @@ type ImageGenerateOptions = {
|
|
|
237
270
|
prompt: string;
|
|
238
271
|
n?: number;
|
|
239
272
|
size?: string;
|
|
240
|
-
providerOptions?:
|
|
273
|
+
providerOptions?: ImageProviderOptions;
|
|
241
274
|
};
|
|
242
275
|
type ImageGenerateResult = {
|
|
243
276
|
images: GeneratedImage[];
|
|
@@ -252,6 +285,9 @@ declare class LLMError extends Error {
|
|
|
252
285
|
readonly cause?: unknown;
|
|
253
286
|
constructor(message: string, cause?: unknown);
|
|
254
287
|
}
|
|
288
|
+
declare class StreamAbortedError extends LLMError {
|
|
289
|
+
constructor(message?: string, cause?: unknown);
|
|
290
|
+
}
|
|
255
291
|
declare class ProviderError extends LLMError {
|
|
256
292
|
readonly provider: string;
|
|
257
293
|
readonly statusCode?: number;
|
|
@@ -298,15 +334,21 @@ declare function generateObject<TSchema extends z.ZodType>(params: GenerateObjec
|
|
|
298
334
|
type StreamParams = GenerateOptions & {
|
|
299
335
|
model: ChatModel;
|
|
300
336
|
};
|
|
301
|
-
declare function stream(params: StreamParams): Promise<
|
|
337
|
+
declare function stream(params: StreamParams): Promise<ChatStream>;
|
|
302
338
|
|
|
303
339
|
type StreamObjectParams<TSchema extends z.ZodType> = StreamObjectOptions<TSchema> & {
|
|
304
340
|
model: ChatModel;
|
|
305
341
|
};
|
|
306
|
-
declare function streamObject<TSchema extends z.ZodType>(params: StreamObjectParams<TSchema>): Promise<
|
|
307
|
-
declare function
|
|
342
|
+
declare function streamObject<TSchema extends z.ZodType>(params: StreamObjectParams<TSchema>): Promise<ObjectStream<TSchema>>;
|
|
343
|
+
declare function createObjectStream<TSchema extends z.ZodType>(source: AsyncIterable<ObjectStreamEvent<TSchema>>, options?: {
|
|
344
|
+
signal?: AbortSignal;
|
|
345
|
+
}): ObjectStream<TSchema>;
|
|
346
|
+
|
|
347
|
+
declare function createChatStream(source: AsyncIterable<StreamEvent> | (() => Promise<AsyncIterable<StreamEvent>>), options?: {
|
|
348
|
+
signal?: AbortSignal;
|
|
349
|
+
}): ChatStream;
|
|
308
350
|
|
|
309
|
-
declare function
|
|
351
|
+
declare function getProviderMetadata<T extends Record<string, unknown>>(providerMetadata: Record<string, Record<string, unknown>> | undefined, provider: string): T | undefined;
|
|
310
352
|
|
|
311
353
|
type EmbedParams = EmbedOptions & {
|
|
312
354
|
model: EmbeddingModel;
|
|
@@ -318,4 +360,4 @@ type GenerateImageParams = ImageGenerateOptions & {
|
|
|
318
360
|
};
|
|
319
361
|
declare function generateImage(params: GenerateImageParams): Promise<ImageGenerateResult>;
|
|
320
362
|
|
|
321
|
-
export { type AssistantContentPart, type AssistantMessage, type AssistantTextPart, type ChatInputTokenDetails, type ChatModel, type ChatOutputTokenDetails, type ChatUsage, type EmbedOptions, type EmbedResult, type EmbeddingModel, type EmbeddingUsage, type FilePart, type FinishReason, type GenerateObjectOptions, type GenerateObjectResult, type GenerateOptions, type GenerateResult, type GeneratedImage, type ImageGenerateOptions, type ImageGenerateResult, type ImageModel, type ImagePart, LLMError, type Message, type
|
|
363
|
+
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 };
|
package/dist/index.js
CHANGED
|
@@ -7,6 +7,12 @@ var LLMError = class extends Error {
|
|
|
7
7
|
this.cause = cause;
|
|
8
8
|
}
|
|
9
9
|
};
|
|
10
|
+
var StreamAbortedError = class extends LLMError {
|
|
11
|
+
constructor(message = "stream aborted", cause) {
|
|
12
|
+
super(message, cause);
|
|
13
|
+
this.name = "StreamAbortedError";
|
|
14
|
+
}
|
|
15
|
+
};
|
|
10
16
|
var ProviderError = class extends LLMError {
|
|
11
17
|
provider;
|
|
12
18
|
statusCode;
|
|
@@ -68,156 +74,306 @@ function assistantMessage(content) {
|
|
|
68
74
|
};
|
|
69
75
|
}
|
|
70
76
|
|
|
71
|
-
// src/
|
|
72
|
-
|
|
73
|
-
if (
|
|
77
|
+
// src/assertions.ts
|
|
78
|
+
function assertNonEmptyMessages(messages) {
|
|
79
|
+
if (messages.length === 0) {
|
|
74
80
|
throw new LLMError("messages must not be empty");
|
|
75
81
|
}
|
|
82
|
+
}
|
|
83
|
+
function assertNonEmptyEmbedInput(input) {
|
|
84
|
+
if (typeof input === "string" && input.length === 0) {
|
|
85
|
+
throw new LLMError("input must not be empty");
|
|
86
|
+
}
|
|
87
|
+
if (Array.isArray(input) && input.length === 0) {
|
|
88
|
+
throw new LLMError("input must not be empty");
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// src/generate.ts
|
|
93
|
+
async function generate(params) {
|
|
94
|
+
assertNonEmptyMessages(params.messages);
|
|
76
95
|
const { model, ...options } = params;
|
|
77
96
|
return model.generate(options);
|
|
78
97
|
}
|
|
79
98
|
|
|
80
99
|
// src/generate-object.ts
|
|
81
100
|
async function generateObject(params) {
|
|
82
|
-
|
|
83
|
-
throw new LLMError("messages must not be empty");
|
|
84
|
-
}
|
|
101
|
+
assertNonEmptyMessages(params.messages);
|
|
85
102
|
const { model, ...options } = params;
|
|
86
103
|
return model.generateObject(options);
|
|
87
104
|
}
|
|
88
105
|
|
|
89
106
|
// src/stream-chat.ts
|
|
90
107
|
async function stream(params) {
|
|
91
|
-
|
|
92
|
-
throw new LLMError("messages must not be empty");
|
|
93
|
-
}
|
|
108
|
+
assertNonEmptyMessages(params.messages);
|
|
94
109
|
const { model, ...options } = params;
|
|
95
110
|
return model.stream(options);
|
|
96
111
|
}
|
|
97
112
|
|
|
98
|
-
// src/stream
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
113
|
+
// src/base-stream.ts
|
|
114
|
+
function createStream(options) {
|
|
115
|
+
const { source, reduceEvent, finalizeResult, signal } = options;
|
|
116
|
+
const iterator = source[Symbol.asyncIterator]();
|
|
117
|
+
const bufferedEvents = [];
|
|
118
|
+
let terminalState = { status: "running" };
|
|
119
|
+
let resolveResult;
|
|
120
|
+
let rejectResult;
|
|
121
|
+
let resolveEvents;
|
|
122
|
+
const result = new Promise((resolve, reject) => {
|
|
123
|
+
resolveResult = resolve;
|
|
124
|
+
rejectResult = reject;
|
|
125
|
+
});
|
|
126
|
+
void result.catch(() => {
|
|
127
|
+
});
|
|
128
|
+
const events = new Promise((resolve) => {
|
|
129
|
+
resolveEvents = resolve;
|
|
130
|
+
});
|
|
131
|
+
const waiters = /* @__PURE__ */ new Set();
|
|
132
|
+
let closeSourceIteratorPromise;
|
|
133
|
+
function notifyWaiters() {
|
|
134
|
+
for (const waiter of waiters) {
|
|
135
|
+
waiter();
|
|
136
|
+
}
|
|
137
|
+
waiters.clear();
|
|
102
138
|
}
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
function createObjectStreamResult(source) {
|
|
107
|
-
let resolveResponse;
|
|
108
|
-
let rejectResponse;
|
|
109
|
-
const responsePromise = new Promise(
|
|
110
|
-
(resolve, reject) => {
|
|
111
|
-
resolveResponse = resolve;
|
|
112
|
-
rejectResponse = reject;
|
|
139
|
+
function resolveWhenUpdated() {
|
|
140
|
+
if (terminalState.status !== "running") {
|
|
141
|
+
return Promise.resolve();
|
|
113
142
|
}
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
143
|
+
return new Promise((resolve) => {
|
|
144
|
+
waiters.add(resolve);
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
function cleanupSignalListener() {
|
|
148
|
+
signal?.removeEventListener("abort", abortStream);
|
|
149
|
+
}
|
|
150
|
+
function settleCompleted(finalResult) {
|
|
151
|
+
if (terminalState.status !== "running") {
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
terminalState = {
|
|
155
|
+
status: "completed",
|
|
156
|
+
result: finalResult
|
|
127
157
|
};
|
|
158
|
+
cleanupSignalListener();
|
|
159
|
+
resolveResult?.(finalResult);
|
|
160
|
+
resolveEvents?.([...bufferedEvents]);
|
|
161
|
+
notifyWaiters();
|
|
162
|
+
}
|
|
163
|
+
function settleRejected(error) {
|
|
164
|
+
if (terminalState.status !== "running") {
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
terminalState = {
|
|
168
|
+
status: "rejected",
|
|
169
|
+
error
|
|
170
|
+
};
|
|
171
|
+
cleanupSignalListener();
|
|
172
|
+
rejectResult?.(error);
|
|
173
|
+
resolveEvents?.([...bufferedEvents]);
|
|
174
|
+
notifyWaiters();
|
|
175
|
+
}
|
|
176
|
+
function closeSourceIterator() {
|
|
177
|
+
if (closeSourceIteratorPromise) {
|
|
178
|
+
return closeSourceIteratorPromise;
|
|
179
|
+
}
|
|
180
|
+
closeSourceIteratorPromise = (async () => {
|
|
181
|
+
try {
|
|
182
|
+
await iterator.return?.();
|
|
183
|
+
} catch {
|
|
184
|
+
}
|
|
185
|
+
})();
|
|
186
|
+
return closeSourceIteratorPromise;
|
|
187
|
+
}
|
|
188
|
+
function abortStream() {
|
|
189
|
+
if (terminalState.status !== "running") {
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
settleRejected(new StreamAbortedError("stream aborted"));
|
|
193
|
+
void closeSourceIterator();
|
|
194
|
+
}
|
|
195
|
+
if (signal) {
|
|
196
|
+
if (signal.aborted) {
|
|
197
|
+
abortStream();
|
|
198
|
+
} else {
|
|
199
|
+
signal.addEventListener("abort", abortStream, { once: true });
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
async function pump() {
|
|
128
203
|
try {
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
usage = event.usage;
|
|
204
|
+
while (terminalState.status === "running") {
|
|
205
|
+
const next = await iterator.next();
|
|
206
|
+
if (terminalState.status !== "running") {
|
|
207
|
+
await closeSourceIterator();
|
|
208
|
+
return;
|
|
135
209
|
}
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
210
|
+
if (next.done) {
|
|
211
|
+
try {
|
|
212
|
+
settleCompleted(finalizeResult());
|
|
213
|
+
} catch (error) {
|
|
214
|
+
settleRejected(error);
|
|
215
|
+
}
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
bufferedEvents.push(next.value);
|
|
219
|
+
notifyWaiters();
|
|
220
|
+
reduceEvent(next.value);
|
|
142
221
|
}
|
|
143
|
-
resolveResponse?.({
|
|
144
|
-
object: objectResult,
|
|
145
|
-
finishReason,
|
|
146
|
-
usage
|
|
147
|
-
});
|
|
148
222
|
} catch (error) {
|
|
149
|
-
|
|
150
|
-
|
|
223
|
+
settleRejected(error);
|
|
224
|
+
await closeSourceIterator();
|
|
151
225
|
}
|
|
152
226
|
}
|
|
153
|
-
|
|
227
|
+
void pump();
|
|
154
228
|
return {
|
|
155
229
|
[Symbol.asyncIterator]() {
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
230
|
+
let index = 0;
|
|
231
|
+
let closed = false;
|
|
232
|
+
return {
|
|
233
|
+
async next() {
|
|
234
|
+
if (closed) {
|
|
235
|
+
return {
|
|
236
|
+
done: true,
|
|
237
|
+
value: void 0
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
while (!closed && index >= bufferedEvents.length) {
|
|
241
|
+
if (terminalState.status === "completed") {
|
|
242
|
+
return {
|
|
243
|
+
done: true,
|
|
244
|
+
value: void 0
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
if (terminalState.status === "rejected") {
|
|
248
|
+
throw terminalState.error;
|
|
168
249
|
}
|
|
169
|
-
|
|
250
|
+
await resolveWhenUpdated();
|
|
170
251
|
}
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
252
|
+
if (closed) {
|
|
253
|
+
return {
|
|
254
|
+
done: true,
|
|
255
|
+
value: void 0
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
const value = bufferedEvents[index];
|
|
259
|
+
index += 1;
|
|
260
|
+
return {
|
|
261
|
+
done: false,
|
|
262
|
+
value
|
|
263
|
+
};
|
|
264
|
+
},
|
|
265
|
+
async return() {
|
|
266
|
+
closed = true;
|
|
267
|
+
notifyWaiters();
|
|
268
|
+
return {
|
|
269
|
+
done: true,
|
|
270
|
+
value: void 0
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
};
|
|
274
|
+
},
|
|
275
|
+
result,
|
|
276
|
+
events
|
|
175
277
|
};
|
|
176
278
|
}
|
|
177
279
|
|
|
178
|
-
// src/stream.ts
|
|
179
|
-
function
|
|
180
|
-
|
|
181
|
-
const
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
280
|
+
// src/stream-object.ts
|
|
281
|
+
async function streamObject(params) {
|
|
282
|
+
assertNonEmptyMessages(params.messages);
|
|
283
|
+
const { model, ...options } = params;
|
|
284
|
+
return model.streamObject(options);
|
|
285
|
+
}
|
|
286
|
+
function createObjectStream(source, options = {}) {
|
|
287
|
+
const { signal } = options;
|
|
288
|
+
let objectState = {
|
|
289
|
+
status: "pending"
|
|
290
|
+
};
|
|
291
|
+
let finishReason = "unknown";
|
|
292
|
+
let usage = {
|
|
293
|
+
inputTokens: 0,
|
|
294
|
+
outputTokens: 0,
|
|
295
|
+
inputTokenDetails: {
|
|
296
|
+
cacheReadTokens: 0,
|
|
297
|
+
cacheWriteTokens: 0
|
|
298
|
+
},
|
|
299
|
+
outputTokenDetails: {}
|
|
300
|
+
};
|
|
301
|
+
return createStream({
|
|
302
|
+
source,
|
|
303
|
+
signal,
|
|
304
|
+
reduceEvent(event) {
|
|
305
|
+
if (event.type === "object") {
|
|
306
|
+
objectState = {
|
|
307
|
+
status: "ready",
|
|
308
|
+
object: event.object
|
|
309
|
+
};
|
|
310
|
+
} else if (event.type === "finish") {
|
|
311
|
+
finishReason = event.finishReason;
|
|
312
|
+
usage = event.usage;
|
|
203
313
|
}
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
const flushReasoning = () => {
|
|
211
|
-
if (reasoningBuffer.length === 0) {
|
|
212
|
-
return;
|
|
314
|
+
},
|
|
315
|
+
finalizeResult() {
|
|
316
|
+
if (objectState.status !== "ready") {
|
|
317
|
+
throw new LLMError(
|
|
318
|
+
"object stream completed without emitting a final object"
|
|
319
|
+
);
|
|
213
320
|
}
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
}
|
|
220
|
-
|
|
321
|
+
return {
|
|
322
|
+
object: objectState.object,
|
|
323
|
+
finishReason,
|
|
324
|
+
usage
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
// src/stream.ts
|
|
331
|
+
function createChatStream(source, options = {}) {
|
|
332
|
+
const { signal } = options;
|
|
333
|
+
const resolvedSource = typeof source === "function" ? (async function* () {
|
|
334
|
+
yield* await source();
|
|
335
|
+
})() : source;
|
|
336
|
+
const parts = [];
|
|
337
|
+
let textBuffer = "";
|
|
338
|
+
let reasoningBuffer = "";
|
|
339
|
+
let reasoningProviderMetadata;
|
|
340
|
+
let insideReasoning = false;
|
|
341
|
+
let finishReason = "unknown";
|
|
342
|
+
let usage = {
|
|
343
|
+
inputTokens: 0,
|
|
344
|
+
outputTokens: 0,
|
|
345
|
+
inputTokenDetails: {
|
|
346
|
+
cacheReadTokens: 0,
|
|
347
|
+
cacheWriteTokens: 0
|
|
348
|
+
},
|
|
349
|
+
outputTokenDetails: {}
|
|
350
|
+
};
|
|
351
|
+
const flushText = () => {
|
|
352
|
+
if (textBuffer.length === 0) {
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
355
|
+
parts.push({
|
|
356
|
+
type: "text",
|
|
357
|
+
text: textBuffer
|
|
358
|
+
});
|
|
359
|
+
textBuffer = "";
|
|
360
|
+
};
|
|
361
|
+
const flushReasoning = () => {
|
|
362
|
+
if (reasoningBuffer.length === 0 && reasoningProviderMetadata === void 0) {
|
|
363
|
+
return;
|
|
364
|
+
}
|
|
365
|
+
parts.push({
|
|
366
|
+
type: "reasoning",
|
|
367
|
+
text: reasoningBuffer,
|
|
368
|
+
...reasoningProviderMetadata ? { providerMetadata: reasoningProviderMetadata } : {}
|
|
369
|
+
});
|
|
370
|
+
reasoningBuffer = "";
|
|
371
|
+
reasoningProviderMetadata = void 0;
|
|
372
|
+
};
|
|
373
|
+
return createStream({
|
|
374
|
+
source: resolvedSource,
|
|
375
|
+
signal,
|
|
376
|
+
reduceEvent(event) {
|
|
221
377
|
if (event.type === "reasoning-start") {
|
|
222
378
|
flushText();
|
|
223
379
|
flushReasoning();
|
|
@@ -229,6 +385,7 @@ function createStreamResult(source) {
|
|
|
229
385
|
}
|
|
230
386
|
reasoningBuffer += event.text;
|
|
231
387
|
} else if (event.type === "reasoning-end") {
|
|
388
|
+
reasoningProviderMetadata = event.providerMetadata;
|
|
232
389
|
flushReasoning();
|
|
233
390
|
insideReasoning = false;
|
|
234
391
|
} else if (event.type === "text-delta") {
|
|
@@ -249,55 +406,37 @@ function createStreamResult(source) {
|
|
|
249
406
|
finishReason = event.finishReason;
|
|
250
407
|
usage = event.usage;
|
|
251
408
|
}
|
|
252
|
-
yield event;
|
|
253
|
-
}
|
|
254
|
-
flushText();
|
|
255
|
-
flushReasoning();
|
|
256
|
-
const content = parts.flatMap((part) => part.type === "text" ? [part.text] : []).join("");
|
|
257
|
-
const reasoning = parts.flatMap((part) => part.type === "reasoning" ? [part.text] : []).join("");
|
|
258
|
-
const toolCalls = parts.flatMap(
|
|
259
|
-
(part) => part.type === "tool-call" ? [part.toolCall] : []
|
|
260
|
-
);
|
|
261
|
-
resolveResponse?.({
|
|
262
|
-
parts,
|
|
263
|
-
content: content.length > 0 ? content : null,
|
|
264
|
-
reasoning: reasoning.length > 0 ? reasoning : null,
|
|
265
|
-
toolCalls,
|
|
266
|
-
finishReason,
|
|
267
|
-
usage
|
|
268
|
-
});
|
|
269
|
-
}
|
|
270
|
-
const generator = iterate();
|
|
271
|
-
return {
|
|
272
|
-
[Symbol.asyncIterator]() {
|
|
273
|
-
if (iteratorCreated) {
|
|
274
|
-
throw new Error("Stream can only be iterated once");
|
|
275
|
-
}
|
|
276
|
-
iteratorCreated = true;
|
|
277
|
-
return generator;
|
|
278
409
|
},
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
410
|
+
finalizeResult() {
|
|
411
|
+
flushText();
|
|
412
|
+
flushReasoning();
|
|
413
|
+
const content = parts.flatMap((part) => part.type === "text" ? [part.text] : []).join("");
|
|
414
|
+
const reasoning = parts.flatMap(
|
|
415
|
+
(part) => part.type === "reasoning" ? [part.text] : []
|
|
416
|
+
).join("");
|
|
417
|
+
const toolCalls = parts.flatMap(
|
|
418
|
+
(part) => part.type === "tool-call" ? [part.toolCall] : []
|
|
419
|
+
);
|
|
420
|
+
return {
|
|
421
|
+
parts,
|
|
422
|
+
content: content.length > 0 ? content : null,
|
|
423
|
+
reasoning: reasoning.length > 0 ? reasoning : null,
|
|
424
|
+
toolCalls,
|
|
425
|
+
finishReason,
|
|
426
|
+
usage
|
|
427
|
+
};
|
|
288
428
|
}
|
|
289
|
-
};
|
|
429
|
+
});
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
// src/provider-metadata.ts
|
|
433
|
+
function getProviderMetadata(providerMetadata, provider) {
|
|
434
|
+
return providerMetadata?.[provider];
|
|
290
435
|
}
|
|
291
436
|
|
|
292
437
|
// src/embed.ts
|
|
293
438
|
async function embed(params) {
|
|
294
|
-
|
|
295
|
-
if (typeof input === "string" && input.length === 0) {
|
|
296
|
-
throw new LLMError("input must not be empty");
|
|
297
|
-
}
|
|
298
|
-
if (Array.isArray(input) && input.length === 0) {
|
|
299
|
-
throw new LLMError("input must not be empty");
|
|
300
|
-
}
|
|
439
|
+
assertNonEmptyEmbedInput(params.input);
|
|
301
440
|
const { model, ...options } = params;
|
|
302
441
|
return model.embed(options);
|
|
303
442
|
}
|
|
@@ -313,18 +452,20 @@ async function generateImage(params) {
|
|
|
313
452
|
export {
|
|
314
453
|
LLMError,
|
|
315
454
|
ProviderError,
|
|
455
|
+
StreamAbortedError,
|
|
316
456
|
StructuredOutputError,
|
|
317
457
|
StructuredOutputNoObjectGeneratedError,
|
|
318
458
|
StructuredOutputParseError,
|
|
319
459
|
StructuredOutputValidationError,
|
|
320
460
|
assistantMessage,
|
|
321
|
-
|
|
322
|
-
|
|
461
|
+
createChatStream,
|
|
462
|
+
createObjectStream,
|
|
323
463
|
defineTool,
|
|
324
464
|
embed,
|
|
325
465
|
generate,
|
|
326
466
|
generateImage,
|
|
327
467
|
generateObject,
|
|
468
|
+
getProviderMetadata,
|
|
328
469
|
resultToMessage,
|
|
329
470
|
stream,
|
|
330
471
|
streamObject
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@core-ai/core-ai",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "Type-safe LLM abstraction layer over native provider SDKs",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Omnifact (https://omnifact.ai)",
|
|
@@ -47,8 +47,9 @@
|
|
|
47
47
|
"zod-to-json-schema": "^3.25.1"
|
|
48
48
|
},
|
|
49
49
|
"devDependencies": {
|
|
50
|
-
"@core-ai/eslint-config": "
|
|
51
|
-
"@core-ai/
|
|
50
|
+
"@core-ai/eslint-config": "*",
|
|
51
|
+
"@core-ai/testing": "*",
|
|
52
|
+
"@core-ai/typescript-config": "*",
|
|
52
53
|
"typescript": "^5.7.3",
|
|
53
54
|
"vitest": "^3.2.4"
|
|
54
55
|
}
|