ai 2.2.1 → 2.2.2

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();
@@ -152,27 +294,49 @@ function OpenAIStream(res, callbacks) {
152
294
  let stream;
153
295
  if (Symbol.asyncIterator in res) {
154
296
  stream = readableFromAsyncIterable(streamable(res)).pipeThrough(
155
- createCallbacksTransformer(cb)
297
+ createCallbacksTransformer(
298
+ (cb == null ? void 0 : cb.experimental_onFunctionCall) ? {
299
+ ...cb,
300
+ onFinal: void 0
301
+ } : {
302
+ ...cb
303
+ }
304
+ )
156
305
  );
157
306
  } else {
158
- stream = AIStream(res, parseOpenAIStream(), cb);
307
+ stream = AIStream(
308
+ res,
309
+ parseOpenAIStream(),
310
+ (cb == null ? void 0 : cb.experimental_onFunctionCall) ? {
311
+ ...cb,
312
+ onFinal: void 0
313
+ } : {
314
+ ...cb
315
+ }
316
+ );
159
317
  }
160
318
  if (cb && cb.experimental_onFunctionCall) {
161
319
  const functionCallTransformer = createFunctionCallTransformer(cb);
162
320
  return stream.pipeThrough(functionCallTransformer);
163
321
  } else {
164
- return stream;
322
+ return stream.pipeThrough(
323
+ createStreamDataTransformer(cb == null ? void 0 : cb.experimental_streamData)
324
+ );
165
325
  }
166
326
  }
167
327
  function createFunctionCallTransformer(callbacks) {
168
328
  const textEncoder = new TextEncoder();
169
329
  let isFirstChunk = true;
170
330
  let aggregatedResponse = "";
331
+ let aggregatedFinalCompletionResponse = "";
171
332
  let isFunctionStreamingIn = false;
172
333
  let functionCallMessages = callbacks[__internal__OpenAIFnMessagesSymbol] || [];
334
+ const isComplexMode = callbacks == null ? void 0 : callbacks.experimental_streamData;
335
+ const decode = createChunkDecoder();
173
336
  return new TransformStream({
174
337
  async transform(chunk, controller) {
175
- const message = new TextDecoder().decode(chunk);
338
+ const message = decode(chunk);
339
+ aggregatedFinalCompletionResponse += message;
176
340
  const shouldHandleAsFunction = isFirstChunk && message.startsWith('{"function_call":');
177
341
  if (shouldHandleAsFunction) {
178
342
  isFunctionStreamingIn = true;
@@ -181,64 +345,80 @@ function createFunctionCallTransformer(callbacks) {
181
345
  return;
182
346
  }
183
347
  if (!isFunctionStreamingIn) {
184
- controller.enqueue(chunk);
348
+ controller.enqueue(
349
+ isComplexMode ? textEncoder.encode(getStreamString("text", message)) : chunk
350
+ );
185
351
  return;
186
352
  } else {
187
353
  aggregatedResponse += message;
188
354
  }
189
355
  },
190
356
  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;
357
+ try {
358
+ const isEndOfFunction = !isFirstChunk && callbacks.experimental_onFunctionCall && isFunctionStreamingIn;
359
+ if (isEndOfFunction && callbacks.experimental_onFunctionCall) {
360
+ isFunctionStreamingIn = false;
361
+ const payload = JSON.parse(aggregatedResponse);
362
+ const argumentsPayload = JSON.parse(payload.function_call.arguments);
363
+ let newFunctionCallMessages = [
364
+ ...functionCallMessages
365
+ ];
366
+ const functionResponse = await callbacks.experimental_onFunctionCall(
367
+ {
368
+ name: payload.function_call.name,
369
+ arguments: argumentsPayload
370
+ },
371
+ (result) => {
372
+ newFunctionCallMessages = [
373
+ ...functionCallMessages,
374
+ {
375
+ role: "assistant",
376
+ content: "",
377
+ function_call: payload.function_call
378
+ },
379
+ {
380
+ role: "function",
381
+ name: payload.function_call.name,
382
+ content: JSON.stringify(result)
383
+ }
384
+ ];
385
+ return newFunctionCallMessages;
386
+ }
387
+ );
388
+ if (!functionResponse) {
389
+ controller.enqueue(
390
+ textEncoder.encode(
391
+ isComplexMode ? getStreamString("function_call", aggregatedResponse) : aggregatedResponse
392
+ )
393
+ );
394
+ return;
395
+ } else if (typeof functionResponse === "string") {
396
+ controller.enqueue(
397
+ isComplexMode ? textEncoder.encode(getStreamString("text", functionResponse)) : textEncoder.encode(functionResponse)
398
+ );
399
+ return;
217
400
  }
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;
401
+ const filteredCallbacks = {
402
+ ...callbacks,
403
+ onStart: void 0
404
+ };
405
+ callbacks.onFinal = void 0;
406
+ const openAIStream = OpenAIStream(functionResponse, {
407
+ ...filteredCallbacks,
408
+ [__internal__OpenAIFnMessagesSymbol]: newFunctionCallMessages
409
+ });
410
+ const reader = openAIStream.getReader();
411
+ while (true) {
412
+ const { done, value } = await reader.read();
413
+ if (done) {
414
+ break;
415
+ }
416
+ controller.enqueue(value);
240
417
  }
241
- controller.enqueue(value);
418
+ }
419
+ } finally {
420
+ if (callbacks.onFinal && aggregatedFinalCompletionResponse) {
421
+ await callbacks.onFinal(aggregatedFinalCompletionResponse);
242
422
  }
243
423
  }
244
424
  }
@@ -247,12 +427,17 @@ function createFunctionCallTransformer(callbacks) {
247
427
 
248
428
  // streams/streaming-text-response.ts
249
429
  var StreamingTextResponse = class extends Response {
250
- constructor(res, init) {
251
- super(res, {
430
+ constructor(res, init, data) {
431
+ let processedStream = res;
432
+ if (data) {
433
+ processedStream = res.pipeThrough(data.stream);
434
+ }
435
+ super(processedStream, {
252
436
  ...init,
253
437
  status: 200,
254
438
  headers: {
255
439
  "Content-Type": "text/plain; charset=utf-8",
440
+ [COMPLEX_HEADER]: data ? "true" : "false",
256
441
  ...init == null ? void 0 : init.headers
257
442
  }
258
443
  });
@@ -304,7 +489,9 @@ function createParser2(res) {
304
489
  });
305
490
  }
306
491
  function HuggingFaceStream(res, callbacks) {
307
- return createParser2(res).pipeThrough(createCallbacksTransformer(callbacks));
492
+ return createParser2(res).pipeThrough(createCallbacksTransformer(callbacks)).pipeThrough(
493
+ createStreamDataTransformer(callbacks == null ? void 0 : callbacks.experimental_streamData)
494
+ );
308
495
  }
309
496
 
310
497
  // streams/cohere-stream.ts
@@ -351,7 +538,9 @@ function createParser3(res) {
351
538
  });
352
539
  }
353
540
  function CohereStream(reader, callbacks) {
354
- return createParser3(reader).pipeThrough(createCallbacksTransformer(callbacks));
541
+ return createParser3(reader).pipeThrough(createCallbacksTransformer(callbacks)).pipeThrough(
542
+ createStreamDataTransformer(callbacks == null ? void 0 : callbacks.experimental_streamData)
543
+ );
355
544
  }
356
545
 
357
546
  // streams/anthropic-stream.ts
@@ -383,11 +572,11 @@ async function* streamable2(stream) {
383
572
  }
384
573
  function AnthropicStream(res, cb) {
385
574
  if (Symbol.asyncIterator in res) {
386
- return readableFromAsyncIterable(streamable2(res)).pipeThrough(
387
- createCallbacksTransformer(cb)
388
- );
575
+ return readableFromAsyncIterable(streamable2(res)).pipeThrough(createCallbacksTransformer(cb)).pipeThrough(createStreamDataTransformer(cb == null ? void 0 : cb.experimental_streamData));
389
576
  } else {
390
- return AIStream(res, parseAnthropicStream(), cb);
577
+ return AIStream(res, parseAnthropicStream(), cb).pipeThrough(
578
+ createStreamDataTransformer(cb == null ? void 0 : cb.experimental_streamData)
579
+ );
391
580
  }
392
581
  }
393
582
 
@@ -412,7 +601,9 @@ function LangChainStream(callbacks) {
412
601
  }
413
602
  };
414
603
  return {
415
- stream: stream.readable.pipeThrough(createCallbacksTransformer(callbacks)),
604
+ stream: stream.readable.pipeThrough(createCallbacksTransformer(callbacks)).pipeThrough(
605
+ createStreamDataTransformer(callbacks == null ? void 0 : callbacks.experimental_streamData)
606
+ ),
416
607
  handlers: {
417
608
  handleLLMNewToken: async (token) => {
418
609
  await writer.ready;
@@ -465,35 +656,29 @@ async function ReplicateStream(res, cb) {
465
656
  Accept: "text/event-stream"
466
657
  }
467
658
  });
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
- };
659
+ return AIStream(eventStream, void 0, cb).pipeThrough(
660
+ createStreamDataTransformer(cb == null ? void 0 : cb.experimental_streamData)
661
+ );
484
662
  }
485
663
  export {
486
664
  AIStream,
487
665
  AnthropicStream,
666
+ COMPLEX_HEADER,
488
667
  CohereStream,
489
668
  HuggingFaceStream,
490
669
  LangChainStream,
491
670
  OpenAIStream,
492
671
  ReplicateStream,
672
+ StreamStringPrefixes,
493
673
  StreamingTextResponse,
494
674
  createCallbacksTransformer,
495
675
  createChunkDecoder,
496
676
  createEventStreamTransformer,
677
+ createStreamDataTransformer,
678
+ experimental_StreamData,
679
+ getStreamString,
680
+ getStreamStringTypeAndValue,
681
+ isStreamStringEqualToType,
497
682
  nanoid,
498
683
  readableFromAsyncIterable,
499
684
  streamToResponse,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai",
3
- "version": "2.2.1",
3
+ "version": "2.2.2",
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