@dudousxd/nestjs-agent-react 0.17.0 → 0.18.0
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 +43 -6
- package/dist/index.cjs +556 -213
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +134 -1
- package/dist/index.d.ts +134 -1
- package/dist/index.js +512 -175
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -125,6 +125,9 @@ var AgentClient = class {
|
|
|
125
125
|
* what a caller then rides on `sendMessage({ text }, { body: { attachments: [...] } })`.
|
|
126
126
|
*/
|
|
127
127
|
async uploadAttachment(file, options = {}) {
|
|
128
|
+
if (options.onProgress !== void 0 && this.options.fetch === void 0 && typeof XMLHttpRequest !== "undefined") {
|
|
129
|
+
return this.uploadWithProgress(file, options);
|
|
130
|
+
}
|
|
128
131
|
const formData = new FormData();
|
|
129
132
|
formData.append("file", file);
|
|
130
133
|
const response = await this.fetchImpl()(`${this.baseUrl()}/agent/attachments`, {
|
|
@@ -139,7 +142,47 @@ var AgentClient = class {
|
|
|
139
142
|
signal: options.signal
|
|
140
143
|
} : {}
|
|
141
144
|
});
|
|
142
|
-
|
|
145
|
+
const attachment = await this.handleResponse(response, "POST", "/agent/attachments");
|
|
146
|
+
options.onProgress?.(1);
|
|
147
|
+
return attachment;
|
|
148
|
+
}
|
|
149
|
+
async uploadWithProgress(file, { signal, onProgress }) {
|
|
150
|
+
const headers = {
|
|
151
|
+
accept: "application/json",
|
|
152
|
+
...await this.resolveHeaders()
|
|
153
|
+
};
|
|
154
|
+
const url = `${this.baseUrl()}/agent/attachments`;
|
|
155
|
+
return new Promise((resolve, reject) => {
|
|
156
|
+
const xhr = new XMLHttpRequest();
|
|
157
|
+
xhr.open("POST", url);
|
|
158
|
+
for (const [name, value] of Object.entries(headers)) xhr.setRequestHeader(name, value);
|
|
159
|
+
xhr.withCredentials = this.options.credentials === "include";
|
|
160
|
+
xhr.upload.onprogress = (event) => {
|
|
161
|
+
if (event.lengthComputable && event.total > 0) onProgress?.(event.loaded / event.total);
|
|
162
|
+
};
|
|
163
|
+
xhr.onload = () => {
|
|
164
|
+
if (xhr.status < 200 || xhr.status >= 300) {
|
|
165
|
+
reject(new AgentHttpError(xhr.status, "POST", "/agent/attachments", xhr.statusText));
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
onProgress?.(1);
|
|
169
|
+
resolve(JSON.parse(xhr.responseText));
|
|
170
|
+
};
|
|
171
|
+
xhr.onerror = () => reject(new TypeError("Network error while uploading the attachment"));
|
|
172
|
+
xhr.onabort = () => reject(new DOMException("The upload was aborted", "AbortError"));
|
|
173
|
+
if (signal !== void 0) {
|
|
174
|
+
if (signal.aborted) {
|
|
175
|
+
reject(new DOMException("The upload was aborted", "AbortError"));
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
signal.addEventListener("abort", () => xhr.abort(), {
|
|
179
|
+
once: true
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
const formData = new FormData();
|
|
183
|
+
formData.append("file", file);
|
|
184
|
+
xhr.send(formData);
|
|
185
|
+
});
|
|
143
186
|
}
|
|
144
187
|
promoteThread(id) {
|
|
145
188
|
return this.request("POST", `/agent/threads/${encodeURIComponent(id)}/promote`);
|
|
@@ -987,6 +1030,68 @@ function delay(ms, signal) {
|
|
|
987
1030
|
}
|
|
988
1031
|
__name(delay, "delay");
|
|
989
1032
|
|
|
1033
|
+
// src/attachments/files.ts
|
|
1034
|
+
function fileKind(mediaType) {
|
|
1035
|
+
const type = mediaType.toLowerCase();
|
|
1036
|
+
if (type.startsWith("image/")) return "image";
|
|
1037
|
+
if (type === "application/pdf") return "pdf";
|
|
1038
|
+
if (type.startsWith("text/") || type === "application/json") return "text";
|
|
1039
|
+
if (type.startsWith("audio/")) return "audio";
|
|
1040
|
+
if (type.startsWith("video/")) return "video";
|
|
1041
|
+
return "other";
|
|
1042
|
+
}
|
|
1043
|
+
__name(fileKind, "fileKind");
|
|
1044
|
+
function messageFiles(message) {
|
|
1045
|
+
const files = [];
|
|
1046
|
+
for (const part of message.parts) {
|
|
1047
|
+
if (part.type !== "file") continue;
|
|
1048
|
+
const file = part;
|
|
1049
|
+
const filename = file.filename ?? null;
|
|
1050
|
+
const dot = filename?.lastIndexOf(".") ?? -1;
|
|
1051
|
+
const mediaId = file.providerMetadata?.agent?.mediaId;
|
|
1052
|
+
files.push({
|
|
1053
|
+
url: file.url,
|
|
1054
|
+
mediaType: file.mediaType,
|
|
1055
|
+
filename,
|
|
1056
|
+
kind: fileKind(file.mediaType),
|
|
1057
|
+
extension: filename !== null && dot > 0 ? filename.slice(dot + 1).toLowerCase() : null,
|
|
1058
|
+
mediaId: typeof mediaId === "string" ? mediaId : null
|
|
1059
|
+
});
|
|
1060
|
+
}
|
|
1061
|
+
return files;
|
|
1062
|
+
}
|
|
1063
|
+
__name(messageFiles, "messageFiles");
|
|
1064
|
+
function acceptsFile(accept, file) {
|
|
1065
|
+
const rules = (typeof accept === "string" ? accept.split(",") : accept ?? []).map((rule) => rule.trim().toLowerCase()).filter((rule) => rule.length > 0);
|
|
1066
|
+
if (rules.length === 0) return true;
|
|
1067
|
+
const type = file.type.toLowerCase();
|
|
1068
|
+
const name = file.name.toLowerCase();
|
|
1069
|
+
return rules.some((rule) => {
|
|
1070
|
+
if (rule.startsWith(".")) return name.endsWith(rule);
|
|
1071
|
+
if (rule.endsWith("/*")) return type.startsWith(rule.slice(0, -1));
|
|
1072
|
+
return type === rule;
|
|
1073
|
+
});
|
|
1074
|
+
}
|
|
1075
|
+
__name(acceptsFile, "acceptsFile");
|
|
1076
|
+
function filesFromClipboard(data) {
|
|
1077
|
+
if (!data) return [];
|
|
1078
|
+
const files = [];
|
|
1079
|
+
for (const item of Array.from(data.items ?? [])) {
|
|
1080
|
+
if (item.kind !== "file") continue;
|
|
1081
|
+
const file = item.getAsFile();
|
|
1082
|
+
if (file !== null) files.push(file);
|
|
1083
|
+
}
|
|
1084
|
+
return files.length > 0 ? files : Array.from(data.files ?? []);
|
|
1085
|
+
}
|
|
1086
|
+
__name(filesFromClipboard, "filesFromClipboard");
|
|
1087
|
+
function dragHasFiles(data) {
|
|
1088
|
+
return Array.from(data?.types ?? []).includes("Files");
|
|
1089
|
+
}
|
|
1090
|
+
__name(dragHasFiles, "dragHasFiles");
|
|
1091
|
+
|
|
1092
|
+
// src/attachments/use-attachments.ts
|
|
1093
|
+
import { useCallback, useEffect as useEffect2, useMemo, useRef as useRef2, useState as useState2 } from "react";
|
|
1094
|
+
|
|
990
1095
|
// src/backend.ts
|
|
991
1096
|
var AgentBackendUnsupportedError = class extends Error {
|
|
992
1097
|
static {
|
|
@@ -1007,19 +1112,239 @@ function requireBackendMethod(backend, name) {
|
|
|
1007
1112
|
}
|
|
1008
1113
|
__name(requireBackendMethod, "requireBackendMethod");
|
|
1009
1114
|
|
|
1115
|
+
// src/attachments/use-attachments.ts
|
|
1116
|
+
var DEFAULT_REJECTION = {
|
|
1117
|
+
type: /* @__PURE__ */ __name((file) => `${file.name} is not a supported file type`, "type"),
|
|
1118
|
+
size: /* @__PURE__ */ __name((file) => `${file.name} is too large`, "size"),
|
|
1119
|
+
count: /* @__PURE__ */ __name(() => "Too many files", "count")
|
|
1120
|
+
};
|
|
1121
|
+
var sequence = 0;
|
|
1122
|
+
function useAttachments(options) {
|
|
1123
|
+
const latest = useRef2(options);
|
|
1124
|
+
latest.current = options;
|
|
1125
|
+
const [items, setItems] = useState2([]);
|
|
1126
|
+
const itemsRef = useRef2(items);
|
|
1127
|
+
itemsRef.current = items;
|
|
1128
|
+
const controllers = useRef2(/* @__PURE__ */ new Map());
|
|
1129
|
+
const [dragDepth, setDragDepth] = useState2(0);
|
|
1130
|
+
const patch = useCallback((id, change) => {
|
|
1131
|
+
setItems((current) => current.map((item) => item.id === id ? {
|
|
1132
|
+
...item,
|
|
1133
|
+
...change
|
|
1134
|
+
} : item));
|
|
1135
|
+
}, []);
|
|
1136
|
+
const start = useCallback((item) => {
|
|
1137
|
+
const { upload, backend } = latest.current;
|
|
1138
|
+
const run = upload ?? (backend?.uploadAttachment !== void 0 ? backend.uploadAttachment.bind(backend) : void 0);
|
|
1139
|
+
if (run === void 0) {
|
|
1140
|
+
patch(item.id, {
|
|
1141
|
+
status: "error",
|
|
1142
|
+
error: new AgentBackendUnsupportedError("uploadAttachment").message
|
|
1143
|
+
});
|
|
1144
|
+
return;
|
|
1145
|
+
}
|
|
1146
|
+
const controller = new AbortController();
|
|
1147
|
+
controllers.current.set(item.id, controller);
|
|
1148
|
+
run(item.file, {
|
|
1149
|
+
signal: controller.signal,
|
|
1150
|
+
onProgress: /* @__PURE__ */ __name((fraction) => patch(item.id, {
|
|
1151
|
+
progress: Math.max(0, Math.min(1, fraction))
|
|
1152
|
+
}), "onProgress")
|
|
1153
|
+
}).then((attachment) => {
|
|
1154
|
+
if (controller.signal.aborted) return;
|
|
1155
|
+
controllers.current.delete(item.id);
|
|
1156
|
+
patch(item.id, {
|
|
1157
|
+
status: "ready",
|
|
1158
|
+
progress: 1,
|
|
1159
|
+
attachment
|
|
1160
|
+
});
|
|
1161
|
+
}, (error) => {
|
|
1162
|
+
if (controller.signal.aborted) return;
|
|
1163
|
+
controllers.current.delete(item.id);
|
|
1164
|
+
patch(item.id, {
|
|
1165
|
+
status: "error",
|
|
1166
|
+
error: error instanceof Error ? error.message : String(error)
|
|
1167
|
+
});
|
|
1168
|
+
});
|
|
1169
|
+
}, [
|
|
1170
|
+
patch
|
|
1171
|
+
]);
|
|
1172
|
+
const add = useCallback((files) => {
|
|
1173
|
+
if (files == null) return;
|
|
1174
|
+
const { accept: accept2, maxBytes, maxFiles, describeRejection } = latest.current;
|
|
1175
|
+
const describe = /* @__PURE__ */ __name((reason, file) => describeRejection?.(reason, file) ?? DEFAULT_REJECTION[reason](file), "describe");
|
|
1176
|
+
let room = maxFiles === void 0 ? Number.POSITIVE_INFINITY : maxFiles - itemsRef.current.filter((item) => item.status !== "rejected").length;
|
|
1177
|
+
const staged = [];
|
|
1178
|
+
for (const file of Array.from(files)) {
|
|
1179
|
+
sequence += 1;
|
|
1180
|
+
const base = {
|
|
1181
|
+
id: `att-${sequence}`,
|
|
1182
|
+
file,
|
|
1183
|
+
name: file.name,
|
|
1184
|
+
size: file.size,
|
|
1185
|
+
type: file.type,
|
|
1186
|
+
progress: 0
|
|
1187
|
+
};
|
|
1188
|
+
const reason = !acceptsFile(accept2, file) ? "type" : maxBytes !== void 0 && file.size > maxBytes ? "size" : room <= 0 ? "count" : void 0;
|
|
1189
|
+
if (reason !== void 0) {
|
|
1190
|
+
staged.push({
|
|
1191
|
+
...base,
|
|
1192
|
+
status: "rejected",
|
|
1193
|
+
error: describe(reason, file)
|
|
1194
|
+
});
|
|
1195
|
+
continue;
|
|
1196
|
+
}
|
|
1197
|
+
room -= 1;
|
|
1198
|
+
const previewUrl = file.type.startsWith("image/") && typeof URL.createObjectURL === "function" ? URL.createObjectURL(file) : void 0;
|
|
1199
|
+
staged.push({
|
|
1200
|
+
...base,
|
|
1201
|
+
status: "uploading",
|
|
1202
|
+
...previewUrl ? {
|
|
1203
|
+
previewUrl
|
|
1204
|
+
} : {}
|
|
1205
|
+
});
|
|
1206
|
+
}
|
|
1207
|
+
if (staged.length === 0) return;
|
|
1208
|
+
setItems((current) => [
|
|
1209
|
+
...current,
|
|
1210
|
+
...staged
|
|
1211
|
+
]);
|
|
1212
|
+
for (const item of staged) {
|
|
1213
|
+
if (item.status === "uploading") start(item);
|
|
1214
|
+
}
|
|
1215
|
+
}, [
|
|
1216
|
+
start
|
|
1217
|
+
]);
|
|
1218
|
+
const release = useCallback((item) => {
|
|
1219
|
+
if (item === void 0) return;
|
|
1220
|
+
controllers.current.get(item.id)?.abort();
|
|
1221
|
+
controllers.current.delete(item.id);
|
|
1222
|
+
if (item.previewUrl !== void 0 && typeof URL.revokeObjectURL === "function") {
|
|
1223
|
+
URL.revokeObjectURL(item.previewUrl);
|
|
1224
|
+
}
|
|
1225
|
+
}, []);
|
|
1226
|
+
const remove = useCallback((id) => {
|
|
1227
|
+
release(itemsRef.current.find((item) => item.id === id));
|
|
1228
|
+
setItems((current) => current.filter((item) => item.id !== id));
|
|
1229
|
+
}, [
|
|
1230
|
+
release
|
|
1231
|
+
]);
|
|
1232
|
+
const clear = useCallback(() => {
|
|
1233
|
+
for (const item of itemsRef.current) release(item);
|
|
1234
|
+
setItems([]);
|
|
1235
|
+
}, [
|
|
1236
|
+
release
|
|
1237
|
+
]);
|
|
1238
|
+
const retry = useCallback((id) => {
|
|
1239
|
+
const item = itemsRef.current.find((candidate) => candidate.id === id);
|
|
1240
|
+
if (item === void 0 || item.status !== "error") return;
|
|
1241
|
+
const { error: _previous, ...rest } = item;
|
|
1242
|
+
const again = {
|
|
1243
|
+
...rest,
|
|
1244
|
+
status: "uploading",
|
|
1245
|
+
progress: 0
|
|
1246
|
+
};
|
|
1247
|
+
setItems((current) => current.map((candidate) => candidate.id === id ? again : candidate));
|
|
1248
|
+
start(again);
|
|
1249
|
+
}, [
|
|
1250
|
+
start
|
|
1251
|
+
]);
|
|
1252
|
+
useEffect2(() => () => {
|
|
1253
|
+
for (const item of itemsRef.current) release(item);
|
|
1254
|
+
}, [
|
|
1255
|
+
release
|
|
1256
|
+
]);
|
|
1257
|
+
const onPaste = useCallback((event) => {
|
|
1258
|
+
const files = filesFromClipboard(event.clipboardData);
|
|
1259
|
+
if (files.length === 0) return;
|
|
1260
|
+
event.preventDefault();
|
|
1261
|
+
add(files);
|
|
1262
|
+
}, [
|
|
1263
|
+
add
|
|
1264
|
+
]);
|
|
1265
|
+
const dropZoneProps = useMemo(() => ({
|
|
1266
|
+
onDragEnter: /* @__PURE__ */ __name((event) => {
|
|
1267
|
+
if (!dragHasFiles(event.dataTransfer)) return;
|
|
1268
|
+
event.preventDefault();
|
|
1269
|
+
setDragDepth((depth) => depth + 1);
|
|
1270
|
+
}, "onDragEnter"),
|
|
1271
|
+
onDragOver: /* @__PURE__ */ __name((event) => {
|
|
1272
|
+
if (dragHasFiles(event.dataTransfer)) event.preventDefault();
|
|
1273
|
+
}, "onDragOver"),
|
|
1274
|
+
onDragLeave: /* @__PURE__ */ __name((event) => {
|
|
1275
|
+
if (!dragHasFiles(event.dataTransfer)) return;
|
|
1276
|
+
setDragDepth((depth) => Math.max(0, depth - 1));
|
|
1277
|
+
}, "onDragLeave"),
|
|
1278
|
+
onDrop: /* @__PURE__ */ __name((event) => {
|
|
1279
|
+
if (!dragHasFiles(event.dataTransfer)) return;
|
|
1280
|
+
event.preventDefault();
|
|
1281
|
+
setDragDepth(0);
|
|
1282
|
+
add(event.dataTransfer?.files);
|
|
1283
|
+
}, "onDrop")
|
|
1284
|
+
}), [
|
|
1285
|
+
add
|
|
1286
|
+
]);
|
|
1287
|
+
const accept = options.accept;
|
|
1288
|
+
const inputProps = useMemo(() => ({
|
|
1289
|
+
type: "file",
|
|
1290
|
+
accept: typeof accept === "string" ? accept : accept?.join(","),
|
|
1291
|
+
multiple: options.maxFiles === void 0 || options.maxFiles > 1,
|
|
1292
|
+
onChange: /* @__PURE__ */ __name((event) => {
|
|
1293
|
+
const input = event.currentTarget;
|
|
1294
|
+
add(input.files);
|
|
1295
|
+
input.value = "";
|
|
1296
|
+
}, "onChange")
|
|
1297
|
+
}), [
|
|
1298
|
+
accept,
|
|
1299
|
+
options.maxFiles,
|
|
1300
|
+
add
|
|
1301
|
+
]);
|
|
1302
|
+
return useMemo(() => {
|
|
1303
|
+
const ready = items.filter((item) => item.status === "ready" && item.attachment !== void 0);
|
|
1304
|
+
const attachments = ready.map((item) => item.attachment);
|
|
1305
|
+
return {
|
|
1306
|
+
items,
|
|
1307
|
+
add,
|
|
1308
|
+
remove,
|
|
1309
|
+
retry,
|
|
1310
|
+
clear,
|
|
1311
|
+
isUploading: items.some((item) => item.status === "uploading"),
|
|
1312
|
+
attachments,
|
|
1313
|
+
refs: attachments.map((attachment) => ({
|
|
1314
|
+
mediaId: attachment.mediaId
|
|
1315
|
+
})),
|
|
1316
|
+
inputProps,
|
|
1317
|
+
dropZoneProps,
|
|
1318
|
+
isDragging: dragDepth > 0,
|
|
1319
|
+
onPaste
|
|
1320
|
+
};
|
|
1321
|
+
}, [
|
|
1322
|
+
items,
|
|
1323
|
+
add,
|
|
1324
|
+
remove,
|
|
1325
|
+
retry,
|
|
1326
|
+
clear,
|
|
1327
|
+
inputProps,
|
|
1328
|
+
dropZoneProps,
|
|
1329
|
+
dragDepth,
|
|
1330
|
+
onPaste
|
|
1331
|
+
]);
|
|
1332
|
+
}
|
|
1333
|
+
__name(useAttachments, "useAttachments");
|
|
1334
|
+
|
|
1010
1335
|
// src/catalog/use-agents.ts
|
|
1011
|
-
import { useMemo } from "react";
|
|
1336
|
+
import { useMemo as useMemo2 } from "react";
|
|
1012
1337
|
|
|
1013
1338
|
// src/catalog/use-resource.ts
|
|
1014
|
-
import { useCallback, useEffect as
|
|
1339
|
+
import { useCallback as useCallback2, useEffect as useEffect3, useRef as useRef3, useState as useState3 } from "react";
|
|
1015
1340
|
function useResource(load2, key, enabled) {
|
|
1016
|
-
const [data, setData] =
|
|
1017
|
-
const [isLoading, setIsLoading] =
|
|
1018
|
-
const [error, setError] =
|
|
1019
|
-
const loadRef =
|
|
1341
|
+
const [data, setData] = useState3(void 0);
|
|
1342
|
+
const [isLoading, setIsLoading] = useState3(enabled);
|
|
1343
|
+
const [error, setError] = useState3(null);
|
|
1344
|
+
const loadRef = useRef3(load2);
|
|
1020
1345
|
loadRef.current = load2;
|
|
1021
|
-
const generation =
|
|
1022
|
-
const refresh =
|
|
1346
|
+
const generation = useRef3(0);
|
|
1347
|
+
const refresh = useCallback2(async () => {
|
|
1023
1348
|
const mine = ++generation.current;
|
|
1024
1349
|
setIsLoading(true);
|
|
1025
1350
|
try {
|
|
@@ -1034,7 +1359,7 @@ function useResource(load2, key, enabled) {
|
|
|
1034
1359
|
if (mine === generation.current) setIsLoading(false);
|
|
1035
1360
|
}
|
|
1036
1361
|
}, []);
|
|
1037
|
-
|
|
1362
|
+
useEffect3(() => {
|
|
1038
1363
|
if (!enabled) return;
|
|
1039
1364
|
void refresh();
|
|
1040
1365
|
}, [
|
|
@@ -1055,7 +1380,7 @@ __name(useResource, "useResource");
|
|
|
1055
1380
|
function useAgents(options) {
|
|
1056
1381
|
const { backend, enabled = true } = options;
|
|
1057
1382
|
const { data, isLoading, error, refresh } = useResource(() => requireBackendMethod(backend, "listAgents")(), "", enabled);
|
|
1058
|
-
return
|
|
1383
|
+
return useMemo2(() => {
|
|
1059
1384
|
const agents = data ?? [];
|
|
1060
1385
|
return {
|
|
1061
1386
|
agents,
|
|
@@ -1074,11 +1399,11 @@ function useAgents(options) {
|
|
|
1074
1399
|
__name(useAgents, "useAgents");
|
|
1075
1400
|
|
|
1076
1401
|
// src/catalog/use-models.ts
|
|
1077
|
-
import { useMemo as
|
|
1402
|
+
import { useMemo as useMemo3 } from "react";
|
|
1078
1403
|
function useModels(options) {
|
|
1079
1404
|
const { backend, agent, enabled = true } = options;
|
|
1080
1405
|
const { data, isLoading, error, refresh } = useResource(() => requireBackendMethod(backend, "listModels")(agent), `${agent ?? ""}`, enabled);
|
|
1081
|
-
return
|
|
1406
|
+
return useMemo3(() => {
|
|
1082
1407
|
const providers = data?.providers ?? [];
|
|
1083
1408
|
const models = providers.flatMap((provider) => provider.models.map((model) => ({
|
|
1084
1409
|
...model,
|
|
@@ -1108,7 +1433,7 @@ function useModels(options) {
|
|
|
1108
1433
|
__name(useModels, "useModels");
|
|
1109
1434
|
|
|
1110
1435
|
// src/quota/use-quota.ts
|
|
1111
|
-
import { useEffect as
|
|
1436
|
+
import { useEffect as useEffect4, useMemo as useMemo4 } from "react";
|
|
1112
1437
|
|
|
1113
1438
|
// src/threads/threads-events.ts
|
|
1114
1439
|
var listeners = /* @__PURE__ */ new WeakMap();
|
|
@@ -1135,7 +1460,7 @@ __name(onThreadsEvent, "onThreadsEvent");
|
|
|
1135
1460
|
function useQuota(options) {
|
|
1136
1461
|
const { backend, enabled = true, pollMs } = options;
|
|
1137
1462
|
const { data, isLoading, error, refresh } = useResource(() => requireBackendMethod(backend, "getQuota")(), "", enabled);
|
|
1138
|
-
|
|
1463
|
+
useEffect4(() => {
|
|
1139
1464
|
if (!enabled) return;
|
|
1140
1465
|
return onThreadsEvent(backend, (event) => {
|
|
1141
1466
|
if (event.type === "changed") void refresh();
|
|
@@ -1145,7 +1470,7 @@ function useQuota(options) {
|
|
|
1145
1470
|
enabled,
|
|
1146
1471
|
refresh
|
|
1147
1472
|
]);
|
|
1148
|
-
|
|
1473
|
+
useEffect4(() => {
|
|
1149
1474
|
if (!enabled || pollMs === void 0 || pollMs <= 0) return;
|
|
1150
1475
|
const timer = setInterval(() => void refresh(), pollMs);
|
|
1151
1476
|
return () => clearInterval(timer);
|
|
@@ -1154,7 +1479,7 @@ function useQuota(options) {
|
|
|
1154
1479
|
pollMs,
|
|
1155
1480
|
refresh
|
|
1156
1481
|
]);
|
|
1157
|
-
return
|
|
1482
|
+
return useMemo4(() => {
|
|
1158
1483
|
const windows = data?.windows ?? [];
|
|
1159
1484
|
return {
|
|
1160
1485
|
report: data,
|
|
@@ -1176,27 +1501,27 @@ function useQuota(options) {
|
|
|
1176
1501
|
__name(useQuota, "useQuota");
|
|
1177
1502
|
|
|
1178
1503
|
// src/feedback/use-message-feedback.ts
|
|
1179
|
-
import { useCallback as
|
|
1504
|
+
import { useCallback as useCallback3, useRef as useRef4, useState as useState4 } from "react";
|
|
1180
1505
|
function useMessageFeedback(options) {
|
|
1181
|
-
const latest =
|
|
1506
|
+
const latest = useRef4(options);
|
|
1182
1507
|
latest.current = options;
|
|
1183
|
-
const [local, setLocal] =
|
|
1184
|
-
const [pending, setPending] =
|
|
1185
|
-
const [error, setError] =
|
|
1186
|
-
const localRef =
|
|
1508
|
+
const [local, setLocal] = useState4(/* @__PURE__ */ new Map());
|
|
1509
|
+
const [pending, setPending] = useState4(/* @__PURE__ */ new Set());
|
|
1510
|
+
const [error, setError] = useState4(null);
|
|
1511
|
+
const localRef = useRef4(local);
|
|
1187
1512
|
localRef.current = local;
|
|
1188
|
-
const resolved =
|
|
1189
|
-
const feedbackOf =
|
|
1513
|
+
const resolved = useRef4(/* @__PURE__ */ new Map());
|
|
1514
|
+
const feedbackOf = useCallback3((message) => {
|
|
1190
1515
|
const mine = local.get(message.id);
|
|
1191
1516
|
if (mine !== void 0) return mine.feedback;
|
|
1192
1517
|
return metadataOf(message).feedback ?? null;
|
|
1193
1518
|
}, [
|
|
1194
1519
|
local
|
|
1195
1520
|
]);
|
|
1196
|
-
const isPending =
|
|
1521
|
+
const isPending = useCallback3((message) => pending.has(message.id), [
|
|
1197
1522
|
pending
|
|
1198
1523
|
]);
|
|
1199
|
-
const storedIdFor =
|
|
1524
|
+
const storedIdFor = useCallback3(async (message) => {
|
|
1200
1525
|
const runId = metadataOf(message).runId;
|
|
1201
1526
|
if (runId === void 0) return message.id;
|
|
1202
1527
|
const known = resolved.current.get(message.id);
|
|
@@ -1216,7 +1541,7 @@ function useMessageFeedback(options) {
|
|
|
1216
1541
|
resolved.current.set(message.id, row.id);
|
|
1217
1542
|
return row.id;
|
|
1218
1543
|
}, []);
|
|
1219
|
-
const rate =
|
|
1544
|
+
const rate = useCallback3(async (message, value, comment) => {
|
|
1220
1545
|
const setFeedback = requireBackendMethod(latest.current.backend, "setMessageFeedback");
|
|
1221
1546
|
const had = localRef.current.get(message.id);
|
|
1222
1547
|
const optimistic = value === null ? null : {
|
|
@@ -1262,7 +1587,7 @@ function useMessageFeedback(options) {
|
|
|
1262
1587
|
}, [
|
|
1263
1588
|
storedIdFor
|
|
1264
1589
|
]);
|
|
1265
|
-
const toggle =
|
|
1590
|
+
const toggle = useCallback3((message, value) => {
|
|
1266
1591
|
const mine = localRef.current.get(message.id);
|
|
1267
1592
|
const current = mine !== void 0 ? mine.feedback : metadataOf(message).feedback ?? null;
|
|
1268
1593
|
return rate(message, current?.value === value ? null : value);
|
|
@@ -1285,16 +1610,16 @@ function metadataOf(message) {
|
|
|
1285
1610
|
__name(metadataOf, "metadataOf");
|
|
1286
1611
|
|
|
1287
1612
|
// src/threads/use-threads.ts
|
|
1288
|
-
import { useCallback as
|
|
1613
|
+
import { useCallback as useCallback4, useEffect as useEffect5, useRef as useRef5, useState as useState5 } from "react";
|
|
1289
1614
|
function useThreads(options) {
|
|
1290
1615
|
const { backend, enabled = true } = options;
|
|
1291
|
-
const [threads, setThreads] =
|
|
1292
|
-
const [isLoading, setIsLoading] =
|
|
1293
|
-
const [error, setError] =
|
|
1294
|
-
const threadsRef =
|
|
1616
|
+
const [threads, setThreads] = useState5([]);
|
|
1617
|
+
const [isLoading, setIsLoading] = useState5(enabled);
|
|
1618
|
+
const [error, setError] = useState5(null);
|
|
1619
|
+
const threadsRef = useRef5(threads);
|
|
1295
1620
|
threadsRef.current = threads;
|
|
1296
|
-
const generation =
|
|
1297
|
-
const refresh =
|
|
1621
|
+
const generation = useRef5(0);
|
|
1622
|
+
const refresh = useCallback4(async () => {
|
|
1298
1623
|
const mine = ++generation.current;
|
|
1299
1624
|
setIsLoading(true);
|
|
1300
1625
|
try {
|
|
@@ -1311,7 +1636,7 @@ function useThreads(options) {
|
|
|
1311
1636
|
}, [
|
|
1312
1637
|
backend
|
|
1313
1638
|
]);
|
|
1314
|
-
|
|
1639
|
+
useEffect5(() => {
|
|
1315
1640
|
if (!enabled) return;
|
|
1316
1641
|
void refresh();
|
|
1317
1642
|
return onThreadsEvent(backend, (event) => {
|
|
@@ -1331,7 +1656,7 @@ function useThreads(options) {
|
|
|
1331
1656
|
enabled,
|
|
1332
1657
|
refresh
|
|
1333
1658
|
]);
|
|
1334
|
-
const rename =
|
|
1659
|
+
const rename = useCallback4(async (id, title) => {
|
|
1335
1660
|
const before = threadsRef.current;
|
|
1336
1661
|
setThreads((current) => current.map((thread) => thread.id === id ? {
|
|
1337
1662
|
...thread,
|
|
@@ -1353,7 +1678,7 @@ function useThreads(options) {
|
|
|
1353
1678
|
}, [
|
|
1354
1679
|
backend
|
|
1355
1680
|
]);
|
|
1356
|
-
const remove =
|
|
1681
|
+
const remove = useCallback4(async (id) => {
|
|
1357
1682
|
const before = threadsRef.current;
|
|
1358
1683
|
setThreads((current) => current.filter((thread) => thread.id !== id));
|
|
1359
1684
|
try {
|
|
@@ -1428,10 +1753,10 @@ function backgroundRunsFromThread(messages) {
|
|
|
1428
1753
|
__name(backgroundRunsFromThread, "backgroundRunsFromThread");
|
|
1429
1754
|
|
|
1430
1755
|
// src/components/chat-input.tsx
|
|
1431
|
-
import React2, { useEffect as
|
|
1756
|
+
import React2, { useEffect as useEffect7, useState as useState7 } from "react";
|
|
1432
1757
|
|
|
1433
1758
|
// src/components/use-speech-recognition.ts
|
|
1434
|
-
import { useCallback as
|
|
1759
|
+
import { useCallback as useCallback5, useEffect as useEffect6, useMemo as useMemo5, useRef as useRef6, useState as useState6 } from "react";
|
|
1435
1760
|
function getRecognitionCtor() {
|
|
1436
1761
|
if (typeof window === "undefined") return null;
|
|
1437
1762
|
const scope = window;
|
|
@@ -1439,15 +1764,15 @@ function getRecognitionCtor() {
|
|
|
1439
1764
|
}
|
|
1440
1765
|
__name(getRecognitionCtor, "getRecognitionCtor");
|
|
1441
1766
|
function useSpeechRecognition({ lang = "en-US", onFinalTranscript, onInterimTranscript }) {
|
|
1442
|
-
const recognitionRef =
|
|
1443
|
-
const [isListening, setIsListening] =
|
|
1444
|
-
const ctor =
|
|
1767
|
+
const recognitionRef = useRef6(null);
|
|
1768
|
+
const [isListening, setIsListening] = useState6(false);
|
|
1769
|
+
const ctor = useMemo5(() => getRecognitionCtor(), []);
|
|
1445
1770
|
const isSupported = ctor !== null;
|
|
1446
|
-
const finalRef =
|
|
1447
|
-
const interimRef =
|
|
1771
|
+
const finalRef = useRef6(onFinalTranscript);
|
|
1772
|
+
const interimRef = useRef6(onInterimTranscript);
|
|
1448
1773
|
finalRef.current = onFinalTranscript;
|
|
1449
1774
|
interimRef.current = onInterimTranscript;
|
|
1450
|
-
|
|
1775
|
+
useEffect6(() => {
|
|
1451
1776
|
if (!ctor) return;
|
|
1452
1777
|
const recognition = new ctor();
|
|
1453
1778
|
recognition.lang = lang;
|
|
@@ -1486,7 +1811,7 @@ function useSpeechRecognition({ lang = "en-US", onFinalTranscript, onInterimTran
|
|
|
1486
1811
|
ctor,
|
|
1487
1812
|
lang
|
|
1488
1813
|
]);
|
|
1489
|
-
const start =
|
|
1814
|
+
const start = useCallback5(() => {
|
|
1490
1815
|
const recognition = recognitionRef.current;
|
|
1491
1816
|
if (!recognition) return;
|
|
1492
1817
|
try {
|
|
@@ -1496,7 +1821,7 @@ function useSpeechRecognition({ lang = "en-US", onFinalTranscript, onInterimTran
|
|
|
1496
1821
|
console.warn("SpeechRecognition start failed", error);
|
|
1497
1822
|
}
|
|
1498
1823
|
}, []);
|
|
1499
|
-
const stop =
|
|
1824
|
+
const stop = useCallback5(() => {
|
|
1500
1825
|
const recognition = recognitionRef.current;
|
|
1501
1826
|
if (!recognition) return;
|
|
1502
1827
|
try {
|
|
@@ -1515,8 +1840,8 @@ __name(useSpeechRecognition, "useSpeechRecognition");
|
|
|
1515
1840
|
|
|
1516
1841
|
// src/components/chat-input.tsx
|
|
1517
1842
|
function ChatInput({ onSubmit, disabled, placeholder, rows = 2, enableSpeech = true, speechLang = "en-US", sendLabel = "Send", onStop, isStreaming = false, stopLabel = "Stop generating", className, textareaClassName, sendButtonClassName, micButtonClassName, stopButtonClassName, renderMic }) {
|
|
1518
|
-
const [value, setValue] =
|
|
1519
|
-
const [interim, setInterim] =
|
|
1843
|
+
const [value, setValue] = useState7("");
|
|
1844
|
+
const [interim, setInterim] = useState7("");
|
|
1520
1845
|
const speech = useSpeechRecognition({
|
|
1521
1846
|
lang: speechLang,
|
|
1522
1847
|
onFinalTranscript: /* @__PURE__ */ __name((text) => {
|
|
@@ -1527,7 +1852,7 @@ function ChatInput({ onSubmit, disabled, placeholder, rows = 2, enableSpeech = t
|
|
|
1527
1852
|
}, "onFinalTranscript"),
|
|
1528
1853
|
onInterimTranscript: /* @__PURE__ */ __name((text) => setInterim(text), "onInterimTranscript")
|
|
1529
1854
|
});
|
|
1530
|
-
|
|
1855
|
+
useEffect7(() => {
|
|
1531
1856
|
if (!speech.isListening) setInterim("");
|
|
1532
1857
|
}, [
|
|
1533
1858
|
speech.isListening
|
|
@@ -1594,7 +1919,7 @@ __name(ChatInput, "ChatInput");
|
|
|
1594
1919
|
import React3 from "react";
|
|
1595
1920
|
|
|
1596
1921
|
// src/transcript/use-chat-transcript.ts
|
|
1597
|
-
import { useCallback as
|
|
1922
|
+
import { useCallback as useCallback7, useEffect as useEffect9, useRef as useRef8, useState as useState9 } from "react";
|
|
1598
1923
|
|
|
1599
1924
|
// src/transcript/model.ts
|
|
1600
1925
|
import { readElicitationInput, validateElicitationAnswer as validateElicitationAnswer2 } from "@dudousxd/nestjs-agent-core";
|
|
@@ -2571,11 +2896,11 @@ function formatCostUsd(cost) {
|
|
|
2571
2896
|
__name(formatCostUsd, "formatCostUsd");
|
|
2572
2897
|
|
|
2573
2898
|
// src/transcript/use-stick-to-bottom.ts
|
|
2574
|
-
import { useCallback as
|
|
2899
|
+
import { useCallback as useCallback6, useEffect as useEffect8, useRef as useRef7, useState as useState8 } from "react";
|
|
2575
2900
|
function useStickToBottom({ contentKey, threshold = 32 }) {
|
|
2576
|
-
const containerRef =
|
|
2577
|
-
const [isAtBottom, setIsAtBottom] =
|
|
2578
|
-
const measure =
|
|
2901
|
+
const containerRef = useRef7(null);
|
|
2902
|
+
const [isAtBottom, setIsAtBottom] = useState8(true);
|
|
2903
|
+
const measure = useCallback6(() => {
|
|
2579
2904
|
const element = containerRef.current;
|
|
2580
2905
|
if (!element) {
|
|
2581
2906
|
return;
|
|
@@ -2585,7 +2910,7 @@ function useStickToBottom({ contentKey, threshold = 32 }) {
|
|
|
2585
2910
|
}, [
|
|
2586
2911
|
threshold
|
|
2587
2912
|
]);
|
|
2588
|
-
const scrollToBottom =
|
|
2913
|
+
const scrollToBottom = useCallback6(() => {
|
|
2589
2914
|
const element = containerRef.current;
|
|
2590
2915
|
if (!element) {
|
|
2591
2916
|
return;
|
|
@@ -2593,7 +2918,7 @@ function useStickToBottom({ contentKey, threshold = 32 }) {
|
|
|
2593
2918
|
element.scrollTop = element.scrollHeight;
|
|
2594
2919
|
setIsAtBottom(true);
|
|
2595
2920
|
}, []);
|
|
2596
|
-
const setContainer =
|
|
2921
|
+
const setContainer = useCallback6((element) => {
|
|
2597
2922
|
containerRef.current = element;
|
|
2598
2923
|
if (element) {
|
|
2599
2924
|
measure();
|
|
@@ -2601,7 +2926,7 @@ function useStickToBottom({ contentKey, threshold = 32 }) {
|
|
|
2601
2926
|
}, [
|
|
2602
2927
|
measure
|
|
2603
2928
|
]);
|
|
2604
|
-
|
|
2929
|
+
useEffect8(() => {
|
|
2605
2930
|
if (isAtBottom) {
|
|
2606
2931
|
scrollToBottom();
|
|
2607
2932
|
}
|
|
@@ -2610,7 +2935,7 @@ function useStickToBottom({ contentKey, threshold = 32 }) {
|
|
|
2610
2935
|
isAtBottom,
|
|
2611
2936
|
scrollToBottom
|
|
2612
2937
|
]);
|
|
2613
|
-
const getContainerProps =
|
|
2938
|
+
const getContainerProps = useCallback6(() => ({
|
|
2614
2939
|
ref: setContainer,
|
|
2615
2940
|
onScroll: measure
|
|
2616
2941
|
}), [
|
|
@@ -2632,14 +2957,14 @@ var DEFAULT_LOAD_EARLIER_STEP = 50;
|
|
|
2632
2957
|
var DEFAULT_COPY_RESET_MS = 1500;
|
|
2633
2958
|
function useChatTranscript(options) {
|
|
2634
2959
|
const { messages, status, initialVisibleCount = DEFAULT_VISIBLE_COUNT, loadEarlierStep = DEFAULT_LOAD_EARLIER_STEP, followUps, stickToBottomThreshold } = options;
|
|
2635
|
-
const latest =
|
|
2960
|
+
const latest = useRef8(options);
|
|
2636
2961
|
latest.current = options;
|
|
2637
|
-
const [visibleCount, setVisibleCount] =
|
|
2638
|
-
const [stopRequested, setStopRequested] =
|
|
2962
|
+
const [visibleCount, setVisibleCount] = useState9(initialVisibleCount);
|
|
2963
|
+
const [stopRequested, setStopRequested] = useState9(false);
|
|
2639
2964
|
const isStreaming = status === "streaming" || status === "reconnecting";
|
|
2640
2965
|
const isBusy = status === "submitted" || isStreaming;
|
|
2641
2966
|
const isEmpty = messages.length === 0;
|
|
2642
|
-
|
|
2967
|
+
useEffect9(() => {
|
|
2643
2968
|
if (!isBusy) {
|
|
2644
2969
|
setStopRequested(false);
|
|
2645
2970
|
}
|
|
@@ -2656,7 +2981,7 @@ function useChatTranscript(options) {
|
|
|
2656
2981
|
streamingMessageId,
|
|
2657
2982
|
options
|
|
2658
2983
|
});
|
|
2659
|
-
const stop =
|
|
2984
|
+
const stop = useCallback7(() => {
|
|
2660
2985
|
const current = latest.current;
|
|
2661
2986
|
if (current.status !== "submitted" && current.status !== "streaming" && current.status !== "reconnecting") {
|
|
2662
2987
|
return;
|
|
@@ -2664,8 +2989,8 @@ function useChatTranscript(options) {
|
|
|
2664
2989
|
setStopRequested(true);
|
|
2665
2990
|
void current.onStop?.();
|
|
2666
2991
|
}, []);
|
|
2667
|
-
const loadEarlier =
|
|
2668
|
-
const showAll =
|
|
2992
|
+
const loadEarlier = useCallback7(() => setVisibleCount((count) => count + (latest.current.loadEarlierStep ?? DEFAULT_LOAD_EARLIER_STEP)), []);
|
|
2993
|
+
const showAll = useCallback7(() => setVisibleCount(latest.current.messages.length), []);
|
|
2669
2994
|
const scroll = useStickToBottom({
|
|
2670
2995
|
contentKey: contentSignature(messages),
|
|
2671
2996
|
...stickToBottomThreshold !== void 0 ? {
|
|
@@ -2701,7 +3026,7 @@ function useChatTranscript(options) {
|
|
|
2701
3026
|
__name(useChatTranscript, "useChatTranscript");
|
|
2702
3027
|
function useTranscriptItem(options) {
|
|
2703
3028
|
const { message, isStreaming = false } = options;
|
|
2704
|
-
const messagesRef =
|
|
3029
|
+
const messagesRef = useRef8([
|
|
2705
3030
|
message
|
|
2706
3031
|
]);
|
|
2707
3032
|
if (messagesRef.current[0] !== message) {
|
|
@@ -2719,13 +3044,13 @@ function useTranscriptItem(options) {
|
|
|
2719
3044
|
}
|
|
2720
3045
|
__name(useTranscriptItem, "useTranscriptItem");
|
|
2721
3046
|
function useTranscriptItems({ messages, visibleStart, streamingMessageId, options }) {
|
|
2722
|
-
const [drafts, setDrafts] =
|
|
2723
|
-
const [copied, setCopied] =
|
|
2724
|
-
const [openReasoning, setOpenReasoning] =
|
|
2725
|
-
const [picks, setPicks] =
|
|
2726
|
-
const [settling, setSettling] =
|
|
2727
|
-
const [settleErrors, setSettleErrors] =
|
|
2728
|
-
const latest =
|
|
3047
|
+
const [drafts, setDrafts] = useState9(() => /* @__PURE__ */ new Map());
|
|
3048
|
+
const [copied, setCopied] = useState9(() => /* @__PURE__ */ new Set());
|
|
3049
|
+
const [openReasoning, setOpenReasoning] = useState9(() => /* @__PURE__ */ new Map());
|
|
3050
|
+
const [picks, setPicks] = useState9(() => /* @__PURE__ */ new Map());
|
|
3051
|
+
const [settling, setSettling] = useState9(() => /* @__PURE__ */ new Map());
|
|
3052
|
+
const [settleErrors, setSettleErrors] = useState9(() => /* @__PURE__ */ new Map());
|
|
3053
|
+
const latest = useRef8({
|
|
2729
3054
|
options,
|
|
2730
3055
|
drafts,
|
|
2731
3056
|
picks,
|
|
@@ -2737,23 +3062,23 @@ function useTranscriptItems({ messages, visibleStart, streamingMessageId, option
|
|
|
2737
3062
|
picks,
|
|
2738
3063
|
messages
|
|
2739
3064
|
};
|
|
2740
|
-
const copyTimers =
|
|
2741
|
-
|
|
3065
|
+
const copyTimers = useRef8(/* @__PURE__ */ new Map());
|
|
3066
|
+
useEffect9(() => () => {
|
|
2742
3067
|
for (const timer of copyTimers.current.values()) {
|
|
2743
3068
|
clearTimeout(timer);
|
|
2744
3069
|
}
|
|
2745
3070
|
copyTimers.current.clear();
|
|
2746
3071
|
}, []);
|
|
2747
|
-
const callbackCache =
|
|
2748
|
-
const reasoningToggleCache =
|
|
2749
|
-
const toggleReasoning =
|
|
3072
|
+
const callbackCache = useRef8(/* @__PURE__ */ new Map());
|
|
3073
|
+
const reasoningToggleCache = useRef8(/* @__PURE__ */ new Map());
|
|
3074
|
+
const toggleReasoning = useCallback7((key, open) => {
|
|
2750
3075
|
setOpenReasoning((current) => {
|
|
2751
3076
|
const next = new Map(current);
|
|
2752
3077
|
next.set(key, open ?? !(current.get(key) ?? false));
|
|
2753
3078
|
return next;
|
|
2754
3079
|
});
|
|
2755
3080
|
}, []);
|
|
2756
|
-
const stableToggle =
|
|
3081
|
+
const stableToggle = useCallback7((key) => {
|
|
2757
3082
|
let cached = reasoningToggleCache.current.get(key);
|
|
2758
3083
|
if (!cached) {
|
|
2759
3084
|
cached = /* @__PURE__ */ __name((open) => toggleReasoning(key, open), "cached");
|
|
@@ -2763,10 +3088,10 @@ function useTranscriptItems({ messages, visibleStart, streamingMessageId, option
|
|
|
2763
3088
|
}, [
|
|
2764
3089
|
toggleReasoning
|
|
2765
3090
|
]);
|
|
2766
|
-
const pick =
|
|
3091
|
+
const pick = useCallback7((toolCallId, questionId, values) => {
|
|
2767
3092
|
setPicks((current) => new Map(current).set(pickKey(toolCallId, questionId), values));
|
|
2768
3093
|
}, []);
|
|
2769
|
-
const settle =
|
|
3094
|
+
const settle = useCallback7((toolCallId, action, send) => {
|
|
2770
3095
|
setSettleErrors((current) => {
|
|
2771
3096
|
if (!current.has(toolCallId)) {
|
|
2772
3097
|
return current;
|
|
@@ -2790,7 +3115,7 @@ function useTranscriptItems({ messages, visibleStart, streamingMessageId, option
|
|
|
2790
3115
|
failed(error);
|
|
2791
3116
|
}
|
|
2792
3117
|
}, []);
|
|
2793
|
-
const answer =
|
|
3118
|
+
const answer = useCallback7((toolCallId) => {
|
|
2794
3119
|
const current = latest.current;
|
|
2795
3120
|
const onAnswer = current.options.onAnswer;
|
|
2796
3121
|
if (!onAnswer) {
|
|
@@ -2800,7 +3125,7 @@ function useTranscriptItems({ messages, visibleStart, streamingMessageId, option
|
|
|
2800
3125
|
}, [
|
|
2801
3126
|
settle
|
|
2802
3127
|
]);
|
|
2803
|
-
const skip =
|
|
3128
|
+
const skip = useCallback7((toolCallId) => {
|
|
2804
3129
|
const onSkip = latest.current.options.onSkip;
|
|
2805
3130
|
if (onSkip) {
|
|
2806
3131
|
settle(toolCallId, "skip", () => onSkip(toolCallId));
|
|
@@ -2808,7 +3133,7 @@ function useTranscriptItems({ messages, visibleStart, streamingMessageId, option
|
|
|
2808
3133
|
}, [
|
|
2809
3134
|
settle
|
|
2810
3135
|
]);
|
|
2811
|
-
const approve =
|
|
3136
|
+
const approve = useCallback7((toolCallId, options2) => {
|
|
2812
3137
|
const onApprove = latest.current.options.onApprove;
|
|
2813
3138
|
if (onApprove) {
|
|
2814
3139
|
settle(toolCallId, "approve", () => options2 === void 0 ? onApprove(toolCallId) : onApprove(toolCallId, options2));
|
|
@@ -2816,7 +3141,7 @@ function useTranscriptItems({ messages, visibleStart, streamingMessageId, option
|
|
|
2816
3141
|
}, [
|
|
2817
3142
|
settle
|
|
2818
3143
|
]);
|
|
2819
|
-
const reject =
|
|
3144
|
+
const reject = useCallback7((toolCallId) => {
|
|
2820
3145
|
const onReject = latest.current.options.onReject;
|
|
2821
3146
|
if (onReject) {
|
|
2822
3147
|
settle(toolCallId, "reject", () => onReject(toolCallId));
|
|
@@ -2824,7 +3149,7 @@ function useTranscriptItems({ messages, visibleStart, streamingMessageId, option
|
|
|
2824
3149
|
}, [
|
|
2825
3150
|
settle
|
|
2826
3151
|
]);
|
|
2827
|
-
const callbacksFor =
|
|
3152
|
+
const callbacksFor = useCallback7((id) => {
|
|
2828
3153
|
const cached = callbackCache.current.get(id);
|
|
2829
3154
|
if (cached) {
|
|
2830
3155
|
return cached;
|
|
@@ -3481,35 +3806,35 @@ function toItem(entry) {
|
|
|
3481
3806
|
__name(toItem, "toItem");
|
|
3482
3807
|
|
|
3483
3808
|
// src/composer/use-composer-autocomplete.ts
|
|
3484
|
-
import { useCallback as
|
|
3809
|
+
import { useCallback as useCallback8, useEffect as useEffect10, useId, useLayoutEffect, useMemo as useMemo6, useRef as useRef9, useState as useState10 } from "react";
|
|
3485
3810
|
function useComposerAutocomplete(options) {
|
|
3486
3811
|
const { value, sources, acceptOnTab = true } = options;
|
|
3487
|
-
const latest =
|
|
3812
|
+
const latest = useRef9(options);
|
|
3488
3813
|
latest.current = options;
|
|
3489
|
-
const inputRef =
|
|
3490
|
-
const [caret, setCaret] =
|
|
3491
|
-
const [items, setItems] =
|
|
3492
|
-
const [isLoading, setLoading] =
|
|
3493
|
-
const [error, setError] =
|
|
3494
|
-
const [activeIndex, setActiveIndex] =
|
|
3495
|
-
const [dismissedIndex, setDismissedIndex] =
|
|
3814
|
+
const inputRef = useRef9(null);
|
|
3815
|
+
const [caret, setCaret] = useState10(value.length);
|
|
3816
|
+
const [items, setItems] = useState10([]);
|
|
3817
|
+
const [isLoading, setLoading] = useState10(false);
|
|
3818
|
+
const [error, setError] = useState10(null);
|
|
3819
|
+
const [activeIndex, setActiveIndex] = useState10(0);
|
|
3820
|
+
const [dismissedIndex, setDismissedIndex] = useState10(null);
|
|
3496
3821
|
const safeCaret = Math.min(caret, value.length);
|
|
3497
|
-
const match =
|
|
3822
|
+
const match = useMemo6(() => findActiveTrigger(value, safeCaret, sources), [
|
|
3498
3823
|
value,
|
|
3499
3824
|
safeCaret,
|
|
3500
3825
|
sources
|
|
3501
3826
|
]);
|
|
3502
3827
|
const isActive = match !== null && dismissedIndex !== match.index;
|
|
3503
|
-
const matchRef =
|
|
3828
|
+
const matchRef = useRef9(match);
|
|
3504
3829
|
matchRef.current = match;
|
|
3505
|
-
const caretRef =
|
|
3830
|
+
const caretRef = useRef9(safeCaret);
|
|
3506
3831
|
caretRef.current = safeCaret;
|
|
3507
|
-
const itemsRef =
|
|
3832
|
+
const itemsRef = useRef9(items);
|
|
3508
3833
|
itemsRef.current = items;
|
|
3509
|
-
const activeIndexRef =
|
|
3834
|
+
const activeIndexRef = useRef9(activeIndex);
|
|
3510
3835
|
activeIndexRef.current = activeIndex;
|
|
3511
3836
|
const requestKey = isActive && match ? `${match.source.id}\0${match.query}` : null;
|
|
3512
|
-
|
|
3837
|
+
useEffect10(() => {
|
|
3513
3838
|
const current = matchRef.current;
|
|
3514
3839
|
if (requestKey === null || current === null) {
|
|
3515
3840
|
setItems([]);
|
|
@@ -3559,23 +3884,23 @@ function useComposerAutocomplete(options) {
|
|
|
3559
3884
|
const activeItem = isOpen ? items[activeIndex] ?? null : null;
|
|
3560
3885
|
const reactId = useId();
|
|
3561
3886
|
const listboxId = options.id ?? `agent-autocomplete-${reactId}`;
|
|
3562
|
-
const optionId =
|
|
3887
|
+
const optionId = useCallback8((index) => `${listboxId}-option-${index}`, [
|
|
3563
3888
|
listboxId
|
|
3564
3889
|
]);
|
|
3565
|
-
const highlight =
|
|
3890
|
+
const highlight = useCallback8((index) => {
|
|
3566
3891
|
const total = itemsRef.current.length;
|
|
3567
3892
|
if (total === 0) return;
|
|
3568
3893
|
setActiveIndex((index % total + total) % total);
|
|
3569
3894
|
}, []);
|
|
3570
|
-
const moveHighlight =
|
|
3895
|
+
const moveHighlight = useCallback8((delta) => highlight(activeIndexRef.current + delta), [
|
|
3571
3896
|
highlight
|
|
3572
3897
|
]);
|
|
3573
|
-
const dismiss =
|
|
3898
|
+
const dismiss = useCallback8(() => {
|
|
3574
3899
|
const current = matchRef.current;
|
|
3575
3900
|
if (current) setDismissedIndex(current.index);
|
|
3576
3901
|
}, []);
|
|
3577
|
-
const pendingCaret =
|
|
3578
|
-
const accept =
|
|
3902
|
+
const pendingCaret = useRef9(null);
|
|
3903
|
+
const accept = useCallback8((item) => {
|
|
3579
3904
|
const current = matchRef.current;
|
|
3580
3905
|
if (!current) return;
|
|
3581
3906
|
const chosen = item ?? itemsRef.current[activeIndexRef.current];
|
|
@@ -3592,10 +3917,10 @@ function useComposerAutocomplete(options) {
|
|
|
3592
3917
|
pendingCaret.current = null;
|
|
3593
3918
|
inputRef.current?.setSelectionRange(position, position);
|
|
3594
3919
|
});
|
|
3595
|
-
const readCaret =
|
|
3920
|
+
const readCaret = useCallback8((element) => {
|
|
3596
3921
|
setCaret(element.selectionStart ?? element.value.length);
|
|
3597
3922
|
}, []);
|
|
3598
|
-
const onKeyDown =
|
|
3923
|
+
const onKeyDown = useCallback8((event) => {
|
|
3599
3924
|
if (!isOpen) return;
|
|
3600
3925
|
const hasItems = itemsRef.current.length > 0;
|
|
3601
3926
|
switch (event.key) {
|
|
@@ -3633,23 +3958,23 @@ function useComposerAutocomplete(options) {
|
|
|
3633
3958
|
dismiss,
|
|
3634
3959
|
moveHighlight
|
|
3635
3960
|
]);
|
|
3636
|
-
const onChange =
|
|
3961
|
+
const onChange = useCallback8((event) => {
|
|
3637
3962
|
readCaret(event.target);
|
|
3638
3963
|
const next = findActiveTrigger(event.target.value, event.target.selectionStart ?? event.target.value.length, latest.current.sources);
|
|
3639
3964
|
setDismissedIndex((current) => current !== null && next?.index === current ? current : null);
|
|
3640
3965
|
}, [
|
|
3641
3966
|
readCaret
|
|
3642
3967
|
]);
|
|
3643
|
-
const onSelect =
|
|
3968
|
+
const onSelect = useCallback8((event) => readCaret(event.currentTarget), [
|
|
3644
3969
|
readCaret
|
|
3645
3970
|
]);
|
|
3646
|
-
const onClick =
|
|
3971
|
+
const onClick = useCallback8((event) => readCaret(event.currentTarget), [
|
|
3647
3972
|
readCaret
|
|
3648
3973
|
]);
|
|
3649
|
-
const setInput =
|
|
3974
|
+
const setInput = useCallback8((element) => {
|
|
3650
3975
|
inputRef.current = element;
|
|
3651
3976
|
}, []);
|
|
3652
|
-
const getInputProps =
|
|
3977
|
+
const getInputProps = useCallback8(() => ({
|
|
3653
3978
|
ref: setInput,
|
|
3654
3979
|
onChange,
|
|
3655
3980
|
onKeyDown,
|
|
@@ -3677,7 +4002,7 @@ function useComposerAutocomplete(options) {
|
|
|
3677
4002
|
activeIndex,
|
|
3678
4003
|
optionId
|
|
3679
4004
|
]);
|
|
3680
|
-
const getListboxProps =
|
|
4005
|
+
const getListboxProps = useCallback8(() => ({
|
|
3681
4006
|
id: listboxId,
|
|
3682
4007
|
role: "listbox",
|
|
3683
4008
|
"aria-label": match?.source.label ?? match?.source.id ?? "Suggestions"
|
|
@@ -3685,7 +4010,7 @@ function useComposerAutocomplete(options) {
|
|
|
3685
4010
|
listboxId,
|
|
3686
4011
|
match
|
|
3687
4012
|
]);
|
|
3688
|
-
const getOptionProps =
|
|
4013
|
+
const getOptionProps = useCallback8((index) => ({
|
|
3689
4014
|
id: optionId(index),
|
|
3690
4015
|
role: "option",
|
|
3691
4016
|
"aria-selected": index === activeIndex
|
|
@@ -3719,7 +4044,7 @@ function isPromise(value) {
|
|
|
3719
4044
|
__name(isPromise, "isPromise");
|
|
3720
4045
|
|
|
3721
4046
|
// src/presentation/use-tool-catalog.ts
|
|
3722
|
-
import { useCallback as
|
|
4047
|
+
import { useCallback as useCallback9, useEffect as useEffect11, useMemo as useMemo7, useState as useState11 } from "react";
|
|
3723
4048
|
var shared = /* @__PURE__ */ new WeakMap();
|
|
3724
4049
|
function load(client, agent) {
|
|
3725
4050
|
let byAgent = shared.get(client);
|
|
@@ -3743,11 +4068,11 @@ function load(client, agent) {
|
|
|
3743
4068
|
__name(load, "load");
|
|
3744
4069
|
function useToolCatalog(options) {
|
|
3745
4070
|
const { client, agent, enabled = true } = options;
|
|
3746
|
-
const [entries, setEntries] =
|
|
3747
|
-
const [isLoading, setLoading] =
|
|
3748
|
-
const [error, setError] =
|
|
3749
|
-
const [generation, setGeneration] =
|
|
3750
|
-
|
|
4071
|
+
const [entries, setEntries] = useState11([]);
|
|
4072
|
+
const [isLoading, setLoading] = useState11(enabled);
|
|
4073
|
+
const [error, setError] = useState11(null);
|
|
4074
|
+
const [generation, setGeneration] = useState11(0);
|
|
4075
|
+
useEffect11(() => {
|
|
3751
4076
|
if (!enabled) {
|
|
3752
4077
|
setLoading(false);
|
|
3753
4078
|
return;
|
|
@@ -3773,14 +4098,14 @@ function useToolCatalog(options) {
|
|
|
3773
4098
|
enabled,
|
|
3774
4099
|
generation
|
|
3775
4100
|
]);
|
|
3776
|
-
const refresh =
|
|
4101
|
+
const refresh = useCallback9(() => {
|
|
3777
4102
|
shared.get(client)?.delete(agent ?? "");
|
|
3778
4103
|
setGeneration((current) => current + 1);
|
|
3779
4104
|
}, [
|
|
3780
4105
|
client,
|
|
3781
4106
|
agent
|
|
3782
4107
|
]);
|
|
3783
|
-
const catalog =
|
|
4108
|
+
const catalog = useMemo7(() => toolCatalogFrom(entries), [
|
|
3784
4109
|
entries
|
|
3785
4110
|
]);
|
|
3786
4111
|
return {
|
|
@@ -3794,7 +4119,7 @@ function useToolCatalog(options) {
|
|
|
3794
4119
|
__name(useToolCatalog, "useToolCatalog");
|
|
3795
4120
|
|
|
3796
4121
|
// src/approvals/countdown.ts
|
|
3797
|
-
import { useEffect as
|
|
4122
|
+
import { useEffect as useEffect12, useRef as useRef10, useState as useState12 } from "react";
|
|
3798
4123
|
function approvalCountdown(expiresAt, now = Date.now()) {
|
|
3799
4124
|
const deadline = expiresAt == null ? Number.NaN : Date.parse(expiresAt);
|
|
3800
4125
|
if (!Number.isFinite(deadline)) {
|
|
@@ -3812,10 +4137,10 @@ function approvalCountdown(expiresAt, now = Date.now()) {
|
|
|
3812
4137
|
__name(approvalCountdown, "approvalCountdown");
|
|
3813
4138
|
function useApprovalCountdown(expiresAt, options = {}) {
|
|
3814
4139
|
const { intervalMs = 1e3 } = options;
|
|
3815
|
-
const nowRef =
|
|
4140
|
+
const nowRef = useRef10(options.now ?? Date.now);
|
|
3816
4141
|
nowRef.current = options.now ?? Date.now;
|
|
3817
|
-
const [state, setState] =
|
|
3818
|
-
|
|
4142
|
+
const [state, setState] = useState12(() => approvalCountdown(expiresAt, nowRef.current()));
|
|
4143
|
+
useEffect12(() => {
|
|
3819
4144
|
const read = /* @__PURE__ */ __name(() => approvalCountdown(expiresAt, nowRef.current()), "read");
|
|
3820
4145
|
const first = read();
|
|
3821
4146
|
setState(first);
|
|
@@ -3878,7 +4203,13 @@ function storedMessageToUiMessage(message) {
|
|
|
3878
4203
|
type: "file",
|
|
3879
4204
|
mediaType: attachment.contentType,
|
|
3880
4205
|
filename: attachment.name,
|
|
3881
|
-
url: attachment.url
|
|
4206
|
+
url: attachment.url,
|
|
4207
|
+
// The stored id rides along, so a replayed file can be referenced again (`messageFiles`).
|
|
4208
|
+
providerMetadata: {
|
|
4209
|
+
agent: {
|
|
4210
|
+
mediaId: attachment.mediaId
|
|
4211
|
+
}
|
|
4212
|
+
}
|
|
3882
4213
|
});
|
|
3883
4214
|
}
|
|
3884
4215
|
const toolCallIds = new Set((message.toolCalls ?? []).map((call) => call.id));
|
|
@@ -4057,20 +4388,20 @@ __name(sumUsage, "sumUsage");
|
|
|
4057
4388
|
|
|
4058
4389
|
// src/use-agent-chat.ts
|
|
4059
4390
|
import { useChat } from "@ai-sdk/react";
|
|
4060
|
-
import { useCallback as
|
|
4391
|
+
import { useCallback as useCallback10, useEffect as useEffect13, useMemo as useMemo8, useRef as useRef11, useState as useState13 } from "react";
|
|
4061
4392
|
function useAgentChat(options) {
|
|
4062
|
-
const latest =
|
|
4393
|
+
const latest = useRef11(options);
|
|
4063
4394
|
latest.current = options;
|
|
4064
|
-
const [runId, setRunId] =
|
|
4065
|
-
const runIdRef =
|
|
4395
|
+
const [runId, setRunId] = useState13(options.resumeRunId);
|
|
4396
|
+
const runIdRef = useRef11(runId);
|
|
4066
4397
|
runIdRef.current = runId;
|
|
4067
|
-
const settlingRunIdRef =
|
|
4068
|
-
const autoResumeRunIdRef =
|
|
4069
|
-
const [autoResume, setAutoResume] =
|
|
4070
|
-
const [activeRunId, setActiveRunId] =
|
|
4071
|
-
const regenerateNext =
|
|
4072
|
-
const createdThreadId =
|
|
4073
|
-
const client =
|
|
4398
|
+
const settlingRunIdRef = useRef11(void 0);
|
|
4399
|
+
const autoResumeRunIdRef = useRef11(void 0);
|
|
4400
|
+
const [autoResume, setAutoResume] = useState13(false);
|
|
4401
|
+
const [activeRunId, setActiveRunId] = useState13(null);
|
|
4402
|
+
const regenerateNext = useRef11(false);
|
|
4403
|
+
const createdThreadId = useRef11(void 0);
|
|
4404
|
+
const client = useMemo8(() => {
|
|
4074
4405
|
if (options.backend) return options.backend;
|
|
4075
4406
|
if (options.client) return options.client;
|
|
4076
4407
|
return new AgentClient({
|
|
@@ -4086,11 +4417,11 @@ function useAgentChat(options) {
|
|
|
4086
4417
|
getHeaders: /* @__PURE__ */ __name(async () => mergeHeaders(latest.current), "getHeaders")
|
|
4087
4418
|
});
|
|
4088
4419
|
}, []);
|
|
4089
|
-
const [connection, setConnection] =
|
|
4420
|
+
const [connection, setConnection] = useState13({
|
|
4090
4421
|
status: "live"
|
|
4091
4422
|
});
|
|
4092
|
-
const resyncAfterSettle =
|
|
4093
|
-
|
|
4423
|
+
const resyncAfterSettle = useRef11(false);
|
|
4424
|
+
useEffect13(() => {
|
|
4094
4425
|
if (!options.resume || options.threadId === void 0) return;
|
|
4095
4426
|
let cancelled = false;
|
|
4096
4427
|
const threadId = options.threadId;
|
|
@@ -4110,7 +4441,7 @@ function useAgentChat(options) {
|
|
|
4110
4441
|
options.resume,
|
|
4111
4442
|
options.threadId
|
|
4112
4443
|
]);
|
|
4113
|
-
const transport =
|
|
4444
|
+
const transport = useMemo8(() => {
|
|
4114
4445
|
function onMeta(meta) {
|
|
4115
4446
|
settlingRunIdRef.current = meta.runId;
|
|
4116
4447
|
setRunId(meta.runId);
|
|
@@ -4165,7 +4496,7 @@ function useAgentChat(options) {
|
|
|
4165
4496
|
}, "onAttemptStart")
|
|
4166
4497
|
});
|
|
4167
4498
|
}, []);
|
|
4168
|
-
const backgroundRef =
|
|
4499
|
+
const backgroundRef = useRef11(() => Promise.resolve());
|
|
4169
4500
|
const chat = useChat({
|
|
4170
4501
|
transport,
|
|
4171
4502
|
resume: options.resumeRunId !== void 0 || autoResume,
|
|
@@ -4214,7 +4545,7 @@ function useAgentChat(options) {
|
|
|
4214
4545
|
}
|
|
4215
4546
|
}, "onFinish")
|
|
4216
4547
|
});
|
|
4217
|
-
const chatRef =
|
|
4548
|
+
const chatRef = useRef11(chat);
|
|
4218
4549
|
chatRef.current = chat;
|
|
4219
4550
|
async function resyncFromThread() {
|
|
4220
4551
|
const threadId = latest.current.threadId ?? createdThreadId.current;
|
|
@@ -4226,11 +4557,11 @@ function useAgentChat(options) {
|
|
|
4226
4557
|
}
|
|
4227
4558
|
}
|
|
4228
4559
|
__name(resyncFromThread, "resyncFromThread");
|
|
4229
|
-
const turnInFlight =
|
|
4230
|
-
const isTurnInFlight =
|
|
4560
|
+
const turnInFlight = useRef11(false);
|
|
4561
|
+
const isTurnInFlight = useCallback10(() => turnInFlight.current || transport.isAttemptLive, [
|
|
4231
4562
|
transport
|
|
4232
4563
|
]);
|
|
4233
|
-
const sendMessage =
|
|
4564
|
+
const sendMessage = useCallback10(async (...args) => {
|
|
4234
4565
|
const blocked = latest.current.blocked;
|
|
4235
4566
|
if (blocked != null) throw new QuotaBlockedError(blocked);
|
|
4236
4567
|
if (isTurnInFlight()) return;
|
|
@@ -4243,15 +4574,15 @@ function useAgentChat(options) {
|
|
|
4243
4574
|
}, [
|
|
4244
4575
|
isTurnInFlight
|
|
4245
4576
|
]);
|
|
4246
|
-
const addToolResult =
|
|
4577
|
+
const addToolResult = useCallback10(({ tool, toolCallId, output }) => chatRef.current.addToolResult({
|
|
4247
4578
|
tool,
|
|
4248
4579
|
toolCallId,
|
|
4249
4580
|
output
|
|
4250
4581
|
}), []);
|
|
4251
|
-
const [threads, setThreads] =
|
|
4252
|
-
const [quota, setQuota] =
|
|
4253
|
-
const [backgroundRuns, setBackgroundRuns] =
|
|
4254
|
-
const refreshBackground =
|
|
4582
|
+
const [threads, setThreads] = useState13([]);
|
|
4583
|
+
const [quota, setQuota] = useState13(null);
|
|
4584
|
+
const [backgroundRuns, setBackgroundRuns] = useState13([]);
|
|
4585
|
+
const refreshBackground = useCallback10(async () => {
|
|
4255
4586
|
const threadId = latest.current.threadId ?? createdThreadId.current;
|
|
4256
4587
|
if (threadId === void 0) {
|
|
4257
4588
|
return;
|
|
@@ -4276,7 +4607,7 @@ function useAgentChat(options) {
|
|
|
4276
4607
|
]);
|
|
4277
4608
|
backgroundRef.current = refreshBackground;
|
|
4278
4609
|
const isWorking = backgroundRuns.some((run) => run.status === "running");
|
|
4279
|
-
|
|
4610
|
+
useEffect13(() => {
|
|
4280
4611
|
if (options.background !== true || options.threadId === void 0) {
|
|
4281
4612
|
return;
|
|
4282
4613
|
}
|
|
@@ -4286,7 +4617,7 @@ function useAgentChat(options) {
|
|
|
4286
4617
|
options.threadId,
|
|
4287
4618
|
refreshBackground
|
|
4288
4619
|
]);
|
|
4289
|
-
|
|
4620
|
+
useEffect13(() => {
|
|
4290
4621
|
const every = latest.current.backgroundPollMs ?? 5e3;
|
|
4291
4622
|
if (latest.current.background !== true || !isWorking || every <= 0) {
|
|
4292
4623
|
return;
|
|
@@ -4297,26 +4628,26 @@ function useAgentChat(options) {
|
|
|
4297
4628
|
isWorking,
|
|
4298
4629
|
refreshBackground
|
|
4299
4630
|
]);
|
|
4300
|
-
const loadThreads =
|
|
4631
|
+
const loadThreads = useCallback10(async () => {
|
|
4301
4632
|
const list = await client.listThreads();
|
|
4302
4633
|
setThreads(list);
|
|
4303
4634
|
return list;
|
|
4304
4635
|
}, [
|
|
4305
4636
|
client
|
|
4306
4637
|
]);
|
|
4307
|
-
const loadThread =
|
|
4638
|
+
const loadThread = useCallback10((id) => client.getThread(id), [
|
|
4308
4639
|
client
|
|
4309
4640
|
]);
|
|
4310
|
-
const deleteThread =
|
|
4641
|
+
const deleteThread = useCallback10(async (id) => {
|
|
4311
4642
|
await client.deleteThread(id);
|
|
4312
4643
|
setThreads((current) => current.filter((thread) => thread.id !== id));
|
|
4313
4644
|
}, [
|
|
4314
4645
|
client
|
|
4315
4646
|
]);
|
|
4316
|
-
const forkThread =
|
|
4647
|
+
const forkThread = useCallback10((threadId, messageId) => requireBackendMethod(client, "forkFromMessage")(threadId, messageId), [
|
|
4317
4648
|
client
|
|
4318
4649
|
]);
|
|
4319
|
-
const renameThread =
|
|
4650
|
+
const renameThread = useCallback10(async (id, title) => {
|
|
4320
4651
|
await client.updateThread(id, {
|
|
4321
4652
|
title
|
|
4322
4653
|
});
|
|
@@ -4327,24 +4658,24 @@ function useAgentChat(options) {
|
|
|
4327
4658
|
}, [
|
|
4328
4659
|
client
|
|
4329
4660
|
]);
|
|
4330
|
-
const promoteThread =
|
|
4661
|
+
const promoteThread = useCallback10(async (id) => {
|
|
4331
4662
|
await requireBackendMethod(client, "promoteThread")(id);
|
|
4332
4663
|
await loadThreads();
|
|
4333
4664
|
}, [
|
|
4334
4665
|
client,
|
|
4335
4666
|
loadThreads
|
|
4336
4667
|
]);
|
|
4337
|
-
const truncateFromMessage =
|
|
4668
|
+
const truncateFromMessage = useCallback10((threadId, messageId) => requireBackendMethod(client, "truncateFromMessage")(threadId, messageId).then(() => void 0), [
|
|
4338
4669
|
client
|
|
4339
4670
|
]);
|
|
4340
|
-
const loadQuota =
|
|
4671
|
+
const loadQuota = useCallback10(async () => {
|
|
4341
4672
|
const today = await requireBackendMethod(client, "getQuotaToday")();
|
|
4342
4673
|
setQuota(today);
|
|
4343
4674
|
return today;
|
|
4344
4675
|
}, [
|
|
4345
4676
|
client
|
|
4346
4677
|
]);
|
|
4347
|
-
const cancel =
|
|
4678
|
+
const cancel = useCallback10(async () => {
|
|
4348
4679
|
chatRef.current.stop();
|
|
4349
4680
|
const activeRunId2 = runIdRef.current;
|
|
4350
4681
|
if (activeRunId2) {
|
|
@@ -4356,7 +4687,7 @@ function useAgentChat(options) {
|
|
|
4356
4687
|
}, [
|
|
4357
4688
|
client
|
|
4358
4689
|
]);
|
|
4359
|
-
const approve =
|
|
4690
|
+
const approve = useCallback10(async ({ toolCallId, remember, via }) => {
|
|
4360
4691
|
await requireBackendMethod(client, "approveToolCall")({
|
|
4361
4692
|
toolCallId,
|
|
4362
4693
|
...remember === true ? {
|
|
@@ -4369,7 +4700,7 @@ function useAgentChat(options) {
|
|
|
4369
4700
|
}, [
|
|
4370
4701
|
client
|
|
4371
4702
|
]);
|
|
4372
|
-
const reject =
|
|
4703
|
+
const reject = useCallback10(async ({ toolCallId, reason, via }) => {
|
|
4373
4704
|
await requireBackendMethod(client, "rejectToolCall")({
|
|
4374
4705
|
toolCallId,
|
|
4375
4706
|
...reason !== void 0 ? {
|
|
@@ -4382,7 +4713,7 @@ function useAgentChat(options) {
|
|
|
4382
4713
|
}, [
|
|
4383
4714
|
client
|
|
4384
4715
|
]);
|
|
4385
|
-
const answer =
|
|
4716
|
+
const answer = useCallback10(async ({ toolCallId, answers }) => {
|
|
4386
4717
|
await requireBackendMethod(client, "answerToolCall")({
|
|
4387
4718
|
toolCallId,
|
|
4388
4719
|
...answers !== void 0 ? {
|
|
@@ -4392,14 +4723,14 @@ function useAgentChat(options) {
|
|
|
4392
4723
|
}, [
|
|
4393
4724
|
client
|
|
4394
4725
|
]);
|
|
4395
|
-
const skip =
|
|
4726
|
+
const skip = useCallback10(async ({ toolCallId }) => {
|
|
4396
4727
|
await requireBackendMethod(client, "skipToolCall")({
|
|
4397
4728
|
toolCallId
|
|
4398
4729
|
});
|
|
4399
4730
|
}, [
|
|
4400
4731
|
client
|
|
4401
4732
|
]);
|
|
4402
|
-
const regenerate =
|
|
4733
|
+
const regenerate = useCallback10(() => {
|
|
4403
4734
|
const blocked = latest.current.blocked;
|
|
4404
4735
|
if (blocked != null) throw new QuotaBlockedError(blocked);
|
|
4405
4736
|
if (isTurnInFlight()) return;
|
|
@@ -4416,7 +4747,7 @@ function useAgentChat(options) {
|
|
|
4416
4747
|
isWorking,
|
|
4417
4748
|
refresh: refreshBackground
|
|
4418
4749
|
};
|
|
4419
|
-
const setThreadModel =
|
|
4750
|
+
const setThreadModel = useCallback10(async (model) => {
|
|
4420
4751
|
const threadId = latest.current.threadId ?? createdThreadId.current;
|
|
4421
4752
|
if (threadId === void 0) {
|
|
4422
4753
|
throw new Error("setThreadModel: this chat has no thread yet");
|
|
@@ -4430,7 +4761,7 @@ function useAgentChat(options) {
|
|
|
4430
4761
|
}, [
|
|
4431
4762
|
client
|
|
4432
4763
|
]);
|
|
4433
|
-
const getThreadId =
|
|
4764
|
+
const getThreadId = useCallback10(() => latest.current.threadId ?? createdThreadId.current, []);
|
|
4434
4765
|
const status = connection.status === "reconnecting" ? "reconnecting" : chat.status;
|
|
4435
4766
|
return {
|
|
4436
4767
|
...chat,
|
|
@@ -4503,6 +4834,7 @@ export {
|
|
|
4503
4834
|
MessageList,
|
|
4504
4835
|
QuotaBlockedError,
|
|
4505
4836
|
SPEECH_LANGUAGES,
|
|
4837
|
+
acceptsFile,
|
|
4506
4838
|
applyCompletion,
|
|
4507
4839
|
approvalCountdown,
|
|
4508
4840
|
backgroundRunsFromThread,
|
|
@@ -4513,7 +4845,10 @@ export {
|
|
|
4513
4845
|
describeTimestamp,
|
|
4514
4846
|
describeToolCall,
|
|
4515
4847
|
describeUsage,
|
|
4848
|
+
dragHasFiles,
|
|
4516
4849
|
extractMessageText,
|
|
4850
|
+
fileKind,
|
|
4851
|
+
filesFromClipboard,
|
|
4517
4852
|
fillTemplate,
|
|
4518
4853
|
filterAutocompleteItems,
|
|
4519
4854
|
findActiveTrigger,
|
|
@@ -4523,6 +4858,7 @@ export {
|
|
|
4523
4858
|
inferResultView,
|
|
4524
4859
|
isActionCall,
|
|
4525
4860
|
loadStoredSpeechLang,
|
|
4861
|
+
messageFiles,
|
|
4526
4862
|
notifyThreads,
|
|
4527
4863
|
onThreadsEvent,
|
|
4528
4864
|
persistSpeechLang,
|
|
@@ -4538,6 +4874,7 @@ export {
|
|
|
4538
4874
|
useAgentChat,
|
|
4539
4875
|
useAgents,
|
|
4540
4876
|
useApprovalCountdown,
|
|
4877
|
+
useAttachments,
|
|
4541
4878
|
useChatTranscript,
|
|
4542
4879
|
useComposerAutocomplete,
|
|
4543
4880
|
useElapsed,
|