ai 2.2.22 → 2.2.24

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.
@@ -6,6 +6,129 @@ import useSWR from "swr";
6
6
 
7
7
  // shared/utils.ts
8
8
  import { customAlphabet } from "nanoid/non-secure";
9
+
10
+ // shared/stream-parts.ts
11
+ var textStreamPart = {
12
+ code: "0",
13
+ name: "text",
14
+ parse: (value) => {
15
+ if (typeof value !== "string") {
16
+ throw new Error('"text" parts expect a string value.');
17
+ }
18
+ return { type: "text", value };
19
+ }
20
+ };
21
+ var functionCallStreamPart = {
22
+ code: "1",
23
+ name: "function_call",
24
+ parse: (value) => {
25
+ if (value == null || typeof value !== "object" || !("function_call" in value) || typeof value.function_call !== "object" || value.function_call == null || !("name" in value.function_call) || !("arguments" in value.function_call) || typeof value.function_call.name !== "string" || typeof value.function_call.arguments !== "string") {
26
+ throw new Error(
27
+ '"function_call" parts expect an object with a "function_call" property.'
28
+ );
29
+ }
30
+ return {
31
+ type: "function_call",
32
+ value
33
+ };
34
+ }
35
+ };
36
+ var dataStreamPart = {
37
+ code: "2",
38
+ name: "data",
39
+ parse: (value) => {
40
+ if (!Array.isArray(value)) {
41
+ throw new Error('"data" parts expect an array value.');
42
+ }
43
+ return { type: "data", value };
44
+ }
45
+ };
46
+ var errorStreamPart = {
47
+ code: "3",
48
+ name: "error",
49
+ parse: (value) => {
50
+ if (typeof value !== "string") {
51
+ throw new Error('"error" parts expect a string value.');
52
+ }
53
+ return { type: "error", value };
54
+ }
55
+ };
56
+ var assistantMessage = {
57
+ code: "4",
58
+ name: "assistant_message",
59
+ parse: (value) => {
60
+ if (value == null || typeof value !== "object" || !("id" in value) || !("role" in value) || !("content" in value) || typeof value.id !== "string" || typeof value.role !== "string" || value.role !== "assistant" || !Array.isArray(value.content) || !value.content.every(
61
+ (item) => item != null && typeof item === "object" && "type" in item && item.type === "text" && "text" in item && item.text != null && typeof item.text === "object" && "value" in item.text && typeof item.text.value === "string"
62
+ )) {
63
+ throw new Error(
64
+ '"assistant_message" parts expect an object with an "id", "role", and "content" property.'
65
+ );
66
+ }
67
+ return {
68
+ type: "assistant_message",
69
+ value
70
+ };
71
+ }
72
+ };
73
+ var assistantControlData = {
74
+ code: "5",
75
+ name: "assistant_control_data",
76
+ parse: (value) => {
77
+ if (value == null || typeof value !== "object" || !("threadId" in value) || !("messageId" in value) || typeof value.threadId !== "string" || typeof value.messageId !== "string") {
78
+ throw new Error(
79
+ '"assistant_control_data" parts expect an object with a "threadId" and "messageId" property.'
80
+ );
81
+ }
82
+ return {
83
+ type: "assistant_control_data",
84
+ value: {
85
+ threadId: value.threadId,
86
+ messageId: value.messageId
87
+ }
88
+ };
89
+ }
90
+ };
91
+ var streamParts = [
92
+ textStreamPart,
93
+ functionCallStreamPart,
94
+ dataStreamPart,
95
+ errorStreamPart,
96
+ assistantMessage,
97
+ assistantControlData
98
+ ];
99
+ var streamPartsByCode = {
100
+ [textStreamPart.code]: textStreamPart,
101
+ [functionCallStreamPart.code]: functionCallStreamPart,
102
+ [dataStreamPart.code]: dataStreamPart,
103
+ [errorStreamPart.code]: errorStreamPart,
104
+ [assistantMessage.code]: assistantMessage,
105
+ [assistantControlData.code]: assistantControlData
106
+ };
107
+ var StreamStringPrefixes = {
108
+ [textStreamPart.name]: textStreamPart.code,
109
+ [functionCallStreamPart.name]: functionCallStreamPart.code,
110
+ [dataStreamPart.name]: dataStreamPart.code,
111
+ [errorStreamPart.name]: errorStreamPart.code,
112
+ [assistantMessage.name]: assistantMessage.code,
113
+ [assistantControlData.name]: assistantControlData.code
114
+ };
115
+ var validCodes = streamParts.map((part) => part.code);
116
+ var parseStreamPart = (line) => {
117
+ const firstSeparatorIndex = line.indexOf(":");
118
+ if (firstSeparatorIndex === -1) {
119
+ throw new Error("Failed to parse stream string. No separator found.");
120
+ }
121
+ const prefix = line.slice(0, firstSeparatorIndex);
122
+ if (!validCodes.includes(prefix)) {
123
+ throw new Error(`Failed to parse stream string. Invalid code ${prefix}.`);
124
+ }
125
+ const code = prefix;
126
+ const textValue = line.slice(firstSeparatorIndex + 1);
127
+ const jsonValue = JSON.parse(textValue);
128
+ return streamPartsByCode[code].parse(jsonValue);
129
+ };
130
+
131
+ // shared/utils.ts
9
132
  var nanoid = customAlphabet(
10
133
  "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
11
134
  7
@@ -21,46 +144,30 @@ function createChunkDecoder(complex) {
21
144
  }
22
145
  return function(chunk) {
23
146
  const decoded = decoder.decode(chunk, { stream: true }).split("\n").filter((line) => line !== "");
24
- return decoded.map(getStreamStringTypeAndValue).filter(Boolean);
147
+ return decoded.map(parseStreamPart).filter(Boolean);
25
148
  };
26
149
  }
27
- var StreamStringPrefixes = {
28
- text: 0,
29
- function_call: 1,
30
- data: 2
31
- // user_err: 3?
32
- };
33
- var getStreamStringTypeAndValue = (line) => {
34
- const firstSeperatorIndex = line.indexOf(":");
35
- const prefix = line.slice(0, firstSeperatorIndex);
36
- const type = Object.keys(StreamStringPrefixes).find(
37
- (key) => StreamStringPrefixes[key] === Number(prefix)
38
- );
39
- const val = line.slice(firstSeperatorIndex + 1);
40
- let parsedVal = val;
41
- if (!val) {
42
- return { type, value: "" };
43
- }
44
- try {
45
- parsedVal = JSON.parse(val);
46
- } catch (e) {
47
- console.error("Failed to parse JSON value:", val);
48
- }
49
- return { type, value: parsedVal };
50
- };
51
150
  var COMPLEX_HEADER = "X-Experimental-Stream-Data";
52
151
 
53
- // react/parse-complex-response.ts
152
+ // shared/call-api.ts
153
+ import { nanoid as nanoid2 } from "nanoid";
154
+
155
+ // shared/parse-complex-response.ts
54
156
  async function parseComplexResponse({
55
157
  reader,
56
158
  abortControllerRef,
57
- update
159
+ update,
160
+ onFinish,
161
+ generateId = nanoid,
162
+ getCurrentDate = () => /* @__PURE__ */ new Date()
58
163
  }) {
164
+ const createdAt = getCurrentDate();
59
165
  const decode = createChunkDecoder(true);
60
- const createdAt = /* @__PURE__ */ new Date();
61
- const prefixMap = {};
166
+ const prefixMap = {
167
+ data: []
168
+ };
62
169
  const NEWLINE = "\n".charCodeAt(0);
63
- let chunks = [];
170
+ const chunks = [];
64
171
  let totalLength = 0;
65
172
  while (true) {
66
173
  const { value } = await reader.read();
@@ -97,7 +204,7 @@ async function parseComplexResponse({
97
204
  };
98
205
  } else {
99
206
  prefixMap["text"] = {
100
- id: nanoid(),
207
+ id: generateId(),
101
208
  role: "assistant",
102
209
  content: value2,
103
210
  createdAt
@@ -106,44 +213,182 @@ async function parseComplexResponse({
106
213
  }
107
214
  let functionCallMessage = null;
108
215
  if (type === "function_call") {
109
- prefixMap["function_call"] = value2;
110
- let functionCall = prefixMap["function_call"];
111
- if (functionCall && typeof functionCall === "string") {
112
- const parsedFunctionCall = JSON.parse(
113
- functionCall
114
- ).function_call;
115
- functionCallMessage = {
116
- id: nanoid(),
117
- role: "assistant",
118
- content: "",
119
- function_call: parsedFunctionCall,
120
- name: parsedFunctionCall.name,
121
- createdAt
122
- };
123
- prefixMap["function_call"] = functionCallMessage;
124
- }
216
+ prefixMap["function_call"] = {
217
+ id: generateId(),
218
+ role: "assistant",
219
+ content: "",
220
+ function_call: value2.function_call,
221
+ name: value2.function_call.name,
222
+ createdAt
223
+ };
224
+ functionCallMessage = prefixMap["function_call"];
125
225
  }
126
226
  if (type === "data") {
127
- const parsedValue = JSON.parse(value2);
128
- if (prefixMap["data"]) {
129
- prefixMap["data"] = [...prefixMap["data"], ...parsedValue];
130
- } else {
131
- prefixMap["data"] = parsedValue;
132
- }
227
+ prefixMap["data"].push(...value2);
133
228
  }
134
- const data = prefixMap["data"];
135
229
  const responseMessage = prefixMap["text"];
136
230
  const merged = [functionCallMessage, responseMessage].filter(
137
231
  Boolean
138
232
  );
139
- update(merged, data);
140
- if (abortControllerRef.current === null) {
233
+ update(merged, [...prefixMap["data"]]);
234
+ if ((abortControllerRef == null ? void 0 : abortControllerRef.current) === null) {
235
+ reader.cancel();
236
+ break;
237
+ }
238
+ }
239
+ }
240
+ onFinish == null ? void 0 : onFinish(prefixMap);
241
+ return {
242
+ messages: [prefixMap.text, prefixMap.function_call].filter(
243
+ Boolean
244
+ ),
245
+ data: prefixMap.data
246
+ };
247
+ }
248
+
249
+ // shared/call-api.ts
250
+ async function callApi({
251
+ api,
252
+ messages,
253
+ body,
254
+ credentials,
255
+ headers,
256
+ abortController,
257
+ appendMessage,
258
+ restoreMessagesOnFailure,
259
+ onResponse,
260
+ onUpdate,
261
+ onFinish
262
+ }) {
263
+ var _a;
264
+ const response = await fetch(api, {
265
+ method: "POST",
266
+ body: JSON.stringify({
267
+ messages,
268
+ ...body
269
+ }),
270
+ headers,
271
+ signal: (_a = abortController == null ? void 0 : abortController()) == null ? void 0 : _a.signal,
272
+ credentials
273
+ }).catch((err) => {
274
+ restoreMessagesOnFailure();
275
+ throw err;
276
+ });
277
+ if (onResponse) {
278
+ try {
279
+ await onResponse(response);
280
+ } catch (err) {
281
+ throw err;
282
+ }
283
+ }
284
+ if (!response.ok) {
285
+ restoreMessagesOnFailure();
286
+ throw new Error(
287
+ await response.text() || "Failed to fetch the chat response."
288
+ );
289
+ }
290
+ if (!response.body) {
291
+ throw new Error("The response body is empty.");
292
+ }
293
+ const reader = response.body.getReader();
294
+ const isComplexMode = response.headers.get(COMPLEX_HEADER) === "true";
295
+ if (isComplexMode) {
296
+ return await parseComplexResponse({
297
+ reader,
298
+ abortControllerRef: abortController != null ? { current: abortController() } : void 0,
299
+ update: onUpdate,
300
+ onFinish(prefixMap) {
301
+ if (onFinish && prefixMap.text != null) {
302
+ onFinish(prefixMap.text);
303
+ }
304
+ }
305
+ });
306
+ } else {
307
+ const createdAt = /* @__PURE__ */ new Date();
308
+ const decode = createChunkDecoder(false);
309
+ let streamedResponse = "";
310
+ const replyId = nanoid2();
311
+ let responseMessage = {
312
+ id: replyId,
313
+ createdAt,
314
+ content: "",
315
+ role: "assistant"
316
+ };
317
+ while (true) {
318
+ const { done, value } = await reader.read();
319
+ if (done) {
320
+ break;
321
+ }
322
+ streamedResponse += decode(value);
323
+ if (streamedResponse.startsWith('{"function_call":')) {
324
+ responseMessage["function_call"] = streamedResponse;
325
+ } else {
326
+ responseMessage["content"] = streamedResponse;
327
+ }
328
+ appendMessage({ ...responseMessage });
329
+ if ((abortController == null ? void 0 : abortController()) === null) {
141
330
  reader.cancel();
142
331
  break;
143
332
  }
144
333
  }
334
+ if (streamedResponse.startsWith('{"function_call":')) {
335
+ const parsedFunctionCall = JSON.parse(streamedResponse).function_call;
336
+ responseMessage["function_call"] = parsedFunctionCall;
337
+ appendMessage({ ...responseMessage });
338
+ }
339
+ if (onFinish) {
340
+ onFinish(responseMessage);
341
+ }
342
+ return responseMessage;
343
+ }
344
+ }
345
+
346
+ // shared/process-chat-stream.ts
347
+ async function processChatStream({
348
+ getStreamedResponse: getStreamedResponse2,
349
+ experimental_onFunctionCall,
350
+ updateChatRequest,
351
+ getCurrentMessages
352
+ }) {
353
+ while (true) {
354
+ const messagesAndDataOrJustMessage = await getStreamedResponse2();
355
+ if ("messages" in messagesAndDataOrJustMessage) {
356
+ let hasFollowingResponse = false;
357
+ for (const message of messagesAndDataOrJustMessage.messages) {
358
+ if (message.function_call === void 0 || typeof message.function_call === "string") {
359
+ continue;
360
+ }
361
+ hasFollowingResponse = true;
362
+ if (experimental_onFunctionCall) {
363
+ const functionCall = message.function_call;
364
+ const functionCallResponse = await experimental_onFunctionCall(
365
+ getCurrentMessages(),
366
+ functionCall
367
+ );
368
+ if (functionCallResponse === void 0) {
369
+ hasFollowingResponse = false;
370
+ break;
371
+ }
372
+ updateChatRequest(functionCallResponse);
373
+ }
374
+ }
375
+ if (!hasFollowingResponse) {
376
+ break;
377
+ }
378
+ } else {
379
+ const streamedResponseMessage = messagesAndDataOrJustMessage;
380
+ if (streamedResponseMessage.function_call === void 0 || typeof streamedResponseMessage.function_call === "string") {
381
+ break;
382
+ }
383
+ if (experimental_onFunctionCall) {
384
+ const functionCall = streamedResponseMessage.function_call;
385
+ const functionCallResponse = await experimental_onFunctionCall(getCurrentMessages(), functionCall);
386
+ if (functionCallResponse === void 0)
387
+ break;
388
+ updateChatRequest(functionCallResponse);
389
+ }
390
+ }
145
391
  }
146
- return prefixMap;
147
392
  }
148
393
 
149
394
  // react/use-chat.ts
@@ -179,7 +424,8 @@ var getStreamedResponse = async (api, chatRequest, mutate, mutateStreamData, exi
179
424
  }
180
425
  try {
181
426
  const promise = api({
182
- messages: constructedMessagesPayload
427
+ messages: constructedMessagesPayload,
428
+ data: chatRequest.data
183
429
  });
184
430
  await readRow(promise);
185
431
  } catch (e) {
@@ -191,10 +437,11 @@ var getStreamedResponse = async (api, chatRequest, mutate, mutateStreamData, exi
191
437
  }
192
438
  return responseMessage;
193
439
  }
194
- const res = await fetch(api, {
195
- method: "POST",
196
- body: JSON.stringify({
197
- messages: constructedMessagesPayload,
440
+ return await callApi({
441
+ api,
442
+ messages: constructedMessagesPayload,
443
+ body: {
444
+ data: chatRequest.data,
198
445
  ...extraMetadataRef.current.body,
199
446
  ...(_a = chatRequest.options) == null ? void 0 : _a.body,
200
447
  ...chatRequest.functions !== void 0 && {
@@ -203,95 +450,26 @@ var getStreamedResponse = async (api, chatRequest, mutate, mutateStreamData, exi
203
450
  ...chatRequest.function_call !== void 0 && {
204
451
  function_call: chatRequest.function_call
205
452
  }
206
- }),
453
+ },
207
454
  credentials: extraMetadataRef.current.credentials,
208
455
  headers: {
209
456
  ...extraMetadataRef.current.headers,
210
457
  ...(_b = chatRequest.options) == null ? void 0 : _b.headers
211
458
  },
212
- ...abortControllerRef.current !== null && {
213
- signal: abortControllerRef.current.signal
214
- }
215
- }).catch((err) => {
216
- mutate(previousMessages, false);
217
- throw err;
459
+ abortController: () => abortControllerRef.current,
460
+ appendMessage(message) {
461
+ mutate([...chatRequest.messages, message], false);
462
+ },
463
+ restoreMessagesOnFailure() {
464
+ mutate(previousMessages, false);
465
+ },
466
+ onResponse,
467
+ onUpdate(merged, data) {
468
+ mutate([...chatRequest.messages, ...merged], false);
469
+ mutateStreamData([...existingData || [], ...data || []], false);
470
+ },
471
+ onFinish
218
472
  });
219
- if (onResponse) {
220
- try {
221
- await onResponse(res);
222
- } catch (err) {
223
- throw err;
224
- }
225
- }
226
- if (!res.ok) {
227
- mutate(previousMessages, false);
228
- throw new Error(await res.text() || "Failed to fetch the chat response.");
229
- }
230
- if (!res.body) {
231
- throw new Error("The response body is empty.");
232
- }
233
- const isComplexMode = res.headers.get(COMPLEX_HEADER) === "true";
234
- let responseMessages = [];
235
- const reader = res.body.getReader();
236
- let responseData = [];
237
- if (isComplexMode) {
238
- const prefixMap = await parseComplexResponse({
239
- reader,
240
- abortControllerRef,
241
- update(merged, data) {
242
- mutate([...chatRequest.messages, ...merged], false);
243
- mutateStreamData([...existingData || [], ...data || []], false);
244
- }
245
- });
246
- for (const [type, item] of Object.entries(prefixMap)) {
247
- if (onFinish && type === "text") {
248
- onFinish(item);
249
- }
250
- if (type === "data") {
251
- responseData.push(item);
252
- } else {
253
- responseMessages.push(item);
254
- }
255
- }
256
- return { messages: responseMessages, data: responseData };
257
- } else {
258
- const createdAt = /* @__PURE__ */ new Date();
259
- const decode = createChunkDecoder(false);
260
- let streamedResponse = "";
261
- const replyId = nanoid();
262
- let responseMessage = {
263
- id: replyId,
264
- createdAt,
265
- content: "",
266
- role: "assistant"
267
- };
268
- while (true) {
269
- const { done, value } = await reader.read();
270
- if (done) {
271
- break;
272
- }
273
- streamedResponse += decode(value);
274
- if (streamedResponse.startsWith('{"function_call":')) {
275
- responseMessage["function_call"] = streamedResponse;
276
- } else {
277
- responseMessage["content"] = streamedResponse;
278
- }
279
- mutate([...chatRequest.messages, { ...responseMessage }], false);
280
- if (abortControllerRef.current === null) {
281
- reader.cancel();
282
- break;
283
- }
284
- }
285
- if (streamedResponse.startsWith('{"function_call":')) {
286
- const parsedFunctionCall = JSON.parse(streamedResponse).function_call;
287
- responseMessage["function_call"] = parsedFunctionCall;
288
- mutate([...chatRequest.messages, { ...responseMessage }]);
289
- }
290
- if (onFinish) {
291
- onFinish(responseMessage);
292
- }
293
- return responseMessage;
294
- }
295
473
  };
296
474
  function useChat({
297
475
  api = "/api/chat",
@@ -317,10 +495,7 @@ function useChat({
317
495
  [chatId, "loading"],
318
496
  null
319
497
  );
320
- const { data: streamData, mutate: mutateStreamData } = useSWR(
321
- [chatId, "streamData"],
322
- null
323
- );
498
+ const { data: streamData, mutate: mutateStreamData } = useSWR([chatId, "streamData"], null);
324
499
  const messagesRef = useRef(messages || []);
325
500
  useEffect(() => {
326
501
  messagesRef.current = messages || [];
@@ -346,8 +521,8 @@ function useChat({
346
521
  setError(void 0);
347
522
  const abortController = new AbortController();
348
523
  abortControllerRef.current = abortController;
349
- while (true) {
350
- const messagesAndDataOrJustMessage = await getStreamedResponse(
524
+ await processChatStream({
525
+ getStreamedResponse: () => getStreamedResponse(
351
526
  api,
352
527
  chatRequest,
353
528
  mutate,
@@ -359,47 +534,13 @@ function useChat({
359
534
  onFinish,
360
535
  onResponse,
361
536
  sendExtraMessageFields
362
- );
363
- if ("messages" in messagesAndDataOrJustMessage) {
364
- let hasFollowingResponse = false;
365
- for (const message of messagesAndDataOrJustMessage.messages) {
366
- if (message.function_call === void 0 || typeof message.function_call === "string") {
367
- continue;
368
- }
369
- hasFollowingResponse = true;
370
- if (experimental_onFunctionCall) {
371
- const functionCall = message.function_call;
372
- const functionCallResponse = await experimental_onFunctionCall(
373
- messagesRef.current,
374
- functionCall
375
- );
376
- if (functionCallResponse === void 0) {
377
- hasFollowingResponse = false;
378
- break;
379
- }
380
- chatRequest = functionCallResponse;
381
- }
382
- }
383
- if (!hasFollowingResponse) {
384
- break;
385
- }
386
- } else {
387
- const streamedResponseMessage = messagesAndDataOrJustMessage;
388
- if (streamedResponseMessage.function_call === void 0 || typeof streamedResponseMessage.function_call === "string") {
389
- break;
390
- }
391
- if (experimental_onFunctionCall) {
392
- const functionCall = streamedResponseMessage.function_call;
393
- const functionCallResponse = await experimental_onFunctionCall(
394
- messagesRef.current,
395
- functionCall
396
- );
397
- if (functionCallResponse === void 0)
398
- break;
399
- chatRequest = functionCallResponse;
400
- }
401
- }
402
- }
537
+ ),
538
+ experimental_onFunctionCall,
539
+ updateChatRequest: (chatRequestParam) => {
540
+ chatRequest = chatRequestParam;
541
+ },
542
+ getCurrentMessages: () => messagesRef.current
543
+ });
403
544
  abortControllerRef.current = null;
404
545
  } catch (err) {
405
546
  if (err.name === "AbortError") {
@@ -432,13 +573,14 @@ function useChat({
432
573
  ]
433
574
  );
434
575
  const append = useCallback(
435
- async (message, { options, functions, function_call } = {}) => {
576
+ async (message, { options, functions, function_call, data } = {}) => {
436
577
  if (!message.id) {
437
578
  message.id = nanoid();
438
579
  }
439
580
  const chatRequest = {
440
581
  messages: messagesRef.current.concat(message),
441
582
  options,
583
+ data,
442
584
  ...functions !== void 0 && { functions },
443
585
  ...function_call !== void 0 && { function_call }
444
586
  };
@@ -485,7 +627,7 @@ function useChat({
485
627
  );
486
628
  const [input, setInput] = useState(initialInput);
487
629
  const handleSubmit = useCallback(
488
- (e, { options, functions, function_call } = {}, metadata) => {
630
+ (e, options = {}, metadata) => {
489
631
  if (metadata) {
490
632
  extraMetadataRef.current = {
491
633
  ...extraMetadataRef.current,
@@ -501,7 +643,7 @@ function useChat({
501
643
  role: "user",
502
644
  createdAt: /* @__PURE__ */ new Date()
503
645
  },
504
- { options, functions, function_call }
646
+ options
505
647
  );
506
648
  setInput("");
507
649
  },
@@ -695,7 +837,114 @@ function useCompletion({
695
837
  isLoading
696
838
  };
697
839
  }
840
+
841
+ // react/use-assistant.ts
842
+ import { useState as useState3 } from "react";
843
+
844
+ // shared/process-message-stream.ts
845
+ async function processMessageStream(reader, processMessage) {
846
+ const decoder = new TextDecoder();
847
+ let buffer = "";
848
+ while (true) {
849
+ const { done, value } = await reader.read();
850
+ if (done) {
851
+ if (buffer.length > 0) {
852
+ processMessage(buffer);
853
+ }
854
+ break;
855
+ }
856
+ buffer += decoder.decode(value, { stream: true });
857
+ let endIndex;
858
+ while ((endIndex = buffer.indexOf("\n")) !== -1) {
859
+ processMessage(buffer.substring(0, endIndex).trim());
860
+ buffer = buffer.substring(endIndex + 1);
861
+ }
862
+ }
863
+ }
864
+
865
+ // react/use-assistant.ts
866
+ function experimental_useAssistant({
867
+ api,
868
+ threadId: threadIdParam
869
+ }) {
870
+ const [messages, setMessages] = useState3([]);
871
+ const [input, setInput] = useState3("");
872
+ const [threadId, setThreadId] = useState3(void 0);
873
+ const [status, setStatus] = useState3("awaiting_message");
874
+ const [error, setError] = useState3(void 0);
875
+ const handleInputChange = (e) => {
876
+ setInput(e.target.value);
877
+ };
878
+ const submitMessage = async (e) => {
879
+ var _a;
880
+ e.preventDefault();
881
+ if (input === "") {
882
+ return;
883
+ }
884
+ setStatus("in_progress");
885
+ setMessages((messages2) => [
886
+ ...messages2,
887
+ { id: "", role: "user", content: input }
888
+ ]);
889
+ setInput("");
890
+ const result = await fetch(api, {
891
+ method: "POST",
892
+ headers: { "Content-Type": "application/json" },
893
+ body: JSON.stringify({
894
+ // always use user-provided threadId when available:
895
+ threadId: (_a = threadIdParam != null ? threadIdParam : threadId) != null ? _a : null,
896
+ message: input
897
+ })
898
+ });
899
+ if (result.body == null) {
900
+ throw new Error("The response body is empty.");
901
+ }
902
+ await processMessageStream(result.body.getReader(), (message) => {
903
+ try {
904
+ const { type, value } = parseStreamPart(message);
905
+ switch (type) {
906
+ case "assistant_message": {
907
+ setMessages((messages2) => [
908
+ ...messages2,
909
+ {
910
+ id: value.id,
911
+ role: value.role,
912
+ content: value.content[0].text.value
913
+ }
914
+ ]);
915
+ break;
916
+ }
917
+ case "assistant_control_data": {
918
+ setThreadId(value.threadId);
919
+ setMessages((messages2) => {
920
+ const lastMessage = messages2[messages2.length - 1];
921
+ lastMessage.id = value.messageId;
922
+ return [...messages2.slice(0, messages2.length - 1), lastMessage];
923
+ });
924
+ break;
925
+ }
926
+ case "error": {
927
+ setError(value);
928
+ break;
929
+ }
930
+ }
931
+ } catch (error2) {
932
+ setError(error2);
933
+ }
934
+ });
935
+ setStatus("awaiting_message");
936
+ };
937
+ return {
938
+ messages,
939
+ input,
940
+ handleInputChange,
941
+ submitMessage,
942
+ status,
943
+ error
944
+ };
945
+ }
698
946
  export {
947
+ experimental_useAssistant,
699
948
  useChat,
700
949
  useCompletion
701
950
  };