ai 2.2.23 → 2.2.25
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.d.ts +66 -25
- package/dist/index.js +282 -87
- package/dist/index.mjs +277 -84
- package/package.json +4 -3
- package/prompts/dist/index.d.ts +8 -1
- package/prompts/dist/index.js +17 -0
- package/prompts/dist/index.mjs +16 -0
- package/react/dist/index.d.ts +16 -2
- package/react/dist/index.js +436 -193
- package/react/dist/index.mjs +435 -193
- package/solid/dist/index.d.ts +6 -1
- package/solid/dist/index.js +425 -109
- package/solid/dist/index.mjs +425 -109
- package/svelte/dist/index.d.ts +5 -0
- package/svelte/dist/index.js +409 -121
- package/svelte/dist/index.mjs +409 -121
- package/vue/dist/index.js +124 -28
- package/vue/dist/index.mjs +124 -28
package/react/dist/index.mjs
CHANGED
@@ -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,50 +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(
|
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
|
-
if (firstSeperatorIndex === -1) {
|
36
|
-
throw new Error("Failed to parse stream string");
|
37
|
-
}
|
38
|
-
const prefix = line.slice(0, firstSeperatorIndex);
|
39
|
-
const type = Object.keys(StreamStringPrefixes).find(
|
40
|
-
(key) => StreamStringPrefixes[key] === Number(prefix)
|
41
|
-
);
|
42
|
-
const val = line.slice(firstSeperatorIndex + 1);
|
43
|
-
let parsedVal = val;
|
44
|
-
if (!val) {
|
45
|
-
return { type, value: "" };
|
46
|
-
}
|
47
|
-
try {
|
48
|
-
parsedVal = JSON.parse(val);
|
49
|
-
} catch (e) {
|
50
|
-
console.error("Failed to parse JSON value:", val);
|
51
|
-
}
|
52
|
-
return { type, value: parsedVal };
|
53
|
-
};
|
54
150
|
var COMPLEX_HEADER = "X-Experimental-Stream-Data";
|
55
151
|
|
56
|
-
//
|
152
|
+
// shared/call-api.ts
|
153
|
+
import { nanoid as nanoid2 } from "nanoid";
|
154
|
+
|
155
|
+
// shared/parse-complex-response.ts
|
57
156
|
async function parseComplexResponse({
|
58
157
|
reader,
|
59
158
|
abortControllerRef,
|
60
159
|
update,
|
61
|
-
onFinish
|
160
|
+
onFinish,
|
161
|
+
generateId = nanoid,
|
162
|
+
getCurrentDate = () => /* @__PURE__ */ new Date()
|
62
163
|
}) {
|
164
|
+
const createdAt = getCurrentDate();
|
63
165
|
const decode = createChunkDecoder(true);
|
64
|
-
const
|
65
|
-
|
166
|
+
const prefixMap = {
|
167
|
+
data: []
|
168
|
+
};
|
66
169
|
const NEWLINE = "\n".charCodeAt(0);
|
67
|
-
|
170
|
+
const chunks = [];
|
68
171
|
let totalLength = 0;
|
69
172
|
while (true) {
|
70
173
|
const { value } = await reader.read();
|
@@ -101,7 +204,7 @@ async function parseComplexResponse({
|
|
101
204
|
};
|
102
205
|
} else {
|
103
206
|
prefixMap["text"] = {
|
104
|
-
id:
|
207
|
+
id: generateId(),
|
105
208
|
role: "assistant",
|
106
209
|
content: value2,
|
107
210
|
createdAt
|
@@ -110,37 +213,24 @@ async function parseComplexResponse({
|
|
110
213
|
}
|
111
214
|
let functionCallMessage = null;
|
112
215
|
if (type === "function_call") {
|
113
|
-
prefixMap["function_call"] =
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
content: "",
|
123
|
-
function_call: parsedFunctionCall,
|
124
|
-
name: parsedFunctionCall.name,
|
125
|
-
createdAt
|
126
|
-
};
|
127
|
-
prefixMap["function_call"] = functionCallMessage;
|
128
|
-
}
|
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"];
|
129
225
|
}
|
130
226
|
if (type === "data") {
|
131
|
-
|
132
|
-
if (prefixMap["data"]) {
|
133
|
-
prefixMap["data"] = [...prefixMap["data"], ...parsedValue];
|
134
|
-
} else {
|
135
|
-
prefixMap["data"] = parsedValue;
|
136
|
-
}
|
227
|
+
prefixMap["data"].push(...value2);
|
137
228
|
}
|
138
|
-
const data = prefixMap["data"];
|
139
229
|
const responseMessage = prefixMap["text"];
|
140
230
|
const merged = [functionCallMessage, responseMessage].filter(
|
141
231
|
Boolean
|
142
232
|
);
|
143
|
-
update(merged, data);
|
233
|
+
update(merged, [...prefixMap["data"]]);
|
144
234
|
if ((abortControllerRef == null ? void 0 : abortControllerRef.current) === null) {
|
145
235
|
reader.cancel();
|
146
236
|
break;
|
@@ -148,7 +238,157 @@ async function parseComplexResponse({
|
|
148
238
|
}
|
149
239
|
}
|
150
240
|
onFinish == null ? void 0 : onFinish(prefixMap);
|
151
|
-
return
|
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) {
|
330
|
+
reader.cancel();
|
331
|
+
break;
|
332
|
+
}
|
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
|
+
}
|
391
|
+
}
|
152
392
|
}
|
153
393
|
|
154
394
|
// react/use-chat.ts
|
@@ -197,10 +437,10 @@ var getStreamedResponse = async (api, chatRequest, mutate, mutateStreamData, exi
|
|
197
437
|
}
|
198
438
|
return responseMessage;
|
199
439
|
}
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
440
|
+
return await callApi({
|
441
|
+
api,
|
442
|
+
messages: constructedMessagesPayload,
|
443
|
+
body: {
|
204
444
|
data: chatRequest.data,
|
205
445
|
...extraMetadataRef.current.body,
|
206
446
|
...(_a = chatRequest.options) == null ? void 0 : _a.body,
|
@@ -210,95 +450,26 @@ var getStreamedResponse = async (api, chatRequest, mutate, mutateStreamData, exi
|
|
210
450
|
...chatRequest.function_call !== void 0 && {
|
211
451
|
function_call: chatRequest.function_call
|
212
452
|
}
|
213
|
-
}
|
453
|
+
},
|
214
454
|
credentials: extraMetadataRef.current.credentials,
|
215
455
|
headers: {
|
216
456
|
...extraMetadataRef.current.headers,
|
217
457
|
...(_b = chatRequest.options) == null ? void 0 : _b.headers
|
218
458
|
},
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
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
|
225
472
|
});
|
226
|
-
if (onResponse) {
|
227
|
-
try {
|
228
|
-
await onResponse(res);
|
229
|
-
} catch (err) {
|
230
|
-
throw err;
|
231
|
-
}
|
232
|
-
}
|
233
|
-
if (!res.ok) {
|
234
|
-
mutate(previousMessages, false);
|
235
|
-
throw new Error(await res.text() || "Failed to fetch the chat response.");
|
236
|
-
}
|
237
|
-
if (!res.body) {
|
238
|
-
throw new Error("The response body is empty.");
|
239
|
-
}
|
240
|
-
const isComplexMode = res.headers.get(COMPLEX_HEADER) === "true";
|
241
|
-
let responseMessages = [];
|
242
|
-
const reader = res.body.getReader();
|
243
|
-
let responseData = [];
|
244
|
-
if (isComplexMode) {
|
245
|
-
const prefixMap = await parseComplexResponse({
|
246
|
-
reader,
|
247
|
-
abortControllerRef,
|
248
|
-
update(merged, data) {
|
249
|
-
mutate([...chatRequest.messages, ...merged], false);
|
250
|
-
mutateStreamData([...existingData || [], ...data || []], false);
|
251
|
-
}
|
252
|
-
});
|
253
|
-
for (const [type, item] of Object.entries(prefixMap)) {
|
254
|
-
if (onFinish && type === "text") {
|
255
|
-
onFinish(item);
|
256
|
-
}
|
257
|
-
if (type === "data") {
|
258
|
-
responseData.push(item);
|
259
|
-
} else {
|
260
|
-
responseMessages.push(item);
|
261
|
-
}
|
262
|
-
}
|
263
|
-
return { messages: responseMessages, data: responseData };
|
264
|
-
} else {
|
265
|
-
const createdAt = /* @__PURE__ */ new Date();
|
266
|
-
const decode = createChunkDecoder(false);
|
267
|
-
let streamedResponse = "";
|
268
|
-
const replyId = nanoid();
|
269
|
-
let responseMessage = {
|
270
|
-
id: replyId,
|
271
|
-
createdAt,
|
272
|
-
content: "",
|
273
|
-
role: "assistant"
|
274
|
-
};
|
275
|
-
while (true) {
|
276
|
-
const { done, value } = await reader.read();
|
277
|
-
if (done) {
|
278
|
-
break;
|
279
|
-
}
|
280
|
-
streamedResponse += decode(value);
|
281
|
-
if (streamedResponse.startsWith('{"function_call":')) {
|
282
|
-
responseMessage["function_call"] = streamedResponse;
|
283
|
-
} else {
|
284
|
-
responseMessage["content"] = streamedResponse;
|
285
|
-
}
|
286
|
-
mutate([...chatRequest.messages, { ...responseMessage }], false);
|
287
|
-
if (abortControllerRef.current === null) {
|
288
|
-
reader.cancel();
|
289
|
-
break;
|
290
|
-
}
|
291
|
-
}
|
292
|
-
if (streamedResponse.startsWith('{"function_call":')) {
|
293
|
-
const parsedFunctionCall = JSON.parse(streamedResponse).function_call;
|
294
|
-
responseMessage["function_call"] = parsedFunctionCall;
|
295
|
-
mutate([...chatRequest.messages, { ...responseMessage }]);
|
296
|
-
}
|
297
|
-
if (onFinish) {
|
298
|
-
onFinish(responseMessage);
|
299
|
-
}
|
300
|
-
return responseMessage;
|
301
|
-
}
|
302
473
|
};
|
303
474
|
function useChat({
|
304
475
|
api = "/api/chat",
|
@@ -324,10 +495,7 @@ function useChat({
|
|
324
495
|
[chatId, "loading"],
|
325
496
|
null
|
326
497
|
);
|
327
|
-
const { data: streamData, mutate: mutateStreamData } = useSWR(
|
328
|
-
[chatId, "streamData"],
|
329
|
-
null
|
330
|
-
);
|
498
|
+
const { data: streamData, mutate: mutateStreamData } = useSWR([chatId, "streamData"], null);
|
331
499
|
const messagesRef = useRef(messages || []);
|
332
500
|
useEffect(() => {
|
333
501
|
messagesRef.current = messages || [];
|
@@ -353,8 +521,8 @@ function useChat({
|
|
353
521
|
setError(void 0);
|
354
522
|
const abortController = new AbortController();
|
355
523
|
abortControllerRef.current = abortController;
|
356
|
-
|
357
|
-
|
524
|
+
await processChatStream({
|
525
|
+
getStreamedResponse: () => getStreamedResponse(
|
358
526
|
api,
|
359
527
|
chatRequest,
|
360
528
|
mutate,
|
@@ -366,47 +534,13 @@ function useChat({
|
|
366
534
|
onFinish,
|
367
535
|
onResponse,
|
368
536
|
sendExtraMessageFields
|
369
|
-
)
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
hasFollowingResponse = true;
|
377
|
-
if (experimental_onFunctionCall) {
|
378
|
-
const functionCall = message.function_call;
|
379
|
-
const functionCallResponse = await experimental_onFunctionCall(
|
380
|
-
messagesRef.current,
|
381
|
-
functionCall
|
382
|
-
);
|
383
|
-
if (functionCallResponse === void 0) {
|
384
|
-
hasFollowingResponse = false;
|
385
|
-
break;
|
386
|
-
}
|
387
|
-
chatRequest = functionCallResponse;
|
388
|
-
}
|
389
|
-
}
|
390
|
-
if (!hasFollowingResponse) {
|
391
|
-
break;
|
392
|
-
}
|
393
|
-
} else {
|
394
|
-
const streamedResponseMessage = messagesAndDataOrJustMessage;
|
395
|
-
if (streamedResponseMessage.function_call === void 0 || typeof streamedResponseMessage.function_call === "string") {
|
396
|
-
break;
|
397
|
-
}
|
398
|
-
if (experimental_onFunctionCall) {
|
399
|
-
const functionCall = streamedResponseMessage.function_call;
|
400
|
-
const functionCallResponse = await experimental_onFunctionCall(
|
401
|
-
messagesRef.current,
|
402
|
-
functionCall
|
403
|
-
);
|
404
|
-
if (functionCallResponse === void 0)
|
405
|
-
break;
|
406
|
-
chatRequest = functionCallResponse;
|
407
|
-
}
|
408
|
-
}
|
409
|
-
}
|
537
|
+
),
|
538
|
+
experimental_onFunctionCall,
|
539
|
+
updateChatRequest: (chatRequestParam) => {
|
540
|
+
chatRequest = chatRequestParam;
|
541
|
+
},
|
542
|
+
getCurrentMessages: () => messagesRef.current
|
543
|
+
});
|
410
544
|
abortControllerRef.current = null;
|
411
545
|
} catch (err) {
|
412
546
|
if (err.name === "AbortError") {
|
@@ -703,7 +837,115 @@ function useCompletion({
|
|
703
837
|
isLoading
|
704
838
|
};
|
705
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
|
+
threadId,
|
940
|
+
input,
|
941
|
+
handleInputChange,
|
942
|
+
submitMessage,
|
943
|
+
status,
|
944
|
+
error
|
945
|
+
};
|
946
|
+
}
|
706
947
|
export {
|
948
|
+
experimental_useAssistant,
|
707
949
|
useChat,
|
708
950
|
useCompletion
|
709
951
|
};
|