@dudousxd/nestjs-agent-react 0.15.0 → 0.17.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 +46 -0
- package/dist/index.cjs +415 -215
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +118 -3
- package/dist/index.d.ts +118 -3
- package/dist/index.js +373 -177
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -147,6 +147,19 @@ var AgentClient = class {
|
|
|
147
147
|
truncateFromMessage(threadId, messageId) {
|
|
148
148
|
return this.request("DELETE", `/agent/threads/${encodeURIComponent(threadId)}/from/${encodeURIComponent(messageId)}`);
|
|
149
149
|
}
|
|
150
|
+
/** `GET /agent/models?agent=` — the models this caller may pick, grouped by provider. */
|
|
151
|
+
listModels(agent) {
|
|
152
|
+
const query = agent === void 0 ? "" : `?agent=${encodeURIComponent(agent)}`;
|
|
153
|
+
return this.request("GET", `/agent/models${query}`);
|
|
154
|
+
}
|
|
155
|
+
/** `GET /agent/agents` — the registered agents, the default one flagged. */
|
|
156
|
+
listAgents() {
|
|
157
|
+
return this.request("GET", "/agent/agents");
|
|
158
|
+
}
|
|
159
|
+
/** `GET /agent/quota` — the caller's budget windows and the one blocking sends, if any. */
|
|
160
|
+
getQuota() {
|
|
161
|
+
return this.request("GET", "/agent/quota");
|
|
162
|
+
}
|
|
150
163
|
getQuotaToday() {
|
|
151
164
|
return this.request("GET", "/agent/quota/today");
|
|
152
165
|
}
|
|
@@ -994,28 +1007,196 @@ function requireBackendMethod(backend, name) {
|
|
|
994
1007
|
}
|
|
995
1008
|
__name(requireBackendMethod, "requireBackendMethod");
|
|
996
1009
|
|
|
1010
|
+
// src/catalog/use-agents.ts
|
|
1011
|
+
import { useMemo } from "react";
|
|
1012
|
+
|
|
1013
|
+
// src/catalog/use-resource.ts
|
|
1014
|
+
import { useCallback, useEffect as useEffect2, useRef as useRef2, useState as useState2 } from "react";
|
|
1015
|
+
function useResource(load2, key, enabled) {
|
|
1016
|
+
const [data, setData] = useState2(void 0);
|
|
1017
|
+
const [isLoading, setIsLoading] = useState2(enabled);
|
|
1018
|
+
const [error, setError] = useState2(null);
|
|
1019
|
+
const loadRef = useRef2(load2);
|
|
1020
|
+
loadRef.current = load2;
|
|
1021
|
+
const generation = useRef2(0);
|
|
1022
|
+
const refresh = useCallback(async () => {
|
|
1023
|
+
const mine = ++generation.current;
|
|
1024
|
+
setIsLoading(true);
|
|
1025
|
+
try {
|
|
1026
|
+
const value = await loadRef.current();
|
|
1027
|
+
if (mine !== generation.current) return;
|
|
1028
|
+
setData(value);
|
|
1029
|
+
setError(null);
|
|
1030
|
+
} catch (caught) {
|
|
1031
|
+
if (mine !== generation.current) return;
|
|
1032
|
+
setError(caught instanceof Error ? caught : new Error(String(caught)));
|
|
1033
|
+
} finally {
|
|
1034
|
+
if (mine === generation.current) setIsLoading(false);
|
|
1035
|
+
}
|
|
1036
|
+
}, []);
|
|
1037
|
+
useEffect2(() => {
|
|
1038
|
+
if (!enabled) return;
|
|
1039
|
+
void refresh();
|
|
1040
|
+
}, [
|
|
1041
|
+
enabled,
|
|
1042
|
+
key,
|
|
1043
|
+
refresh
|
|
1044
|
+
]);
|
|
1045
|
+
return {
|
|
1046
|
+
data,
|
|
1047
|
+
isLoading,
|
|
1048
|
+
error,
|
|
1049
|
+
refresh
|
|
1050
|
+
};
|
|
1051
|
+
}
|
|
1052
|
+
__name(useResource, "useResource");
|
|
1053
|
+
|
|
1054
|
+
// src/catalog/use-agents.ts
|
|
1055
|
+
function useAgents(options) {
|
|
1056
|
+
const { backend, enabled = true } = options;
|
|
1057
|
+
const { data, isLoading, error, refresh } = useResource(() => requireBackendMethod(backend, "listAgents")(), "", enabled);
|
|
1058
|
+
return useMemo(() => {
|
|
1059
|
+
const agents = data ?? [];
|
|
1060
|
+
return {
|
|
1061
|
+
agents,
|
|
1062
|
+
defaultAgent: agents.find((agent) => agent.isDefault === true)?.name ?? null,
|
|
1063
|
+
isLoading,
|
|
1064
|
+
error,
|
|
1065
|
+
refresh
|
|
1066
|
+
};
|
|
1067
|
+
}, [
|
|
1068
|
+
data,
|
|
1069
|
+
isLoading,
|
|
1070
|
+
error,
|
|
1071
|
+
refresh
|
|
1072
|
+
]);
|
|
1073
|
+
}
|
|
1074
|
+
__name(useAgents, "useAgents");
|
|
1075
|
+
|
|
1076
|
+
// src/catalog/use-models.ts
|
|
1077
|
+
import { useMemo as useMemo2 } from "react";
|
|
1078
|
+
function useModels(options) {
|
|
1079
|
+
const { backend, agent, enabled = true } = options;
|
|
1080
|
+
const { data, isLoading, error, refresh } = useResource(() => requireBackendMethod(backend, "listModels")(agent), `${agent ?? ""}`, enabled);
|
|
1081
|
+
return useMemo2(() => {
|
|
1082
|
+
const providers = data?.providers ?? [];
|
|
1083
|
+
const models = providers.flatMap((provider) => provider.models.map((model) => ({
|
|
1084
|
+
...model,
|
|
1085
|
+
providerId: provider.id,
|
|
1086
|
+
providerLabel: provider.label
|
|
1087
|
+
})));
|
|
1088
|
+
const byId = new Map(models.map((model) => [
|
|
1089
|
+
model.id,
|
|
1090
|
+
model
|
|
1091
|
+
]));
|
|
1092
|
+
return {
|
|
1093
|
+
providers,
|
|
1094
|
+
models,
|
|
1095
|
+
defaultModel: data?.default ?? null,
|
|
1096
|
+
find: /* @__PURE__ */ __name((id) => id == null ? void 0 : byId.get(id), "find"),
|
|
1097
|
+
isLoading,
|
|
1098
|
+
error,
|
|
1099
|
+
refresh
|
|
1100
|
+
};
|
|
1101
|
+
}, [
|
|
1102
|
+
data,
|
|
1103
|
+
isLoading,
|
|
1104
|
+
error,
|
|
1105
|
+
refresh
|
|
1106
|
+
]);
|
|
1107
|
+
}
|
|
1108
|
+
__name(useModels, "useModels");
|
|
1109
|
+
|
|
1110
|
+
// src/quota/use-quota.ts
|
|
1111
|
+
import { useEffect as useEffect3, useMemo as useMemo3 } from "react";
|
|
1112
|
+
|
|
1113
|
+
// src/threads/threads-events.ts
|
|
1114
|
+
var listeners = /* @__PURE__ */ new WeakMap();
|
|
1115
|
+
function notifyThreads(backend, event) {
|
|
1116
|
+
for (const listener of listeners.get(backend) ?? []) {
|
|
1117
|
+
listener(event);
|
|
1118
|
+
}
|
|
1119
|
+
}
|
|
1120
|
+
__name(notifyThreads, "notifyThreads");
|
|
1121
|
+
function onThreadsEvent(backend, listener) {
|
|
1122
|
+
let set = listeners.get(backend);
|
|
1123
|
+
if (set === void 0) {
|
|
1124
|
+
set = /* @__PURE__ */ new Set();
|
|
1125
|
+
listeners.set(backend, set);
|
|
1126
|
+
}
|
|
1127
|
+
set.add(listener);
|
|
1128
|
+
return () => {
|
|
1129
|
+
set.delete(listener);
|
|
1130
|
+
};
|
|
1131
|
+
}
|
|
1132
|
+
__name(onThreadsEvent, "onThreadsEvent");
|
|
1133
|
+
|
|
1134
|
+
// src/quota/use-quota.ts
|
|
1135
|
+
function useQuota(options) {
|
|
1136
|
+
const { backend, enabled = true, pollMs } = options;
|
|
1137
|
+
const { data, isLoading, error, refresh } = useResource(() => requireBackendMethod(backend, "getQuota")(), "", enabled);
|
|
1138
|
+
useEffect3(() => {
|
|
1139
|
+
if (!enabled) return;
|
|
1140
|
+
return onThreadsEvent(backend, (event) => {
|
|
1141
|
+
if (event.type === "changed") void refresh();
|
|
1142
|
+
});
|
|
1143
|
+
}, [
|
|
1144
|
+
backend,
|
|
1145
|
+
enabled,
|
|
1146
|
+
refresh
|
|
1147
|
+
]);
|
|
1148
|
+
useEffect3(() => {
|
|
1149
|
+
if (!enabled || pollMs === void 0 || pollMs <= 0) return;
|
|
1150
|
+
const timer = setInterval(() => void refresh(), pollMs);
|
|
1151
|
+
return () => clearInterval(timer);
|
|
1152
|
+
}, [
|
|
1153
|
+
enabled,
|
|
1154
|
+
pollMs,
|
|
1155
|
+
refresh
|
|
1156
|
+
]);
|
|
1157
|
+
return useMemo3(() => {
|
|
1158
|
+
const windows = data?.windows ?? [];
|
|
1159
|
+
return {
|
|
1160
|
+
report: data,
|
|
1161
|
+
windows,
|
|
1162
|
+
day: windows.find((window2) => window2.period === "day"),
|
|
1163
|
+
month: windows.find((window2) => window2.period === "month"),
|
|
1164
|
+
blocked: data?.blocked ?? null,
|
|
1165
|
+
isLoading,
|
|
1166
|
+
error,
|
|
1167
|
+
refresh
|
|
1168
|
+
};
|
|
1169
|
+
}, [
|
|
1170
|
+
data,
|
|
1171
|
+
isLoading,
|
|
1172
|
+
error,
|
|
1173
|
+
refresh
|
|
1174
|
+
]);
|
|
1175
|
+
}
|
|
1176
|
+
__name(useQuota, "useQuota");
|
|
1177
|
+
|
|
997
1178
|
// src/feedback/use-message-feedback.ts
|
|
998
|
-
import { useCallback, useRef as
|
|
1179
|
+
import { useCallback as useCallback2, useRef as useRef3, useState as useState3 } from "react";
|
|
999
1180
|
function useMessageFeedback(options) {
|
|
1000
|
-
const latest =
|
|
1181
|
+
const latest = useRef3(options);
|
|
1001
1182
|
latest.current = options;
|
|
1002
|
-
const [local, setLocal] =
|
|
1003
|
-
const [pending, setPending] =
|
|
1004
|
-
const [error, setError] =
|
|
1005
|
-
const localRef =
|
|
1183
|
+
const [local, setLocal] = useState3(/* @__PURE__ */ new Map());
|
|
1184
|
+
const [pending, setPending] = useState3(/* @__PURE__ */ new Set());
|
|
1185
|
+
const [error, setError] = useState3(null);
|
|
1186
|
+
const localRef = useRef3(local);
|
|
1006
1187
|
localRef.current = local;
|
|
1007
|
-
const resolved =
|
|
1008
|
-
const feedbackOf =
|
|
1188
|
+
const resolved = useRef3(/* @__PURE__ */ new Map());
|
|
1189
|
+
const feedbackOf = useCallback2((message) => {
|
|
1009
1190
|
const mine = local.get(message.id);
|
|
1010
1191
|
if (mine !== void 0) return mine.feedback;
|
|
1011
1192
|
return metadataOf(message).feedback ?? null;
|
|
1012
1193
|
}, [
|
|
1013
1194
|
local
|
|
1014
1195
|
]);
|
|
1015
|
-
const isPending =
|
|
1196
|
+
const isPending = useCallback2((message) => pending.has(message.id), [
|
|
1016
1197
|
pending
|
|
1017
1198
|
]);
|
|
1018
|
-
const storedIdFor =
|
|
1199
|
+
const storedIdFor = useCallback2(async (message) => {
|
|
1019
1200
|
const runId = metadataOf(message).runId;
|
|
1020
1201
|
if (runId === void 0) return message.id;
|
|
1021
1202
|
const known = resolved.current.get(message.id);
|
|
@@ -1035,7 +1216,7 @@ function useMessageFeedback(options) {
|
|
|
1035
1216
|
resolved.current.set(message.id, row.id);
|
|
1036
1217
|
return row.id;
|
|
1037
1218
|
}, []);
|
|
1038
|
-
const rate =
|
|
1219
|
+
const rate = useCallback2(async (message, value, comment) => {
|
|
1039
1220
|
const setFeedback = requireBackendMethod(latest.current.backend, "setMessageFeedback");
|
|
1040
1221
|
const had = localRef.current.get(message.id);
|
|
1041
1222
|
const optimistic = value === null ? null : {
|
|
@@ -1081,7 +1262,7 @@ function useMessageFeedback(options) {
|
|
|
1081
1262
|
}, [
|
|
1082
1263
|
storedIdFor
|
|
1083
1264
|
]);
|
|
1084
|
-
const toggle =
|
|
1265
|
+
const toggle = useCallback2((message, value) => {
|
|
1085
1266
|
const mine = localRef.current.get(message.id);
|
|
1086
1267
|
const current = mine !== void 0 ? mine.feedback : metadataOf(message).feedback ?? null;
|
|
1087
1268
|
return rate(message, current?.value === value ? null : value);
|
|
@@ -1103,38 +1284,17 @@ function metadataOf(message) {
|
|
|
1103
1284
|
}
|
|
1104
1285
|
__name(metadataOf, "metadataOf");
|
|
1105
1286
|
|
|
1106
|
-
// src/threads/threads-events.ts
|
|
1107
|
-
var listeners = /* @__PURE__ */ new WeakMap();
|
|
1108
|
-
function notifyThreads(backend, event) {
|
|
1109
|
-
for (const listener of listeners.get(backend) ?? []) {
|
|
1110
|
-
listener(event);
|
|
1111
|
-
}
|
|
1112
|
-
}
|
|
1113
|
-
__name(notifyThreads, "notifyThreads");
|
|
1114
|
-
function onThreadsEvent(backend, listener) {
|
|
1115
|
-
let set = listeners.get(backend);
|
|
1116
|
-
if (set === void 0) {
|
|
1117
|
-
set = /* @__PURE__ */ new Set();
|
|
1118
|
-
listeners.set(backend, set);
|
|
1119
|
-
}
|
|
1120
|
-
set.add(listener);
|
|
1121
|
-
return () => {
|
|
1122
|
-
set.delete(listener);
|
|
1123
|
-
};
|
|
1124
|
-
}
|
|
1125
|
-
__name(onThreadsEvent, "onThreadsEvent");
|
|
1126
|
-
|
|
1127
1287
|
// src/threads/use-threads.ts
|
|
1128
|
-
import { useCallback as
|
|
1288
|
+
import { useCallback as useCallback3, useEffect as useEffect4, useRef as useRef4, useState as useState4 } from "react";
|
|
1129
1289
|
function useThreads(options) {
|
|
1130
1290
|
const { backend, enabled = true } = options;
|
|
1131
|
-
const [threads, setThreads] =
|
|
1132
|
-
const [isLoading, setIsLoading] =
|
|
1133
|
-
const [error, setError] =
|
|
1134
|
-
const threadsRef =
|
|
1291
|
+
const [threads, setThreads] = useState4([]);
|
|
1292
|
+
const [isLoading, setIsLoading] = useState4(enabled);
|
|
1293
|
+
const [error, setError] = useState4(null);
|
|
1294
|
+
const threadsRef = useRef4(threads);
|
|
1135
1295
|
threadsRef.current = threads;
|
|
1136
|
-
const generation =
|
|
1137
|
-
const refresh =
|
|
1296
|
+
const generation = useRef4(0);
|
|
1297
|
+
const refresh = useCallback3(async () => {
|
|
1138
1298
|
const mine = ++generation.current;
|
|
1139
1299
|
setIsLoading(true);
|
|
1140
1300
|
try {
|
|
@@ -1151,7 +1311,7 @@ function useThreads(options) {
|
|
|
1151
1311
|
}, [
|
|
1152
1312
|
backend
|
|
1153
1313
|
]);
|
|
1154
|
-
|
|
1314
|
+
useEffect4(() => {
|
|
1155
1315
|
if (!enabled) return;
|
|
1156
1316
|
void refresh();
|
|
1157
1317
|
return onThreadsEvent(backend, (event) => {
|
|
@@ -1171,7 +1331,7 @@ function useThreads(options) {
|
|
|
1171
1331
|
enabled,
|
|
1172
1332
|
refresh
|
|
1173
1333
|
]);
|
|
1174
|
-
const rename =
|
|
1334
|
+
const rename = useCallback3(async (id, title) => {
|
|
1175
1335
|
const before = threadsRef.current;
|
|
1176
1336
|
setThreads((current) => current.map((thread) => thread.id === id ? {
|
|
1177
1337
|
...thread,
|
|
@@ -1193,7 +1353,7 @@ function useThreads(options) {
|
|
|
1193
1353
|
}, [
|
|
1194
1354
|
backend
|
|
1195
1355
|
]);
|
|
1196
|
-
const remove =
|
|
1356
|
+
const remove = useCallback3(async (id) => {
|
|
1197
1357
|
const before = threadsRef.current;
|
|
1198
1358
|
setThreads((current) => current.filter((thread) => thread.id !== id));
|
|
1199
1359
|
try {
|
|
@@ -1268,10 +1428,10 @@ function backgroundRunsFromThread(messages) {
|
|
|
1268
1428
|
__name(backgroundRunsFromThread, "backgroundRunsFromThread");
|
|
1269
1429
|
|
|
1270
1430
|
// src/components/chat-input.tsx
|
|
1271
|
-
import React2, { useEffect as
|
|
1431
|
+
import React2, { useEffect as useEffect6, useState as useState6 } from "react";
|
|
1272
1432
|
|
|
1273
1433
|
// src/components/use-speech-recognition.ts
|
|
1274
|
-
import { useCallback as
|
|
1434
|
+
import { useCallback as useCallback4, useEffect as useEffect5, useMemo as useMemo4, useRef as useRef5, useState as useState5 } from "react";
|
|
1275
1435
|
function getRecognitionCtor() {
|
|
1276
1436
|
if (typeof window === "undefined") return null;
|
|
1277
1437
|
const scope = window;
|
|
@@ -1279,15 +1439,15 @@ function getRecognitionCtor() {
|
|
|
1279
1439
|
}
|
|
1280
1440
|
__name(getRecognitionCtor, "getRecognitionCtor");
|
|
1281
1441
|
function useSpeechRecognition({ lang = "en-US", onFinalTranscript, onInterimTranscript }) {
|
|
1282
|
-
const recognitionRef =
|
|
1283
|
-
const [isListening, setIsListening] =
|
|
1284
|
-
const ctor =
|
|
1442
|
+
const recognitionRef = useRef5(null);
|
|
1443
|
+
const [isListening, setIsListening] = useState5(false);
|
|
1444
|
+
const ctor = useMemo4(() => getRecognitionCtor(), []);
|
|
1285
1445
|
const isSupported = ctor !== null;
|
|
1286
|
-
const finalRef =
|
|
1287
|
-
const interimRef =
|
|
1446
|
+
const finalRef = useRef5(onFinalTranscript);
|
|
1447
|
+
const interimRef = useRef5(onInterimTranscript);
|
|
1288
1448
|
finalRef.current = onFinalTranscript;
|
|
1289
1449
|
interimRef.current = onInterimTranscript;
|
|
1290
|
-
|
|
1450
|
+
useEffect5(() => {
|
|
1291
1451
|
if (!ctor) return;
|
|
1292
1452
|
const recognition = new ctor();
|
|
1293
1453
|
recognition.lang = lang;
|
|
@@ -1326,7 +1486,7 @@ function useSpeechRecognition({ lang = "en-US", onFinalTranscript, onInterimTran
|
|
|
1326
1486
|
ctor,
|
|
1327
1487
|
lang
|
|
1328
1488
|
]);
|
|
1329
|
-
const start =
|
|
1489
|
+
const start = useCallback4(() => {
|
|
1330
1490
|
const recognition = recognitionRef.current;
|
|
1331
1491
|
if (!recognition) return;
|
|
1332
1492
|
try {
|
|
@@ -1336,7 +1496,7 @@ function useSpeechRecognition({ lang = "en-US", onFinalTranscript, onInterimTran
|
|
|
1336
1496
|
console.warn("SpeechRecognition start failed", error);
|
|
1337
1497
|
}
|
|
1338
1498
|
}, []);
|
|
1339
|
-
const stop =
|
|
1499
|
+
const stop = useCallback4(() => {
|
|
1340
1500
|
const recognition = recognitionRef.current;
|
|
1341
1501
|
if (!recognition) return;
|
|
1342
1502
|
try {
|
|
@@ -1355,8 +1515,8 @@ __name(useSpeechRecognition, "useSpeechRecognition");
|
|
|
1355
1515
|
|
|
1356
1516
|
// src/components/chat-input.tsx
|
|
1357
1517
|
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 }) {
|
|
1358
|
-
const [value, setValue] =
|
|
1359
|
-
const [interim, setInterim] =
|
|
1518
|
+
const [value, setValue] = useState6("");
|
|
1519
|
+
const [interim, setInterim] = useState6("");
|
|
1360
1520
|
const speech = useSpeechRecognition({
|
|
1361
1521
|
lang: speechLang,
|
|
1362
1522
|
onFinalTranscript: /* @__PURE__ */ __name((text) => {
|
|
@@ -1367,7 +1527,7 @@ function ChatInput({ onSubmit, disabled, placeholder, rows = 2, enableSpeech = t
|
|
|
1367
1527
|
}, "onFinalTranscript"),
|
|
1368
1528
|
onInterimTranscript: /* @__PURE__ */ __name((text) => setInterim(text), "onInterimTranscript")
|
|
1369
1529
|
});
|
|
1370
|
-
|
|
1530
|
+
useEffect6(() => {
|
|
1371
1531
|
if (!speech.isListening) setInterim("");
|
|
1372
1532
|
}, [
|
|
1373
1533
|
speech.isListening
|
|
@@ -1434,7 +1594,7 @@ __name(ChatInput, "ChatInput");
|
|
|
1434
1594
|
import React3 from "react";
|
|
1435
1595
|
|
|
1436
1596
|
// src/transcript/use-chat-transcript.ts
|
|
1437
|
-
import { useCallback as
|
|
1597
|
+
import { useCallback as useCallback6, useEffect as useEffect8, useRef as useRef7, useState as useState8 } from "react";
|
|
1438
1598
|
|
|
1439
1599
|
// src/transcript/model.ts
|
|
1440
1600
|
import { readElicitationInput, validateElicitationAnswer as validateElicitationAnswer2 } from "@dudousxd/nestjs-agent-core";
|
|
@@ -2411,11 +2571,11 @@ function formatCostUsd(cost) {
|
|
|
2411
2571
|
__name(formatCostUsd, "formatCostUsd");
|
|
2412
2572
|
|
|
2413
2573
|
// src/transcript/use-stick-to-bottom.ts
|
|
2414
|
-
import { useCallback as
|
|
2574
|
+
import { useCallback as useCallback5, useEffect as useEffect7, useRef as useRef6, useState as useState7 } from "react";
|
|
2415
2575
|
function useStickToBottom({ contentKey, threshold = 32 }) {
|
|
2416
|
-
const containerRef =
|
|
2417
|
-
const [isAtBottom, setIsAtBottom] =
|
|
2418
|
-
const measure =
|
|
2576
|
+
const containerRef = useRef6(null);
|
|
2577
|
+
const [isAtBottom, setIsAtBottom] = useState7(true);
|
|
2578
|
+
const measure = useCallback5(() => {
|
|
2419
2579
|
const element = containerRef.current;
|
|
2420
2580
|
if (!element) {
|
|
2421
2581
|
return;
|
|
@@ -2425,7 +2585,7 @@ function useStickToBottom({ contentKey, threshold = 32 }) {
|
|
|
2425
2585
|
}, [
|
|
2426
2586
|
threshold
|
|
2427
2587
|
]);
|
|
2428
|
-
const scrollToBottom =
|
|
2588
|
+
const scrollToBottom = useCallback5(() => {
|
|
2429
2589
|
const element = containerRef.current;
|
|
2430
2590
|
if (!element) {
|
|
2431
2591
|
return;
|
|
@@ -2433,7 +2593,7 @@ function useStickToBottom({ contentKey, threshold = 32 }) {
|
|
|
2433
2593
|
element.scrollTop = element.scrollHeight;
|
|
2434
2594
|
setIsAtBottom(true);
|
|
2435
2595
|
}, []);
|
|
2436
|
-
const setContainer =
|
|
2596
|
+
const setContainer = useCallback5((element) => {
|
|
2437
2597
|
containerRef.current = element;
|
|
2438
2598
|
if (element) {
|
|
2439
2599
|
measure();
|
|
@@ -2441,7 +2601,7 @@ function useStickToBottom({ contentKey, threshold = 32 }) {
|
|
|
2441
2601
|
}, [
|
|
2442
2602
|
measure
|
|
2443
2603
|
]);
|
|
2444
|
-
|
|
2604
|
+
useEffect7(() => {
|
|
2445
2605
|
if (isAtBottom) {
|
|
2446
2606
|
scrollToBottom();
|
|
2447
2607
|
}
|
|
@@ -2450,7 +2610,7 @@ function useStickToBottom({ contentKey, threshold = 32 }) {
|
|
|
2450
2610
|
isAtBottom,
|
|
2451
2611
|
scrollToBottom
|
|
2452
2612
|
]);
|
|
2453
|
-
const getContainerProps =
|
|
2613
|
+
const getContainerProps = useCallback5(() => ({
|
|
2454
2614
|
ref: setContainer,
|
|
2455
2615
|
onScroll: measure
|
|
2456
2616
|
}), [
|
|
@@ -2472,14 +2632,14 @@ var DEFAULT_LOAD_EARLIER_STEP = 50;
|
|
|
2472
2632
|
var DEFAULT_COPY_RESET_MS = 1500;
|
|
2473
2633
|
function useChatTranscript(options) {
|
|
2474
2634
|
const { messages, status, initialVisibleCount = DEFAULT_VISIBLE_COUNT, loadEarlierStep = DEFAULT_LOAD_EARLIER_STEP, followUps, stickToBottomThreshold } = options;
|
|
2475
|
-
const latest =
|
|
2635
|
+
const latest = useRef7(options);
|
|
2476
2636
|
latest.current = options;
|
|
2477
|
-
const [visibleCount, setVisibleCount] =
|
|
2478
|
-
const [stopRequested, setStopRequested] =
|
|
2637
|
+
const [visibleCount, setVisibleCount] = useState8(initialVisibleCount);
|
|
2638
|
+
const [stopRequested, setStopRequested] = useState8(false);
|
|
2479
2639
|
const isStreaming = status === "streaming" || status === "reconnecting";
|
|
2480
2640
|
const isBusy = status === "submitted" || isStreaming;
|
|
2481
2641
|
const isEmpty = messages.length === 0;
|
|
2482
|
-
|
|
2642
|
+
useEffect8(() => {
|
|
2483
2643
|
if (!isBusy) {
|
|
2484
2644
|
setStopRequested(false);
|
|
2485
2645
|
}
|
|
@@ -2496,7 +2656,7 @@ function useChatTranscript(options) {
|
|
|
2496
2656
|
streamingMessageId,
|
|
2497
2657
|
options
|
|
2498
2658
|
});
|
|
2499
|
-
const stop =
|
|
2659
|
+
const stop = useCallback6(() => {
|
|
2500
2660
|
const current = latest.current;
|
|
2501
2661
|
if (current.status !== "submitted" && current.status !== "streaming" && current.status !== "reconnecting") {
|
|
2502
2662
|
return;
|
|
@@ -2504,8 +2664,8 @@ function useChatTranscript(options) {
|
|
|
2504
2664
|
setStopRequested(true);
|
|
2505
2665
|
void current.onStop?.();
|
|
2506
2666
|
}, []);
|
|
2507
|
-
const loadEarlier =
|
|
2508
|
-
const showAll =
|
|
2667
|
+
const loadEarlier = useCallback6(() => setVisibleCount((count) => count + (latest.current.loadEarlierStep ?? DEFAULT_LOAD_EARLIER_STEP)), []);
|
|
2668
|
+
const showAll = useCallback6(() => setVisibleCount(latest.current.messages.length), []);
|
|
2509
2669
|
const scroll = useStickToBottom({
|
|
2510
2670
|
contentKey: contentSignature(messages),
|
|
2511
2671
|
...stickToBottomThreshold !== void 0 ? {
|
|
@@ -2541,7 +2701,7 @@ function useChatTranscript(options) {
|
|
|
2541
2701
|
__name(useChatTranscript, "useChatTranscript");
|
|
2542
2702
|
function useTranscriptItem(options) {
|
|
2543
2703
|
const { message, isStreaming = false } = options;
|
|
2544
|
-
const messagesRef =
|
|
2704
|
+
const messagesRef = useRef7([
|
|
2545
2705
|
message
|
|
2546
2706
|
]);
|
|
2547
2707
|
if (messagesRef.current[0] !== message) {
|
|
@@ -2559,13 +2719,13 @@ function useTranscriptItem(options) {
|
|
|
2559
2719
|
}
|
|
2560
2720
|
__name(useTranscriptItem, "useTranscriptItem");
|
|
2561
2721
|
function useTranscriptItems({ messages, visibleStart, streamingMessageId, options }) {
|
|
2562
|
-
const [drafts, setDrafts] =
|
|
2563
|
-
const [copied, setCopied] =
|
|
2564
|
-
const [openReasoning, setOpenReasoning] =
|
|
2565
|
-
const [picks, setPicks] =
|
|
2566
|
-
const [settling, setSettling] =
|
|
2567
|
-
const [settleErrors, setSettleErrors] =
|
|
2568
|
-
const latest =
|
|
2722
|
+
const [drafts, setDrafts] = useState8(() => /* @__PURE__ */ new Map());
|
|
2723
|
+
const [copied, setCopied] = useState8(() => /* @__PURE__ */ new Set());
|
|
2724
|
+
const [openReasoning, setOpenReasoning] = useState8(() => /* @__PURE__ */ new Map());
|
|
2725
|
+
const [picks, setPicks] = useState8(() => /* @__PURE__ */ new Map());
|
|
2726
|
+
const [settling, setSettling] = useState8(() => /* @__PURE__ */ new Map());
|
|
2727
|
+
const [settleErrors, setSettleErrors] = useState8(() => /* @__PURE__ */ new Map());
|
|
2728
|
+
const latest = useRef7({
|
|
2569
2729
|
options,
|
|
2570
2730
|
drafts,
|
|
2571
2731
|
picks,
|
|
@@ -2577,23 +2737,23 @@ function useTranscriptItems({ messages, visibleStart, streamingMessageId, option
|
|
|
2577
2737
|
picks,
|
|
2578
2738
|
messages
|
|
2579
2739
|
};
|
|
2580
|
-
const copyTimers =
|
|
2581
|
-
|
|
2740
|
+
const copyTimers = useRef7(/* @__PURE__ */ new Map());
|
|
2741
|
+
useEffect8(() => () => {
|
|
2582
2742
|
for (const timer of copyTimers.current.values()) {
|
|
2583
2743
|
clearTimeout(timer);
|
|
2584
2744
|
}
|
|
2585
2745
|
copyTimers.current.clear();
|
|
2586
2746
|
}, []);
|
|
2587
|
-
const callbackCache =
|
|
2588
|
-
const reasoningToggleCache =
|
|
2589
|
-
const toggleReasoning =
|
|
2747
|
+
const callbackCache = useRef7(/* @__PURE__ */ new Map());
|
|
2748
|
+
const reasoningToggleCache = useRef7(/* @__PURE__ */ new Map());
|
|
2749
|
+
const toggleReasoning = useCallback6((key, open) => {
|
|
2590
2750
|
setOpenReasoning((current) => {
|
|
2591
2751
|
const next = new Map(current);
|
|
2592
2752
|
next.set(key, open ?? !(current.get(key) ?? false));
|
|
2593
2753
|
return next;
|
|
2594
2754
|
});
|
|
2595
2755
|
}, []);
|
|
2596
|
-
const stableToggle =
|
|
2756
|
+
const stableToggle = useCallback6((key) => {
|
|
2597
2757
|
let cached = reasoningToggleCache.current.get(key);
|
|
2598
2758
|
if (!cached) {
|
|
2599
2759
|
cached = /* @__PURE__ */ __name((open) => toggleReasoning(key, open), "cached");
|
|
@@ -2603,10 +2763,10 @@ function useTranscriptItems({ messages, visibleStart, streamingMessageId, option
|
|
|
2603
2763
|
}, [
|
|
2604
2764
|
toggleReasoning
|
|
2605
2765
|
]);
|
|
2606
|
-
const pick =
|
|
2766
|
+
const pick = useCallback6((toolCallId, questionId, values) => {
|
|
2607
2767
|
setPicks((current) => new Map(current).set(pickKey(toolCallId, questionId), values));
|
|
2608
2768
|
}, []);
|
|
2609
|
-
const settle =
|
|
2769
|
+
const settle = useCallback6((toolCallId, action, send) => {
|
|
2610
2770
|
setSettleErrors((current) => {
|
|
2611
2771
|
if (!current.has(toolCallId)) {
|
|
2612
2772
|
return current;
|
|
@@ -2630,7 +2790,7 @@ function useTranscriptItems({ messages, visibleStart, streamingMessageId, option
|
|
|
2630
2790
|
failed(error);
|
|
2631
2791
|
}
|
|
2632
2792
|
}, []);
|
|
2633
|
-
const answer =
|
|
2793
|
+
const answer = useCallback6((toolCallId) => {
|
|
2634
2794
|
const current = latest.current;
|
|
2635
2795
|
const onAnswer = current.options.onAnswer;
|
|
2636
2796
|
if (!onAnswer) {
|
|
@@ -2640,7 +2800,7 @@ function useTranscriptItems({ messages, visibleStart, streamingMessageId, option
|
|
|
2640
2800
|
}, [
|
|
2641
2801
|
settle
|
|
2642
2802
|
]);
|
|
2643
|
-
const skip =
|
|
2803
|
+
const skip = useCallback6((toolCallId) => {
|
|
2644
2804
|
const onSkip = latest.current.options.onSkip;
|
|
2645
2805
|
if (onSkip) {
|
|
2646
2806
|
settle(toolCallId, "skip", () => onSkip(toolCallId));
|
|
@@ -2648,7 +2808,7 @@ function useTranscriptItems({ messages, visibleStart, streamingMessageId, option
|
|
|
2648
2808
|
}, [
|
|
2649
2809
|
settle
|
|
2650
2810
|
]);
|
|
2651
|
-
const approve =
|
|
2811
|
+
const approve = useCallback6((toolCallId, options2) => {
|
|
2652
2812
|
const onApprove = latest.current.options.onApprove;
|
|
2653
2813
|
if (onApprove) {
|
|
2654
2814
|
settle(toolCallId, "approve", () => options2 === void 0 ? onApprove(toolCallId) : onApprove(toolCallId, options2));
|
|
@@ -2656,7 +2816,7 @@ function useTranscriptItems({ messages, visibleStart, streamingMessageId, option
|
|
|
2656
2816
|
}, [
|
|
2657
2817
|
settle
|
|
2658
2818
|
]);
|
|
2659
|
-
const reject =
|
|
2819
|
+
const reject = useCallback6((toolCallId) => {
|
|
2660
2820
|
const onReject = latest.current.options.onReject;
|
|
2661
2821
|
if (onReject) {
|
|
2662
2822
|
settle(toolCallId, "reject", () => onReject(toolCallId));
|
|
@@ -2664,7 +2824,7 @@ function useTranscriptItems({ messages, visibleStart, streamingMessageId, option
|
|
|
2664
2824
|
}, [
|
|
2665
2825
|
settle
|
|
2666
2826
|
]);
|
|
2667
|
-
const callbacksFor =
|
|
2827
|
+
const callbacksFor = useCallback6((id) => {
|
|
2668
2828
|
const cached = callbackCache.current.get(id);
|
|
2669
2829
|
if (cached) {
|
|
2670
2830
|
return cached;
|
|
@@ -3321,35 +3481,35 @@ function toItem(entry) {
|
|
|
3321
3481
|
__name(toItem, "toItem");
|
|
3322
3482
|
|
|
3323
3483
|
// src/composer/use-composer-autocomplete.ts
|
|
3324
|
-
import { useCallback as
|
|
3484
|
+
import { useCallback as useCallback7, useEffect as useEffect9, useId, useLayoutEffect, useMemo as useMemo5, useRef as useRef8, useState as useState9 } from "react";
|
|
3325
3485
|
function useComposerAutocomplete(options) {
|
|
3326
3486
|
const { value, sources, acceptOnTab = true } = options;
|
|
3327
|
-
const latest =
|
|
3487
|
+
const latest = useRef8(options);
|
|
3328
3488
|
latest.current = options;
|
|
3329
|
-
const inputRef =
|
|
3330
|
-
const [caret, setCaret] =
|
|
3331
|
-
const [items, setItems] =
|
|
3332
|
-
const [isLoading, setLoading] =
|
|
3333
|
-
const [error, setError] =
|
|
3334
|
-
const [activeIndex, setActiveIndex] =
|
|
3335
|
-
const [dismissedIndex, setDismissedIndex] =
|
|
3489
|
+
const inputRef = useRef8(null);
|
|
3490
|
+
const [caret, setCaret] = useState9(value.length);
|
|
3491
|
+
const [items, setItems] = useState9([]);
|
|
3492
|
+
const [isLoading, setLoading] = useState9(false);
|
|
3493
|
+
const [error, setError] = useState9(null);
|
|
3494
|
+
const [activeIndex, setActiveIndex] = useState9(0);
|
|
3495
|
+
const [dismissedIndex, setDismissedIndex] = useState9(null);
|
|
3336
3496
|
const safeCaret = Math.min(caret, value.length);
|
|
3337
|
-
const match =
|
|
3497
|
+
const match = useMemo5(() => findActiveTrigger(value, safeCaret, sources), [
|
|
3338
3498
|
value,
|
|
3339
3499
|
safeCaret,
|
|
3340
3500
|
sources
|
|
3341
3501
|
]);
|
|
3342
3502
|
const isActive = match !== null && dismissedIndex !== match.index;
|
|
3343
|
-
const matchRef =
|
|
3503
|
+
const matchRef = useRef8(match);
|
|
3344
3504
|
matchRef.current = match;
|
|
3345
|
-
const caretRef =
|
|
3505
|
+
const caretRef = useRef8(safeCaret);
|
|
3346
3506
|
caretRef.current = safeCaret;
|
|
3347
|
-
const itemsRef =
|
|
3507
|
+
const itemsRef = useRef8(items);
|
|
3348
3508
|
itemsRef.current = items;
|
|
3349
|
-
const activeIndexRef =
|
|
3509
|
+
const activeIndexRef = useRef8(activeIndex);
|
|
3350
3510
|
activeIndexRef.current = activeIndex;
|
|
3351
3511
|
const requestKey = isActive && match ? `${match.source.id}\0${match.query}` : null;
|
|
3352
|
-
|
|
3512
|
+
useEffect9(() => {
|
|
3353
3513
|
const current = matchRef.current;
|
|
3354
3514
|
if (requestKey === null || current === null) {
|
|
3355
3515
|
setItems([]);
|
|
@@ -3399,23 +3559,23 @@ function useComposerAutocomplete(options) {
|
|
|
3399
3559
|
const activeItem = isOpen ? items[activeIndex] ?? null : null;
|
|
3400
3560
|
const reactId = useId();
|
|
3401
3561
|
const listboxId = options.id ?? `agent-autocomplete-${reactId}`;
|
|
3402
|
-
const optionId =
|
|
3562
|
+
const optionId = useCallback7((index) => `${listboxId}-option-${index}`, [
|
|
3403
3563
|
listboxId
|
|
3404
3564
|
]);
|
|
3405
|
-
const highlight =
|
|
3565
|
+
const highlight = useCallback7((index) => {
|
|
3406
3566
|
const total = itemsRef.current.length;
|
|
3407
3567
|
if (total === 0) return;
|
|
3408
3568
|
setActiveIndex((index % total + total) % total);
|
|
3409
3569
|
}, []);
|
|
3410
|
-
const moveHighlight =
|
|
3570
|
+
const moveHighlight = useCallback7((delta) => highlight(activeIndexRef.current + delta), [
|
|
3411
3571
|
highlight
|
|
3412
3572
|
]);
|
|
3413
|
-
const dismiss =
|
|
3573
|
+
const dismiss = useCallback7(() => {
|
|
3414
3574
|
const current = matchRef.current;
|
|
3415
3575
|
if (current) setDismissedIndex(current.index);
|
|
3416
3576
|
}, []);
|
|
3417
|
-
const pendingCaret =
|
|
3418
|
-
const accept =
|
|
3577
|
+
const pendingCaret = useRef8(null);
|
|
3578
|
+
const accept = useCallback7((item) => {
|
|
3419
3579
|
const current = matchRef.current;
|
|
3420
3580
|
if (!current) return;
|
|
3421
3581
|
const chosen = item ?? itemsRef.current[activeIndexRef.current];
|
|
@@ -3432,10 +3592,10 @@ function useComposerAutocomplete(options) {
|
|
|
3432
3592
|
pendingCaret.current = null;
|
|
3433
3593
|
inputRef.current?.setSelectionRange(position, position);
|
|
3434
3594
|
});
|
|
3435
|
-
const readCaret =
|
|
3595
|
+
const readCaret = useCallback7((element) => {
|
|
3436
3596
|
setCaret(element.selectionStart ?? element.value.length);
|
|
3437
3597
|
}, []);
|
|
3438
|
-
const onKeyDown =
|
|
3598
|
+
const onKeyDown = useCallback7((event) => {
|
|
3439
3599
|
if (!isOpen) return;
|
|
3440
3600
|
const hasItems = itemsRef.current.length > 0;
|
|
3441
3601
|
switch (event.key) {
|
|
@@ -3473,23 +3633,23 @@ function useComposerAutocomplete(options) {
|
|
|
3473
3633
|
dismiss,
|
|
3474
3634
|
moveHighlight
|
|
3475
3635
|
]);
|
|
3476
|
-
const onChange =
|
|
3636
|
+
const onChange = useCallback7((event) => {
|
|
3477
3637
|
readCaret(event.target);
|
|
3478
3638
|
const next = findActiveTrigger(event.target.value, event.target.selectionStart ?? event.target.value.length, latest.current.sources);
|
|
3479
3639
|
setDismissedIndex((current) => current !== null && next?.index === current ? current : null);
|
|
3480
3640
|
}, [
|
|
3481
3641
|
readCaret
|
|
3482
3642
|
]);
|
|
3483
|
-
const onSelect =
|
|
3643
|
+
const onSelect = useCallback7((event) => readCaret(event.currentTarget), [
|
|
3484
3644
|
readCaret
|
|
3485
3645
|
]);
|
|
3486
|
-
const onClick =
|
|
3646
|
+
const onClick = useCallback7((event) => readCaret(event.currentTarget), [
|
|
3487
3647
|
readCaret
|
|
3488
3648
|
]);
|
|
3489
|
-
const setInput =
|
|
3649
|
+
const setInput = useCallback7((element) => {
|
|
3490
3650
|
inputRef.current = element;
|
|
3491
3651
|
}, []);
|
|
3492
|
-
const getInputProps =
|
|
3652
|
+
const getInputProps = useCallback7(() => ({
|
|
3493
3653
|
ref: setInput,
|
|
3494
3654
|
onChange,
|
|
3495
3655
|
onKeyDown,
|
|
@@ -3517,7 +3677,7 @@ function useComposerAutocomplete(options) {
|
|
|
3517
3677
|
activeIndex,
|
|
3518
3678
|
optionId
|
|
3519
3679
|
]);
|
|
3520
|
-
const getListboxProps =
|
|
3680
|
+
const getListboxProps = useCallback7(() => ({
|
|
3521
3681
|
id: listboxId,
|
|
3522
3682
|
role: "listbox",
|
|
3523
3683
|
"aria-label": match?.source.label ?? match?.source.id ?? "Suggestions"
|
|
@@ -3525,7 +3685,7 @@ function useComposerAutocomplete(options) {
|
|
|
3525
3685
|
listboxId,
|
|
3526
3686
|
match
|
|
3527
3687
|
]);
|
|
3528
|
-
const getOptionProps =
|
|
3688
|
+
const getOptionProps = useCallback7((index) => ({
|
|
3529
3689
|
id: optionId(index),
|
|
3530
3690
|
role: "option",
|
|
3531
3691
|
"aria-selected": index === activeIndex
|
|
@@ -3559,7 +3719,7 @@ function isPromise(value) {
|
|
|
3559
3719
|
__name(isPromise, "isPromise");
|
|
3560
3720
|
|
|
3561
3721
|
// src/presentation/use-tool-catalog.ts
|
|
3562
|
-
import { useCallback as
|
|
3722
|
+
import { useCallback as useCallback8, useEffect as useEffect10, useMemo as useMemo6, useState as useState10 } from "react";
|
|
3563
3723
|
var shared = /* @__PURE__ */ new WeakMap();
|
|
3564
3724
|
function load(client, agent) {
|
|
3565
3725
|
let byAgent = shared.get(client);
|
|
@@ -3583,11 +3743,11 @@ function load(client, agent) {
|
|
|
3583
3743
|
__name(load, "load");
|
|
3584
3744
|
function useToolCatalog(options) {
|
|
3585
3745
|
const { client, agent, enabled = true } = options;
|
|
3586
|
-
const [entries, setEntries] =
|
|
3587
|
-
const [isLoading, setLoading] =
|
|
3588
|
-
const [error, setError] =
|
|
3589
|
-
const [generation, setGeneration] =
|
|
3590
|
-
|
|
3746
|
+
const [entries, setEntries] = useState10([]);
|
|
3747
|
+
const [isLoading, setLoading] = useState10(enabled);
|
|
3748
|
+
const [error, setError] = useState10(null);
|
|
3749
|
+
const [generation, setGeneration] = useState10(0);
|
|
3750
|
+
useEffect10(() => {
|
|
3591
3751
|
if (!enabled) {
|
|
3592
3752
|
setLoading(false);
|
|
3593
3753
|
return;
|
|
@@ -3613,14 +3773,14 @@ function useToolCatalog(options) {
|
|
|
3613
3773
|
enabled,
|
|
3614
3774
|
generation
|
|
3615
3775
|
]);
|
|
3616
|
-
const refresh =
|
|
3776
|
+
const refresh = useCallback8(() => {
|
|
3617
3777
|
shared.get(client)?.delete(agent ?? "");
|
|
3618
3778
|
setGeneration((current) => current + 1);
|
|
3619
3779
|
}, [
|
|
3620
3780
|
client,
|
|
3621
3781
|
agent
|
|
3622
3782
|
]);
|
|
3623
|
-
const catalog =
|
|
3783
|
+
const catalog = useMemo6(() => toolCatalogFrom(entries), [
|
|
3624
3784
|
entries
|
|
3625
3785
|
]);
|
|
3626
3786
|
return {
|
|
@@ -3634,7 +3794,7 @@ function useToolCatalog(options) {
|
|
|
3634
3794
|
__name(useToolCatalog, "useToolCatalog");
|
|
3635
3795
|
|
|
3636
3796
|
// src/approvals/countdown.ts
|
|
3637
|
-
import { useEffect as
|
|
3797
|
+
import { useEffect as useEffect11, useRef as useRef9, useState as useState11 } from "react";
|
|
3638
3798
|
function approvalCountdown(expiresAt, now = Date.now()) {
|
|
3639
3799
|
const deadline = expiresAt == null ? Number.NaN : Date.parse(expiresAt);
|
|
3640
3800
|
if (!Number.isFinite(deadline)) {
|
|
@@ -3652,10 +3812,10 @@ function approvalCountdown(expiresAt, now = Date.now()) {
|
|
|
3652
3812
|
__name(approvalCountdown, "approvalCountdown");
|
|
3653
3813
|
function useApprovalCountdown(expiresAt, options = {}) {
|
|
3654
3814
|
const { intervalMs = 1e3 } = options;
|
|
3655
|
-
const nowRef =
|
|
3815
|
+
const nowRef = useRef9(options.now ?? Date.now);
|
|
3656
3816
|
nowRef.current = options.now ?? Date.now;
|
|
3657
|
-
const [state, setState] =
|
|
3658
|
-
|
|
3817
|
+
const [state, setState] = useState11(() => approvalCountdown(expiresAt, nowRef.current()));
|
|
3818
|
+
useEffect11(() => {
|
|
3659
3819
|
const read = /* @__PURE__ */ __name(() => approvalCountdown(expiresAt, nowRef.current()), "read");
|
|
3660
3820
|
const first = read();
|
|
3661
3821
|
setState(first);
|
|
@@ -3897,20 +4057,20 @@ __name(sumUsage, "sumUsage");
|
|
|
3897
4057
|
|
|
3898
4058
|
// src/use-agent-chat.ts
|
|
3899
4059
|
import { useChat } from "@ai-sdk/react";
|
|
3900
|
-
import { useCallback as
|
|
4060
|
+
import { useCallback as useCallback9, useEffect as useEffect12, useMemo as useMemo7, useRef as useRef10, useState as useState12 } from "react";
|
|
3901
4061
|
function useAgentChat(options) {
|
|
3902
|
-
const latest =
|
|
4062
|
+
const latest = useRef10(options);
|
|
3903
4063
|
latest.current = options;
|
|
3904
|
-
const [runId, setRunId] =
|
|
3905
|
-
const runIdRef =
|
|
4064
|
+
const [runId, setRunId] = useState12(options.resumeRunId);
|
|
4065
|
+
const runIdRef = useRef10(runId);
|
|
3906
4066
|
runIdRef.current = runId;
|
|
3907
|
-
const settlingRunIdRef =
|
|
3908
|
-
const autoResumeRunIdRef =
|
|
3909
|
-
const [autoResume, setAutoResume] =
|
|
3910
|
-
const [activeRunId, setActiveRunId] =
|
|
3911
|
-
const regenerateNext =
|
|
3912
|
-
const createdThreadId =
|
|
3913
|
-
const client =
|
|
4067
|
+
const settlingRunIdRef = useRef10(void 0);
|
|
4068
|
+
const autoResumeRunIdRef = useRef10(void 0);
|
|
4069
|
+
const [autoResume, setAutoResume] = useState12(false);
|
|
4070
|
+
const [activeRunId, setActiveRunId] = useState12(null);
|
|
4071
|
+
const regenerateNext = useRef10(false);
|
|
4072
|
+
const createdThreadId = useRef10(void 0);
|
|
4073
|
+
const client = useMemo7(() => {
|
|
3914
4074
|
if (options.backend) return options.backend;
|
|
3915
4075
|
if (options.client) return options.client;
|
|
3916
4076
|
return new AgentClient({
|
|
@@ -3926,11 +4086,11 @@ function useAgentChat(options) {
|
|
|
3926
4086
|
getHeaders: /* @__PURE__ */ __name(async () => mergeHeaders(latest.current), "getHeaders")
|
|
3927
4087
|
});
|
|
3928
4088
|
}, []);
|
|
3929
|
-
const [connection, setConnection] =
|
|
4089
|
+
const [connection, setConnection] = useState12({
|
|
3930
4090
|
status: "live"
|
|
3931
4091
|
});
|
|
3932
|
-
const resyncAfterSettle =
|
|
3933
|
-
|
|
4092
|
+
const resyncAfterSettle = useRef10(false);
|
|
4093
|
+
useEffect12(() => {
|
|
3934
4094
|
if (!options.resume || options.threadId === void 0) return;
|
|
3935
4095
|
let cancelled = false;
|
|
3936
4096
|
const threadId = options.threadId;
|
|
@@ -3950,7 +4110,7 @@ function useAgentChat(options) {
|
|
|
3950
4110
|
options.resume,
|
|
3951
4111
|
options.threadId
|
|
3952
4112
|
]);
|
|
3953
|
-
const transport =
|
|
4113
|
+
const transport = useMemo7(() => {
|
|
3954
4114
|
function onMeta(meta) {
|
|
3955
4115
|
settlingRunIdRef.current = meta.runId;
|
|
3956
4116
|
setRunId(meta.runId);
|
|
@@ -3987,6 +4147,9 @@ function useAgentChat(options) {
|
|
|
3987
4147
|
...threadId !== void 0 ? {
|
|
3988
4148
|
threadId
|
|
3989
4149
|
} : {},
|
|
4150
|
+
...current.model !== void 0 ? {
|
|
4151
|
+
model: current.model
|
|
4152
|
+
} : {},
|
|
3990
4153
|
...pageContext ? {
|
|
3991
4154
|
pageContext
|
|
3992
4155
|
} : {},
|
|
@@ -4002,7 +4165,7 @@ function useAgentChat(options) {
|
|
|
4002
4165
|
}, "onAttemptStart")
|
|
4003
4166
|
});
|
|
4004
4167
|
}, []);
|
|
4005
|
-
const backgroundRef =
|
|
4168
|
+
const backgroundRef = useRef10(() => Promise.resolve());
|
|
4006
4169
|
const chat = useChat({
|
|
4007
4170
|
transport,
|
|
4008
4171
|
resume: options.resumeRunId !== void 0 || autoResume,
|
|
@@ -4051,7 +4214,7 @@ function useAgentChat(options) {
|
|
|
4051
4214
|
}
|
|
4052
4215
|
}, "onFinish")
|
|
4053
4216
|
});
|
|
4054
|
-
const chatRef =
|
|
4217
|
+
const chatRef = useRef10(chat);
|
|
4055
4218
|
chatRef.current = chat;
|
|
4056
4219
|
async function resyncFromThread() {
|
|
4057
4220
|
const threadId = latest.current.threadId ?? createdThreadId.current;
|
|
@@ -4063,11 +4226,13 @@ function useAgentChat(options) {
|
|
|
4063
4226
|
}
|
|
4064
4227
|
}
|
|
4065
4228
|
__name(resyncFromThread, "resyncFromThread");
|
|
4066
|
-
const turnInFlight =
|
|
4067
|
-
const isTurnInFlight =
|
|
4229
|
+
const turnInFlight = useRef10(false);
|
|
4230
|
+
const isTurnInFlight = useCallback9(() => turnInFlight.current || transport.isAttemptLive, [
|
|
4068
4231
|
transport
|
|
4069
4232
|
]);
|
|
4070
|
-
const sendMessage =
|
|
4233
|
+
const sendMessage = useCallback9(async (...args) => {
|
|
4234
|
+
const blocked = latest.current.blocked;
|
|
4235
|
+
if (blocked != null) throw new QuotaBlockedError(blocked);
|
|
4071
4236
|
if (isTurnInFlight()) return;
|
|
4072
4237
|
turnInFlight.current = true;
|
|
4073
4238
|
try {
|
|
@@ -4078,15 +4243,15 @@ function useAgentChat(options) {
|
|
|
4078
4243
|
}, [
|
|
4079
4244
|
isTurnInFlight
|
|
4080
4245
|
]);
|
|
4081
|
-
const addToolResult =
|
|
4246
|
+
const addToolResult = useCallback9(({ tool, toolCallId, output }) => chatRef.current.addToolResult({
|
|
4082
4247
|
tool,
|
|
4083
4248
|
toolCallId,
|
|
4084
4249
|
output
|
|
4085
4250
|
}), []);
|
|
4086
|
-
const [threads, setThreads] =
|
|
4087
|
-
const [quota, setQuota] =
|
|
4088
|
-
const [backgroundRuns, setBackgroundRuns] =
|
|
4089
|
-
const refreshBackground =
|
|
4251
|
+
const [threads, setThreads] = useState12([]);
|
|
4252
|
+
const [quota, setQuota] = useState12(null);
|
|
4253
|
+
const [backgroundRuns, setBackgroundRuns] = useState12([]);
|
|
4254
|
+
const refreshBackground = useCallback9(async () => {
|
|
4090
4255
|
const threadId = latest.current.threadId ?? createdThreadId.current;
|
|
4091
4256
|
if (threadId === void 0) {
|
|
4092
4257
|
return;
|
|
@@ -4111,7 +4276,7 @@ function useAgentChat(options) {
|
|
|
4111
4276
|
]);
|
|
4112
4277
|
backgroundRef.current = refreshBackground;
|
|
4113
4278
|
const isWorking = backgroundRuns.some((run) => run.status === "running");
|
|
4114
|
-
|
|
4279
|
+
useEffect12(() => {
|
|
4115
4280
|
if (options.background !== true || options.threadId === void 0) {
|
|
4116
4281
|
return;
|
|
4117
4282
|
}
|
|
@@ -4121,7 +4286,7 @@ function useAgentChat(options) {
|
|
|
4121
4286
|
options.threadId,
|
|
4122
4287
|
refreshBackground
|
|
4123
4288
|
]);
|
|
4124
|
-
|
|
4289
|
+
useEffect12(() => {
|
|
4125
4290
|
const every = latest.current.backgroundPollMs ?? 5e3;
|
|
4126
4291
|
if (latest.current.background !== true || !isWorking || every <= 0) {
|
|
4127
4292
|
return;
|
|
@@ -4132,26 +4297,26 @@ function useAgentChat(options) {
|
|
|
4132
4297
|
isWorking,
|
|
4133
4298
|
refreshBackground
|
|
4134
4299
|
]);
|
|
4135
|
-
const loadThreads =
|
|
4300
|
+
const loadThreads = useCallback9(async () => {
|
|
4136
4301
|
const list = await client.listThreads();
|
|
4137
4302
|
setThreads(list);
|
|
4138
4303
|
return list;
|
|
4139
4304
|
}, [
|
|
4140
4305
|
client
|
|
4141
4306
|
]);
|
|
4142
|
-
const loadThread =
|
|
4307
|
+
const loadThread = useCallback9((id) => client.getThread(id), [
|
|
4143
4308
|
client
|
|
4144
4309
|
]);
|
|
4145
|
-
const deleteThread =
|
|
4310
|
+
const deleteThread = useCallback9(async (id) => {
|
|
4146
4311
|
await client.deleteThread(id);
|
|
4147
4312
|
setThreads((current) => current.filter((thread) => thread.id !== id));
|
|
4148
4313
|
}, [
|
|
4149
4314
|
client
|
|
4150
4315
|
]);
|
|
4151
|
-
const forkThread =
|
|
4316
|
+
const forkThread = useCallback9((threadId, messageId) => requireBackendMethod(client, "forkFromMessage")(threadId, messageId), [
|
|
4152
4317
|
client
|
|
4153
4318
|
]);
|
|
4154
|
-
const renameThread =
|
|
4319
|
+
const renameThread = useCallback9(async (id, title) => {
|
|
4155
4320
|
await client.updateThread(id, {
|
|
4156
4321
|
title
|
|
4157
4322
|
});
|
|
@@ -4162,24 +4327,24 @@ function useAgentChat(options) {
|
|
|
4162
4327
|
}, [
|
|
4163
4328
|
client
|
|
4164
4329
|
]);
|
|
4165
|
-
const promoteThread =
|
|
4330
|
+
const promoteThread = useCallback9(async (id) => {
|
|
4166
4331
|
await requireBackendMethod(client, "promoteThread")(id);
|
|
4167
4332
|
await loadThreads();
|
|
4168
4333
|
}, [
|
|
4169
4334
|
client,
|
|
4170
4335
|
loadThreads
|
|
4171
4336
|
]);
|
|
4172
|
-
const truncateFromMessage =
|
|
4337
|
+
const truncateFromMessage = useCallback9((threadId, messageId) => requireBackendMethod(client, "truncateFromMessage")(threadId, messageId).then(() => void 0), [
|
|
4173
4338
|
client
|
|
4174
4339
|
]);
|
|
4175
|
-
const loadQuota =
|
|
4340
|
+
const loadQuota = useCallback9(async () => {
|
|
4176
4341
|
const today = await requireBackendMethod(client, "getQuotaToday")();
|
|
4177
4342
|
setQuota(today);
|
|
4178
4343
|
return today;
|
|
4179
4344
|
}, [
|
|
4180
4345
|
client
|
|
4181
4346
|
]);
|
|
4182
|
-
const cancel =
|
|
4347
|
+
const cancel = useCallback9(async () => {
|
|
4183
4348
|
chatRef.current.stop();
|
|
4184
4349
|
const activeRunId2 = runIdRef.current;
|
|
4185
4350
|
if (activeRunId2) {
|
|
@@ -4191,7 +4356,7 @@ function useAgentChat(options) {
|
|
|
4191
4356
|
}, [
|
|
4192
4357
|
client
|
|
4193
4358
|
]);
|
|
4194
|
-
const approve =
|
|
4359
|
+
const approve = useCallback9(async ({ toolCallId, remember, via }) => {
|
|
4195
4360
|
await requireBackendMethod(client, "approveToolCall")({
|
|
4196
4361
|
toolCallId,
|
|
4197
4362
|
...remember === true ? {
|
|
@@ -4204,7 +4369,7 @@ function useAgentChat(options) {
|
|
|
4204
4369
|
}, [
|
|
4205
4370
|
client
|
|
4206
4371
|
]);
|
|
4207
|
-
const reject =
|
|
4372
|
+
const reject = useCallback9(async ({ toolCallId, reason, via }) => {
|
|
4208
4373
|
await requireBackendMethod(client, "rejectToolCall")({
|
|
4209
4374
|
toolCallId,
|
|
4210
4375
|
...reason !== void 0 ? {
|
|
@@ -4217,7 +4382,7 @@ function useAgentChat(options) {
|
|
|
4217
4382
|
}, [
|
|
4218
4383
|
client
|
|
4219
4384
|
]);
|
|
4220
|
-
const answer =
|
|
4385
|
+
const answer = useCallback9(async ({ toolCallId, answers }) => {
|
|
4221
4386
|
await requireBackendMethod(client, "answerToolCall")({
|
|
4222
4387
|
toolCallId,
|
|
4223
4388
|
...answers !== void 0 ? {
|
|
@@ -4227,14 +4392,16 @@ function useAgentChat(options) {
|
|
|
4227
4392
|
}, [
|
|
4228
4393
|
client
|
|
4229
4394
|
]);
|
|
4230
|
-
const skip =
|
|
4395
|
+
const skip = useCallback9(async ({ toolCallId }) => {
|
|
4231
4396
|
await requireBackendMethod(client, "skipToolCall")({
|
|
4232
4397
|
toolCallId
|
|
4233
4398
|
});
|
|
4234
4399
|
}, [
|
|
4235
4400
|
client
|
|
4236
4401
|
]);
|
|
4237
|
-
const regenerate =
|
|
4402
|
+
const regenerate = useCallback9(() => {
|
|
4403
|
+
const blocked = latest.current.blocked;
|
|
4404
|
+
if (blocked != null) throw new QuotaBlockedError(blocked);
|
|
4238
4405
|
if (isTurnInFlight()) return;
|
|
4239
4406
|
regenerateNext.current = true;
|
|
4240
4407
|
turnInFlight.current = true;
|
|
@@ -4249,7 +4416,21 @@ function useAgentChat(options) {
|
|
|
4249
4416
|
isWorking,
|
|
4250
4417
|
refresh: refreshBackground
|
|
4251
4418
|
};
|
|
4252
|
-
const
|
|
4419
|
+
const setThreadModel = useCallback9(async (model) => {
|
|
4420
|
+
const threadId = latest.current.threadId ?? createdThreadId.current;
|
|
4421
|
+
if (threadId === void 0) {
|
|
4422
|
+
throw new Error("setThreadModel: this chat has no thread yet");
|
|
4423
|
+
}
|
|
4424
|
+
await client.updateThread(threadId, {
|
|
4425
|
+
model
|
|
4426
|
+
});
|
|
4427
|
+
notifyThreads(client, {
|
|
4428
|
+
type: "changed"
|
|
4429
|
+
});
|
|
4430
|
+
}, [
|
|
4431
|
+
client
|
|
4432
|
+
]);
|
|
4433
|
+
const getThreadId = useCallback9(() => latest.current.threadId ?? createdThreadId.current, []);
|
|
4253
4434
|
const status = connection.status === "reconnecting" ? "reconnecting" : chat.status;
|
|
4254
4435
|
return {
|
|
4255
4436
|
...chat,
|
|
@@ -4268,6 +4449,7 @@ function useAgentChat(options) {
|
|
|
4268
4449
|
* on the first send. A getter, because the created id is learned mid-stream.
|
|
4269
4450
|
*/
|
|
4270
4451
|
getThreadId,
|
|
4452
|
+
setThreadModel,
|
|
4271
4453
|
/** The backend this chat talks to — pass it to `useThreads`, `useMessageFeedback`, … */
|
|
4272
4454
|
backend: client,
|
|
4273
4455
|
/** Same object as {@link backend}; kept for callers that read it under its old name. */
|
|
@@ -4291,6 +4473,16 @@ function useAgentChat(options) {
|
|
|
4291
4473
|
};
|
|
4292
4474
|
}
|
|
4293
4475
|
__name(useAgentChat, "useAgentChat");
|
|
4476
|
+
var QuotaBlockedError = class extends Error {
|
|
4477
|
+
static {
|
|
4478
|
+
__name(this, "QuotaBlockedError");
|
|
4479
|
+
}
|
|
4480
|
+
block;
|
|
4481
|
+
constructor(block) {
|
|
4482
|
+
super(block.reason ?? `The ${block.period === "day" ? "daily" : "monthly"} quota is used up`), this.block = block;
|
|
4483
|
+
this.name = "QuotaBlockedError";
|
|
4484
|
+
}
|
|
4485
|
+
};
|
|
4294
4486
|
async function mergeHeaders(options) {
|
|
4295
4487
|
const dynamic = await options.getHeaders?.() ?? {};
|
|
4296
4488
|
return {
|
|
@@ -4309,6 +4501,7 @@ export {
|
|
|
4309
4501
|
MessageItem,
|
|
4310
4502
|
MessageItemView,
|
|
4311
4503
|
MessageList,
|
|
4504
|
+
QuotaBlockedError,
|
|
4312
4505
|
SPEECH_LANGUAGES,
|
|
4313
4506
|
applyCompletion,
|
|
4314
4507
|
approvalCountdown,
|
|
@@ -4343,11 +4536,14 @@ export {
|
|
|
4343
4536
|
toolCallState,
|
|
4344
4537
|
toolCatalogFrom,
|
|
4345
4538
|
useAgentChat,
|
|
4539
|
+
useAgents,
|
|
4346
4540
|
useApprovalCountdown,
|
|
4347
4541
|
useChatTranscript,
|
|
4348
4542
|
useComposerAutocomplete,
|
|
4349
4543
|
useElapsed,
|
|
4350
4544
|
useMessageFeedback,
|
|
4545
|
+
useModels,
|
|
4546
|
+
useQuota,
|
|
4351
4547
|
useSpeechRecognition,
|
|
4352
4548
|
useStickToBottom,
|
|
4353
4549
|
useThreads,
|