ai 2.2.1 → 2.2.3

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.mjs CHANGED
@@ -28,28 +28,36 @@ function createEventStreamTransformer(customParser) {
28
28
  }
29
29
  });
30
30
  }
31
- function createCallbacksTransformer(callbacks) {
31
+ function createCallbacksTransformer(cb) {
32
32
  const textEncoder = new TextEncoder();
33
33
  let aggregatedResponse = "";
34
- const { onStart, onToken, onCompletion } = callbacks || {};
34
+ const callbacks = cb || {};
35
35
  return new TransformStream({
36
36
  async start() {
37
- if (onStart)
38
- await onStart();
37
+ if (callbacks.onStart)
38
+ await callbacks.onStart();
39
39
  },
40
40
  async transform(message, controller) {
41
41
  controller.enqueue(textEncoder.encode(message));
42
- if (onToken)
43
- await onToken(message);
44
- if (onCompletion)
42
+ if (callbacks.onToken)
43
+ await callbacks.onToken(message);
44
+ if (callbacks.onCompletion)
45
45
  aggregatedResponse += message;
46
46
  },
47
47
  async flush() {
48
- if (onCompletion)
49
- await onCompletion(aggregatedResponse);
48
+ const isOpenAICallbacks = isOfTypeOpenAIStreamCallbacks(callbacks);
49
+ if (callbacks.onCompletion) {
50
+ await callbacks.onCompletion(aggregatedResponse);
51
+ }
52
+ if (callbacks.onFinal && !isOpenAICallbacks) {
53
+ await callbacks.onFinal(aggregatedResponse);
54
+ }
50
55
  }
51
56
  });
52
57
  }
58
+ function isOfTypeOpenAIStreamCallbacks(callbacks) {
59
+ return "experimental_onFunctionCall" in callbacks;
60
+ }
53
61
  function trimStartOfStreamHelper() {
54
62
  let isStreamStart = true;
55
63
  return (text) => {
@@ -109,6 +117,140 @@ function readableFromAsyncIterable(iterable) {
109
117
  });
110
118
  }
111
119
 
120
+ // shared/utils.ts
121
+ import { customAlphabet } from "nanoid/non-secure";
122
+ var nanoid = customAlphabet(
123
+ "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
124
+ 7
125
+ );
126
+ function createChunkDecoder(complex) {
127
+ const decoder = new TextDecoder();
128
+ if (!complex) {
129
+ return function(chunk) {
130
+ if (!chunk)
131
+ return "";
132
+ return decoder.decode(chunk, { stream: true });
133
+ };
134
+ }
135
+ return function(chunk) {
136
+ const decoded = decoder.decode(chunk, { stream: true }).split("\n");
137
+ return decoded.map(getStreamStringTypeAndValue).filter(Boolean);
138
+ };
139
+ }
140
+ var StreamStringPrefixes = {
141
+ text: 0,
142
+ function_call: 1,
143
+ data: 2
144
+ // user_err: 3?
145
+ };
146
+ var isStreamStringEqualToType = (type, value) => value.startsWith(`${StreamStringPrefixes[type]}:`) && value.endsWith("\n");
147
+ var getStreamString = (type, value) => `${StreamStringPrefixes[type]}:${JSON.stringify(value)}
148
+ `;
149
+ var getStreamStringTypeAndValue = (line) => {
150
+ const firstSeperatorIndex = line.indexOf(":");
151
+ const prefix = line.slice(0, firstSeperatorIndex);
152
+ const type = Object.keys(StreamStringPrefixes).find(
153
+ (key) => StreamStringPrefixes[key] === Number(prefix)
154
+ );
155
+ const val = line.slice(firstSeperatorIndex + 1);
156
+ let parsedVal = val;
157
+ if (!val) {
158
+ return { type, value: "" };
159
+ }
160
+ try {
161
+ parsedVal = JSON.parse(val);
162
+ } catch (e) {
163
+ console.error("Failed to parse JSON value:", val);
164
+ }
165
+ return { type, value: parsedVal };
166
+ };
167
+ var COMPLEX_HEADER = "X-Experimental-Stream-Data";
168
+
169
+ // streams/stream-data.ts
170
+ var experimental_StreamData = class {
171
+ constructor() {
172
+ this.encoder = new TextEncoder();
173
+ this.controller = null;
174
+ // closing the stream is synchronous, but we want to return a promise
175
+ // in case we're doing async work
176
+ this.isClosedPromise = null;
177
+ this.isClosedPromiseResolver = void 0;
178
+ this.isClosed = false;
179
+ // array to store appended data
180
+ this.data = [];
181
+ this.isClosedPromise = new Promise((resolve) => {
182
+ this.isClosedPromiseResolver = resolve;
183
+ });
184
+ const self = this;
185
+ this.stream = new TransformStream({
186
+ start: async (controller) => {
187
+ self.controller = controller;
188
+ },
189
+ transform: async (chunk, controller) => {
190
+ controller.enqueue(chunk);
191
+ if (self.data.length > 0) {
192
+ const encodedData = self.encoder.encode(
193
+ getStreamString("data", JSON.stringify(self.data))
194
+ );
195
+ self.data = [];
196
+ controller.enqueue(encodedData);
197
+ }
198
+ },
199
+ async flush(controller) {
200
+ const warningTimeout = process.env.NODE_ENV === "development" ? setTimeout(() => {
201
+ console.warn(
202
+ "The data stream is hanging. Did you forget to close it with `data.close()`?"
203
+ );
204
+ }, 3e3) : null;
205
+ await self.isClosedPromise;
206
+ if (warningTimeout !== null) {
207
+ clearTimeout(warningTimeout);
208
+ }
209
+ if (self.data.length) {
210
+ const encodedData = self.encoder.encode(
211
+ getStreamString("data", JSON.stringify(self.data))
212
+ );
213
+ controller.enqueue(encodedData);
214
+ }
215
+ }
216
+ });
217
+ }
218
+ async close() {
219
+ var _a;
220
+ if (this.isClosed) {
221
+ throw new Error("Data Stream has already been closed.");
222
+ }
223
+ if (!this.controller) {
224
+ throw new Error("Stream controller is not initialized.");
225
+ }
226
+ (_a = this.isClosedPromiseResolver) == null ? void 0 : _a.call(this);
227
+ this.isClosed = true;
228
+ }
229
+ append(value) {
230
+ if (this.isClosed) {
231
+ throw new Error("Data Stream has already been closed.");
232
+ }
233
+ this.data.push(value);
234
+ }
235
+ };
236
+ function createStreamDataTransformer(experimental_streamData) {
237
+ if (!experimental_streamData) {
238
+ return new TransformStream({
239
+ transform: async (chunk, controller) => {
240
+ controller.enqueue(chunk);
241
+ }
242
+ });
243
+ }
244
+ const encoder = new TextEncoder();
245
+ const decoder = new TextDecoder();
246
+ return new TransformStream({
247
+ transform: async (chunk, controller) => {
248
+ const message = decoder.decode(chunk);
249
+ controller.enqueue(encoder.encode(getStreamString("text", message)));
250
+ }
251
+ });
252
+ }
253
+
112
254
  // streams/openai-stream.ts
113
255
  function parseOpenAIStream() {
114
256
  const extract = chunkToText();
@@ -128,11 +270,11 @@ function chunkToText() {
128
270
  const trimStartOfStream = trimStartOfStreamHelper();
129
271
  let isFunctionStreamingIn;
130
272
  return (json) => {
131
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o;
132
- if ((_c = (_b = (_a = json.choices[0]) == null ? void 0 : _a.delta) == null ? void 0 : _b.function_call) == null ? void 0 : _c.name) {
273
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
274
+ if (isChatCompletionChunk(json) && ((_c = (_b = (_a = json.choices[0]) == null ? void 0 : _a.delta) == null ? void 0 : _b.function_call) == null ? void 0 : _c.name)) {
133
275
  isFunctionStreamingIn = true;
134
276
  return `{"function_call": {"name": "${(_e = (_d = json.choices[0]) == null ? void 0 : _d.delta) == null ? void 0 : _e.function_call.name}", "arguments": "`;
135
- } else if ((_h = (_g = (_f = json.choices[0]) == null ? void 0 : _f.delta) == null ? void 0 : _g.function_call) == null ? void 0 : _h.arguments) {
277
+ } else if (isChatCompletionChunk(json) && ((_h = (_g = (_f = json.choices[0]) == null ? void 0 : _f.delta) == null ? void 0 : _g.function_call) == null ? void 0 : _h.arguments)) {
136
278
  const argumentChunk = json.choices[0].delta.function_call.arguments;
137
279
  let escapedPartialJson = argumentChunk.replace(/\\/g, "\\\\").replace(/\//g, "\\/").replace(/"/g, '\\"').replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/\t/g, "\\t").replace(/\f/g, "\\f");
138
280
  return `${escapedPartialJson}`;
@@ -141,38 +283,66 @@ function chunkToText() {
141
283
  return '"}}';
142
284
  }
143
285
  const text = trimStartOfStream(
144
- (_o = (_n = (_l = (_k = json.choices[0]) == null ? void 0 : _k.delta) == null ? void 0 : _l.content) != null ? _n : (_m = json.choices[0]) == null ? void 0 : _m.text) != null ? _o : ""
286
+ isChatCompletionChunk(json) && json.choices[0].delta.content ? json.choices[0].delta.content : isCompletion(json) ? json.choices[0].text : ""
145
287
  );
146
288
  return text;
147
289
  };
148
290
  }
149
291
  var __internal__OpenAIFnMessagesSymbol = Symbol("internal_openai_fn_messages");
292
+ function isChatCompletionChunk(data) {
293
+ return "choices" in data && "delta" in data.choices[0];
294
+ }
295
+ function isCompletion(data) {
296
+ return "choices" in data && "text" in data.choices[0];
297
+ }
150
298
  function OpenAIStream(res, callbacks) {
151
299
  const cb = callbacks;
152
300
  let stream;
153
301
  if (Symbol.asyncIterator in res) {
154
302
  stream = readableFromAsyncIterable(streamable(res)).pipeThrough(
155
- createCallbacksTransformer(cb)
303
+ createCallbacksTransformer(
304
+ (cb == null ? void 0 : cb.experimental_onFunctionCall) ? {
305
+ ...cb,
306
+ onFinal: void 0
307
+ } : {
308
+ ...cb
309
+ }
310
+ )
156
311
  );
157
312
  } else {
158
- stream = AIStream(res, parseOpenAIStream(), cb);
313
+ stream = AIStream(
314
+ res,
315
+ parseOpenAIStream(),
316
+ (cb == null ? void 0 : cb.experimental_onFunctionCall) ? {
317
+ ...cb,
318
+ onFinal: void 0
319
+ } : {
320
+ ...cb
321
+ }
322
+ );
159
323
  }
160
324
  if (cb && cb.experimental_onFunctionCall) {
161
325
  const functionCallTransformer = createFunctionCallTransformer(cb);
162
326
  return stream.pipeThrough(functionCallTransformer);
163
327
  } else {
164
- return stream;
328
+ return stream.pipeThrough(
329
+ createStreamDataTransformer(cb == null ? void 0 : cb.experimental_streamData)
330
+ );
165
331
  }
166
332
  }
167
333
  function createFunctionCallTransformer(callbacks) {
168
334
  const textEncoder = new TextEncoder();
169
335
  let isFirstChunk = true;
170
336
  let aggregatedResponse = "";
337
+ let aggregatedFinalCompletionResponse = "";
171
338
  let isFunctionStreamingIn = false;
172
339
  let functionCallMessages = callbacks[__internal__OpenAIFnMessagesSymbol] || [];
340
+ const isComplexMode = callbacks == null ? void 0 : callbacks.experimental_streamData;
341
+ const decode = createChunkDecoder();
173
342
  return new TransformStream({
174
343
  async transform(chunk, controller) {
175
- const message = new TextDecoder().decode(chunk);
344
+ const message = decode(chunk);
345
+ aggregatedFinalCompletionResponse += message;
176
346
  const shouldHandleAsFunction = isFirstChunk && message.startsWith('{"function_call":');
177
347
  if (shouldHandleAsFunction) {
178
348
  isFunctionStreamingIn = true;
@@ -181,64 +351,80 @@ function createFunctionCallTransformer(callbacks) {
181
351
  return;
182
352
  }
183
353
  if (!isFunctionStreamingIn) {
184
- controller.enqueue(chunk);
354
+ controller.enqueue(
355
+ isComplexMode ? textEncoder.encode(getStreamString("text", message)) : chunk
356
+ );
185
357
  return;
186
358
  } else {
187
359
  aggregatedResponse += message;
188
360
  }
189
361
  },
190
362
  async flush(controller) {
191
- const isEndOfFunction = !isFirstChunk && callbacks.experimental_onFunctionCall && isFunctionStreamingIn;
192
- if (isEndOfFunction && callbacks.experimental_onFunctionCall) {
193
- isFunctionStreamingIn = false;
194
- const payload = JSON.parse(aggregatedResponse);
195
- const argumentsPayload = JSON.parse(payload.function_call.arguments);
196
- let newFunctionCallMessages = [...functionCallMessages];
197
- const functionResponse = await callbacks.experimental_onFunctionCall(
198
- {
199
- name: payload.function_call.name,
200
- arguments: argumentsPayload
201
- },
202
- (result) => {
203
- newFunctionCallMessages = [
204
- ...functionCallMessages,
205
- {
206
- role: "assistant",
207
- content: "",
208
- function_call: payload.function_call
209
- },
210
- {
211
- role: "function",
212
- name: payload.function_call.name,
213
- content: JSON.stringify(result)
214
- }
215
- ];
216
- return newFunctionCallMessages;
363
+ try {
364
+ const isEndOfFunction = !isFirstChunk && callbacks.experimental_onFunctionCall && isFunctionStreamingIn;
365
+ if (isEndOfFunction && callbacks.experimental_onFunctionCall) {
366
+ isFunctionStreamingIn = false;
367
+ const payload = JSON.parse(aggregatedResponse);
368
+ const argumentsPayload = JSON.parse(payload.function_call.arguments);
369
+ let newFunctionCallMessages = [
370
+ ...functionCallMessages
371
+ ];
372
+ const functionResponse = await callbacks.experimental_onFunctionCall(
373
+ {
374
+ name: payload.function_call.name,
375
+ arguments: argumentsPayload
376
+ },
377
+ (result) => {
378
+ newFunctionCallMessages = [
379
+ ...functionCallMessages,
380
+ {
381
+ role: "assistant",
382
+ content: "",
383
+ function_call: payload.function_call
384
+ },
385
+ {
386
+ role: "function",
387
+ name: payload.function_call.name,
388
+ content: JSON.stringify(result)
389
+ }
390
+ ];
391
+ return newFunctionCallMessages;
392
+ }
393
+ );
394
+ if (!functionResponse) {
395
+ controller.enqueue(
396
+ textEncoder.encode(
397
+ isComplexMode ? getStreamString("function_call", aggregatedResponse) : aggregatedResponse
398
+ )
399
+ );
400
+ return;
401
+ } else if (typeof functionResponse === "string") {
402
+ controller.enqueue(
403
+ isComplexMode ? textEncoder.encode(getStreamString("text", functionResponse)) : textEncoder.encode(functionResponse)
404
+ );
405
+ return;
217
406
  }
218
- );
219
- if (!functionResponse) {
220
- controller.enqueue(textEncoder.encode(aggregatedResponse));
221
- return;
222
- } else if (typeof functionResponse === "string") {
223
- controller.enqueue(textEncoder.encode(functionResponse));
224
- return;
225
- }
226
- const filteredCallbacks = {
227
- ...callbacks,
228
- onStart: void 0,
229
- onCompletion: void 0
230
- };
231
- const openAIStream = OpenAIStream(functionResponse, {
232
- ...filteredCallbacks,
233
- [__internal__OpenAIFnMessagesSymbol]: newFunctionCallMessages
234
- });
235
- const reader = openAIStream.getReader();
236
- while (true) {
237
- const { done, value } = await reader.read();
238
- if (done) {
239
- break;
407
+ const filteredCallbacks = {
408
+ ...callbacks,
409
+ onStart: void 0
410
+ };
411
+ callbacks.onFinal = void 0;
412
+ const openAIStream = OpenAIStream(functionResponse, {
413
+ ...filteredCallbacks,
414
+ [__internal__OpenAIFnMessagesSymbol]: newFunctionCallMessages
415
+ });
416
+ const reader = openAIStream.getReader();
417
+ while (true) {
418
+ const { done, value } = await reader.read();
419
+ if (done) {
420
+ break;
421
+ }
422
+ controller.enqueue(value);
240
423
  }
241
- controller.enqueue(value);
424
+ }
425
+ } finally {
426
+ if (callbacks.onFinal && aggregatedFinalCompletionResponse) {
427
+ await callbacks.onFinal(aggregatedFinalCompletionResponse);
242
428
  }
243
429
  }
244
430
  }
@@ -247,12 +433,17 @@ function createFunctionCallTransformer(callbacks) {
247
433
 
248
434
  // streams/streaming-text-response.ts
249
435
  var StreamingTextResponse = class extends Response {
250
- constructor(res, init) {
251
- super(res, {
436
+ constructor(res, init, data) {
437
+ let processedStream = res;
438
+ if (data) {
439
+ processedStream = res.pipeThrough(data.stream);
440
+ }
441
+ super(processedStream, {
252
442
  ...init,
253
443
  status: 200,
254
444
  headers: {
255
445
  "Content-Type": "text/plain; charset=utf-8",
446
+ [COMPLEX_HEADER]: data ? "true" : "false",
256
447
  ...init == null ? void 0 : init.headers
257
448
  }
258
449
  });
@@ -304,7 +495,9 @@ function createParser2(res) {
304
495
  });
305
496
  }
306
497
  function HuggingFaceStream(res, callbacks) {
307
- return createParser2(res).pipeThrough(createCallbacksTransformer(callbacks));
498
+ return createParser2(res).pipeThrough(createCallbacksTransformer(callbacks)).pipeThrough(
499
+ createStreamDataTransformer(callbacks == null ? void 0 : callbacks.experimental_streamData)
500
+ );
308
501
  }
309
502
 
310
503
  // streams/cohere-stream.ts
@@ -351,7 +544,9 @@ function createParser3(res) {
351
544
  });
352
545
  }
353
546
  function CohereStream(reader, callbacks) {
354
- return createParser3(reader).pipeThrough(createCallbacksTransformer(callbacks));
547
+ return createParser3(reader).pipeThrough(createCallbacksTransformer(callbacks)).pipeThrough(
548
+ createStreamDataTransformer(callbacks == null ? void 0 : callbacks.experimental_streamData)
549
+ );
355
550
  }
356
551
 
357
552
  // streams/anthropic-stream.ts
@@ -383,11 +578,11 @@ async function* streamable2(stream) {
383
578
  }
384
579
  function AnthropicStream(res, cb) {
385
580
  if (Symbol.asyncIterator in res) {
386
- return readableFromAsyncIterable(streamable2(res)).pipeThrough(
387
- createCallbacksTransformer(cb)
388
- );
581
+ return readableFromAsyncIterable(streamable2(res)).pipeThrough(createCallbacksTransformer(cb)).pipeThrough(createStreamDataTransformer(cb == null ? void 0 : cb.experimental_streamData));
389
582
  } else {
390
- return AIStream(res, parseAnthropicStream(), cb);
583
+ return AIStream(res, parseAnthropicStream(), cb).pipeThrough(
584
+ createStreamDataTransformer(cb == null ? void 0 : cb.experimental_streamData)
585
+ );
391
586
  }
392
587
  }
393
588
 
@@ -412,7 +607,9 @@ function LangChainStream(callbacks) {
412
607
  }
413
608
  };
414
609
  return {
415
- stream: stream.readable.pipeThrough(createCallbacksTransformer(callbacks)),
610
+ stream: stream.readable.pipeThrough(createCallbacksTransformer(callbacks)).pipeThrough(
611
+ createStreamDataTransformer(callbacks == null ? void 0 : callbacks.experimental_streamData)
612
+ ),
416
613
  handlers: {
417
614
  handleLLMNewToken: async (token) => {
418
615
  await writer.ready;
@@ -465,35 +662,29 @@ async function ReplicateStream(res, cb) {
465
662
  Accept: "text/event-stream"
466
663
  }
467
664
  });
468
- return AIStream(eventStream, void 0, cb);
469
- }
470
-
471
- // shared/utils.ts
472
- import { customAlphabet } from "nanoid/non-secure";
473
- var nanoid = customAlphabet(
474
- "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
475
- 7
476
- );
477
- function createChunkDecoder() {
478
- const decoder = new TextDecoder();
479
- return function(chunk) {
480
- if (!chunk)
481
- return "";
482
- return decoder.decode(chunk, { stream: true });
483
- };
665
+ return AIStream(eventStream, void 0, cb).pipeThrough(
666
+ createStreamDataTransformer(cb == null ? void 0 : cb.experimental_streamData)
667
+ );
484
668
  }
485
669
  export {
486
670
  AIStream,
487
671
  AnthropicStream,
672
+ COMPLEX_HEADER,
488
673
  CohereStream,
489
674
  HuggingFaceStream,
490
675
  LangChainStream,
491
676
  OpenAIStream,
492
677
  ReplicateStream,
678
+ StreamStringPrefixes,
493
679
  StreamingTextResponse,
494
680
  createCallbacksTransformer,
495
681
  createChunkDecoder,
496
682
  createEventStreamTransformer,
683
+ createStreamDataTransformer,
684
+ experimental_StreamData,
685
+ getStreamString,
686
+ getStreamStringTypeAndValue,
687
+ isStreamStringEqualToType,
497
688
  nanoid,
498
689
  readableFromAsyncIterable,
499
690
  streamToResponse,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai",
3
- "version": "2.2.1",
3
+ "version": "2.2.3",
4
4
  "license": "Apache-2.0",
5
5
  "sideEffects": false,
6
6
  "main": "./dist/index.js",
@@ -203,6 +203,8 @@ type UseChatHelpers = {
203
203
  metadata?: Object;
204
204
  /** Whether the API request is in progress */
205
205
  isLoading: boolean;
206
+ /** Additional data added on the server via StreamData */
207
+ data?: any;
206
208
  };
207
209
  declare function useChat({ api, id, initialMessages, initialInput, sendExtraMessageFields, experimental_onFunctionCall, onResponse, onFinish, onError, credentials, headers, body }?: UseChatOptions): UseChatHelpers;
208
210