@paymanai/payman-ask-sdk 4.0.23 → 4.0.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +540 -429
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +282 -171
- package/dist/index.mjs.map +1 -1
- package/dist/index.native.js +241 -46
- package/dist/index.native.js.map +1 -1
- package/dist/styles.css +0 -30
- package/dist/styles.css.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var react = require('react');
|
|
4
4
|
var framerMotion = require('framer-motion');
|
|
5
5
|
var clsx = require('clsx');
|
|
6
6
|
var tailwindMerge = require('tailwind-merge');
|
|
@@ -33,7 +33,6 @@ function _interopNamespace(e) {
|
|
|
33
33
|
return Object.freeze(n);
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
var React__namespace = /*#__PURE__*/_interopNamespace(React);
|
|
37
36
|
var Sentry__namespace = /*#__PURE__*/_interopNamespace(Sentry);
|
|
38
37
|
var ReactMarkdown__default = /*#__PURE__*/_interopDefault(ReactMarkdown);
|
|
39
38
|
var remarkGfm__default = /*#__PURE__*/_interopDefault(remarkGfm);
|
|
@@ -523,9 +522,9 @@ function processStreamEventV2(rawEvent, state) {
|
|
|
523
522
|
state.hasError = true;
|
|
524
523
|
state.errorMessage = "WORKFLOW_FAILED";
|
|
525
524
|
}
|
|
526
|
-
state.steps.forEach((
|
|
527
|
-
if (
|
|
528
|
-
|
|
525
|
+
state.steps.forEach((step2) => {
|
|
526
|
+
if (step2.status === "in_progress") {
|
|
527
|
+
step2.status = "completed";
|
|
529
528
|
}
|
|
530
529
|
});
|
|
531
530
|
state.lastEventType = eventType;
|
|
@@ -737,7 +736,8 @@ function buildRequestBody(config, userMessage, sessionId, options) {
|
|
|
737
736
|
sessionAttributes,
|
|
738
737
|
analysisMode: options?.analysisMode,
|
|
739
738
|
locale: resolveLocale(config.locale),
|
|
740
|
-
timezone: resolveTimezone(config.timezone)
|
|
739
|
+
timezone: resolveTimezone(config.timezone),
|
|
740
|
+
...options?.attachments?.length ? { attachments: options.attachments } : {}
|
|
741
741
|
};
|
|
742
742
|
}
|
|
743
743
|
function resolveLocale(configured) {
|
|
@@ -782,6 +782,7 @@ function buildResolveImagesUrl(config) {
|
|
|
782
782
|
const basePath = normalizedEndpointPath.endsWith("/stream") ? normalizedEndpointPath.slice(0, -"/stream".length) : normalizedEndpointPath;
|
|
783
783
|
return `${config.api.baseUrl}${basePath}/resolve-image-urls`;
|
|
784
784
|
}
|
|
785
|
+
var NGROK_SKIP_BROWSER_WARNING = "ngrok-skip-browser-warning";
|
|
785
786
|
function buildRequestHeaders(config) {
|
|
786
787
|
const headers = {
|
|
787
788
|
...config.api.headers
|
|
@@ -789,6 +790,9 @@ function buildRequestHeaders(config) {
|
|
|
789
790
|
if (config.api.authToken) {
|
|
790
791
|
headers.Authorization = `Bearer ${config.api.authToken}`;
|
|
791
792
|
}
|
|
793
|
+
if (!headers[NGROK_SKIP_BROWSER_WARNING]) {
|
|
794
|
+
headers[NGROK_SKIP_BROWSER_WARNING] = "true";
|
|
795
|
+
}
|
|
792
796
|
return headers;
|
|
793
797
|
}
|
|
794
798
|
var RAG_IMAGE_REGEX = /\/api\/rag\/chunks\/[^"'\s]+\/image/;
|
|
@@ -841,12 +845,12 @@ async function resolveRagImageUrls(config, content, signal) {
|
|
|
841
845
|
}
|
|
842
846
|
var FRIENDLY_ERROR_MESSAGE = "Oops, something went wrong. Please try again.";
|
|
843
847
|
function useStreamManagerV2(config, callbacks, setMessages, setIsWaitingForResponse) {
|
|
844
|
-
const abortControllerRef =
|
|
845
|
-
const configRef =
|
|
848
|
+
const abortControllerRef = react.useRef(null);
|
|
849
|
+
const configRef = react.useRef(config);
|
|
846
850
|
configRef.current = config;
|
|
847
|
-
const callbacksRef =
|
|
851
|
+
const callbacksRef = react.useRef(callbacks);
|
|
848
852
|
callbacksRef.current = callbacks;
|
|
849
|
-
const startStream =
|
|
853
|
+
const startStream = react.useCallback(
|
|
850
854
|
async (userMessage, streamingId, sessionId, externalAbortController, options) => {
|
|
851
855
|
abortControllerRef.current?.abort();
|
|
852
856
|
const abortController = externalAbortController ?? new AbortController();
|
|
@@ -940,11 +944,11 @@ function useStreamManagerV2(config, callbacks, setMessages, setIsWaitingForRespo
|
|
|
940
944
|
errorDetails: isAborted ? void 0 : error.message,
|
|
941
945
|
content: isAborted ? state.finalResponse || "" : state.finalResponse || FRIENDLY_ERROR_MESSAGE,
|
|
942
946
|
currentMessage: isAborted ? "Thinking..." : void 0,
|
|
943
|
-
steps: [...state.steps].map((
|
|
944
|
-
if (
|
|
945
|
-
return { ...
|
|
947
|
+
steps: [...state.steps].map((step2) => {
|
|
948
|
+
if (step2.status === "in_progress" && isAborted) {
|
|
949
|
+
return { ...step2, status: "pending" };
|
|
946
950
|
}
|
|
947
|
-
return
|
|
951
|
+
return step2;
|
|
948
952
|
}),
|
|
949
953
|
currentExecutingStepId: void 0
|
|
950
954
|
} : msg
|
|
@@ -1030,11 +1034,11 @@ function useStreamManagerV2(config, callbacks, setMessages, setIsWaitingForRespo
|
|
|
1030
1034
|
isCancelled: isAborted,
|
|
1031
1035
|
errorDetails: isAborted ? void 0 : error.message,
|
|
1032
1036
|
content: isAborted ? state.finalResponse || "" : state.finalResponse || FRIENDLY_ERROR_MESSAGE,
|
|
1033
|
-
steps: [...state.steps].map((
|
|
1034
|
-
if (
|
|
1035
|
-
return { ...
|
|
1037
|
+
steps: [...state.steps].map((step2) => {
|
|
1038
|
+
if (step2.status === "in_progress" && isAborted) {
|
|
1039
|
+
return { ...step2, status: "pending" };
|
|
1036
1040
|
}
|
|
1037
|
-
return
|
|
1041
|
+
return step2;
|
|
1038
1042
|
}),
|
|
1039
1043
|
currentExecutingStepId: void 0
|
|
1040
1044
|
} : msg
|
|
@@ -1045,7 +1049,7 @@ function useStreamManagerV2(config, callbacks, setMessages, setIsWaitingForRespo
|
|
|
1045
1049
|
},
|
|
1046
1050
|
[setMessages, setIsWaitingForResponse]
|
|
1047
1051
|
);
|
|
1048
|
-
const cancelStream =
|
|
1052
|
+
const cancelStream = react.useCallback(() => {
|
|
1049
1053
|
abortControllerRef.current?.abort();
|
|
1050
1054
|
}, []);
|
|
1051
1055
|
return {
|
|
@@ -1055,11 +1059,11 @@ function useStreamManagerV2(config, callbacks, setMessages, setIsWaitingForRespo
|
|
|
1055
1059
|
};
|
|
1056
1060
|
}
|
|
1057
1061
|
function createCancelledMessageUpdate(steps, currentMessage) {
|
|
1058
|
-
const updatedSteps = steps.map((
|
|
1059
|
-
if (
|
|
1060
|
-
return { ...
|
|
1062
|
+
const updatedSteps = steps.map((step2) => {
|
|
1063
|
+
if (step2.status === "in_progress") {
|
|
1064
|
+
return { ...step2, status: "pending" };
|
|
1061
1065
|
}
|
|
1062
|
-
return
|
|
1066
|
+
return step2;
|
|
1063
1067
|
});
|
|
1064
1068
|
return {
|
|
1065
1069
|
isStreaming: false,
|
|
@@ -1069,6 +1073,81 @@ function createCancelledMessageUpdate(steps, currentMessage) {
|
|
|
1069
1073
|
currentMessage: currentMessage || "Thinking..."
|
|
1070
1074
|
};
|
|
1071
1075
|
}
|
|
1076
|
+
var DEFAULT_SIGNED_URL_ENDPOINT = "/api/files/signed-url";
|
|
1077
|
+
function fileExtension(filename) {
|
|
1078
|
+
const ext = filename.split(".").pop()?.toLowerCase().replace(/^\./, "");
|
|
1079
|
+
return ext && ext.length > 0 ? ext : "bin";
|
|
1080
|
+
}
|
|
1081
|
+
function resolveMimeType(file) {
|
|
1082
|
+
if (file.type && file.type.trim().length > 0) return file.type;
|
|
1083
|
+
const ext = fileExtension(file.name);
|
|
1084
|
+
const byExt = {
|
|
1085
|
+
pdf: "application/pdf",
|
|
1086
|
+
png: "image/png",
|
|
1087
|
+
jpg: "image/jpeg",
|
|
1088
|
+
jpeg: "image/jpeg",
|
|
1089
|
+
gif: "image/gif",
|
|
1090
|
+
webp: "image/webp"
|
|
1091
|
+
};
|
|
1092
|
+
return byExt[ext] ?? "application/octet-stream";
|
|
1093
|
+
}
|
|
1094
|
+
function buildSignedUrlEndpoint(config, ext) {
|
|
1095
|
+
const endpoint = config.api.signedUrlEndpoint || DEFAULT_SIGNED_URL_ENDPOINT;
|
|
1096
|
+
const queryParams = new URLSearchParams({ extn: ext.replace(/^\./, "") });
|
|
1097
|
+
return `${config.api.baseUrl}${endpoint}?${queryParams.toString()}`;
|
|
1098
|
+
}
|
|
1099
|
+
async function requestSignedUrl(config, ext, signal) {
|
|
1100
|
+
const url = buildSignedUrlEndpoint(config, ext);
|
|
1101
|
+
const headers = buildRequestHeaders(config);
|
|
1102
|
+
const response = await fetch(url, {
|
|
1103
|
+
method: "GET",
|
|
1104
|
+
headers,
|
|
1105
|
+
signal
|
|
1106
|
+
});
|
|
1107
|
+
if (!response.ok) {
|
|
1108
|
+
const errorText = await response.text().catch(() => "");
|
|
1109
|
+
throw new Error(
|
|
1110
|
+
errorText ? `Failed to get upload URL (${response.status}): ${errorText}` : `Failed to get upload URL (${response.status})`
|
|
1111
|
+
);
|
|
1112
|
+
}
|
|
1113
|
+
const data = await response.json();
|
|
1114
|
+
if (!data.key || !data.url) {
|
|
1115
|
+
throw new Error("Signed URL response missing key or url");
|
|
1116
|
+
}
|
|
1117
|
+
return { key: data.key, url: data.url };
|
|
1118
|
+
}
|
|
1119
|
+
async function uploadToSignedUrl(signedUrl, file, mimeType, signal) {
|
|
1120
|
+
const response = await fetch(signedUrl, {
|
|
1121
|
+
method: "PUT",
|
|
1122
|
+
headers: {
|
|
1123
|
+
"Content-Type": mimeType,
|
|
1124
|
+
"x-ms-blob-type": "BlockBlob"
|
|
1125
|
+
},
|
|
1126
|
+
body: file,
|
|
1127
|
+
signal
|
|
1128
|
+
});
|
|
1129
|
+
if (!response.ok) {
|
|
1130
|
+
const errorText = await response.text().catch(() => "");
|
|
1131
|
+
throw new Error(
|
|
1132
|
+
errorText ? `Failed to upload file (${response.status}): ${errorText}` : `Failed to upload file (${response.status})`
|
|
1133
|
+
);
|
|
1134
|
+
}
|
|
1135
|
+
}
|
|
1136
|
+
async function uploadAttachment(config, file, signal) {
|
|
1137
|
+
const ext = fileExtension(file.name);
|
|
1138
|
+
const mimeType = resolveMimeType(file);
|
|
1139
|
+
const { key, url } = await requestSignedUrl(config, ext, signal);
|
|
1140
|
+
await uploadToSignedUrl(url, file, mimeType, signal);
|
|
1141
|
+
return {
|
|
1142
|
+
tempKey: key,
|
|
1143
|
+
filename: file.name,
|
|
1144
|
+
mimeType
|
|
1145
|
+
};
|
|
1146
|
+
}
|
|
1147
|
+
async function uploadAttachments(config, files, signal) {
|
|
1148
|
+
const uploads = files.map((file) => uploadAttachment(config, file, signal));
|
|
1149
|
+
return Promise.all(uploads);
|
|
1150
|
+
}
|
|
1072
1151
|
var UserActionStaleError = class extends Error {
|
|
1073
1152
|
constructor(userActionId, message = "User action is no longer actionable") {
|
|
1074
1153
|
super(message);
|
|
@@ -1105,9 +1184,6 @@ async function cancelUserAction(config, userActionId) {
|
|
|
1105
1184
|
async function resendUserAction(config, userActionId) {
|
|
1106
1185
|
return sendUserActionRequest(config, userActionId, "resend");
|
|
1107
1186
|
}
|
|
1108
|
-
async function expireUserAction(config, userActionId) {
|
|
1109
|
-
return sendUserActionRequest(config, userActionId, "expired");
|
|
1110
|
-
}
|
|
1111
1187
|
var EMPTY_USER_ACTION_STATE = { prompts: [], notifications: [] };
|
|
1112
1188
|
function upsertPrompt(prompts, req) {
|
|
1113
1189
|
const active = { ...req, status: "pending" };
|
|
@@ -1136,25 +1212,45 @@ function getStoredOrInitialMessages(config) {
|
|
|
1136
1212
|
function getSessionIdFromMessages(messages) {
|
|
1137
1213
|
return messages.find((message) => message.sessionId)?.sessionId;
|
|
1138
1214
|
}
|
|
1215
|
+
var IMAGE_EXTENSIONS = /* @__PURE__ */ new Set(["jpg", "jpeg", "png", "gif", "webp", "avif"]);
|
|
1216
|
+
function attachmentKindFromFile(file) {
|
|
1217
|
+
const ext = file.name.split(".").pop()?.toLowerCase() ?? "";
|
|
1218
|
+
if (IMAGE_EXTENSIONS.has(ext) || file.type.startsWith("image/")) return "image";
|
|
1219
|
+
return "file";
|
|
1220
|
+
}
|
|
1221
|
+
function buildMessageAttachments(files) {
|
|
1222
|
+
return files.map((file, index) => {
|
|
1223
|
+
const kind = attachmentKindFromFile(file);
|
|
1224
|
+
return {
|
|
1225
|
+
id: `att-${Date.now()}-${index}`,
|
|
1226
|
+
filename: file.name,
|
|
1227
|
+
mimeType: file.type || "application/octet-stream",
|
|
1228
|
+
// Blob URL for all local files so PDFs/docs stay previewable after send.
|
|
1229
|
+
previewUrl: URL.createObjectURL(file),
|
|
1230
|
+
kind
|
|
1231
|
+
};
|
|
1232
|
+
});
|
|
1233
|
+
}
|
|
1139
1234
|
function useChatV2(config, callbacks = {}) {
|
|
1140
|
-
const [messages, setMessages] =
|
|
1141
|
-
const [isWaitingForResponse, setIsWaitingForResponse] =
|
|
1235
|
+
const [messages, setMessages] = react.useState(() => getStoredOrInitialMessages(config));
|
|
1236
|
+
const [isWaitingForResponse, setIsWaitingForResponse] = react.useState(() => {
|
|
1142
1237
|
if (!config.userId) return false;
|
|
1143
1238
|
return activeStreamStore.get(config.userId)?.isWaiting ?? false;
|
|
1144
1239
|
});
|
|
1145
|
-
const
|
|
1240
|
+
const [isUploadingAttachments, setIsUploadingAttachments] = react.useState(false);
|
|
1241
|
+
const sessionIdRef = react.useRef(
|
|
1146
1242
|
getSessionIdFromMessages(getStoredOrInitialMessages(config)) ?? config.initialSessionId ?? void 0
|
|
1147
1243
|
);
|
|
1148
|
-
const prevUserIdRef =
|
|
1149
|
-
const streamUserIdRef =
|
|
1150
|
-
const subscriptionPrevUserIdRef =
|
|
1151
|
-
const callbacksRef =
|
|
1244
|
+
const prevUserIdRef = react.useRef(config.userId);
|
|
1245
|
+
const streamUserIdRef = react.useRef(void 0);
|
|
1246
|
+
const subscriptionPrevUserIdRef = react.useRef(config.userId);
|
|
1247
|
+
const callbacksRef = react.useRef(callbacks);
|
|
1152
1248
|
callbacksRef.current = callbacks;
|
|
1153
|
-
const configRef =
|
|
1249
|
+
const configRef = react.useRef(config);
|
|
1154
1250
|
configRef.current = config;
|
|
1155
|
-
const messagesRef =
|
|
1251
|
+
const messagesRef = react.useRef(messages);
|
|
1156
1252
|
messagesRef.current = messages;
|
|
1157
|
-
const storeAwareSetMessages =
|
|
1253
|
+
const storeAwareSetMessages = react.useCallback(
|
|
1158
1254
|
(updater) => {
|
|
1159
1255
|
const streamUserId = streamUserIdRef.current;
|
|
1160
1256
|
const currentUserId = configRef.current.userId;
|
|
@@ -1169,7 +1265,7 @@ function useChatV2(config, callbacks = {}) {
|
|
|
1169
1265
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
1170
1266
|
[]
|
|
1171
1267
|
);
|
|
1172
|
-
const storeAwareSetIsWaiting =
|
|
1268
|
+
const storeAwareSetIsWaiting = react.useCallback(
|
|
1173
1269
|
(waiting) => {
|
|
1174
1270
|
const streamUserId = streamUserIdRef.current;
|
|
1175
1271
|
const currentUserId = configRef.current.userId;
|
|
@@ -1184,8 +1280,8 @@ function useChatV2(config, callbacks = {}) {
|
|
|
1184
1280
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
1185
1281
|
[]
|
|
1186
1282
|
);
|
|
1187
|
-
const [userActionState, setUserActionState] =
|
|
1188
|
-
const wrappedCallbacks =
|
|
1283
|
+
const [userActionState, setUserActionState] = react.useState(EMPTY_USER_ACTION_STATE);
|
|
1284
|
+
const wrappedCallbacks = react.useMemo(() => ({
|
|
1189
1285
|
...callbacksRef.current,
|
|
1190
1286
|
onMessageSent: (message) => callbacksRef.current.onMessageSent?.(message),
|
|
1191
1287
|
onStreamStart: () => callbacksRef.current.onStreamStart?.(),
|
|
@@ -1214,23 +1310,47 @@ function useChatV2(config, callbacks = {}) {
|
|
|
1214
1310
|
storeAwareSetMessages,
|
|
1215
1311
|
storeAwareSetIsWaiting
|
|
1216
1312
|
);
|
|
1217
|
-
const sendMessage =
|
|
1313
|
+
const sendMessage = react.useCallback(
|
|
1218
1314
|
async (userMessage, options) => {
|
|
1219
|
-
|
|
1315
|
+
const trimmedMessage = userMessage.trim();
|
|
1316
|
+
const files = options?.files ?? [];
|
|
1317
|
+
const hasPreuploadedAttachments = (options?.attachments?.length ?? 0) > 0;
|
|
1318
|
+
if (!trimmedMessage && files.length === 0 && !hasPreuploadedAttachments) return;
|
|
1319
|
+
let streamAttachments = options?.attachments;
|
|
1320
|
+
if (!streamAttachments && files.length > 0) {
|
|
1321
|
+
setIsUploadingAttachments(true);
|
|
1322
|
+
try {
|
|
1323
|
+
streamAttachments = await uploadAttachments(configRef.current, files);
|
|
1324
|
+
} catch (error) {
|
|
1325
|
+
if (error.name !== "AbortError") {
|
|
1326
|
+
callbacksRef.current.onError?.(error);
|
|
1327
|
+
}
|
|
1328
|
+
throw error;
|
|
1329
|
+
} finally {
|
|
1330
|
+
setIsUploadingAttachments(false);
|
|
1331
|
+
}
|
|
1332
|
+
}
|
|
1220
1333
|
if (!sessionIdRef.current && configRef.current.autoGenerateSessionId !== false) {
|
|
1221
1334
|
sessionIdRef.current = generateId();
|
|
1222
1335
|
callbacksRef.current.onSessionIdChange?.(sessionIdRef.current);
|
|
1223
1336
|
}
|
|
1337
|
+
const messageAttachments = files.length > 0 ? buildMessageAttachments(files) : streamAttachments?.length ? streamAttachments.map((attachment, index) => ({
|
|
1338
|
+
id: `att-${Date.now()}-${index}`,
|
|
1339
|
+
filename: attachment.filename,
|
|
1340
|
+
mimeType: attachment.mimeType,
|
|
1341
|
+
kind: attachment.mimeType.startsWith("image/") ? "image" : "file"
|
|
1342
|
+
})) : void 0;
|
|
1224
1343
|
const userMessageId = `user-${Date.now()}`;
|
|
1225
1344
|
const userMsg = {
|
|
1226
1345
|
id: userMessageId,
|
|
1227
1346
|
sessionId: sessionIdRef.current,
|
|
1228
1347
|
role: "user",
|
|
1229
|
-
content:
|
|
1230
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
1348
|
+
content: trimmedMessage,
|
|
1349
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1350
|
+
attachments: messageAttachments
|
|
1231
1351
|
};
|
|
1232
1352
|
setMessages((prev) => [...prev, userMsg]);
|
|
1233
|
-
callbacksRef.current.onMessageSent?.(
|
|
1353
|
+
callbacksRef.current.onMessageSent?.(trimmedMessage);
|
|
1234
1354
|
setIsWaitingForResponse(true);
|
|
1235
1355
|
callbacksRef.current.onStreamStart?.();
|
|
1236
1356
|
const streamingId = `assistant-${Date.now()}`;
|
|
@@ -1257,11 +1377,14 @@ function useChatV2(config, callbacks = {}) {
|
|
|
1257
1377
|
activeStreamStore.start(userId, abortController, initialMessages);
|
|
1258
1378
|
}
|
|
1259
1379
|
const newSessionId = await startStream(
|
|
1260
|
-
|
|
1380
|
+
trimmedMessage,
|
|
1261
1381
|
streamingId,
|
|
1262
1382
|
sessionIdRef.current,
|
|
1263
1383
|
abortController,
|
|
1264
|
-
|
|
1384
|
+
{
|
|
1385
|
+
analysisMode: options?.analysisMode,
|
|
1386
|
+
attachments: streamAttachments
|
|
1387
|
+
}
|
|
1265
1388
|
);
|
|
1266
1389
|
const finalStreamUserId = streamUserIdRef.current ?? userId;
|
|
1267
1390
|
if (finalStreamUserId) {
|
|
@@ -1274,16 +1397,16 @@ function useChatV2(config, callbacks = {}) {
|
|
|
1274
1397
|
},
|
|
1275
1398
|
[startStream]
|
|
1276
1399
|
);
|
|
1277
|
-
const clearMessages =
|
|
1400
|
+
const clearMessages = react.useCallback(() => {
|
|
1278
1401
|
if (configRef.current.userId) {
|
|
1279
1402
|
chatStore.delete(configRef.current.userId);
|
|
1280
1403
|
}
|
|
1281
1404
|
setMessages([]);
|
|
1282
1405
|
}, []);
|
|
1283
|
-
const prependMessages =
|
|
1406
|
+
const prependMessages = react.useCallback((msgs) => {
|
|
1284
1407
|
setMessages((prev) => [...msgs, ...prev]);
|
|
1285
1408
|
}, []);
|
|
1286
|
-
const cancelStream =
|
|
1409
|
+
const cancelStream = react.useCallback(() => {
|
|
1287
1410
|
const streamUserId = streamUserIdRef.current ?? configRef.current.userId;
|
|
1288
1411
|
if (streamUserId) {
|
|
1289
1412
|
activeStreamStore.abort(streamUserId);
|
|
@@ -1307,7 +1430,7 @@ function useChatV2(config, callbacks = {}) {
|
|
|
1307
1430
|
})
|
|
1308
1431
|
);
|
|
1309
1432
|
}, [cancelStreamManager]);
|
|
1310
|
-
const resetSession =
|
|
1433
|
+
const resetSession = react.useCallback(() => {
|
|
1311
1434
|
const streamUserId = streamUserIdRef.current ?? configRef.current.userId;
|
|
1312
1435
|
if (streamUserId) {
|
|
1313
1436
|
activeStreamStore.abort(streamUserId);
|
|
@@ -1322,13 +1445,13 @@ function useChatV2(config, callbacks = {}) {
|
|
|
1322
1445
|
setIsWaitingForResponse(false);
|
|
1323
1446
|
setUserActionState(EMPTY_USER_ACTION_STATE);
|
|
1324
1447
|
}, []);
|
|
1325
|
-
const getSessionId =
|
|
1448
|
+
const getSessionId = react.useCallback(() => {
|
|
1326
1449
|
return sessionIdRef.current;
|
|
1327
1450
|
}, []);
|
|
1328
|
-
const getMessages =
|
|
1451
|
+
const getMessages = react.useCallback(() => {
|
|
1329
1452
|
return messages;
|
|
1330
1453
|
}, [messages]);
|
|
1331
|
-
const setPromptStatus =
|
|
1454
|
+
const setPromptStatus = react.useCallback(
|
|
1332
1455
|
(userActionId, status) => {
|
|
1333
1456
|
setUserActionState((prev) => ({
|
|
1334
1457
|
...prev,
|
|
@@ -1339,13 +1462,13 @@ function useChatV2(config, callbacks = {}) {
|
|
|
1339
1462
|
},
|
|
1340
1463
|
[]
|
|
1341
1464
|
);
|
|
1342
|
-
const removePrompt =
|
|
1465
|
+
const removePrompt = react.useCallback((userActionId) => {
|
|
1343
1466
|
setUserActionState((prev) => ({
|
|
1344
1467
|
...prev,
|
|
1345
1468
|
prompts: prev.prompts.filter((p) => p.userActionId !== userActionId)
|
|
1346
1469
|
}));
|
|
1347
1470
|
}, []);
|
|
1348
|
-
const submitUserAction2 =
|
|
1471
|
+
const submitUserAction2 = react.useCallback(
|
|
1349
1472
|
async (userActionId, content) => {
|
|
1350
1473
|
setPromptStatus(userActionId, "submitting");
|
|
1351
1474
|
try {
|
|
@@ -1363,7 +1486,7 @@ function useChatV2(config, callbacks = {}) {
|
|
|
1363
1486
|
},
|
|
1364
1487
|
[removePrompt, setPromptStatus]
|
|
1365
1488
|
);
|
|
1366
|
-
const cancelUserAction2 =
|
|
1489
|
+
const cancelUserAction2 = react.useCallback(
|
|
1367
1490
|
async (userActionId) => {
|
|
1368
1491
|
setPromptStatus(userActionId, "submitting");
|
|
1369
1492
|
try {
|
|
@@ -1381,7 +1504,7 @@ function useChatV2(config, callbacks = {}) {
|
|
|
1381
1504
|
},
|
|
1382
1505
|
[removePrompt, setPromptStatus]
|
|
1383
1506
|
);
|
|
1384
|
-
const resendUserAction2 =
|
|
1507
|
+
const resendUserAction2 = react.useCallback(
|
|
1385
1508
|
async (userActionId) => {
|
|
1386
1509
|
setPromptStatus(userActionId, "submitting");
|
|
1387
1510
|
try {
|
|
@@ -1399,26 +1522,13 @@ function useChatV2(config, callbacks = {}) {
|
|
|
1399
1522
|
},
|
|
1400
1523
|
[setPromptStatus]
|
|
1401
1524
|
);
|
|
1402
|
-
const
|
|
1403
|
-
async (userActionId) => {
|
|
1404
|
-
setPromptStatus(userActionId, "expired");
|
|
1405
|
-
try {
|
|
1406
|
-
await expireUserAction(configRef.current, userActionId);
|
|
1407
|
-
} catch (error) {
|
|
1408
|
-
if (error instanceof UserActionStaleError) return;
|
|
1409
|
-
callbacksRef.current.onError?.(error);
|
|
1410
|
-
throw error;
|
|
1411
|
-
}
|
|
1412
|
-
},
|
|
1413
|
-
[setPromptStatus]
|
|
1414
|
-
);
|
|
1415
|
-
const dismissNotification = React.useCallback((id) => {
|
|
1525
|
+
const dismissNotification = react.useCallback((id) => {
|
|
1416
1526
|
setUserActionState((prev) => ({
|
|
1417
1527
|
...prev,
|
|
1418
1528
|
notifications: prev.notifications.filter((n) => n.id !== id)
|
|
1419
1529
|
}));
|
|
1420
1530
|
}, []);
|
|
1421
|
-
|
|
1531
|
+
react.useEffect(() => {
|
|
1422
1532
|
const prevSubscriptionUserId = subscriptionPrevUserIdRef.current;
|
|
1423
1533
|
subscriptionPrevUserIdRef.current = config.userId;
|
|
1424
1534
|
const { userId } = config;
|
|
@@ -1437,7 +1547,7 @@ function useChatV2(config, callbacks = {}) {
|
|
|
1437
1547
|
}
|
|
1438
1548
|
return unsubscribe;
|
|
1439
1549
|
}, [config.userId]);
|
|
1440
|
-
|
|
1550
|
+
react.useEffect(() => {
|
|
1441
1551
|
if (!config.userId) return;
|
|
1442
1552
|
if (prevUserIdRef.current !== config.userId) return;
|
|
1443
1553
|
const toSave = messages.filter((m) => !m.isStreaming);
|
|
@@ -1445,14 +1555,26 @@ function useChatV2(config, callbacks = {}) {
|
|
|
1445
1555
|
chatStore.set(config.userId, toSave);
|
|
1446
1556
|
}
|
|
1447
1557
|
}, [messages, config.userId]);
|
|
1448
|
-
|
|
1558
|
+
react.useEffect(() => {
|
|
1449
1559
|
if (!config.userId || activeStreamStore.has(config.userId)) return;
|
|
1450
1560
|
if (!config.initialMessages?.length || messagesRef.current.length > 0) return;
|
|
1451
1561
|
chatStore.set(config.userId, config.initialMessages);
|
|
1452
1562
|
setMessages(config.initialMessages);
|
|
1453
1563
|
sessionIdRef.current = getSessionIdFromMessages(config.initialMessages) ?? config.initialSessionId;
|
|
1454
1564
|
}, [config.initialMessages, config.initialSessionId, config.userId]);
|
|
1455
|
-
|
|
1565
|
+
const hydratedSessionIdRef = react.useRef(void 0);
|
|
1566
|
+
react.useEffect(() => {
|
|
1567
|
+
if (config.userId) return;
|
|
1568
|
+
if (!config.initialMessages?.length) return;
|
|
1569
|
+
const sessionId = config.initialSessionId;
|
|
1570
|
+
if (hydratedSessionIdRef.current === sessionId && messagesRef.current.length > 0) {
|
|
1571
|
+
return;
|
|
1572
|
+
}
|
|
1573
|
+
hydratedSessionIdRef.current = sessionId;
|
|
1574
|
+
setMessages(config.initialMessages);
|
|
1575
|
+
sessionIdRef.current = getSessionIdFromMessages(config.initialMessages) ?? sessionId;
|
|
1576
|
+
}, [config.initialMessages, config.initialSessionId, config.userId]);
|
|
1577
|
+
react.useEffect(() => {
|
|
1456
1578
|
const prevUserId = prevUserIdRef.current;
|
|
1457
1579
|
prevUserIdRef.current = config.userId;
|
|
1458
1580
|
if (prevUserId === config.userId) return;
|
|
@@ -1486,12 +1608,12 @@ function useChatV2(config, callbacks = {}) {
|
|
|
1486
1608
|
getSessionId,
|
|
1487
1609
|
getMessages,
|
|
1488
1610
|
isWaitingForResponse,
|
|
1611
|
+
isUploadingAttachments,
|
|
1489
1612
|
sessionId: sessionIdRef.current,
|
|
1490
1613
|
userActionState,
|
|
1491
1614
|
submitUserAction: submitUserAction2,
|
|
1492
1615
|
cancelUserAction: cancelUserAction2,
|
|
1493
1616
|
resendUserAction: resendUserAction2,
|
|
1494
|
-
expireUserAction: expireUserAction2,
|
|
1495
1617
|
dismissNotification
|
|
1496
1618
|
};
|
|
1497
1619
|
}
|
|
@@ -1500,12 +1622,12 @@ function getSpeechRecognition() {
|
|
|
1500
1622
|
return window.SpeechRecognition || window.webkitSpeechRecognition || null;
|
|
1501
1623
|
}
|
|
1502
1624
|
function useVoice(config = {}, callbacks = {}) {
|
|
1503
|
-
const [voiceState, setVoiceState] =
|
|
1504
|
-
const [transcribedText, setTranscribedText] =
|
|
1505
|
-
const [isAvailable, setIsAvailable] =
|
|
1506
|
-
const [isRecording, setIsRecording] =
|
|
1507
|
-
const recognitionRef =
|
|
1508
|
-
const autoStopTimerRef =
|
|
1625
|
+
const [voiceState, setVoiceState] = react.useState("idle");
|
|
1626
|
+
const [transcribedText, setTranscribedText] = react.useState("");
|
|
1627
|
+
const [isAvailable, setIsAvailable] = react.useState(false);
|
|
1628
|
+
const [isRecording, setIsRecording] = react.useState(false);
|
|
1629
|
+
const recognitionRef = react.useRef(null);
|
|
1630
|
+
const autoStopTimerRef = react.useRef(null);
|
|
1509
1631
|
const {
|
|
1510
1632
|
lang = "en-US",
|
|
1511
1633
|
interimResults = true,
|
|
@@ -1514,14 +1636,14 @@ function useVoice(config = {}, callbacks = {}) {
|
|
|
1514
1636
|
autoStopAfterSilence
|
|
1515
1637
|
} = config;
|
|
1516
1638
|
const { onStart, onEnd, onResult, onError, onStateChange } = callbacks;
|
|
1517
|
-
|
|
1639
|
+
react.useEffect(() => {
|
|
1518
1640
|
const SpeechRecognitionAPI = getSpeechRecognition();
|
|
1519
1641
|
setIsAvailable(SpeechRecognitionAPI !== null);
|
|
1520
1642
|
}, []);
|
|
1521
|
-
|
|
1643
|
+
react.useEffect(() => {
|
|
1522
1644
|
onStateChange?.(voiceState);
|
|
1523
1645
|
}, [voiceState, onStateChange]);
|
|
1524
|
-
const requestPermissions =
|
|
1646
|
+
const requestPermissions = react.useCallback(async () => {
|
|
1525
1647
|
try {
|
|
1526
1648
|
const result = await navigator.mediaDevices.getUserMedia({
|
|
1527
1649
|
audio: true
|
|
@@ -1538,7 +1660,7 @@ function useVoice(config = {}, callbacks = {}) {
|
|
|
1538
1660
|
};
|
|
1539
1661
|
}
|
|
1540
1662
|
}, []);
|
|
1541
|
-
const getPermissions =
|
|
1663
|
+
const getPermissions = react.useCallback(async () => {
|
|
1542
1664
|
if (typeof navigator === "undefined" || !navigator.permissions) {
|
|
1543
1665
|
return {
|
|
1544
1666
|
granted: false,
|
|
@@ -1560,13 +1682,13 @@ function useVoice(config = {}, callbacks = {}) {
|
|
|
1560
1682
|
};
|
|
1561
1683
|
}
|
|
1562
1684
|
}, []);
|
|
1563
|
-
const clearAutoStopTimer =
|
|
1685
|
+
const clearAutoStopTimer = react.useCallback(() => {
|
|
1564
1686
|
if (autoStopTimerRef.current) {
|
|
1565
1687
|
clearTimeout(autoStopTimerRef.current);
|
|
1566
1688
|
autoStopTimerRef.current = null;
|
|
1567
1689
|
}
|
|
1568
1690
|
}, []);
|
|
1569
|
-
const resetAutoStopTimer =
|
|
1691
|
+
const resetAutoStopTimer = react.useCallback(() => {
|
|
1570
1692
|
clearAutoStopTimer();
|
|
1571
1693
|
if (autoStopAfterSilence && autoStopAfterSilence > 0) {
|
|
1572
1694
|
autoStopTimerRef.current = setTimeout(() => {
|
|
@@ -1576,7 +1698,7 @@ function useVoice(config = {}, callbacks = {}) {
|
|
|
1576
1698
|
}, autoStopAfterSilence);
|
|
1577
1699
|
}
|
|
1578
1700
|
}, [autoStopAfterSilence, clearAutoStopTimer, isRecording]);
|
|
1579
|
-
const stopRecording =
|
|
1701
|
+
const stopRecording = react.useCallback(() => {
|
|
1580
1702
|
if (recognitionRef.current) {
|
|
1581
1703
|
try {
|
|
1582
1704
|
recognitionRef.current.stop();
|
|
@@ -1588,7 +1710,7 @@ function useVoice(config = {}, callbacks = {}) {
|
|
|
1588
1710
|
setIsRecording(false);
|
|
1589
1711
|
setVoiceState("idle");
|
|
1590
1712
|
}, [clearAutoStopTimer]);
|
|
1591
|
-
const startRecording =
|
|
1713
|
+
const startRecording = react.useCallback(async () => {
|
|
1592
1714
|
const SpeechRecognitionAPI = getSpeechRecognition();
|
|
1593
1715
|
if (!SpeechRecognitionAPI) {
|
|
1594
1716
|
onError?.("Speech recognition not supported in this browser");
|
|
@@ -1678,15 +1800,15 @@ function useVoice(config = {}, callbacks = {}) {
|
|
|
1678
1800
|
resetAutoStopTimer,
|
|
1679
1801
|
clearAutoStopTimer
|
|
1680
1802
|
]);
|
|
1681
|
-
const clearTranscript =
|
|
1803
|
+
const clearTranscript = react.useCallback(() => {
|
|
1682
1804
|
setTranscribedText("");
|
|
1683
1805
|
}, []);
|
|
1684
|
-
const reset =
|
|
1806
|
+
const reset = react.useCallback(() => {
|
|
1685
1807
|
stopRecording();
|
|
1686
1808
|
setTranscribedText("");
|
|
1687
1809
|
setVoiceState("idle");
|
|
1688
1810
|
}, [stopRecording]);
|
|
1689
|
-
|
|
1811
|
+
react.useEffect(() => {
|
|
1690
1812
|
return () => {
|
|
1691
1813
|
if (recognitionRef.current) {
|
|
1692
1814
|
try {
|
|
@@ -1826,9 +1948,9 @@ function buildContent(schema, values) {
|
|
|
1826
1948
|
}
|
|
1827
1949
|
return content;
|
|
1828
1950
|
}
|
|
1829
|
-
var PaymanChatContext =
|
|
1951
|
+
var PaymanChatContext = react.createContext(void 0);
|
|
1830
1952
|
function usePaymanChat() {
|
|
1831
|
-
const context =
|
|
1953
|
+
const context = react.useContext(PaymanChatContext);
|
|
1832
1954
|
if (!context) {
|
|
1833
1955
|
throw new Error("usePaymanChat must be used within a PaymanChat component");
|
|
1834
1956
|
}
|
|
@@ -2086,8 +2208,8 @@ function ImageLightbox({
|
|
|
2086
2208
|
alt = "",
|
|
2087
2209
|
onClose
|
|
2088
2210
|
}) {
|
|
2089
|
-
const [isMounted, setIsMounted] =
|
|
2090
|
-
const [isImageLoaded, setIsImageLoaded] =
|
|
2211
|
+
const [isMounted, setIsMounted] = react.useState(false);
|
|
2212
|
+
const [isImageLoaded, setIsImageLoaded] = react.useState(false);
|
|
2091
2213
|
const overlayStyle = {
|
|
2092
2214
|
position: "fixed",
|
|
2093
2215
|
inset: 0,
|
|
@@ -2108,14 +2230,14 @@ function ImageLightbox({
|
|
|
2108
2230
|
justifyContent: "center",
|
|
2109
2231
|
overflow: "hidden"
|
|
2110
2232
|
};
|
|
2111
|
-
|
|
2233
|
+
react.useEffect(() => {
|
|
2112
2234
|
setIsMounted(true);
|
|
2113
2235
|
return () => setIsMounted(false);
|
|
2114
2236
|
}, []);
|
|
2115
|
-
|
|
2237
|
+
react.useEffect(() => {
|
|
2116
2238
|
setIsImageLoaded(false);
|
|
2117
2239
|
}, [src]);
|
|
2118
|
-
|
|
2240
|
+
react.useEffect(() => {
|
|
2119
2241
|
if (typeof document === "undefined") return;
|
|
2120
2242
|
const previousOverflow = document.body.style.overflow;
|
|
2121
2243
|
document.body.style.overflow = "hidden";
|
|
@@ -2123,7 +2245,7 @@ function ImageLightbox({
|
|
|
2123
2245
|
document.body.style.overflow = previousOverflow;
|
|
2124
2246
|
};
|
|
2125
2247
|
}, []);
|
|
2126
|
-
|
|
2248
|
+
react.useEffect(() => {
|
|
2127
2249
|
if (typeof document === "undefined") return;
|
|
2128
2250
|
const handleKeyDown = (event) => {
|
|
2129
2251
|
if (event.key === "Escape") {
|
|
@@ -2219,15 +2341,15 @@ function MarkdownImage({
|
|
|
2219
2341
|
maxHeight: "18rem",
|
|
2220
2342
|
objectFit: "contain"
|
|
2221
2343
|
};
|
|
2222
|
-
const [isLoaded, setIsLoaded] =
|
|
2223
|
-
const [hasError, setHasError] =
|
|
2224
|
-
const [isLightboxOpen, setIsLightboxOpen] =
|
|
2225
|
-
const isUnresolvedRagImage =
|
|
2344
|
+
const [isLoaded, setIsLoaded] = react.useState(false);
|
|
2345
|
+
const [hasError, setHasError] = react.useState(false);
|
|
2346
|
+
const [isLightboxOpen, setIsLightboxOpen] = react.useState(false);
|
|
2347
|
+
const isUnresolvedRagImage = react.useMemo(
|
|
2226
2348
|
() => src ? isUnresolvedRagImageSource(src) : false,
|
|
2227
2349
|
[src]
|
|
2228
2350
|
);
|
|
2229
2351
|
const isResolvingRagImage = isResolving && isUnresolvedRagImage;
|
|
2230
|
-
|
|
2352
|
+
react.useEffect(() => {
|
|
2231
2353
|
setIsLoaded(false);
|
|
2232
2354
|
setHasError(false);
|
|
2233
2355
|
setIsLightboxOpen(false);
|
|
@@ -2296,7 +2418,7 @@ function createMarkdownComponents(options = {}) {
|
|
|
2296
2418
|
},
|
|
2297
2419
|
pre: ({ children }) => /* @__PURE__ */ jsxRuntime.jsx("pre", { className: "my-2 max-w-full overflow-x-auto rounded-lg", children }),
|
|
2298
2420
|
ul: ({ children }) => /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "mb-3 ml-4 list-disc space-y-1 text-sm", children }),
|
|
2299
|
-
ol: ({ children }) => /* @__PURE__ */ jsxRuntime.jsx("ol", { className: "mb-3 ml-4 list-decimal space-y-1 text-sm", children }),
|
|
2421
|
+
ol: ({ children, start }) => /* @__PURE__ */ jsxRuntime.jsx("ol", { className: "mb-3 ml-4 list-decimal space-y-1 text-sm", start, children }),
|
|
2300
2422
|
li: ({ children }) => /* @__PURE__ */ jsxRuntime.jsx("li", { className: "text-sm leading-relaxed", children }),
|
|
2301
2423
|
h1: ({ children }) => /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "mt-4 mb-2 text-lg font-semibold first:mt-0", children }),
|
|
2302
2424
|
h2: ({ children }) => /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "mt-3 mb-2 text-base font-semibold first:mt-0", children }),
|
|
@@ -2354,9 +2476,9 @@ function AgentMessage({
|
|
|
2354
2476
|
const hasTraceData = !!(message.tracingData || message.executionId) && !isStreaming;
|
|
2355
2477
|
const isCancelled = message.isCancelled ?? false;
|
|
2356
2478
|
const currentExecutingStepId = message.currentExecutingStepId;
|
|
2357
|
-
const [isStepsExpanded, setIsStepsExpanded] =
|
|
2358
|
-
const wasStreamingRef =
|
|
2359
|
-
|
|
2479
|
+
const [isStepsExpanded, setIsStepsExpanded] = react.useState(false);
|
|
2480
|
+
const wasStreamingRef = react.useRef(isStreaming);
|
|
2481
|
+
react.useEffect(() => {
|
|
2360
2482
|
if (isStreaming && hasSteps) {
|
|
2361
2483
|
setIsStepsExpanded(true);
|
|
2362
2484
|
}
|
|
@@ -2365,7 +2487,7 @@ function AgentMessage({
|
|
|
2365
2487
|
}
|
|
2366
2488
|
wasStreamingRef.current = isStreaming;
|
|
2367
2489
|
}, [isStreaming, hasSteps]);
|
|
2368
|
-
const totalElapsedMs = hasSteps ? message.steps.reduce((sum,
|
|
2490
|
+
const totalElapsedMs = hasSteps ? message.steps.reduce((sum, step2) => sum + (step2.elapsedMs || 0), 0) : 0;
|
|
2369
2491
|
const currentMessage = message.currentMessage;
|
|
2370
2492
|
const rawContent = message.streamingContent || message.content || "";
|
|
2371
2493
|
const content = rawContent.replace(/\\n/g, "\n");
|
|
@@ -2373,13 +2495,13 @@ function AgentMessage({
|
|
|
2373
2495
|
const completedWithNoContent = !isStreaming && !isCancelled && content.length === 0 && (message.streamProgress === "completed" || message.streamProgress === "error");
|
|
2374
2496
|
const conflictErrorMessage = getConflictErrorMessage(message.errorDetails);
|
|
2375
2497
|
const isError = !!conflictErrorMessage || (isFriendlyWorkflowError(message.errorDetails) || looksLikeRawError(content)) && !hasMeaningfulContent || completedWithNoContent;
|
|
2376
|
-
const currentStep =
|
|
2498
|
+
const currentStep = react.useMemo(
|
|
2377
2499
|
() => message.steps?.find(
|
|
2378
2500
|
(s) => s.id === currentExecutingStepId && s.status === "in_progress"
|
|
2379
2501
|
),
|
|
2380
2502
|
[message.steps, currentExecutingStepId]
|
|
2381
2503
|
);
|
|
2382
|
-
const markdownRenderers =
|
|
2504
|
+
const markdownRenderers = react.useMemo(
|
|
2383
2505
|
() => createMarkdownComponents({
|
|
2384
2506
|
isResolvingImages: message.isResolvingImages
|
|
2385
2507
|
}),
|
|
@@ -2393,25 +2515,25 @@ function AgentMessage({
|
|
|
2393
2515
|
}
|
|
2394
2516
|
return `${count} ${stepWord} completed`;
|
|
2395
2517
|
};
|
|
2396
|
-
const renderStepIcon = (
|
|
2518
|
+
const renderStepIcon = (step2, isCurrentlyExecuting) => {
|
|
2397
2519
|
const wrapper = "h-4 w-4 flex items-center justify-center shrink-0";
|
|
2398
2520
|
if (isCurrentlyExecuting)
|
|
2399
2521
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: wrapper, children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "h-3.5 w-3.5 payman-agent-step-icon--active animate-spin" }) });
|
|
2400
|
-
if (
|
|
2522
|
+
if (step2.status === "pending" && isCancelled)
|
|
2401
2523
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: wrapper, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-1.5 w-1.5 rounded-full payman-agent-step-icon--pending" }) });
|
|
2402
|
-
if (
|
|
2524
|
+
if (step2.status === "pending" || step2.status === "in_progress")
|
|
2403
2525
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: wrapper, children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "h-3.5 w-3.5 payman-agent-step-icon--in-progress-dim animate-spin" }) });
|
|
2404
|
-
if (
|
|
2526
|
+
if (step2.status === "completed")
|
|
2405
2527
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: wrapper, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2406
2528
|
lucideReact.Check,
|
|
2407
2529
|
{
|
|
2408
2530
|
className: cn(
|
|
2409
2531
|
"h-3.5 w-3.5",
|
|
2410
|
-
|
|
2532
|
+
step2.eventType === "USER_ACTION_SUCCESS" ? "payman-agent-step-icon--success" : "payman-agent-step-icon--success-dim"
|
|
2411
2533
|
)
|
|
2412
2534
|
}
|
|
2413
2535
|
) });
|
|
2414
|
-
if (
|
|
2536
|
+
if (step2.status === "error")
|
|
2415
2537
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: wrapper, children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "h-3.5 w-3.5 payman-agent-step-icon--error" }) });
|
|
2416
2538
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: wrapper, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-1.5 w-1.5 rounded-full payman-agent-step-icon--pending-dim" }) });
|
|
2417
2539
|
};
|
|
@@ -2423,38 +2545,38 @@ function AgentMessage({
|
|
|
2423
2545
|
exit: { height: 0, opacity: 0 },
|
|
2424
2546
|
transition: { duration: 0.2, ease: "easeInOut" },
|
|
2425
2547
|
className: "overflow-hidden",
|
|
2426
|
-
children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pt-1.5", children: message.steps.map((
|
|
2427
|
-
const isCurrentlyExecuting =
|
|
2428
|
-
const hasTime =
|
|
2548
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pt-1.5", children: message.steps.map((step2) => {
|
|
2549
|
+
const isCurrentlyExecuting = step2.id === currentExecutingStepId && step2.status === "in_progress" && isStreaming && !isCancelled;
|
|
2550
|
+
const hasTime = step2.elapsedMs != null && step2.elapsedMs > 0;
|
|
2429
2551
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-1.5", children: [
|
|
2430
2552
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-1.5 items-start", children: [
|
|
2431
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-px", children: renderStepIcon(
|
|
2553
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-px", children: renderStepIcon(step2, isCurrentlyExecuting) }),
|
|
2432
2554
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2433
2555
|
"span",
|
|
2434
2556
|
{
|
|
2435
2557
|
className: cn(
|
|
2436
2558
|
"text-xs leading-relaxed min-w-0 break-words",
|
|
2437
2559
|
isCurrentlyExecuting && "shimmer-text font-medium",
|
|
2438
|
-
!isCurrentlyExecuting &&
|
|
2439
|
-
!isCurrentlyExecuting &&
|
|
2440
|
-
!isCurrentlyExecuting &&
|
|
2441
|
-
!isCurrentlyExecuting &&
|
|
2442
|
-
!isCurrentlyExecuting &&
|
|
2560
|
+
!isCurrentlyExecuting && step2.status === "error" && "payman-agent-step-text--error",
|
|
2561
|
+
!isCurrentlyExecuting && step2.eventType === "USER_ACTION_SUCCESS" && "payman-agent-step-text--success",
|
|
2562
|
+
!isCurrentlyExecuting && step2.status === "completed" && "payman-agent-step-text--completed",
|
|
2563
|
+
!isCurrentlyExecuting && step2.status === "pending" && "payman-agent-step-text--pending",
|
|
2564
|
+
!isCurrentlyExecuting && step2.status === "in_progress" && "payman-agent-step-text--in-progress"
|
|
2443
2565
|
),
|
|
2444
|
-
children:
|
|
2566
|
+
children: step2.message
|
|
2445
2567
|
}
|
|
2446
2568
|
)
|
|
2447
2569
|
] }),
|
|
2448
2570
|
hasTime && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pl-[22px] mt-1", children: /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-1 px-1.5 py-0.5 rounded-md payman-agent-step-time leading-none", children: [
|
|
2449
2571
|
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Clock, { className: "h-2.5 w-2.5 shrink-0 payman-agent-step-time-icon" }),
|
|
2450
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] font-mono payman-agent-step-time-text", children: formatElapsedTime(
|
|
2572
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] font-mono payman-agent-step-time-text", children: formatElapsedTime(step2.elapsedMs) })
|
|
2451
2573
|
] }) })
|
|
2452
|
-
] },
|
|
2574
|
+
] }, step2.id);
|
|
2453
2575
|
}) })
|
|
2454
2576
|
}
|
|
2455
2577
|
) });
|
|
2456
|
-
const stepsToggleRef =
|
|
2457
|
-
const handleStepsToggle =
|
|
2578
|
+
const stepsToggleRef = react.useRef(null);
|
|
2579
|
+
const handleStepsToggle = react.useCallback(() => {
|
|
2458
2580
|
setIsStepsExpanded((prev) => {
|
|
2459
2581
|
const next = !prev;
|
|
2460
2582
|
if (next) {
|
|
@@ -2782,23 +2904,23 @@ function MessageList({
|
|
|
2782
2904
|
isLoadingMoreMessages = false,
|
|
2783
2905
|
hasMoreMessages = false
|
|
2784
2906
|
}) {
|
|
2785
|
-
const scrollRef =
|
|
2786
|
-
const isNearBottomRef =
|
|
2787
|
-
const [showScrollBtn, setShowScrollBtn] =
|
|
2788
|
-
const prevMessageCountRef =
|
|
2789
|
-
const scrollHeightBeforePrependRef =
|
|
2790
|
-
const firstMessageIdRef =
|
|
2791
|
-
const getDistanceFromBottom =
|
|
2907
|
+
const scrollRef = react.useRef(null);
|
|
2908
|
+
const isNearBottomRef = react.useRef(true);
|
|
2909
|
+
const [showScrollBtn, setShowScrollBtn] = react.useState(false);
|
|
2910
|
+
const prevMessageCountRef = react.useRef(messages.length);
|
|
2911
|
+
const scrollHeightBeforePrependRef = react.useRef(null);
|
|
2912
|
+
const firstMessageIdRef = react.useRef(messages[0]?.id);
|
|
2913
|
+
const getDistanceFromBottom = react.useCallback(() => {
|
|
2792
2914
|
const el = scrollRef.current;
|
|
2793
2915
|
if (!el) return 0;
|
|
2794
2916
|
return el.scrollHeight - el.scrollTop - el.clientHeight;
|
|
2795
2917
|
}, []);
|
|
2796
|
-
const scrollToBottom =
|
|
2918
|
+
const scrollToBottom = react.useCallback((behavior = "smooth") => {
|
|
2797
2919
|
const el = scrollRef.current;
|
|
2798
2920
|
if (!el) return;
|
|
2799
2921
|
el.scrollTo({ top: el.scrollHeight, behavior });
|
|
2800
2922
|
}, []);
|
|
2801
|
-
const handleScroll =
|
|
2923
|
+
const handleScroll = react.useCallback(() => {
|
|
2802
2924
|
const el = scrollRef.current;
|
|
2803
2925
|
if (!el) return;
|
|
2804
2926
|
const distance = getDistanceFromBottom();
|
|
@@ -2810,7 +2932,7 @@ function MessageList({
|
|
|
2810
2932
|
onLoadMoreMessages();
|
|
2811
2933
|
}
|
|
2812
2934
|
}, [getDistanceFromBottom, hasMoreMessages, isLoadingMoreMessages, onLoadMoreMessages]);
|
|
2813
|
-
|
|
2935
|
+
react.useLayoutEffect(() => {
|
|
2814
2936
|
const el = scrollRef.current;
|
|
2815
2937
|
const prevHeight = scrollHeightBeforePrependRef.current;
|
|
2816
2938
|
const newFirstId = messages[0]?.id;
|
|
@@ -2820,25 +2942,25 @@ function MessageList({
|
|
|
2820
2942
|
}
|
|
2821
2943
|
firstMessageIdRef.current = newFirstId;
|
|
2822
2944
|
}, [messages]);
|
|
2823
|
-
|
|
2945
|
+
react.useEffect(() => {
|
|
2824
2946
|
const prevCount = prevMessageCountRef.current;
|
|
2825
2947
|
prevMessageCountRef.current = messages.length;
|
|
2826
2948
|
if (messages.length > prevCount && isNearBottomRef.current) {
|
|
2827
2949
|
requestAnimationFrame(() => scrollToBottom());
|
|
2828
2950
|
}
|
|
2829
2951
|
}, [messages.length, scrollToBottom]);
|
|
2830
|
-
|
|
2952
|
+
react.useEffect(() => {
|
|
2831
2953
|
const lastMsg = messages[messages.length - 1];
|
|
2832
2954
|
if (!lastMsg?.isStreaming) return;
|
|
2833
2955
|
if (!isNearBottomRef.current) return;
|
|
2834
2956
|
requestAnimationFrame(() => scrollToBottom());
|
|
2835
2957
|
});
|
|
2836
|
-
|
|
2958
|
+
react.useEffect(() => {
|
|
2837
2959
|
if (messages.length > 0) {
|
|
2838
2960
|
setTimeout(() => scrollToBottom("instant"), 50);
|
|
2839
2961
|
}
|
|
2840
2962
|
}, []);
|
|
2841
|
-
|
|
2963
|
+
react.useEffect(() => {
|
|
2842
2964
|
const handleStepsToggle = () => {
|
|
2843
2965
|
requestAnimationFrame(() => {
|
|
2844
2966
|
requestAnimationFrame(() => {
|
|
@@ -2855,7 +2977,7 @@ function MessageList({
|
|
|
2855
2977
|
return () => el.removeEventListener("payman-steps-toggle", handleStepsToggle);
|
|
2856
2978
|
}
|
|
2857
2979
|
}, [getDistanceFromBottom, scrollToBottom]);
|
|
2858
|
-
const handleScrollToBottom =
|
|
2980
|
+
const handleScrollToBottom = react.useCallback(() => {
|
|
2859
2981
|
scrollToBottom();
|
|
2860
2982
|
}, [scrollToBottom]);
|
|
2861
2983
|
if (isLoading) {
|
|
@@ -2988,7 +3110,7 @@ function ResetSessionConfirmModal({
|
|
|
2988
3110
|
onClose,
|
|
2989
3111
|
onConfirm
|
|
2990
3112
|
}) {
|
|
2991
|
-
const handleKeyDown =
|
|
3113
|
+
const handleKeyDown = react.useCallback(
|
|
2992
3114
|
(event) => {
|
|
2993
3115
|
if (event.key === "Escape") {
|
|
2994
3116
|
onClose();
|
|
@@ -2996,7 +3118,7 @@ function ResetSessionConfirmModal({
|
|
|
2996
3118
|
},
|
|
2997
3119
|
[onClose]
|
|
2998
3120
|
);
|
|
2999
|
-
|
|
3121
|
+
react.useEffect(() => {
|
|
3000
3122
|
if (!isOpen || typeof document === "undefined") return;
|
|
3001
3123
|
document.addEventListener("keydown", handleKeyDown);
|
|
3002
3124
|
const previousOverflow = document.body.style.overflow;
|
|
@@ -3102,14 +3224,14 @@ function UserMessageV2({
|
|
|
3102
3224
|
retryDisabled = false,
|
|
3103
3225
|
actions
|
|
3104
3226
|
}) {
|
|
3105
|
-
const [copied, setCopied] =
|
|
3106
|
-
const [toast, setToast] =
|
|
3107
|
-
const copyResetTimerRef =
|
|
3108
|
-
const toastTimerRef =
|
|
3227
|
+
const [copied, setCopied] = react.useState(false);
|
|
3228
|
+
const [toast, setToast] = react.useState(null);
|
|
3229
|
+
const copyResetTimerRef = react.useRef(null);
|
|
3230
|
+
const toastTimerRef = react.useRef(null);
|
|
3109
3231
|
const showCopyAction = actions?.copy ?? true;
|
|
3110
3232
|
const showEditAction = actions?.edit ?? false;
|
|
3111
3233
|
const showRetryAction = actions?.retry ?? false;
|
|
3112
|
-
|
|
3234
|
+
react.useEffect(() => {
|
|
3113
3235
|
return () => {
|
|
3114
3236
|
if (copyResetTimerRef.current) clearTimeout(copyResetTimerRef.current);
|
|
3115
3237
|
if (toastTimerRef.current) clearTimeout(toastTimerRef.current);
|
|
@@ -3265,18 +3387,18 @@ function MarkdownImageV2({
|
|
|
3265
3387
|
onImageClick
|
|
3266
3388
|
}) {
|
|
3267
3389
|
const cachedAlready = src ? loadedImageCache.has(src) : false;
|
|
3268
|
-
const [isVisible, setIsVisible] =
|
|
3269
|
-
const [isLoaded, setIsLoaded] =
|
|
3270
|
-
const [hasError, setHasError] =
|
|
3271
|
-
const [retryCount, setRetryCount] =
|
|
3272
|
-
const sentinelRef =
|
|
3273
|
-
const prevLoadedRef =
|
|
3274
|
-
const isUnresolvedRag =
|
|
3390
|
+
const [isVisible, setIsVisible] = react.useState(cachedAlready);
|
|
3391
|
+
const [isLoaded, setIsLoaded] = react.useState(cachedAlready);
|
|
3392
|
+
const [hasError, setHasError] = react.useState(false);
|
|
3393
|
+
const [retryCount, setRetryCount] = react.useState(0);
|
|
3394
|
+
const sentinelRef = react.useRef(null);
|
|
3395
|
+
const prevLoadedRef = react.useRef(cachedAlready);
|
|
3396
|
+
const isUnresolvedRag = react.useMemo(
|
|
3275
3397
|
() => src ? isUnresolvedRagImageSource2(src) : false,
|
|
3276
3398
|
[src]
|
|
3277
3399
|
);
|
|
3278
3400
|
const isResolvingRag = Boolean(isResolving && isUnresolvedRag);
|
|
3279
|
-
|
|
3401
|
+
react.useEffect(() => {
|
|
3280
3402
|
if (src && loadedImageCache.has(src)) {
|
|
3281
3403
|
setIsLoaded(true);
|
|
3282
3404
|
setIsVisible(true);
|
|
@@ -3285,7 +3407,7 @@ function MarkdownImageV2({
|
|
|
3285
3407
|
setHasError(false);
|
|
3286
3408
|
setRetryCount(0);
|
|
3287
3409
|
}, [src]);
|
|
3288
|
-
|
|
3410
|
+
react.useEffect(() => {
|
|
3289
3411
|
const el = sentinelRef.current;
|
|
3290
3412
|
if (!el || !src) return;
|
|
3291
3413
|
const rect = el.getBoundingClientRect();
|
|
@@ -3406,92 +3528,13 @@ function MarkdownImageV2({
|
|
|
3406
3528
|
}
|
|
3407
3529
|
) });
|
|
3408
3530
|
}
|
|
3409
|
-
|
|
3410
|
-
var RAG_FOLLOW_UP_CLASS = "payman-v2-rag-follow-up";
|
|
3411
|
-
var SOURCE_PATTERN = /^Sources?:\s*\S/i;
|
|
3412
|
-
var MAX_FOLLOW_UP_LENGTH = 320;
|
|
3413
|
-
var HR_PATTERN = /^-{3,}$|^_{3,}$|^\*{3,}$/;
|
|
3414
|
-
function normalizeRagParagraphText(text) {
|
|
3415
|
-
return text.replace(/\s+/g, " ").trim();
|
|
3416
|
-
}
|
|
3417
|
-
function isRagSourceParagraph(text) {
|
|
3418
|
-
return SOURCE_PATTERN.test(normalizeRagParagraphText(text));
|
|
3419
|
-
}
|
|
3420
|
-
function isRagFollowUpCandidate(text) {
|
|
3421
|
-
const normalized = normalizeRagParagraphText(text);
|
|
3422
|
-
return normalized.length > 0 && normalized.length <= MAX_FOLLOW_UP_LENGTH && normalized.endsWith("?");
|
|
3423
|
-
}
|
|
3424
|
-
function extractRagParagraphTexts(content) {
|
|
3425
|
-
const paragraphs = [];
|
|
3426
|
-
const currentParagraph = [];
|
|
3427
|
-
const flushParagraph = () => {
|
|
3428
|
-
const paragraph = normalizeRagParagraphText(currentParagraph.join(" "));
|
|
3429
|
-
currentParagraph.length = 0;
|
|
3430
|
-
if (paragraph) paragraphs.push(paragraph);
|
|
3431
|
-
};
|
|
3432
|
-
content.replace(/\\n/g, "\n").split(/\r?\n/).forEach((line) => {
|
|
3433
|
-
const trimmedLine = line.trim();
|
|
3434
|
-
if (!trimmedLine) {
|
|
3435
|
-
flushParagraph();
|
|
3436
|
-
return;
|
|
3437
|
-
}
|
|
3438
|
-
if (HR_PATTERN.test(trimmedLine)) {
|
|
3439
|
-
flushParagraph();
|
|
3440
|
-
return;
|
|
3441
|
-
}
|
|
3442
|
-
currentParagraph.push(trimmedLine);
|
|
3443
|
-
});
|
|
3444
|
-
flushParagraph();
|
|
3445
|
-
return paragraphs;
|
|
3446
|
-
}
|
|
3447
|
-
function getRagAnswerParagraphRoles(paragraphs) {
|
|
3448
|
-
const normalized = paragraphs.map(normalizeRagParagraphText);
|
|
3449
|
-
const roles = normalized.map(() => null);
|
|
3450
|
-
const sourceIndexes = normalized.map((paragraph, index) => isRagSourceParagraph(paragraph) ? index : -1).filter((index) => index >= 0);
|
|
3451
|
-
for (const sourceIndex of sourceIndexes) {
|
|
3452
|
-
roles[sourceIndex] = "source";
|
|
3453
|
-
for (const candidateIndex of [sourceIndex - 1, sourceIndex + 1]) {
|
|
3454
|
-
if (candidateIndex >= 0 && candidateIndex < normalized.length && roles[candidateIndex] == null && isRagFollowUpCandidate(normalized[candidateIndex] ?? "")) {
|
|
3455
|
-
roles[candidateIndex] = "follow-up";
|
|
3456
|
-
}
|
|
3457
|
-
}
|
|
3458
|
-
}
|
|
3459
|
-
return roles;
|
|
3460
|
-
}
|
|
3461
|
-
function getRagAnswerParagraphRole(paragraph, paragraphs) {
|
|
3462
|
-
const normalizedParagraph = normalizeRagParagraphText(paragraph);
|
|
3463
|
-
if (isRagSourceParagraph(normalizedParagraph)) return "source";
|
|
3464
|
-
const roles = getRagAnswerParagraphRoles(paragraphs);
|
|
3465
|
-
return paragraphs.map(normalizeRagParagraphText).some((candidate, index) => {
|
|
3466
|
-
return candidate === normalizedParagraph && roles[index] === "follow-up";
|
|
3467
|
-
}) ? "follow-up" : null;
|
|
3468
|
-
}
|
|
3469
|
-
function ragAnswerRoleClassName(role) {
|
|
3470
|
-
if (role === "source") return RAG_SOURCE_CLASS;
|
|
3471
|
-
if (role === "follow-up") return RAG_FOLLOW_UP_CLASS;
|
|
3472
|
-
return void 0;
|
|
3473
|
-
}
|
|
3474
|
-
function reactNodeText(node) {
|
|
3475
|
-
if (typeof node === "string" || typeof node === "number") return String(node);
|
|
3476
|
-
if (Array.isArray(node)) return node.map(reactNodeText).join("");
|
|
3477
|
-
if (React__namespace.isValidElement(node)) {
|
|
3478
|
-
return reactNodeText(node.props.children);
|
|
3479
|
-
}
|
|
3480
|
-
return "";
|
|
3481
|
-
}
|
|
3482
|
-
function buildComponents(onImageClick, isResolvingRef, ragParagraphsRef) {
|
|
3531
|
+
function buildComponents(onImageClick, isResolvingRef) {
|
|
3483
3532
|
return {
|
|
3484
|
-
p: ({ children }) => {
|
|
3485
|
-
const role = getRagAnswerParagraphRole(
|
|
3486
|
-
reactNodeText(children),
|
|
3487
|
-
ragParagraphsRef?.current ?? []
|
|
3488
|
-
);
|
|
3489
|
-
return /* @__PURE__ */ jsxRuntime.jsx("p", { className: ragAnswerRoleClassName(role), children });
|
|
3490
|
-
},
|
|
3533
|
+
p: ({ children }) => /* @__PURE__ */ jsxRuntime.jsx("p", { children }),
|
|
3491
3534
|
code: ({ children }) => /* @__PURE__ */ jsxRuntime.jsx("code", { children }),
|
|
3492
3535
|
pre: ({ children }) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "payman-v2-markdown-pre", children: /* @__PURE__ */ jsxRuntime.jsx("pre", { children }) }),
|
|
3493
3536
|
ul: ({ children }) => /* @__PURE__ */ jsxRuntime.jsx("ul", { children }),
|
|
3494
|
-
ol: ({ children }) => /* @__PURE__ */ jsxRuntime.jsx("ol", { children }),
|
|
3537
|
+
ol: ({ children, start }) => /* @__PURE__ */ jsxRuntime.jsx("ol", { start, children }),
|
|
3495
3538
|
li: ({ children }) => /* @__PURE__ */ jsxRuntime.jsx("li", { children }),
|
|
3496
3539
|
h1: ({ children }) => /* @__PURE__ */ jsxRuntime.jsx("h1", { children }),
|
|
3497
3540
|
h2: ({ children }) => /* @__PURE__ */ jsxRuntime.jsx("h2", { children }),
|
|
@@ -3523,15 +3566,10 @@ function MarkdownRendererV2({
|
|
|
3523
3566
|
isResolvingImages,
|
|
3524
3567
|
onImageClick
|
|
3525
3568
|
}) {
|
|
3526
|
-
const isResolvingRef =
|
|
3569
|
+
const isResolvingRef = react.useRef(isResolvingImages);
|
|
3527
3570
|
isResolvingRef.current = isResolvingImages;
|
|
3528
|
-
const
|
|
3529
|
-
|
|
3530
|
-
() => extractRagParagraphTexts(content),
|
|
3531
|
-
[content]
|
|
3532
|
-
);
|
|
3533
|
-
const components = React.useMemo(
|
|
3534
|
-
() => buildComponents(onImageClick, isResolvingRef, ragParagraphsRef),
|
|
3571
|
+
const components = react.useMemo(
|
|
3572
|
+
() => buildComponents(onImageClick, isResolvingRef),
|
|
3535
3573
|
[onImageClick]
|
|
3536
3574
|
);
|
|
3537
3575
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -3588,14 +3626,14 @@ function FeedbackReasonModal({
|
|
|
3588
3626
|
onClose,
|
|
3589
3627
|
onSubmit
|
|
3590
3628
|
}) {
|
|
3591
|
-
const [reason, setReason] =
|
|
3629
|
+
const [reason, setReason] = react.useState(
|
|
3592
3630
|
NEGATIVE_FEEDBACK_REASONS[0].value
|
|
3593
3631
|
);
|
|
3594
|
-
const [details, setDetails] =
|
|
3595
|
-
const [submitting, setSubmitting] =
|
|
3596
|
-
const [error, setError] =
|
|
3597
|
-
const [reasonOpen, setReasonOpen] =
|
|
3598
|
-
|
|
3632
|
+
const [details, setDetails] = react.useState("");
|
|
3633
|
+
const [submitting, setSubmitting] = react.useState(false);
|
|
3634
|
+
const [error, setError] = react.useState(null);
|
|
3635
|
+
const [reasonOpen, setReasonOpen] = react.useState(false);
|
|
3636
|
+
react.useEffect(() => {
|
|
3599
3637
|
if (open) {
|
|
3600
3638
|
setReason(NEGATIVE_FEEDBACK_REASONS[0].value);
|
|
3601
3639
|
setDetails("");
|
|
@@ -3604,7 +3642,7 @@ function FeedbackReasonModal({
|
|
|
3604
3642
|
setReasonOpen(false);
|
|
3605
3643
|
}
|
|
3606
3644
|
}, [open]);
|
|
3607
|
-
const handleKeyDown =
|
|
3645
|
+
const handleKeyDown = react.useCallback(
|
|
3608
3646
|
(event) => {
|
|
3609
3647
|
if (event.key !== "Escape") return;
|
|
3610
3648
|
if (reasonOpen) {
|
|
@@ -3615,7 +3653,7 @@ function FeedbackReasonModal({
|
|
|
3615
3653
|
},
|
|
3616
3654
|
[onClose, reasonOpen]
|
|
3617
3655
|
);
|
|
3618
|
-
|
|
3656
|
+
react.useEffect(() => {
|
|
3619
3657
|
if (!open || typeof document === "undefined") return;
|
|
3620
3658
|
document.addEventListener("keydown", handleKeyDown);
|
|
3621
3659
|
const previousOverflow = document.body.style.overflow;
|
|
@@ -3797,6 +3835,87 @@ function FeedbackReasonModal({
|
|
|
3797
3835
|
}
|
|
3798
3836
|
) : null });
|
|
3799
3837
|
}
|
|
3838
|
+
|
|
3839
|
+
// src/utils/markdownImageToken.ts
|
|
3840
|
+
function step(text, i) {
|
|
3841
|
+
if (text[i] === "\\" && i + 1 < text.length) return i + 2;
|
|
3842
|
+
return i + 1;
|
|
3843
|
+
}
|
|
3844
|
+
function scanAltText(text, start) {
|
|
3845
|
+
let i = start;
|
|
3846
|
+
while (i < text.length) {
|
|
3847
|
+
if (text[i] === "]") return i;
|
|
3848
|
+
i = step(text, i);
|
|
3849
|
+
}
|
|
3850
|
+
return -1;
|
|
3851
|
+
}
|
|
3852
|
+
function scanOptionalTitle(text, start) {
|
|
3853
|
+
let i = start;
|
|
3854
|
+
while (i < text.length && /[\t\n ]/.test(text[i])) i++;
|
|
3855
|
+
if (i >= text.length) return i;
|
|
3856
|
+
const quote = text[i];
|
|
3857
|
+
if (quote !== '"' && quote !== "'") return i;
|
|
3858
|
+
i++;
|
|
3859
|
+
while (i < text.length) {
|
|
3860
|
+
if (text[i] === quote) return i + 1;
|
|
3861
|
+
i = step(text, i);
|
|
3862
|
+
}
|
|
3863
|
+
return -1;
|
|
3864
|
+
}
|
|
3865
|
+
function scanAngleBracketDestination(text, start) {
|
|
3866
|
+
let i = start + 1;
|
|
3867
|
+
while (i < text.length) {
|
|
3868
|
+
if (text[i] === ">") return i + 1;
|
|
3869
|
+
i = step(text, i);
|
|
3870
|
+
}
|
|
3871
|
+
return -1;
|
|
3872
|
+
}
|
|
3873
|
+
function scanRawDestination(text, start) {
|
|
3874
|
+
let i = start;
|
|
3875
|
+
let depth = 1;
|
|
3876
|
+
while (i < text.length) {
|
|
3877
|
+
const char = text[i];
|
|
3878
|
+
if (char === "\\") {
|
|
3879
|
+
if (i + 1 >= text.length) return -1;
|
|
3880
|
+
i += 2;
|
|
3881
|
+
continue;
|
|
3882
|
+
}
|
|
3883
|
+
if (char === "(") depth++;
|
|
3884
|
+
else if (char === ")") {
|
|
3885
|
+
depth--;
|
|
3886
|
+
if (depth === 0) return i + 1;
|
|
3887
|
+
}
|
|
3888
|
+
i++;
|
|
3889
|
+
}
|
|
3890
|
+
return -1;
|
|
3891
|
+
}
|
|
3892
|
+
function completeMarkdownImageTokenLength(text) {
|
|
3893
|
+
if (!text.startsWith("![")) return 0;
|
|
3894
|
+
const altEnd = scanAltText(text, 2);
|
|
3895
|
+
if (altEnd === -1 || altEnd + 1 >= text.length || text[altEnd + 1] !== "(") {
|
|
3896
|
+
return 0;
|
|
3897
|
+
}
|
|
3898
|
+
let i = altEnd + 2;
|
|
3899
|
+
if (i >= text.length) return 0;
|
|
3900
|
+
if (text[i] === "<") {
|
|
3901
|
+
i = scanAngleBracketDestination(text, i);
|
|
3902
|
+
if (i === -1) return 0;
|
|
3903
|
+
i = scanOptionalTitle(text, i);
|
|
3904
|
+
if (i === -1 || i >= text.length || text[i] !== ")") return 0;
|
|
3905
|
+
return i + 1;
|
|
3906
|
+
}
|
|
3907
|
+
i = scanRawDestination(text, i);
|
|
3908
|
+
return i === -1 ? 0 : i;
|
|
3909
|
+
}
|
|
3910
|
+
function stripIncompleteImageToken(text) {
|
|
3911
|
+
const lastBang = text.lastIndexOf("![");
|
|
3912
|
+
if (lastBang === -1) return text;
|
|
3913
|
+
const suffix = text.slice(lastBang);
|
|
3914
|
+
if (completeMarkdownImageTokenLength(suffix) > 0) return text;
|
|
3915
|
+
return text.slice(0, lastBang);
|
|
3916
|
+
}
|
|
3917
|
+
|
|
3918
|
+
// src/components/v2/useTypingEffect.ts
|
|
3800
3919
|
var RESPONSE_SPEED = {
|
|
3801
3920
|
normal: [2, 4],
|
|
3802
3921
|
fast: 1,
|
|
@@ -3804,7 +3923,6 @@ var RESPONSE_SPEED = {
|
|
|
3804
3923
|
newline: [4, 6],
|
|
3805
3924
|
idle: 15
|
|
3806
3925
|
};
|
|
3807
|
-
var MARKDOWN_IMAGE_REGEX = /^!\[[^\]]*\]\([^)]*\)/;
|
|
3808
3926
|
function charDelay(char, speed, multiplier) {
|
|
3809
3927
|
const raw = (() => {
|
|
3810
3928
|
if (char === "*") return speed.fast;
|
|
@@ -3819,17 +3937,17 @@ function charDelay(char, speed, multiplier) {
|
|
|
3819
3937
|
function useTypingEffect(targetText, enabled, speed = RESPONSE_SPEED, initialDisplayedText, speedMultiplier = 1) {
|
|
3820
3938
|
const instant = speedMultiplier === 0;
|
|
3821
3939
|
const multiplier = instant ? 1 : Math.max(speedMultiplier, 0.1);
|
|
3822
|
-
const [displayedText, setDisplayedText] =
|
|
3823
|
-
const displayedRef =
|
|
3824
|
-
const targetRef =
|
|
3825
|
-
const enabledRef =
|
|
3826
|
-
const initialDisplayedRef =
|
|
3827
|
-
const timerRef =
|
|
3828
|
-
const runningRef =
|
|
3940
|
+
const [displayedText, setDisplayedText] = react.useState("");
|
|
3941
|
+
const displayedRef = react.useRef("");
|
|
3942
|
+
const targetRef = react.useRef(targetText);
|
|
3943
|
+
const enabledRef = react.useRef(enabled);
|
|
3944
|
+
const initialDisplayedRef = react.useRef(initialDisplayedText);
|
|
3945
|
+
const timerRef = react.useRef(null);
|
|
3946
|
+
const runningRef = react.useRef(false);
|
|
3829
3947
|
targetRef.current = targetText;
|
|
3830
3948
|
enabledRef.current = enabled;
|
|
3831
3949
|
initialDisplayedRef.current = initialDisplayedText;
|
|
3832
|
-
|
|
3950
|
+
react.useEffect(() => {
|
|
3833
3951
|
if (!enabled || instant) {
|
|
3834
3952
|
if (timerRef.current) {
|
|
3835
3953
|
clearTimeout(timerRef.current);
|
|
@@ -3863,9 +3981,9 @@ function useTypingEffect(targetText, enabled, speed = RESPONSE_SPEED, initialDis
|
|
|
3863
3981
|
}
|
|
3864
3982
|
if (displayedRef.current.length < targetRef.current.length) {
|
|
3865
3983
|
const remaining = targetRef.current.slice(displayedRef.current.length);
|
|
3866
|
-
const
|
|
3867
|
-
if (
|
|
3868
|
-
displayedRef.current +=
|
|
3984
|
+
const imageTokenLength = completeMarkdownImageTokenLength(remaining);
|
|
3985
|
+
if (imageTokenLength > 0) {
|
|
3986
|
+
displayedRef.current += remaining.slice(0, imageTokenLength);
|
|
3869
3987
|
setDisplayedText(displayedRef.current);
|
|
3870
3988
|
timerRef.current = setTimeout(tick, 0);
|
|
3871
3989
|
return;
|
|
@@ -3894,13 +4012,6 @@ function useTypingEffect(targetText, enabled, speed = RESPONSE_SPEED, initialDis
|
|
|
3894
4012
|
isTyping
|
|
3895
4013
|
};
|
|
3896
4014
|
}
|
|
3897
|
-
function stripIncompleteImageToken(text) {
|
|
3898
|
-
const lastBang = text.lastIndexOf("![");
|
|
3899
|
-
if (lastBang === -1) return text;
|
|
3900
|
-
const after = text.slice(lastBang);
|
|
3901
|
-
if (/^!\[[^\]]*\]\([^)]*\)/.test(after)) return text;
|
|
3902
|
-
return text.slice(0, lastBang);
|
|
3903
|
-
}
|
|
3904
4015
|
function getFeedbackState(message) {
|
|
3905
4016
|
const feedback = message.feedback;
|
|
3906
4017
|
if (feedback === "up" || feedback === "down") return feedback;
|
|
@@ -3919,26 +4030,26 @@ function AssistantMessageV2({
|
|
|
3919
4030
|
actions,
|
|
3920
4031
|
typingSpeed = 4
|
|
3921
4032
|
}) {
|
|
3922
|
-
const [copied, setCopied] =
|
|
3923
|
-
const [activeFeedback, setActiveFeedback] =
|
|
4033
|
+
const [copied, setCopied] = react.useState(false);
|
|
4034
|
+
const [activeFeedback, setActiveFeedback] = react.useState(
|
|
3924
4035
|
() => getFeedbackState(message)
|
|
3925
4036
|
);
|
|
3926
|
-
const [reasonModalOpen, setReasonModalOpen] =
|
|
4037
|
+
const [reasonModalOpen, setReasonModalOpen] = react.useState(false);
|
|
3927
4038
|
const canSubmitFeedback = !!onSubmitFeedback && !!message.executionId;
|
|
3928
|
-
const [toast, setToast] =
|
|
3929
|
-
const copyResetTimerRef =
|
|
3930
|
-
const toastTimerRef =
|
|
4039
|
+
const [toast, setToast] = react.useState(null);
|
|
4040
|
+
const copyResetTimerRef = react.useRef(null);
|
|
4041
|
+
const toastTimerRef = react.useRef(null);
|
|
3931
4042
|
const showCopyAction = actions?.copy ?? true;
|
|
3932
4043
|
const showTraceAction = (actions?.trace ?? true) && !!onExecutionTraceClick;
|
|
3933
4044
|
const showThumbsUp = actions?.thumbsUp ?? true;
|
|
3934
4045
|
const showThumbsDown = actions?.thumbsDown ?? true;
|
|
3935
4046
|
const hydratedFeedback = message.feedback;
|
|
3936
|
-
const hasEverStreamed =
|
|
4047
|
+
const hasEverStreamed = react.useRef(!!message.isStreaming);
|
|
3937
4048
|
if (message.isStreaming) hasEverStreamed.current = true;
|
|
3938
|
-
|
|
4049
|
+
react.useEffect(() => {
|
|
3939
4050
|
setActiveFeedback(getFeedbackState(message));
|
|
3940
4051
|
}, [hydratedFeedback, message.id]);
|
|
3941
|
-
|
|
4052
|
+
react.useEffect(() => {
|
|
3942
4053
|
return () => {
|
|
3943
4054
|
if (copyResetTimerRef.current) clearTimeout(copyResetTimerRef.current);
|
|
3944
4055
|
if (toastTimerRef.current) clearTimeout(toastTimerRef.current);
|
|
@@ -4232,10 +4343,10 @@ function OtpInputV2({
|
|
|
4232
4343
|
disabled = false,
|
|
4233
4344
|
error = false
|
|
4234
4345
|
}) {
|
|
4235
|
-
const inputRefs =
|
|
4346
|
+
const inputRefs = react.useRef([]);
|
|
4236
4347
|
const safeMaxLength = Number.isInteger(maxLength) && maxLength > 0 ? Math.min(maxLength, MAX_SUPPORTED_LENGTH) : DEFAULT_MAX_LENGTH;
|
|
4237
4348
|
const digits = value.split("").concat(Array(safeMaxLength).fill("")).slice(0, safeMaxLength);
|
|
4238
|
-
|
|
4349
|
+
react.useEffect(() => {
|
|
4239
4350
|
if (disabled) return;
|
|
4240
4351
|
const timer = window.setTimeout(() => {
|
|
4241
4352
|
inputRefs.current[0]?.focus();
|
|
@@ -4334,31 +4445,31 @@ function VerificationInline({
|
|
|
4334
4445
|
onResend
|
|
4335
4446
|
}) {
|
|
4336
4447
|
const isNumeric = prompt.verificationType !== "ALPHANUMERIC_CODE";
|
|
4337
|
-
const codeLen =
|
|
4338
|
-
const [code, setCode] =
|
|
4339
|
-
const [errored, setErrored] =
|
|
4340
|
-
const [resendSec, setResendSec] =
|
|
4341
|
-
const [hiddenAfterResend, setHiddenAfterResend] =
|
|
4342
|
-
const lastSubmittedRef =
|
|
4343
|
-
const resendTimerRef =
|
|
4448
|
+
const codeLen = react.useMemo(() => codeLengthFromSchema(prompt), [prompt]);
|
|
4449
|
+
const [code, setCode] = react.useState("");
|
|
4450
|
+
const [errored, setErrored] = react.useState(false);
|
|
4451
|
+
const [resendSec, setResendSec] = react.useState(0);
|
|
4452
|
+
const [hiddenAfterResend, setHiddenAfterResend] = react.useState(false);
|
|
4453
|
+
const lastSubmittedRef = react.useRef(null);
|
|
4454
|
+
const resendTimerRef = react.useRef(void 0);
|
|
4344
4455
|
const status = prompt.status;
|
|
4345
4456
|
const busy = status === "submitting";
|
|
4346
4457
|
const stale = status === "stale";
|
|
4347
4458
|
const locked = busy || stale || expired;
|
|
4348
|
-
|
|
4459
|
+
react.useEffect(() => {
|
|
4349
4460
|
if (prompt.subAction === "SubmissionInvalid") {
|
|
4350
4461
|
setErrored(true);
|
|
4351
4462
|
setCode("");
|
|
4352
4463
|
lastSubmittedRef.current = null;
|
|
4353
4464
|
}
|
|
4354
4465
|
}, [prompt.subAction, prompt.userActionId]);
|
|
4355
|
-
|
|
4466
|
+
react.useEffect(() => {
|
|
4356
4467
|
setHiddenAfterResend(false);
|
|
4357
4468
|
}, [prompt.expirySeconds, prompt.message, prompt.subAction, prompt.userActionId]);
|
|
4358
|
-
|
|
4469
|
+
react.useEffect(() => {
|
|
4359
4470
|
if (code.length < codeLen) lastSubmittedRef.current = null;
|
|
4360
4471
|
}, [code, codeLen]);
|
|
4361
|
-
const doSubmit =
|
|
4472
|
+
const doSubmit = react.useCallback(
|
|
4362
4473
|
(value) => {
|
|
4363
4474
|
if (locked || !value) return;
|
|
4364
4475
|
if (lastSubmittedRef.current === value) return;
|
|
@@ -4370,20 +4481,20 @@ function VerificationInline({
|
|
|
4370
4481
|
},
|
|
4371
4482
|
[locked, onSubmit, prompt.userActionId]
|
|
4372
4483
|
);
|
|
4373
|
-
|
|
4484
|
+
react.useEffect(() => {
|
|
4374
4485
|
if (!isNumeric || locked) return;
|
|
4375
4486
|
if (code.length === codeLen && /^\d+$/.test(code)) {
|
|
4376
4487
|
doSubmit(code);
|
|
4377
4488
|
}
|
|
4378
4489
|
}, [code, codeLen, doSubmit, isNumeric, locked]);
|
|
4379
|
-
|
|
4490
|
+
react.useEffect(() => {
|
|
4380
4491
|
return () => {
|
|
4381
4492
|
if (typeof resendTimerRef.current === "number") {
|
|
4382
4493
|
window.clearInterval(resendTimerRef.current);
|
|
4383
4494
|
}
|
|
4384
4495
|
};
|
|
4385
4496
|
}, []);
|
|
4386
|
-
const startResendCooldown =
|
|
4497
|
+
const startResendCooldown = react.useCallback(() => {
|
|
4387
4498
|
setResendSec(RESEND_COOLDOWN_S);
|
|
4388
4499
|
if (typeof resendTimerRef.current === "number") {
|
|
4389
4500
|
window.clearInterval(resendTimerRef.current);
|
|
@@ -4401,7 +4512,7 @@ function VerificationInline({
|
|
|
4401
4512
|
});
|
|
4402
4513
|
}, 1e3);
|
|
4403
4514
|
}, []);
|
|
4404
|
-
const handleResend =
|
|
4515
|
+
const handleResend = react.useCallback(async () => {
|
|
4405
4516
|
if (locked || resendSec > 0) return;
|
|
4406
4517
|
setErrored(false);
|
|
4407
4518
|
setCode("");
|
|
@@ -4414,7 +4525,7 @@ function VerificationInline({
|
|
|
4414
4525
|
setHiddenAfterResend(false);
|
|
4415
4526
|
}
|
|
4416
4527
|
}, [locked, onResend, prompt.userActionId, resendSec, startResendCooldown]);
|
|
4417
|
-
const handleCancel =
|
|
4528
|
+
const handleCancel = react.useCallback(() => {
|
|
4418
4529
|
if (busy) return;
|
|
4419
4530
|
void onCancel(prompt.userActionId);
|
|
4420
4531
|
}, [busy, onCancel, prompt.userActionId]);
|
|
@@ -4504,13 +4615,13 @@ function SchemaFormInline({
|
|
|
4504
4615
|
onCancel
|
|
4505
4616
|
}) {
|
|
4506
4617
|
const schema = prompt.requestedSchema;
|
|
4507
|
-
const fields =
|
|
4508
|
-
const [values, setValues] =
|
|
4618
|
+
const fields = react.useMemo(() => renderableFields(schema), [schema]);
|
|
4619
|
+
const [values, setValues] = react.useState(() => {
|
|
4509
4620
|
const init2 = {};
|
|
4510
4621
|
for (const [key, field] of fields) init2[key] = defaultValueFor(field);
|
|
4511
4622
|
return init2;
|
|
4512
4623
|
});
|
|
4513
|
-
const [errors, setErrors] =
|
|
4624
|
+
const [errors, setErrors] = react.useState({});
|
|
4514
4625
|
const status = prompt.status;
|
|
4515
4626
|
const busy = status === "submitting";
|
|
4516
4627
|
const stale = status === "stale";
|
|
@@ -4651,8 +4762,8 @@ function NotificationInline({ notification, onDismiss }) {
|
|
|
4651
4762
|
}
|
|
4652
4763
|
function useExpiryCountdown(prompt) {
|
|
4653
4764
|
const initial = typeof prompt.expirySeconds === "number" && prompt.expirySeconds > 0 ? Math.floor(prompt.expirySeconds) : void 0;
|
|
4654
|
-
const [secondsLeft, setSecondsLeft] =
|
|
4655
|
-
|
|
4765
|
+
const [secondsLeft, setSecondsLeft] = react.useState(initial);
|
|
4766
|
+
react.useEffect(() => {
|
|
4656
4767
|
if (initial === void 0) {
|
|
4657
4768
|
setSecondsLeft(void 0);
|
|
4658
4769
|
return;
|
|
@@ -4691,7 +4802,7 @@ function UserActionInline({
|
|
|
4691
4802
|
onExpired
|
|
4692
4803
|
}) {
|
|
4693
4804
|
const [secondsLeft, expired] = useExpiryCountdown(prompt);
|
|
4694
|
-
|
|
4805
|
+
react.useEffect(() => {
|
|
4695
4806
|
if (expired && prompt.kind !== "notification") onExpired?.();
|
|
4696
4807
|
}, [expired, onExpired, prompt.kind]);
|
|
4697
4808
|
let body;
|
|
@@ -4754,7 +4865,7 @@ function getPromptViewKey(prompt) {
|
|
|
4754
4865
|
prompt.message ?? ""
|
|
4755
4866
|
].join(PROMPT_KEY_SEPARATOR);
|
|
4756
4867
|
}
|
|
4757
|
-
var MessageListV2 =
|
|
4868
|
+
var MessageListV2 = react.forwardRef(
|
|
4758
4869
|
function MessageListV22({
|
|
4759
4870
|
messages,
|
|
4760
4871
|
isStreaming = false,
|
|
@@ -4774,25 +4885,25 @@ var MessageListV2 = React.forwardRef(
|
|
|
4774
4885
|
onSubmitFeedback,
|
|
4775
4886
|
typingSpeed = 4
|
|
4776
4887
|
}, ref) {
|
|
4777
|
-
const noop =
|
|
4888
|
+
const noop = react.useCallback(async () => {
|
|
4778
4889
|
}, []);
|
|
4779
|
-
const scrollRef =
|
|
4780
|
-
const scrollInnerRef =
|
|
4781
|
-
const isNearBottomRef =
|
|
4782
|
-
const [showScrollBtn, setShowScrollBtn] =
|
|
4783
|
-
const [expiredPromptViewState, setExpiredPromptViewState] =
|
|
4784
|
-
const expiredUserActionIdsRef =
|
|
4785
|
-
const prevCountRef =
|
|
4786
|
-
const pauseStickUntilUserMessageRef =
|
|
4787
|
-
const followingBottomRef =
|
|
4788
|
-
const lastPinAtRef =
|
|
4789
|
-
const prevScrollTopRef =
|
|
4790
|
-
const getDistanceFromBottom =
|
|
4890
|
+
const scrollRef = react.useRef(null);
|
|
4891
|
+
const scrollInnerRef = react.useRef(null);
|
|
4892
|
+
const isNearBottomRef = react.useRef(true);
|
|
4893
|
+
const [showScrollBtn, setShowScrollBtn] = react.useState(false);
|
|
4894
|
+
const [expiredPromptViewState, setExpiredPromptViewState] = react.useState({});
|
|
4895
|
+
const expiredUserActionIdsRef = react.useRef(/* @__PURE__ */ new Set());
|
|
4896
|
+
const prevCountRef = react.useRef(messages.length);
|
|
4897
|
+
const pauseStickUntilUserMessageRef = react.useRef(false);
|
|
4898
|
+
const followingBottomRef = react.useRef(true);
|
|
4899
|
+
const lastPinAtRef = react.useRef(0);
|
|
4900
|
+
const prevScrollTopRef = react.useRef(0);
|
|
4901
|
+
const getDistanceFromBottom = react.useCallback(() => {
|
|
4791
4902
|
const el = scrollRef.current;
|
|
4792
4903
|
if (!el) return 0;
|
|
4793
4904
|
return el.scrollHeight - el.scrollTop - el.clientHeight;
|
|
4794
4905
|
}, []);
|
|
4795
|
-
const messageActivityFingerprint =
|
|
4906
|
+
const messageActivityFingerprint = react.useMemo(() => {
|
|
4796
4907
|
const last = messages[messages.length - 1];
|
|
4797
4908
|
const promptFingerprint = (userActionPrompts ?? []).map((prompt) => `${getPromptViewKey(prompt)}:${prompt.status}`).join(PROMPT_KEY_SEPARATOR);
|
|
4798
4909
|
const notificationFingerprint = (notifications ?? []).map((notification) => notification.id).join(PROMPT_KEY_SEPARATOR);
|
|
@@ -4818,7 +4929,7 @@ var MessageListV2 = React.forwardRef(
|
|
|
4818
4929
|
notificationFingerprint
|
|
4819
4930
|
].join(PROMPT_KEY_SEPARATOR);
|
|
4820
4931
|
}, [isStreaming, messages, notifications, userActionPrompts]);
|
|
4821
|
-
const handleUserActionExpired =
|
|
4932
|
+
const handleUserActionExpired = react.useCallback(
|
|
4822
4933
|
(promptKey, userActionId) => {
|
|
4823
4934
|
setExpiredPromptViewState((prev) => {
|
|
4824
4935
|
if (prev[promptKey]) return prev;
|
|
@@ -4835,7 +4946,7 @@ var MessageListV2 = React.forwardRef(
|
|
|
4835
4946
|
},
|
|
4836
4947
|
[messageActivityFingerprint, onExpireUserAction]
|
|
4837
4948
|
);
|
|
4838
|
-
|
|
4949
|
+
react.useEffect(() => {
|
|
4839
4950
|
setExpiredPromptViewState((prev) => {
|
|
4840
4951
|
let changed = false;
|
|
4841
4952
|
const next = {};
|
|
@@ -4850,7 +4961,7 @@ var MessageListV2 = React.forwardRef(
|
|
|
4850
4961
|
return changed ? next : prev;
|
|
4851
4962
|
});
|
|
4852
4963
|
}, [messageActivityFingerprint]);
|
|
4853
|
-
|
|
4964
|
+
react.useEffect(() => {
|
|
4854
4965
|
const livePromptKeys = new Set((userActionPrompts ?? []).map(getPromptViewKey));
|
|
4855
4966
|
const liveUserActionIds = new Set((userActionPrompts ?? []).map((p) => p.userActionId));
|
|
4856
4967
|
for (const userActionId of expiredUserActionIdsRef.current) {
|
|
@@ -4871,21 +4982,21 @@ var MessageListV2 = React.forwardRef(
|
|
|
4871
4982
|
return changed ? next : prev;
|
|
4872
4983
|
});
|
|
4873
4984
|
}, [userActionPrompts]);
|
|
4874
|
-
const visibleUserActionPrompts =
|
|
4985
|
+
const visibleUserActionPrompts = react.useMemo(
|
|
4875
4986
|
() => userActionPrompts?.filter((prompt) => {
|
|
4876
4987
|
const promptKey = getPromptViewKey(prompt);
|
|
4877
4988
|
return !expiredPromptViewState[promptKey]?.hidden;
|
|
4878
4989
|
}),
|
|
4879
4990
|
[expiredPromptViewState, userActionPrompts]
|
|
4880
4991
|
);
|
|
4881
|
-
const pinToBottom =
|
|
4992
|
+
const pinToBottom = react.useCallback((behavior = "instant") => {
|
|
4882
4993
|
const el = scrollRef.current;
|
|
4883
4994
|
if (!el) return;
|
|
4884
4995
|
lastPinAtRef.current = performance.now();
|
|
4885
4996
|
el.scrollTo({ top: el.scrollHeight, behavior });
|
|
4886
4997
|
prevScrollTopRef.current = el.scrollHeight;
|
|
4887
4998
|
}, []);
|
|
4888
|
-
const scrollToBottom =
|
|
4999
|
+
const scrollToBottom = react.useCallback(
|
|
4889
5000
|
(behavior = "smooth") => {
|
|
4890
5001
|
const el = scrollRef.current;
|
|
4891
5002
|
if (!el) return;
|
|
@@ -4895,7 +5006,7 @@ var MessageListV2 = React.forwardRef(
|
|
|
4895
5006
|
},
|
|
4896
5007
|
[pinToBottom]
|
|
4897
5008
|
);
|
|
4898
|
-
|
|
5009
|
+
react.useImperativeHandle(
|
|
4899
5010
|
ref,
|
|
4900
5011
|
() => ({
|
|
4901
5012
|
scrollToBottom: (behavior = "smooth") => {
|
|
@@ -4908,7 +5019,7 @@ var MessageListV2 = React.forwardRef(
|
|
|
4908
5019
|
}),
|
|
4909
5020
|
[scrollToBottom]
|
|
4910
5021
|
);
|
|
4911
|
-
const handleScroll =
|
|
5022
|
+
const handleScroll = react.useCallback(() => {
|
|
4912
5023
|
const el = scrollRef.current;
|
|
4913
5024
|
if (!el) return;
|
|
4914
5025
|
const currentScrollTop = el.scrollTop;
|
|
@@ -4929,7 +5040,7 @@ var MessageListV2 = React.forwardRef(
|
|
|
4929
5040
|
pauseStickUntilUserMessageRef.current = false;
|
|
4930
5041
|
}
|
|
4931
5042
|
}, [getDistanceFromBottom]);
|
|
4932
|
-
|
|
5043
|
+
react.useEffect(() => {
|
|
4933
5044
|
const prevCount = prevCountRef.current;
|
|
4934
5045
|
prevCountRef.current = messages.length;
|
|
4935
5046
|
if (messages.length > prevCount) {
|
|
@@ -4943,7 +5054,7 @@ var MessageListV2 = React.forwardRef(
|
|
|
4943
5054
|
}
|
|
4944
5055
|
}
|
|
4945
5056
|
}, [messages.length, scrollToBottom]);
|
|
4946
|
-
|
|
5057
|
+
react.useEffect(() => {
|
|
4947
5058
|
const inner = scrollInnerRef.current;
|
|
4948
5059
|
if (!inner) return;
|
|
4949
5060
|
const pinIfFollowing = () => {
|
|
@@ -4968,7 +5079,7 @@ var MessageListV2 = React.forwardRef(
|
|
|
4968
5079
|
mo.disconnect();
|
|
4969
5080
|
};
|
|
4970
5081
|
}, [pinToBottom]);
|
|
4971
|
-
|
|
5082
|
+
react.useEffect(() => {
|
|
4972
5083
|
if (messages.length > 0) {
|
|
4973
5084
|
setTimeout(() => scrollToBottom("instant"), 50);
|
|
4974
5085
|
}
|
|
@@ -5057,7 +5168,7 @@ var MessageListV2 = React.forwardRef(
|
|
|
5057
5168
|
] });
|
|
5058
5169
|
}
|
|
5059
5170
|
);
|
|
5060
|
-
var ChatInputV2 =
|
|
5171
|
+
var ChatInputV2 = react.forwardRef(
|
|
5061
5172
|
function ChatInputV22({
|
|
5062
5173
|
onSend,
|
|
5063
5174
|
disabled = false,
|
|
@@ -5081,20 +5192,20 @@ var ChatInputV2 = React.forwardRef(
|
|
|
5081
5192
|
onAnalysisModeChange,
|
|
5082
5193
|
slashCommands = []
|
|
5083
5194
|
}, ref) {
|
|
5084
|
-
const [value, setValue] =
|
|
5085
|
-
const [isFocused, setIsFocused] =
|
|
5086
|
-
const [showActions, setShowActions] =
|
|
5087
|
-
const [showVoiceTooltip, setShowVoiceTooltip] =
|
|
5088
|
-
const [selectedCommandIndex, setSelectedCommandIndex] =
|
|
5089
|
-
const [inlineHint, setInlineHint] =
|
|
5090
|
-
const [commandMenuDismissed, setCommandMenuDismissed] =
|
|
5091
|
-
const textareaRef =
|
|
5092
|
-
const actionsRef =
|
|
5093
|
-
const preRecordTextRef =
|
|
5094
|
-
const voiceTooltipTimerRef =
|
|
5195
|
+
const [value, setValue] = react.useState("");
|
|
5196
|
+
const [isFocused, setIsFocused] = react.useState(false);
|
|
5197
|
+
const [showActions, setShowActions] = react.useState(false);
|
|
5198
|
+
const [showVoiceTooltip, setShowVoiceTooltip] = react.useState(false);
|
|
5199
|
+
const [selectedCommandIndex, setSelectedCommandIndex] = react.useState(0);
|
|
5200
|
+
const [inlineHint, setInlineHint] = react.useState(null);
|
|
5201
|
+
const [commandMenuDismissed, setCommandMenuDismissed] = react.useState(false);
|
|
5202
|
+
const textareaRef = react.useRef(null);
|
|
5203
|
+
const actionsRef = react.useRef(null);
|
|
5204
|
+
const preRecordTextRef = react.useRef("");
|
|
5205
|
+
const voiceTooltipTimerRef = react.useRef(
|
|
5095
5206
|
null
|
|
5096
5207
|
);
|
|
5097
|
-
const voiceDraftSyncActiveRef =
|
|
5208
|
+
const voiceDraftSyncActiveRef = react.useRef(false);
|
|
5098
5209
|
const isInputLocked = disabled || isRecording;
|
|
5099
5210
|
const hasAttachmentOptions = showUploadImageButton || showAttachFileButton;
|
|
5100
5211
|
const showAttachmentMenuButton = showAttachmentButton && hasAttachmentOptions;
|
|
@@ -5105,14 +5216,14 @@ var ChatInputV2 = React.forwardRef(
|
|
|
5105
5216
|
(command) => command.name.toLowerCase().startsWith(commandQuery)
|
|
5106
5217
|
);
|
|
5107
5218
|
const showCommandSuggestions = !commandMenuDismissed && !isRecording && !disabled && commandSuggestions.length > 0;
|
|
5108
|
-
|
|
5219
|
+
react.useEffect(() => {
|
|
5109
5220
|
if (textareaRef.current) {
|
|
5110
5221
|
textareaRef.current.style.height = "auto";
|
|
5111
5222
|
const scrollHeight = textareaRef.current.scrollHeight;
|
|
5112
5223
|
textareaRef.current.style.height = `${Math.min(scrollHeight, 200)}px`;
|
|
5113
5224
|
}
|
|
5114
5225
|
}, [value]);
|
|
5115
|
-
|
|
5226
|
+
react.useEffect(() => {
|
|
5116
5227
|
if (disabled) {
|
|
5117
5228
|
setIsFocused(false);
|
|
5118
5229
|
setShowActions(false);
|
|
@@ -5122,7 +5233,7 @@ var ChatInputV2 = React.forwardRef(
|
|
|
5122
5233
|
const frameId = requestAnimationFrame(() => textareaRef.current?.focus());
|
|
5123
5234
|
return () => cancelAnimationFrame(frameId);
|
|
5124
5235
|
}, [disabled]);
|
|
5125
|
-
|
|
5236
|
+
react.useImperativeHandle(
|
|
5126
5237
|
ref,
|
|
5127
5238
|
() => ({
|
|
5128
5239
|
setDraft: (message) => {
|
|
@@ -5139,7 +5250,7 @@ var ChatInputV2 = React.forwardRef(
|
|
|
5139
5250
|
}),
|
|
5140
5251
|
[disabled]
|
|
5141
5252
|
);
|
|
5142
|
-
|
|
5253
|
+
react.useEffect(() => {
|
|
5143
5254
|
if (!showActions) return;
|
|
5144
5255
|
const handleClickOutside = (e) => {
|
|
5145
5256
|
if (actionsRef.current && !actionsRef.current.contains(e.target)) {
|
|
@@ -5149,29 +5260,29 @@ var ChatInputV2 = React.forwardRef(
|
|
|
5149
5260
|
document.addEventListener("mousedown", handleClickOutside);
|
|
5150
5261
|
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
5151
5262
|
}, [showActions]);
|
|
5152
|
-
|
|
5263
|
+
react.useEffect(() => {
|
|
5153
5264
|
if (!showAttachmentMenuButton) {
|
|
5154
5265
|
setShowActions(false);
|
|
5155
5266
|
}
|
|
5156
5267
|
}, [showAttachmentMenuButton]);
|
|
5157
|
-
|
|
5268
|
+
react.useEffect(() => {
|
|
5158
5269
|
setSelectedCommandIndex(0);
|
|
5159
5270
|
setCommandMenuDismissed(false);
|
|
5160
5271
|
}, [commandQuery]);
|
|
5161
|
-
|
|
5272
|
+
react.useEffect(() => {
|
|
5162
5273
|
return () => {
|
|
5163
5274
|
if (voiceTooltipTimerRef.current) {
|
|
5164
5275
|
clearTimeout(voiceTooltipTimerRef.current);
|
|
5165
5276
|
}
|
|
5166
5277
|
};
|
|
5167
5278
|
}, []);
|
|
5168
|
-
|
|
5279
|
+
react.useEffect(() => {
|
|
5169
5280
|
if (!voiceDraftSyncActiveRef.current) return;
|
|
5170
5281
|
const base = preRecordTextRef.current;
|
|
5171
5282
|
const separator = base && !base.endsWith(" ") && transcribedText ? " " : "";
|
|
5172
5283
|
setValue(`${base}${separator}${transcribedText}`);
|
|
5173
5284
|
}, [isRecording, transcribedText]);
|
|
5174
|
-
const handleSend =
|
|
5285
|
+
const handleSend = react.useCallback(() => {
|
|
5175
5286
|
if (!value.trim() || disabled) return;
|
|
5176
5287
|
const commandHint = getSlashCommandValidationHint(value);
|
|
5177
5288
|
if (commandHint) {
|
|
@@ -5191,7 +5302,7 @@ var ChatInputV2 = React.forwardRef(
|
|
|
5191
5302
|
}
|
|
5192
5303
|
});
|
|
5193
5304
|
}, [value, disabled, onClearEditing, onSend]);
|
|
5194
|
-
const selectCommand =
|
|
5305
|
+
const selectCommand = react.useCallback(
|
|
5195
5306
|
(command) => {
|
|
5196
5307
|
const insertText = command.insertText ?? `${command.name} `;
|
|
5197
5308
|
setValue(insertText);
|
|
@@ -5247,14 +5358,14 @@ var ChatInputV2 = React.forwardRef(
|
|
|
5247
5358
|
onAttachFileClick?.();
|
|
5248
5359
|
setShowActions(false);
|
|
5249
5360
|
};
|
|
5250
|
-
const hideVoiceTooltip =
|
|
5361
|
+
const hideVoiceTooltip = react.useCallback(() => {
|
|
5251
5362
|
if (voiceTooltipTimerRef.current) {
|
|
5252
5363
|
clearTimeout(voiceTooltipTimerRef.current);
|
|
5253
5364
|
voiceTooltipTimerRef.current = null;
|
|
5254
5365
|
}
|
|
5255
5366
|
setShowVoiceTooltip(false);
|
|
5256
5367
|
}, []);
|
|
5257
|
-
const startVoiceTooltipTimer =
|
|
5368
|
+
const startVoiceTooltipTimer = react.useCallback(() => {
|
|
5258
5369
|
if (isVoiceButtonDisabled || isRecording) return;
|
|
5259
5370
|
if (voiceTooltipTimerRef.current) {
|
|
5260
5371
|
clearTimeout(voiceTooltipTimerRef.current);
|
|
@@ -5576,9 +5687,9 @@ var ChatInputV2 = React.forwardRef(
|
|
|
5576
5687
|
var thinking_atom_default = "data:application/zip;base64,UEsDBBQAAAAIAMWrkFzFrMWzUgAAAF4AAAANAAAAbWFuaWZlc3QuanNvbqtWKkstKs7Mz1OyUjJS0lFKT81LLUosyS8C8h1S8kty8ktKMlP14SzdrGIHQz0zPZDaxLzM3MQSoN5iJavoaqXMFKAe38TMPIXgZKApSrWxtQBQSwMEFAAAAAgAxauQXLRghFpXBAAA1RwAABEAAABhL01haW4gU2NlbmUuanNvbu1YWW/jNhD+KwafJVWkqMtPbdEDfdiiQIq+GMZCcei1GvmApLRdGP7v/YYiddqbGNumR4wcomZGHM7B76N0ZLstm7N3Wb6b3a3UTjGHPTw8sLnvsA2bCx/X3811q+qMzY/sAx74stjXda7WeaGqL1alyup9OeNeEnmcnRxWZB9VWbH54sjqj2weOI2bH5+KYibhoirZnONSa0f7AzykGOQYkGP4X2dFpbq13ONx0mTVu6x6bNXZXosf4erI9OLwjwRw7Tv4WWLSP+ALa7I2Rs0RkvkzRhEZQdWz8iHCms48Z54RMEAs2gABkcGRYVFHBqXv8Sh2GBKgRzDNW00SIClag1GzugVNShk5OUd9zxMj4cI/2UhoSdUwVBJpn53EGPMTOd0hh8hAUwuodC1UoVZ1ud+9UjWog+jvb6hIv9D9egxT8aK8kfte5tD5kiTYCfpaqvUPyABb7beH9/57zlUi4zBwE+FnrsyUdDOfC/c+iNVqzVOVKoH06vwLLDsr1Y6q+VZLgX7+dxQDW29SDGmKsVNPr1iLSyB1Bkui0CDGAEdkEmmpeXghQwe/Td0slnRzyDQ5NwdH8L05htXHLGFqIWk0fQ+YPhc9P3+3VpvsoDrSYR9KFNHWpKvWdgfdV998/e3sF2w70Nb35f7pAFNdfn0z49QpNLHDVnqh0FL9IUXU1kG1eZmDO1rYzB06+imrN30/hNG9JmkiPLIVm9flE2ZFuRZoFzf0hIyXzkJfqXcgtLJGCSHyi1SR/URF9pNJYP8b2adeaEwwoqc6AQ2XS+obXTi7bdi6eGmWs8MmXyEN3+UFPaOzQGOdBcQ52BeeDGXqgB3jRNIlirBe7Vs2TYNkXeiGsFtcTS0w3XLPAp8x0MQ86uluEVPse66t9R4ZdbVd88Vw4tNpqTcZIZekEUrFQi/2fAS3hqPIwBMXSIqBp6yqVN1shjHH5NejpvUyOtdZzNyX93lNVfwPn+vGrHjDpiuxSXAvFIHDhSdFRNghvcSPnMQLhKRbo3dbg0bvNgYWsZ4xcz7txuIYrGOfOzz0/JiTUZB4acwdVwiNa43abfVGrbVnMA79fCXG3WGvPdLLlM5nc6czWiBpKFXxq07ptqBOudg7hDI49vRUOAJYuJggZiQDrqFSxA6CMgj2/8PCNqDty6oCjqlViaL8XOb0iC4JjWfU51Xb6CiLunz8CiPop0cnnIb6Ryd7YGpf4bqTUmhPSpSSYXxuSsBtk3ztGkQwPAJS7QevkWdOa2SLNLSn378smfqMTZF0yRzV8Ez4SToNf4i5drmWByfHdk1B5PxGQW+Xgix5jMlhTB5jchlS0CeNOiK74GREQROOGVLQhKFuFHSjoH+CgkSELwM3CrqCgjDJGQoKbhT0pikIH0oE+CAMgOmpF3HAof580grxHaWRdt9opjr9wWUyj6UWHnvSD4yZ1N9pBiIXshuF3Cjktd9izmHo61CIxeSAPpWd/gRQSwECFAAUAAAACADFq5BcxazFs1IAAABeAAAADQAAAAAAAAAAAAAAAAAAAAAAbWFuaWZlc3QuanNvblBLAQIUABQAAAAIAMWrkFy0YIRaVwQAANUcAAARAAAAAAAAAAAAAAAAAH0AAABhL01haW4gU2NlbmUuanNvblBLBQYAAAAAAgACAHoAAAADBQAAAAA=";
|
|
5577
5688
|
var DEFAULT_SIZE = 36;
|
|
5578
5689
|
function useElapsedSeconds(isStreaming) {
|
|
5579
|
-
const [elapsed, setElapsed] =
|
|
5580
|
-
const startRef =
|
|
5581
|
-
|
|
5690
|
+
const [elapsed, setElapsed] = react.useState(0);
|
|
5691
|
+
const startRef = react.useRef(null);
|
|
5692
|
+
react.useEffect(() => {
|
|
5582
5693
|
if (!isStreaming) {
|
|
5583
5694
|
startRef.current = null;
|
|
5584
5695
|
setElapsed(0);
|
|
@@ -5637,22 +5748,22 @@ function StreamingIndicatorV2({
|
|
|
5637
5748
|
) });
|
|
5638
5749
|
}
|
|
5639
5750
|
function ImageLightboxV2({ src, alt, onClose }) {
|
|
5640
|
-
const [isMounted, setIsMounted] =
|
|
5641
|
-
const [isImageLoaded, setIsImageLoaded] =
|
|
5642
|
-
|
|
5751
|
+
const [isMounted, setIsMounted] = react.useState(false);
|
|
5752
|
+
const [isImageLoaded, setIsImageLoaded] = react.useState(false);
|
|
5753
|
+
react.useEffect(() => {
|
|
5643
5754
|
setIsMounted(true);
|
|
5644
5755
|
return () => setIsMounted(false);
|
|
5645
5756
|
}, []);
|
|
5646
|
-
|
|
5757
|
+
react.useEffect(() => {
|
|
5647
5758
|
setIsImageLoaded(false);
|
|
5648
5759
|
}, [src]);
|
|
5649
|
-
const handleKeyDown =
|
|
5760
|
+
const handleKeyDown = react.useCallback(
|
|
5650
5761
|
(e) => {
|
|
5651
5762
|
if (e.key === "Escape") onClose();
|
|
5652
5763
|
},
|
|
5653
5764
|
[onClose]
|
|
5654
5765
|
);
|
|
5655
|
-
|
|
5766
|
+
react.useEffect(() => {
|
|
5656
5767
|
if (!src || typeof document === "undefined") return;
|
|
5657
5768
|
document.addEventListener("keydown", handleKeyDown);
|
|
5658
5769
|
const previousOverflow = document.body.style.overflow;
|
|
@@ -5784,9 +5895,9 @@ var PRE_PIPELINE_STEPS = /* @__PURE__ */ new Set([
|
|
|
5784
5895
|
"build_pipeline",
|
|
5785
5896
|
"load_skill_index"
|
|
5786
5897
|
]);
|
|
5787
|
-
function stepColor(
|
|
5788
|
-
if (
|
|
5789
|
-
if (PRE_PIPELINE_STEPS.has(
|
|
5898
|
+
function stepColor(step2) {
|
|
5899
|
+
if (step2.status === "failed") return "#ef4444";
|
|
5900
|
+
if (PRE_PIPELINE_STEPS.has(step2.step)) return "#f59e0b";
|
|
5790
5901
|
return "#3b82f6";
|
|
5791
5902
|
}
|
|
5792
5903
|
function formatMs(ms) {
|
|
@@ -5801,10 +5912,10 @@ function TraceTimelineModal({
|
|
|
5801
5912
|
apiBaseUrl,
|
|
5802
5913
|
apiHeaders
|
|
5803
5914
|
}) {
|
|
5804
|
-
const [trace, setTrace] =
|
|
5805
|
-
const [loading, setLoading] =
|
|
5806
|
-
const [error, setError] =
|
|
5807
|
-
|
|
5915
|
+
const [trace, setTrace] = react.useState(null);
|
|
5916
|
+
const [loading, setLoading] = react.useState(false);
|
|
5917
|
+
const [error, setError] = react.useState(null);
|
|
5918
|
+
react.useEffect(() => {
|
|
5808
5919
|
if (!open || !executionId) return;
|
|
5809
5920
|
const ctrl = new AbortController();
|
|
5810
5921
|
setLoading(true);
|
|
@@ -5826,7 +5937,7 @@ function TraceTimelineModal({
|
|
|
5826
5937
|
}).finally(() => setLoading(false));
|
|
5827
5938
|
return () => ctrl.abort();
|
|
5828
5939
|
}, [open, executionId, apiBaseUrl, apiHeaders]);
|
|
5829
|
-
const totalMs =
|
|
5940
|
+
const totalMs = react.useMemo(() => {
|
|
5830
5941
|
if (!trace) return 0;
|
|
5831
5942
|
const meta = trace.runMetadata?.totalTimeMs;
|
|
5832
5943
|
if (typeof meta === "number" && meta > 0) return meta;
|
|
@@ -5835,7 +5946,7 @@ function TraceTimelineModal({
|
|
|
5835
5946
|
if (starts.length === 0 || ends.length === 0) return 0;
|
|
5836
5947
|
return Math.max(...ends) - Math.min(...starts);
|
|
5837
5948
|
}, [trace]);
|
|
5838
|
-
const accountedMs =
|
|
5949
|
+
const accountedMs = react.useMemo(
|
|
5839
5950
|
() => (trace?.pipelineSteps ?? []).reduce(
|
|
5840
5951
|
(sum, s) => sum + (s.durationMs ?? 0),
|
|
5841
5952
|
0
|
|
@@ -5963,10 +6074,10 @@ function TimelineBars({
|
|
|
5963
6074
|
totalMs,
|
|
5964
6075
|
unaccountedMs
|
|
5965
6076
|
}) {
|
|
5966
|
-
const bars = trace.pipelineSteps.map((
|
|
5967
|
-
const duration =
|
|
6077
|
+
const bars = trace.pipelineSteps.map((step2) => {
|
|
6078
|
+
const duration = step2.durationMs ?? 0;
|
|
5968
6079
|
const widthPct = totalMs > 0 ? duration / totalMs * 100 : 0;
|
|
5969
|
-
const llmMs =
|
|
6080
|
+
const llmMs = step2.llmCall?.durationMs ?? null;
|
|
5970
6081
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { marginBottom: 8 }, children: [
|
|
5971
6082
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
5972
6083
|
"div",
|
|
@@ -5980,8 +6091,8 @@ function TimelineBars({
|
|
|
5980
6091
|
},
|
|
5981
6092
|
children: [
|
|
5982
6093
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
5983
|
-
|
|
5984
|
-
|
|
6094
|
+
step2.step,
|
|
6095
|
+
step2.status === "failed" && /* @__PURE__ */ jsxRuntime.jsx("span", { style: { color: "#fca5a5", marginLeft: 6 }, children: "(failed)" })
|
|
5985
6096
|
] }),
|
|
5986
6097
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { style: { opacity: 0.75 }, children: [
|
|
5987
6098
|
formatMs(duration),
|
|
@@ -6009,14 +6120,14 @@ function TimelineBars({
|
|
|
6009
6120
|
style: {
|
|
6010
6121
|
height: "100%",
|
|
6011
6122
|
width: `${Math.max(widthPct, 0.3)}%`,
|
|
6012
|
-
background: stepColor(
|
|
6123
|
+
background: stepColor(step2),
|
|
6013
6124
|
transition: "width 0.2s ease"
|
|
6014
6125
|
}
|
|
6015
6126
|
}
|
|
6016
6127
|
)
|
|
6017
6128
|
}
|
|
6018
6129
|
)
|
|
6019
|
-
] }, `${
|
|
6130
|
+
] }, `${step2.step}-${step2.startTime}`);
|
|
6020
6131
|
});
|
|
6021
6132
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
6022
6133
|
bars,
|
|
@@ -6096,12 +6207,12 @@ var NOOP_ASYNC = async () => {
|
|
|
6096
6207
|
var NOOP = () => {
|
|
6097
6208
|
};
|
|
6098
6209
|
function useSentryChatCallbacks(callbacks, config) {
|
|
6099
|
-
const sentryCtxRef =
|
|
6100
|
-
const callbacksRef =
|
|
6210
|
+
const sentryCtxRef = react.useRef({});
|
|
6211
|
+
const callbacksRef = react.useRef(callbacks);
|
|
6101
6212
|
callbacksRef.current = callbacks;
|
|
6102
6213
|
const initialSessionId = config.initialSessionId;
|
|
6103
6214
|
const apiHeaders = config.api.headers;
|
|
6104
|
-
|
|
6215
|
+
react.useEffect(() => {
|
|
6105
6216
|
sentryCtxRef.current.agentId = config.agentId;
|
|
6106
6217
|
sentryCtxRef.current.sessionOwnerId = config.sessionParams?.id;
|
|
6107
6218
|
if (initialSessionId) {
|
|
@@ -6117,13 +6228,13 @@ function useSentryChatCallbacks(callbacks, config) {
|
|
|
6117
6228
|
initialSessionId,
|
|
6118
6229
|
apiHeaders
|
|
6119
6230
|
]);
|
|
6120
|
-
|
|
6231
|
+
react.useEffect(() => {
|
|
6121
6232
|
const endpoint = config.api.streamEndpoint || "/api/playground/ask/stream";
|
|
6122
6233
|
return subscribeToCfRay(endpoint, (cfRay) => {
|
|
6123
6234
|
sentryCtxRef.current.cfRay = cfRay;
|
|
6124
6235
|
});
|
|
6125
6236
|
}, [config.api.streamEndpoint]);
|
|
6126
|
-
return
|
|
6237
|
+
return react.useMemo(
|
|
6127
6238
|
() => ({
|
|
6128
6239
|
onMessageSent: (msg) => callbacksRef.current?.onMessageSent?.(msg),
|
|
6129
6240
|
onStreamStart: () => callbacksRef.current?.onStreamStart?.(),
|
|
@@ -6172,7 +6283,7 @@ function useSentryChatCallbacks(callbacks, config) {
|
|
|
6172
6283
|
[]
|
|
6173
6284
|
);
|
|
6174
6285
|
}
|
|
6175
|
-
var PaymanChatInner =
|
|
6286
|
+
var PaymanChatInner = react.forwardRef(function PaymanChatInner2({
|
|
6176
6287
|
config,
|
|
6177
6288
|
callbacks = {},
|
|
6178
6289
|
className,
|
|
@@ -6183,18 +6294,18 @@ var PaymanChatInner = React.forwardRef(function PaymanChatInner2({
|
|
|
6183
6294
|
hasMoreMessages = false,
|
|
6184
6295
|
chat
|
|
6185
6296
|
}, ref) {
|
|
6186
|
-
const [inputValue, setInputValue] =
|
|
6187
|
-
const prevInputValueRef =
|
|
6188
|
-
const [hasEverSentMessage, setHasEverSentMessage] =
|
|
6189
|
-
const [lightboxSrc, setLightboxSrc] =
|
|
6190
|
-
const [lightboxAlt, setLightboxAlt] =
|
|
6191
|
-
const [editingMessageId, setEditingMessageId] =
|
|
6192
|
-
const [isResetSessionConfirmOpen, setIsResetSessionConfirmOpen] =
|
|
6193
|
-
const [analysisMode, setAnalysisMode] =
|
|
6194
|
-
const chatInputV2Ref =
|
|
6195
|
-
const messageListV2Ref =
|
|
6196
|
-
const resetToEmptyStateRef =
|
|
6197
|
-
|
|
6297
|
+
const [inputValue, setInputValue] = react.useState("");
|
|
6298
|
+
const prevInputValueRef = react.useRef(inputValue);
|
|
6299
|
+
const [hasEverSentMessage, setHasEverSentMessage] = react.useState(false);
|
|
6300
|
+
const [lightboxSrc, setLightboxSrc] = react.useState(null);
|
|
6301
|
+
const [lightboxAlt, setLightboxAlt] = react.useState("");
|
|
6302
|
+
const [editingMessageId, setEditingMessageId] = react.useState(null);
|
|
6303
|
+
const [isResetSessionConfirmOpen, setIsResetSessionConfirmOpen] = react.useState(false);
|
|
6304
|
+
const [analysisMode, setAnalysisMode] = react.useState("fast");
|
|
6305
|
+
const chatInputV2Ref = react.useRef(null);
|
|
6306
|
+
const messageListV2Ref = react.useRef(null);
|
|
6307
|
+
const resetToEmptyStateRef = react.useRef(false);
|
|
6308
|
+
react.useEffect(() => {
|
|
6198
6309
|
if (config.sentryDsn) {
|
|
6199
6310
|
initSentryIfNeeded(config.sentryDsn);
|
|
6200
6311
|
}
|
|
@@ -6210,7 +6321,7 @@ var PaymanChatInner = React.forwardRef(function PaymanChatInner2({
|
|
|
6210
6321
|
getSessionId,
|
|
6211
6322
|
getMessages
|
|
6212
6323
|
} = chat;
|
|
6213
|
-
|
|
6324
|
+
react.useEffect(() => {
|
|
6214
6325
|
if (resetToEmptyStateRef.current) {
|
|
6215
6326
|
if (messages.length === 0) {
|
|
6216
6327
|
setHasEverSentMessage(false);
|
|
@@ -6222,7 +6333,7 @@ var PaymanChatInner = React.forwardRef(function PaymanChatInner2({
|
|
|
6222
6333
|
setHasEverSentMessage(true);
|
|
6223
6334
|
}
|
|
6224
6335
|
}, [messages.length, hasEverSentMessage]);
|
|
6225
|
-
|
|
6336
|
+
react.useEffect(() => {
|
|
6226
6337
|
if (!editingMessageId) return;
|
|
6227
6338
|
const editingMessageStillExists = messages.some(
|
|
6228
6339
|
(message) => message.id === editingMessageId && message.role === "user"
|
|
@@ -6235,7 +6346,7 @@ var PaymanChatInner = React.forwardRef(function PaymanChatInner2({
|
|
|
6235
6346
|
const submitUserAction2 = chat.submitUserAction ?? NOOP_ASYNC;
|
|
6236
6347
|
const cancelUserAction2 = chat.cancelUserAction ?? NOOP_ASYNC;
|
|
6237
6348
|
const resendUserAction2 = chat.resendUserAction ?? NOOP_ASYNC;
|
|
6238
|
-
const
|
|
6349
|
+
const expireUserAction = chat.expireUserAction ?? NOOP_ASYNC;
|
|
6239
6350
|
const dismissNotification = chat.dismissNotification ?? NOOP;
|
|
6240
6351
|
const isUserActionSupported = typeof chat.submitUserAction === "function" && typeof chat.cancelUserAction === "function" && typeof chat.resendUserAction === "function";
|
|
6241
6352
|
const {
|
|
@@ -6261,7 +6372,7 @@ var PaymanChatInner = React.forwardRef(function PaymanChatInner2({
|
|
|
6261
6372
|
}
|
|
6262
6373
|
}
|
|
6263
6374
|
);
|
|
6264
|
-
const contextValue =
|
|
6375
|
+
const contextValue = react.useMemo(
|
|
6265
6376
|
() => ({
|
|
6266
6377
|
resetSession,
|
|
6267
6378
|
clearMessages,
|
|
@@ -6288,8 +6399,8 @@ var PaymanChatInner = React.forwardRef(function PaymanChatInner2({
|
|
|
6288
6399
|
onAttachFileClick,
|
|
6289
6400
|
onMessageFeedback
|
|
6290
6401
|
} = callbacks;
|
|
6291
|
-
const [debugTraceExecutionId, setDebugTraceExecutionId] =
|
|
6292
|
-
const handleSubmitFeedback =
|
|
6402
|
+
const [debugTraceExecutionId, setDebugTraceExecutionId] = react.useState(null);
|
|
6403
|
+
const handleSubmitFeedback = react.useCallback(
|
|
6293
6404
|
async ({ messageId, executionId, feedback, details }) => {
|
|
6294
6405
|
if (!executionId) {
|
|
6295
6406
|
throw new Error("Cannot submit feedback before the response completes");
|
|
@@ -6320,14 +6431,14 @@ var PaymanChatInner = React.forwardRef(function PaymanChatInner2({
|
|
|
6320
6431
|
onMessageFeedback
|
|
6321
6432
|
]
|
|
6322
6433
|
);
|
|
6323
|
-
const onExecutionTraceClick =
|
|
6434
|
+
const onExecutionTraceClick = react.useMemo(() => {
|
|
6324
6435
|
if (!config.debug) return rawOnExecutionTraceClick;
|
|
6325
6436
|
return (data) => {
|
|
6326
6437
|
rawOnExecutionTraceClick?.(data);
|
|
6327
6438
|
if (data.executionId) setDebugTraceExecutionId(data.executionId);
|
|
6328
6439
|
};
|
|
6329
6440
|
}, [config.debug, rawOnExecutionTraceClick]);
|
|
6330
|
-
const performResetSession =
|
|
6441
|
+
const performResetSession = react.useCallback(() => {
|
|
6331
6442
|
resetToEmptyStateRef.current = true;
|
|
6332
6443
|
setEditingMessageId(null);
|
|
6333
6444
|
setIsResetSessionConfirmOpen(false);
|
|
@@ -6348,13 +6459,13 @@ var PaymanChatInner = React.forwardRef(function PaymanChatInner2({
|
|
|
6348
6459
|
resetSession,
|
|
6349
6460
|
stopRecording
|
|
6350
6461
|
]);
|
|
6351
|
-
const requestResetSession =
|
|
6462
|
+
const requestResetSession = react.useCallback(() => {
|
|
6352
6463
|
setIsResetSessionConfirmOpen(true);
|
|
6353
6464
|
}, []);
|
|
6354
|
-
const closeResetSessionConfirm =
|
|
6465
|
+
const closeResetSessionConfirm = react.useCallback(() => {
|
|
6355
6466
|
setIsResetSessionConfirmOpen(false);
|
|
6356
6467
|
}, []);
|
|
6357
|
-
|
|
6468
|
+
react.useImperativeHandle(ref, () => ({
|
|
6358
6469
|
resetSession: performResetSession,
|
|
6359
6470
|
clearMessages,
|
|
6360
6471
|
cancelStream,
|
|
@@ -6393,7 +6504,7 @@ var PaymanChatInner = React.forwardRef(function PaymanChatInner2({
|
|
|
6393
6504
|
slashCommands: slashCommandsConfig,
|
|
6394
6505
|
commandPermissions
|
|
6395
6506
|
} = config;
|
|
6396
|
-
const messageActions =
|
|
6507
|
+
const messageActions = react.useMemo(
|
|
6397
6508
|
() => ({
|
|
6398
6509
|
userMessageActions: {
|
|
6399
6510
|
copy: messageActionsConfig?.userMessageActions?.copy ?? true,
|
|
@@ -6409,18 +6520,18 @@ var PaymanChatInner = React.forwardRef(function PaymanChatInner2({
|
|
|
6409
6520
|
}),
|
|
6410
6521
|
[messageActionsConfig]
|
|
6411
6522
|
);
|
|
6412
|
-
const slashCommands =
|
|
6523
|
+
const slashCommands = react.useMemo(
|
|
6413
6524
|
() => enableSlashCommands ? filterSlashCommands(
|
|
6414
6525
|
slashCommandsConfig ?? DEFAULT_SLASH_COMMANDS,
|
|
6415
6526
|
commandPermissions
|
|
6416
6527
|
) : [],
|
|
6417
6528
|
[commandPermissions, enableSlashCommands, slashCommandsConfig]
|
|
6418
6529
|
);
|
|
6419
|
-
const isSessionParamsConfigured =
|
|
6530
|
+
const isSessionParamsConfigured = react.useMemo(() => {
|
|
6420
6531
|
if (!sessionParams) return false;
|
|
6421
6532
|
return !!(sessionParams.id?.trim() && sessionParams.name?.trim());
|
|
6422
6533
|
}, [sessionParams?.id, sessionParams?.name]);
|
|
6423
|
-
|
|
6534
|
+
react.useEffect(() => {
|
|
6424
6535
|
const wasEmpty = prevInputValueRef.current.trim() === "";
|
|
6425
6536
|
const isEmpty2 = inputValue.trim() === "";
|
|
6426
6537
|
prevInputValueRef.current = inputValue;
|
|
@@ -6487,7 +6598,7 @@ var PaymanChatInner = React.forwardRef(function PaymanChatInner2({
|
|
|
6487
6598
|
void sendMessage(text.trim(), { analysisMode: effectiveAnalysisMode });
|
|
6488
6599
|
}
|
|
6489
6600
|
};
|
|
6490
|
-
const handleVoicePress =
|
|
6601
|
+
const handleVoicePress = react.useCallback(async () => {
|
|
6491
6602
|
if (!voiceAvailable) return;
|
|
6492
6603
|
if (isRecording) {
|
|
6493
6604
|
stopRecording();
|
|
@@ -6496,7 +6607,7 @@ var PaymanChatInner = React.forwardRef(function PaymanChatInner2({
|
|
|
6496
6607
|
clearTranscript();
|
|
6497
6608
|
await startRecording();
|
|
6498
6609
|
}, [clearTranscript, isRecording, startRecording, stopRecording, voiceAvailable]);
|
|
6499
|
-
const handleEditMessageDraft =
|
|
6610
|
+
const handleEditMessageDraft = react.useCallback((messageId) => {
|
|
6500
6611
|
const targetMessage = messages.find((message) => message.id === messageId);
|
|
6501
6612
|
if (!targetMessage?.content.trim()) return;
|
|
6502
6613
|
setEditingMessageId(messageId);
|
|
@@ -6505,7 +6616,7 @@ var PaymanChatInner = React.forwardRef(function PaymanChatInner2({
|
|
|
6505
6616
|
messageListV2Ref.current?.scrollToBottom("smooth");
|
|
6506
6617
|
});
|
|
6507
6618
|
}, [messages]);
|
|
6508
|
-
const handleRetryUserMessage =
|
|
6619
|
+
const handleRetryUserMessage = react.useCallback((messageId) => {
|
|
6509
6620
|
if (isWaitingForResponse) return;
|
|
6510
6621
|
const targetMessage = messages.find(
|
|
6511
6622
|
(message) => message.id === messageId && message.role === "user"
|
|
@@ -6522,7 +6633,7 @@ var PaymanChatInner = React.forwardRef(function PaymanChatInner2({
|
|
|
6522
6633
|
});
|
|
6523
6634
|
});
|
|
6524
6635
|
}, [isWaitingForResponse, messages, sendMessage, effectiveAnalysisMode]);
|
|
6525
|
-
const handleClearEditing =
|
|
6636
|
+
const handleClearEditing = react.useCallback(() => {
|
|
6526
6637
|
setEditingMessageId(null);
|
|
6527
6638
|
}, []);
|
|
6528
6639
|
return /* @__PURE__ */ jsxRuntime.jsx(PaymanChatContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
@@ -6636,7 +6747,7 @@ var PaymanChatInner = React.forwardRef(function PaymanChatInner2({
|
|
|
6636
6747
|
onSubmitUserAction: isUserActionSupported ? submitUserAction2 : void 0,
|
|
6637
6748
|
onCancelUserAction: isUserActionSupported ? cancelUserAction2 : void 0,
|
|
6638
6749
|
onResendUserAction: isUserActionSupported ? resendUserAction2 : void 0,
|
|
6639
|
-
onExpireUserAction: isUserActionSupported ?
|
|
6750
|
+
onExpireUserAction: isUserActionSupported ? expireUserAction : void 0,
|
|
6640
6751
|
onDismissNotification: dismissNotification,
|
|
6641
6752
|
onSubmitFeedback: handleSubmitFeedback
|
|
6642
6753
|
}
|
|
@@ -6712,7 +6823,7 @@ var PaymanChatInner = React.forwardRef(function PaymanChatInner2({
|
|
|
6712
6823
|
}
|
|
6713
6824
|
) });
|
|
6714
6825
|
});
|
|
6715
|
-
var PaymanChat =
|
|
6826
|
+
var PaymanChat = react.forwardRef(
|
|
6716
6827
|
function PaymanChat2(props, ref) {
|
|
6717
6828
|
const mergedCallbacks = useSentryChatCallbacks(props.callbacks, props.config);
|
|
6718
6829
|
const chat = useChatV2(props.config, mergedCallbacks);
|