@core-ai/core-ai 0.5.1 → 0.6.1
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 +372 -190
- 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,263 +74,439 @@ function assistantMessage(content) {
|
|
|
68
74
|
};
|
|
69
75
|
}
|
|
70
76
|
|
|
71
|
-
// src/
|
|
72
|
-
|
|
73
|
-
|
|
77
|
+
// src/assertions.ts
|
|
78
|
+
function isEmptyText(value) {
|
|
79
|
+
return value.length === 0;
|
|
80
|
+
}
|
|
81
|
+
function assertNonEmptyMessages(messages) {
|
|
82
|
+
if (messages.length === 0) {
|
|
74
83
|
throw new LLMError("messages must not be empty");
|
|
75
84
|
}
|
|
85
|
+
}
|
|
86
|
+
function assertNonEmptyEmbedInput(input) {
|
|
87
|
+
const isEmptyString = typeof input === "string" && isEmptyText(input);
|
|
88
|
+
const isEmptyArray = Array.isArray(input) && input.length === 0;
|
|
89
|
+
if (isEmptyString || isEmptyArray) {
|
|
90
|
+
throw new LLMError("input must not be empty");
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
function assertNonEmptyPrompt(prompt) {
|
|
94
|
+
if (isEmptyText(prompt)) {
|
|
95
|
+
throw new LLMError("prompt must not be empty");
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// src/model-options.ts
|
|
100
|
+
function splitModelFromParams(params) {
|
|
76
101
|
const { model, ...options } = params;
|
|
102
|
+
return {
|
|
103
|
+
model,
|
|
104
|
+
options
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// src/generate.ts
|
|
109
|
+
async function generate(params) {
|
|
110
|
+
assertNonEmptyMessages(params.messages);
|
|
111
|
+
const { model, options } = splitModelFromParams(params);
|
|
77
112
|
return model.generate(options);
|
|
78
113
|
}
|
|
79
114
|
|
|
80
115
|
// src/generate-object.ts
|
|
81
116
|
async function generateObject(params) {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
}
|
|
85
|
-
const { model, ...options } = params;
|
|
117
|
+
assertNonEmptyMessages(params.messages);
|
|
118
|
+
const { model, options } = splitModelFromParams(params);
|
|
86
119
|
return model.generateObject(options);
|
|
87
120
|
}
|
|
88
121
|
|
|
89
122
|
// src/stream-chat.ts
|
|
90
123
|
async function stream(params) {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
}
|
|
94
|
-
const { model, ...options } = params;
|
|
124
|
+
assertNonEmptyMessages(params.messages);
|
|
125
|
+
const { model, options } = splitModelFromParams(params);
|
|
95
126
|
return model.stream(options);
|
|
96
127
|
}
|
|
97
128
|
|
|
98
|
-
// src/stream
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
129
|
+
// src/base-stream.ts
|
|
130
|
+
function createStream(options) {
|
|
131
|
+
const { source, reduceEvent, finalizeResult, signal } = options;
|
|
132
|
+
const iterator = source[Symbol.asyncIterator]();
|
|
133
|
+
const bufferedEvents = [];
|
|
134
|
+
let terminalState = { status: "running" };
|
|
135
|
+
let resolveResult;
|
|
136
|
+
let rejectResult;
|
|
137
|
+
let resolveEvents;
|
|
138
|
+
const result = new Promise((resolve, reject) => {
|
|
139
|
+
resolveResult = resolve;
|
|
140
|
+
rejectResult = reject;
|
|
141
|
+
});
|
|
142
|
+
void result.catch(() => {
|
|
143
|
+
});
|
|
144
|
+
const events = new Promise((resolve) => {
|
|
145
|
+
resolveEvents = resolve;
|
|
146
|
+
});
|
|
147
|
+
const waiters = /* @__PURE__ */ new Set();
|
|
148
|
+
let closeSourceIteratorPromise;
|
|
149
|
+
function notifyWaiters() {
|
|
150
|
+
for (const waiter of waiters) {
|
|
151
|
+
waiter();
|
|
152
|
+
}
|
|
153
|
+
waiters.clear();
|
|
102
154
|
}
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
155
|
+
function resolveWhenUpdated() {
|
|
156
|
+
if (terminalState.status !== "running") {
|
|
157
|
+
return Promise.resolve();
|
|
158
|
+
}
|
|
159
|
+
return new Promise((resolve) => {
|
|
160
|
+
waiters.add(resolve);
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
function cleanupSignalListener() {
|
|
164
|
+
signal?.removeEventListener("abort", abortStream);
|
|
165
|
+
}
|
|
166
|
+
function settleCompleted(finalResult) {
|
|
167
|
+
if (terminalState.status !== "running") {
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
terminalState = {
|
|
171
|
+
status: "completed",
|
|
172
|
+
result: finalResult
|
|
173
|
+
};
|
|
174
|
+
cleanupSignalListener();
|
|
175
|
+
resolveResult?.(finalResult);
|
|
176
|
+
resolveEvents?.([...bufferedEvents]);
|
|
177
|
+
notifyWaiters();
|
|
178
|
+
}
|
|
179
|
+
function settleRejected(error) {
|
|
180
|
+
if (terminalState.status !== "running") {
|
|
181
|
+
return;
|
|
113
182
|
}
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
let objectResult;
|
|
118
|
-
let finishReason = "unknown";
|
|
119
|
-
let usage = {
|
|
120
|
-
inputTokens: 0,
|
|
121
|
-
outputTokens: 0,
|
|
122
|
-
inputTokenDetails: {
|
|
123
|
-
cacheReadTokens: 0,
|
|
124
|
-
cacheWriteTokens: 0
|
|
125
|
-
},
|
|
126
|
-
outputTokenDetails: {}
|
|
183
|
+
terminalState = {
|
|
184
|
+
status: "rejected",
|
|
185
|
+
error
|
|
127
186
|
};
|
|
187
|
+
cleanupSignalListener();
|
|
188
|
+
rejectResult?.(error);
|
|
189
|
+
resolveEvents?.([...bufferedEvents]);
|
|
190
|
+
notifyWaiters();
|
|
191
|
+
}
|
|
192
|
+
function closeSourceIterator() {
|
|
193
|
+
if (closeSourceIteratorPromise) {
|
|
194
|
+
return closeSourceIteratorPromise;
|
|
195
|
+
}
|
|
196
|
+
closeSourceIteratorPromise = (async () => {
|
|
197
|
+
try {
|
|
198
|
+
await iterator.return?.();
|
|
199
|
+
} catch {
|
|
200
|
+
}
|
|
201
|
+
})();
|
|
202
|
+
return closeSourceIteratorPromise;
|
|
203
|
+
}
|
|
204
|
+
function abortStream() {
|
|
205
|
+
if (terminalState.status !== "running") {
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
settleRejected(new StreamAbortedError("stream aborted"));
|
|
209
|
+
void closeSourceIterator();
|
|
210
|
+
}
|
|
211
|
+
if (signal) {
|
|
212
|
+
if (signal.aborted) {
|
|
213
|
+
abortStream();
|
|
214
|
+
} else {
|
|
215
|
+
signal.addEventListener("abort", abortStream, { once: true });
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
async function pump() {
|
|
128
219
|
try {
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
usage = event.usage;
|
|
220
|
+
while (terminalState.status === "running") {
|
|
221
|
+
const next = await iterator.next();
|
|
222
|
+
if (terminalState.status !== "running") {
|
|
223
|
+
await closeSourceIterator();
|
|
224
|
+
return;
|
|
135
225
|
}
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
226
|
+
if (next.done) {
|
|
227
|
+
try {
|
|
228
|
+
settleCompleted(finalizeResult());
|
|
229
|
+
} catch (error) {
|
|
230
|
+
settleRejected(error);
|
|
231
|
+
}
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
bufferedEvents.push(next.value);
|
|
235
|
+
notifyWaiters();
|
|
236
|
+
reduceEvent(next.value);
|
|
142
237
|
}
|
|
143
|
-
resolveResponse?.({
|
|
144
|
-
object: objectResult,
|
|
145
|
-
finishReason,
|
|
146
|
-
usage
|
|
147
|
-
});
|
|
148
238
|
} catch (error) {
|
|
149
|
-
|
|
150
|
-
|
|
239
|
+
settleRejected(error);
|
|
240
|
+
await closeSourceIterator();
|
|
151
241
|
}
|
|
152
242
|
}
|
|
153
|
-
|
|
243
|
+
void pump();
|
|
154
244
|
return {
|
|
155
245
|
[Symbol.asyncIterator]() {
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
246
|
+
let index = 0;
|
|
247
|
+
let closed = false;
|
|
248
|
+
return {
|
|
249
|
+
async next() {
|
|
250
|
+
if (closed) {
|
|
251
|
+
return {
|
|
252
|
+
done: true,
|
|
253
|
+
value: void 0
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
while (!closed && index >= bufferedEvents.length) {
|
|
257
|
+
if (terminalState.status === "completed") {
|
|
258
|
+
return {
|
|
259
|
+
done: true,
|
|
260
|
+
value: void 0
|
|
261
|
+
};
|
|
168
262
|
}
|
|
169
|
-
|
|
263
|
+
if (terminalState.status === "rejected") {
|
|
264
|
+
throw terminalState.error;
|
|
265
|
+
}
|
|
266
|
+
await resolveWhenUpdated();
|
|
170
267
|
}
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
268
|
+
if (closed) {
|
|
269
|
+
return {
|
|
270
|
+
done: true,
|
|
271
|
+
value: void 0
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
const value = bufferedEvents[index];
|
|
275
|
+
index += 1;
|
|
276
|
+
return {
|
|
277
|
+
done: false,
|
|
278
|
+
value
|
|
279
|
+
};
|
|
280
|
+
},
|
|
281
|
+
async return() {
|
|
282
|
+
closed = true;
|
|
283
|
+
notifyWaiters();
|
|
284
|
+
return {
|
|
285
|
+
done: true,
|
|
286
|
+
value: void 0
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
};
|
|
290
|
+
},
|
|
291
|
+
result,
|
|
292
|
+
events
|
|
175
293
|
};
|
|
176
294
|
}
|
|
177
295
|
|
|
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
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
textBuffer = "";
|
|
209
|
-
};
|
|
210
|
-
const flushReasoning = () => {
|
|
211
|
-
if (reasoningBuffer.length === 0) {
|
|
212
|
-
return;
|
|
213
|
-
}
|
|
214
|
-
parts.push({
|
|
215
|
-
type: "reasoning",
|
|
216
|
-
text: reasoningBuffer
|
|
217
|
-
});
|
|
218
|
-
reasoningBuffer = "";
|
|
219
|
-
};
|
|
220
|
-
for await (const event of source) {
|
|
221
|
-
if (event.type === "reasoning-start") {
|
|
222
|
-
flushText();
|
|
223
|
-
flushReasoning();
|
|
224
|
-
insideReasoning = true;
|
|
225
|
-
} else if (event.type === "reasoning-delta") {
|
|
226
|
-
if (!insideReasoning) {
|
|
227
|
-
flushText();
|
|
228
|
-
insideReasoning = true;
|
|
229
|
-
}
|
|
230
|
-
reasoningBuffer += event.text;
|
|
231
|
-
} else if (event.type === "reasoning-end") {
|
|
232
|
-
flushReasoning();
|
|
233
|
-
insideReasoning = false;
|
|
234
|
-
} else if (event.type === "text-delta") {
|
|
235
|
-
if (insideReasoning) {
|
|
236
|
-
flushReasoning();
|
|
237
|
-
insideReasoning = false;
|
|
238
|
-
}
|
|
239
|
-
textBuffer += event.text;
|
|
240
|
-
} else if (event.type === "tool-call-end") {
|
|
241
|
-
flushText();
|
|
242
|
-
flushReasoning();
|
|
243
|
-
insideReasoning = false;
|
|
244
|
-
parts.push({
|
|
245
|
-
type: "tool-call",
|
|
246
|
-
toolCall: event.toolCall
|
|
247
|
-
});
|
|
296
|
+
// src/stream-object.ts
|
|
297
|
+
async function streamObject(params) {
|
|
298
|
+
assertNonEmptyMessages(params.messages);
|
|
299
|
+
const { model, ...options } = params;
|
|
300
|
+
return model.streamObject(options);
|
|
301
|
+
}
|
|
302
|
+
function createObjectStream(source, options = {}) {
|
|
303
|
+
const { signal } = options;
|
|
304
|
+
let objectState = {
|
|
305
|
+
status: "pending"
|
|
306
|
+
};
|
|
307
|
+
let finishReason = "unknown";
|
|
308
|
+
let usage = {
|
|
309
|
+
inputTokens: 0,
|
|
310
|
+
outputTokens: 0,
|
|
311
|
+
inputTokenDetails: {
|
|
312
|
+
cacheReadTokens: 0,
|
|
313
|
+
cacheWriteTokens: 0
|
|
314
|
+
},
|
|
315
|
+
outputTokenDetails: {}
|
|
316
|
+
};
|
|
317
|
+
return createStream({
|
|
318
|
+
source,
|
|
319
|
+
signal,
|
|
320
|
+
reduceEvent(event) {
|
|
321
|
+
if (event.type === "object") {
|
|
322
|
+
objectState = {
|
|
323
|
+
status: "ready",
|
|
324
|
+
object: event.object
|
|
325
|
+
};
|
|
248
326
|
} else if (event.type === "finish") {
|
|
249
327
|
finishReason = event.finishReason;
|
|
250
328
|
usage = event.usage;
|
|
251
329
|
}
|
|
252
|
-
|
|
330
|
+
},
|
|
331
|
+
finalizeResult() {
|
|
332
|
+
if (objectState.status !== "ready") {
|
|
333
|
+
throw new LLMError(
|
|
334
|
+
"object stream completed without emitting a final object"
|
|
335
|
+
);
|
|
336
|
+
}
|
|
337
|
+
return {
|
|
338
|
+
object: objectState.object,
|
|
339
|
+
finishReason,
|
|
340
|
+
usage
|
|
341
|
+
};
|
|
342
|
+
}
|
|
343
|
+
});
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
// src/stream.ts
|
|
347
|
+
function createChatStream(source, options = {}) {
|
|
348
|
+
const { signal } = options;
|
|
349
|
+
const resolvedSource = typeof source === "function" ? (async function* () {
|
|
350
|
+
yield* await source();
|
|
351
|
+
})() : source;
|
|
352
|
+
const parts = [];
|
|
353
|
+
let textBuffer = "";
|
|
354
|
+
let reasoningBuffer = "";
|
|
355
|
+
let reasoningProviderMetadata;
|
|
356
|
+
let insideReasoning = false;
|
|
357
|
+
let finishReason = "unknown";
|
|
358
|
+
let usage = {
|
|
359
|
+
inputTokens: 0,
|
|
360
|
+
outputTokens: 0,
|
|
361
|
+
inputTokenDetails: {
|
|
362
|
+
cacheReadTokens: 0,
|
|
363
|
+
cacheWriteTokens: 0
|
|
364
|
+
},
|
|
365
|
+
outputTokenDetails: {}
|
|
366
|
+
};
|
|
367
|
+
const flushText = () => {
|
|
368
|
+
if (textBuffer.length === 0) {
|
|
369
|
+
return;
|
|
370
|
+
}
|
|
371
|
+
parts.push({
|
|
372
|
+
type: "text",
|
|
373
|
+
text: textBuffer
|
|
374
|
+
});
|
|
375
|
+
textBuffer = "";
|
|
376
|
+
};
|
|
377
|
+
const flushReasoning = () => {
|
|
378
|
+
if (reasoningBuffer.length === 0 && reasoningProviderMetadata === void 0) {
|
|
379
|
+
return;
|
|
253
380
|
}
|
|
381
|
+
parts.push({
|
|
382
|
+
type: "reasoning",
|
|
383
|
+
text: reasoningBuffer,
|
|
384
|
+
...reasoningProviderMetadata ? { providerMetadata: reasoningProviderMetadata } : {}
|
|
385
|
+
});
|
|
386
|
+
reasoningBuffer = "";
|
|
387
|
+
reasoningProviderMetadata = void 0;
|
|
388
|
+
};
|
|
389
|
+
const startReasoning = () => {
|
|
254
390
|
flushText();
|
|
255
391
|
flushReasoning();
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
392
|
+
insideReasoning = true;
|
|
393
|
+
};
|
|
394
|
+
const appendReasoning = (text) => {
|
|
395
|
+
if (!insideReasoning) {
|
|
396
|
+
flushText();
|
|
397
|
+
insideReasoning = true;
|
|
398
|
+
}
|
|
399
|
+
reasoningBuffer += text;
|
|
400
|
+
};
|
|
401
|
+
const endReasoning = (providerMetadata) => {
|
|
402
|
+
reasoningProviderMetadata = providerMetadata;
|
|
403
|
+
flushReasoning();
|
|
404
|
+
insideReasoning = false;
|
|
405
|
+
};
|
|
406
|
+
const appendText = (text) => {
|
|
407
|
+
if (insideReasoning) {
|
|
408
|
+
flushReasoning();
|
|
409
|
+
insideReasoning = false;
|
|
410
|
+
}
|
|
411
|
+
textBuffer += text;
|
|
412
|
+
};
|
|
413
|
+
const appendToolCall = (toolCall) => {
|
|
414
|
+
flushText();
|
|
415
|
+
flushReasoning();
|
|
416
|
+
insideReasoning = false;
|
|
417
|
+
parts.push({
|
|
418
|
+
type: "tool-call",
|
|
419
|
+
toolCall
|
|
268
420
|
});
|
|
269
|
-
}
|
|
270
|
-
const
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
421
|
+
};
|
|
422
|
+
const setFinish = (event) => {
|
|
423
|
+
finishReason = event.finishReason;
|
|
424
|
+
usage = event.usage;
|
|
425
|
+
};
|
|
426
|
+
return createStream({
|
|
427
|
+
source: resolvedSource,
|
|
428
|
+
signal,
|
|
429
|
+
reduceEvent(event) {
|
|
430
|
+
switch (event.type) {
|
|
431
|
+
case "reasoning-start":
|
|
432
|
+
startReasoning();
|
|
433
|
+
break;
|
|
434
|
+
case "reasoning-delta":
|
|
435
|
+
appendReasoning(event.text);
|
|
436
|
+
break;
|
|
437
|
+
case "reasoning-end":
|
|
438
|
+
endReasoning(event.providerMetadata);
|
|
439
|
+
break;
|
|
440
|
+
case "text-delta":
|
|
441
|
+
appendText(event.text);
|
|
442
|
+
break;
|
|
443
|
+
case "tool-call-end":
|
|
444
|
+
appendToolCall(event.toolCall);
|
|
445
|
+
break;
|
|
446
|
+
case "finish":
|
|
447
|
+
setFinish(event);
|
|
448
|
+
break;
|
|
449
|
+
default:
|
|
450
|
+
break;
|
|
275
451
|
}
|
|
276
|
-
iteratorCreated = true;
|
|
277
|
-
return generator;
|
|
278
452
|
},
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
453
|
+
finalizeResult() {
|
|
454
|
+
flushText();
|
|
455
|
+
flushReasoning();
|
|
456
|
+
const content = parts.flatMap((part) => part.type === "text" ? [part.text] : []).join("");
|
|
457
|
+
const reasoning = parts.flatMap(
|
|
458
|
+
(part) => part.type === "reasoning" ? [part.text] : []
|
|
459
|
+
).join("");
|
|
460
|
+
const toolCalls = parts.flatMap(
|
|
461
|
+
(part) => part.type === "tool-call" ? [part.toolCall] : []
|
|
462
|
+
);
|
|
463
|
+
return {
|
|
464
|
+
parts,
|
|
465
|
+
content: content.length > 0 ? content : null,
|
|
466
|
+
reasoning: reasoning.length > 0 ? reasoning : null,
|
|
467
|
+
toolCalls,
|
|
468
|
+
finishReason,
|
|
469
|
+
usage
|
|
470
|
+
};
|
|
288
471
|
}
|
|
289
|
-
};
|
|
472
|
+
});
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
// src/provider-metadata.ts
|
|
476
|
+
function getProviderMetadata(providerMetadata, provider) {
|
|
477
|
+
return providerMetadata?.[provider];
|
|
290
478
|
}
|
|
291
479
|
|
|
292
480
|
// src/embed.ts
|
|
293
481
|
async function embed(params) {
|
|
294
|
-
|
|
295
|
-
|
|
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
|
-
}
|
|
301
|
-
const { model, ...options } = params;
|
|
482
|
+
assertNonEmptyEmbedInput(params.input);
|
|
483
|
+
const { model, options } = splitModelFromParams(params);
|
|
302
484
|
return model.embed(options);
|
|
303
485
|
}
|
|
304
486
|
|
|
305
487
|
// src/generate-image.ts
|
|
306
488
|
async function generateImage(params) {
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
}
|
|
310
|
-
const { model, ...options } = params;
|
|
489
|
+
assertNonEmptyPrompt(params.prompt);
|
|
490
|
+
const { model, options } = splitModelFromParams(params);
|
|
311
491
|
return model.generate(options);
|
|
312
492
|
}
|
|
313
493
|
export {
|
|
314
494
|
LLMError,
|
|
315
495
|
ProviderError,
|
|
496
|
+
StreamAbortedError,
|
|
316
497
|
StructuredOutputError,
|
|
317
498
|
StructuredOutputNoObjectGeneratedError,
|
|
318
499
|
StructuredOutputParseError,
|
|
319
500
|
StructuredOutputValidationError,
|
|
320
501
|
assistantMessage,
|
|
321
|
-
|
|
322
|
-
|
|
502
|
+
createChatStream,
|
|
503
|
+
createObjectStream,
|
|
323
504
|
defineTool,
|
|
324
505
|
embed,
|
|
325
506
|
generate,
|
|
326
507
|
generateImage,
|
|
327
508
|
generateObject,
|
|
509
|
+
getProviderMetadata,
|
|
328
510
|
resultToMessage,
|
|
329
511
|
stream,
|
|
330
512
|
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.1",
|
|
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
|
}
|