@paymanai/payman-ask-sdk 4.0.23 → 4.0.25
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +475 -428
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +218 -171
- package/dist/index.mjs.map +1 -1
- package/dist/index.native.js +199 -63
- package/dist/index.native.js.map +1 -1
- package/dist/styles.css +0 -30
- package/dist/styles.css.map +1 -1
- package/package.json +3 -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);
|
|
@@ -61,6 +60,7 @@ var chatStore = {
|
|
|
61
60
|
memoryStore.delete(key);
|
|
62
61
|
}
|
|
63
62
|
};
|
|
63
|
+
var EMPTY_USER_ACTION_STATE = { prompts: [], notifications: [] };
|
|
64
64
|
var streams = /* @__PURE__ */ new Map();
|
|
65
65
|
var activeStreamStore = {
|
|
66
66
|
has(key) {
|
|
@@ -69,7 +69,11 @@ var activeStreamStore = {
|
|
|
69
69
|
get(key) {
|
|
70
70
|
const entry = streams.get(key);
|
|
71
71
|
if (!entry) return null;
|
|
72
|
-
return {
|
|
72
|
+
return {
|
|
73
|
+
messages: entry.messages,
|
|
74
|
+
isWaiting: entry.isWaiting,
|
|
75
|
+
userActionState: entry.userActionState
|
|
76
|
+
};
|
|
73
77
|
},
|
|
74
78
|
// Called before startStream — registers the controller and initial messages
|
|
75
79
|
start(key, abortController, initialMessages) {
|
|
@@ -77,6 +81,7 @@ var activeStreamStore = {
|
|
|
77
81
|
streams.set(key, {
|
|
78
82
|
messages: initialMessages,
|
|
79
83
|
isWaiting: true,
|
|
84
|
+
userActionState: EMPTY_USER_ACTION_STATE,
|
|
80
85
|
abortController,
|
|
81
86
|
listeners: existing?.listeners ?? /* @__PURE__ */ new Set()
|
|
82
87
|
});
|
|
@@ -87,20 +92,27 @@ var activeStreamStore = {
|
|
|
87
92
|
if (!entry) return;
|
|
88
93
|
const next = typeof updater === "function" ? updater(entry.messages) : updater;
|
|
89
94
|
entry.messages = next;
|
|
90
|
-
entry.listeners.forEach((l) => l(next, entry.isWaiting));
|
|
95
|
+
entry.listeners.forEach((l) => l(next, entry.isWaiting, entry.userActionState));
|
|
91
96
|
},
|
|
92
97
|
setWaiting(key, waiting) {
|
|
93
98
|
const entry = streams.get(key);
|
|
94
99
|
if (!entry) return;
|
|
95
100
|
entry.isWaiting = waiting;
|
|
96
|
-
entry.listeners.forEach((l) => l(entry.messages, waiting));
|
|
101
|
+
entry.listeners.forEach((l) => l(entry.messages, waiting, entry.userActionState));
|
|
102
|
+
},
|
|
103
|
+
applyUserActionState(key, updater) {
|
|
104
|
+
const entry = streams.get(key);
|
|
105
|
+
if (!entry) return;
|
|
106
|
+
const next = typeof updater === "function" ? updater(entry.userActionState) : updater;
|
|
107
|
+
entry.userActionState = next;
|
|
108
|
+
entry.listeners.forEach((l) => l(entry.messages, entry.isWaiting, next));
|
|
97
109
|
},
|
|
98
110
|
// Called when stream completes — persists to chatStore and cleans up
|
|
99
111
|
complete(key) {
|
|
100
112
|
const entry = streams.get(key);
|
|
101
113
|
if (!entry) return;
|
|
102
114
|
entry.isWaiting = false;
|
|
103
|
-
entry.listeners.forEach((l) => l(entry.messages, false));
|
|
115
|
+
entry.listeners.forEach((l) => l(entry.messages, false, entry.userActionState));
|
|
104
116
|
const toSave = entry.messages.filter((m) => !m.isStreaming);
|
|
105
117
|
if (toSave.length > 0) chatStore.set(key, toSave);
|
|
106
118
|
streams.delete(key);
|
|
@@ -523,9 +535,9 @@ function processStreamEventV2(rawEvent, state) {
|
|
|
523
535
|
state.hasError = true;
|
|
524
536
|
state.errorMessage = "WORKFLOW_FAILED";
|
|
525
537
|
}
|
|
526
|
-
state.steps.forEach((
|
|
527
|
-
if (
|
|
528
|
-
|
|
538
|
+
state.steps.forEach((step2) => {
|
|
539
|
+
if (step2.status === "in_progress") {
|
|
540
|
+
step2.status = "completed";
|
|
529
541
|
}
|
|
530
542
|
});
|
|
531
543
|
state.lastEventType = eventType;
|
|
@@ -841,12 +853,12 @@ async function resolveRagImageUrls(config, content, signal) {
|
|
|
841
853
|
}
|
|
842
854
|
var FRIENDLY_ERROR_MESSAGE = "Oops, something went wrong. Please try again.";
|
|
843
855
|
function useStreamManagerV2(config, callbacks, setMessages, setIsWaitingForResponse) {
|
|
844
|
-
const abortControllerRef =
|
|
845
|
-
const configRef =
|
|
856
|
+
const abortControllerRef = react.useRef(null);
|
|
857
|
+
const configRef = react.useRef(config);
|
|
846
858
|
configRef.current = config;
|
|
847
|
-
const callbacksRef =
|
|
859
|
+
const callbacksRef = react.useRef(callbacks);
|
|
848
860
|
callbacksRef.current = callbacks;
|
|
849
|
-
const startStream =
|
|
861
|
+
const startStream = react.useCallback(
|
|
850
862
|
async (userMessage, streamingId, sessionId, externalAbortController, options) => {
|
|
851
863
|
abortControllerRef.current?.abort();
|
|
852
864
|
const abortController = externalAbortController ?? new AbortController();
|
|
@@ -940,11 +952,11 @@ function useStreamManagerV2(config, callbacks, setMessages, setIsWaitingForRespo
|
|
|
940
952
|
errorDetails: isAborted ? void 0 : error.message,
|
|
941
953
|
content: isAborted ? state.finalResponse || "" : state.finalResponse || FRIENDLY_ERROR_MESSAGE,
|
|
942
954
|
currentMessage: isAborted ? "Thinking..." : void 0,
|
|
943
|
-
steps: [...state.steps].map((
|
|
944
|
-
if (
|
|
945
|
-
return { ...
|
|
955
|
+
steps: [...state.steps].map((step2) => {
|
|
956
|
+
if (step2.status === "in_progress" && isAborted) {
|
|
957
|
+
return { ...step2, status: "pending" };
|
|
946
958
|
}
|
|
947
|
-
return
|
|
959
|
+
return step2;
|
|
948
960
|
}),
|
|
949
961
|
currentExecutingStepId: void 0
|
|
950
962
|
} : msg
|
|
@@ -1030,11 +1042,11 @@ function useStreamManagerV2(config, callbacks, setMessages, setIsWaitingForRespo
|
|
|
1030
1042
|
isCancelled: isAborted,
|
|
1031
1043
|
errorDetails: isAborted ? void 0 : error.message,
|
|
1032
1044
|
content: isAborted ? state.finalResponse || "" : state.finalResponse || FRIENDLY_ERROR_MESSAGE,
|
|
1033
|
-
steps: [...state.steps].map((
|
|
1034
|
-
if (
|
|
1035
|
-
return { ...
|
|
1045
|
+
steps: [...state.steps].map((step2) => {
|
|
1046
|
+
if (step2.status === "in_progress" && isAborted) {
|
|
1047
|
+
return { ...step2, status: "pending" };
|
|
1036
1048
|
}
|
|
1037
|
-
return
|
|
1049
|
+
return step2;
|
|
1038
1050
|
}),
|
|
1039
1051
|
currentExecutingStepId: void 0
|
|
1040
1052
|
} : msg
|
|
@@ -1045,7 +1057,7 @@ function useStreamManagerV2(config, callbacks, setMessages, setIsWaitingForRespo
|
|
|
1045
1057
|
},
|
|
1046
1058
|
[setMessages, setIsWaitingForResponse]
|
|
1047
1059
|
);
|
|
1048
|
-
const cancelStream =
|
|
1060
|
+
const cancelStream = react.useCallback(() => {
|
|
1049
1061
|
abortControllerRef.current?.abort();
|
|
1050
1062
|
}, []);
|
|
1051
1063
|
return {
|
|
@@ -1055,11 +1067,11 @@ function useStreamManagerV2(config, callbacks, setMessages, setIsWaitingForRespo
|
|
|
1055
1067
|
};
|
|
1056
1068
|
}
|
|
1057
1069
|
function createCancelledMessageUpdate(steps, currentMessage) {
|
|
1058
|
-
const updatedSteps = steps.map((
|
|
1059
|
-
if (
|
|
1060
|
-
return { ...
|
|
1070
|
+
const updatedSteps = steps.map((step2) => {
|
|
1071
|
+
if (step2.status === "in_progress") {
|
|
1072
|
+
return { ...step2, status: "pending" };
|
|
1061
1073
|
}
|
|
1062
|
-
return
|
|
1074
|
+
return step2;
|
|
1063
1075
|
});
|
|
1064
1076
|
return {
|
|
1065
1077
|
isStreaming: false,
|
|
@@ -1108,12 +1120,31 @@ async function resendUserAction(config, userActionId) {
|
|
|
1108
1120
|
async function expireUserAction(config, userActionId) {
|
|
1109
1121
|
return sendUserActionRequest(config, userActionId, "expired");
|
|
1110
1122
|
}
|
|
1111
|
-
|
|
1123
|
+
function resolveUserActionExpiresAt(req, existing) {
|
|
1124
|
+
if (typeof req.expirySeconds !== "number" || req.expirySeconds <= 0) {
|
|
1125
|
+
return void 0;
|
|
1126
|
+
}
|
|
1127
|
+
if (existing?.expiresAt && existing.userActionId === req.userActionId) {
|
|
1128
|
+
return existing.expiresAt;
|
|
1129
|
+
}
|
|
1130
|
+
return Date.now() + Math.floor(req.expirySeconds) * 1e3;
|
|
1131
|
+
}
|
|
1132
|
+
function getUserActionSecondsLeft(prompt) {
|
|
1133
|
+
if (typeof prompt.expiresAt === "number" && prompt.expiresAt > 0) {
|
|
1134
|
+
return Math.max(0, Math.ceil((prompt.expiresAt - Date.now()) / 1e3));
|
|
1135
|
+
}
|
|
1136
|
+
if (typeof prompt.expirySeconds === "number" && prompt.expirySeconds > 0) {
|
|
1137
|
+
return Math.floor(prompt.expirySeconds);
|
|
1138
|
+
}
|
|
1139
|
+
return void 0;
|
|
1140
|
+
}
|
|
1141
|
+
var EMPTY_USER_ACTION_STATE2 = { prompts: [], notifications: [] };
|
|
1112
1142
|
function upsertPrompt(prompts, req) {
|
|
1113
|
-
const active = { ...req, status: "pending" };
|
|
1114
1143
|
const idx = prompts.findIndex(
|
|
1115
1144
|
(p) => req.toolCallId ? p.toolCallId === req.toolCallId : p.userActionId === req.userActionId
|
|
1116
1145
|
);
|
|
1146
|
+
const expiresAt = resolveUserActionExpiresAt(req, idx >= 0 ? prompts[idx] : void 0);
|
|
1147
|
+
const active = { ...req, status: "pending", expiresAt };
|
|
1117
1148
|
if (idx >= 0) {
|
|
1118
1149
|
const next = prompts.slice();
|
|
1119
1150
|
next[idx] = active;
|
|
@@ -1137,24 +1168,24 @@ function getSessionIdFromMessages(messages) {
|
|
|
1137
1168
|
return messages.find((message) => message.sessionId)?.sessionId;
|
|
1138
1169
|
}
|
|
1139
1170
|
function useChatV2(config, callbacks = {}) {
|
|
1140
|
-
const [messages, setMessages] =
|
|
1141
|
-
const [isWaitingForResponse, setIsWaitingForResponse] =
|
|
1171
|
+
const [messages, setMessages] = react.useState(() => getStoredOrInitialMessages(config));
|
|
1172
|
+
const [isWaitingForResponse, setIsWaitingForResponse] = react.useState(() => {
|
|
1142
1173
|
if (!config.userId) return false;
|
|
1143
1174
|
return activeStreamStore.get(config.userId)?.isWaiting ?? false;
|
|
1144
1175
|
});
|
|
1145
|
-
const sessionIdRef =
|
|
1176
|
+
const sessionIdRef = react.useRef(
|
|
1146
1177
|
getSessionIdFromMessages(getStoredOrInitialMessages(config)) ?? config.initialSessionId ?? void 0
|
|
1147
1178
|
);
|
|
1148
|
-
const prevUserIdRef =
|
|
1149
|
-
const streamUserIdRef =
|
|
1150
|
-
const subscriptionPrevUserIdRef =
|
|
1151
|
-
const callbacksRef =
|
|
1179
|
+
const prevUserIdRef = react.useRef(config.userId);
|
|
1180
|
+
const streamUserIdRef = react.useRef(void 0);
|
|
1181
|
+
const subscriptionPrevUserIdRef = react.useRef(config.userId);
|
|
1182
|
+
const callbacksRef = react.useRef(callbacks);
|
|
1152
1183
|
callbacksRef.current = callbacks;
|
|
1153
|
-
const configRef =
|
|
1184
|
+
const configRef = react.useRef(config);
|
|
1154
1185
|
configRef.current = config;
|
|
1155
|
-
const messagesRef =
|
|
1186
|
+
const messagesRef = react.useRef(messages);
|
|
1156
1187
|
messagesRef.current = messages;
|
|
1157
|
-
const storeAwareSetMessages =
|
|
1188
|
+
const storeAwareSetMessages = react.useCallback(
|
|
1158
1189
|
(updater) => {
|
|
1159
1190
|
const streamUserId = streamUserIdRef.current;
|
|
1160
1191
|
const currentUserId = configRef.current.userId;
|
|
@@ -1169,7 +1200,7 @@ function useChatV2(config, callbacks = {}) {
|
|
|
1169
1200
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
1170
1201
|
[]
|
|
1171
1202
|
);
|
|
1172
|
-
const storeAwareSetIsWaiting =
|
|
1203
|
+
const storeAwareSetIsWaiting = react.useCallback(
|
|
1173
1204
|
(waiting) => {
|
|
1174
1205
|
const streamUserId = streamUserIdRef.current;
|
|
1175
1206
|
const currentUserId = configRef.current.userId;
|
|
@@ -1184,8 +1215,29 @@ function useChatV2(config, callbacks = {}) {
|
|
|
1184
1215
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
1185
1216
|
[]
|
|
1186
1217
|
);
|
|
1187
|
-
const [userActionState, setUserActionState] =
|
|
1188
|
-
|
|
1218
|
+
const [userActionState, setUserActionState] = react.useState(() => {
|
|
1219
|
+
if (!config.userId) return EMPTY_USER_ACTION_STATE2;
|
|
1220
|
+
return activeStreamStore.get(config.userId)?.userActionState ?? EMPTY_USER_ACTION_STATE2;
|
|
1221
|
+
});
|
|
1222
|
+
const storeAwareSetUserActionState = react.useCallback(
|
|
1223
|
+
(updater) => {
|
|
1224
|
+
const streamUserId = streamUserIdRef.current;
|
|
1225
|
+
const currentUserId = configRef.current.userId;
|
|
1226
|
+
const storeKey = streamUserId ?? currentUserId;
|
|
1227
|
+
if (storeKey && activeStreamStore.has(storeKey)) {
|
|
1228
|
+
activeStreamStore.applyUserActionState(
|
|
1229
|
+
storeKey,
|
|
1230
|
+
updater
|
|
1231
|
+
);
|
|
1232
|
+
}
|
|
1233
|
+
if (!streamUserId || streamUserId === currentUserId) {
|
|
1234
|
+
setUserActionState(updater);
|
|
1235
|
+
}
|
|
1236
|
+
},
|
|
1237
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
1238
|
+
[]
|
|
1239
|
+
);
|
|
1240
|
+
const wrappedCallbacks = react.useMemo(() => ({
|
|
1189
1241
|
...callbacksRef.current,
|
|
1190
1242
|
onMessageSent: (message) => callbacksRef.current.onMessageSent?.(message),
|
|
1191
1243
|
onStreamStart: () => callbacksRef.current.onStreamStart?.(),
|
|
@@ -1194,14 +1246,14 @@ function useChatV2(config, callbacks = {}) {
|
|
|
1194
1246
|
onExecutionTraceClick: (data) => callbacksRef.current.onExecutionTraceClick?.(data),
|
|
1195
1247
|
onSessionIdChange: (sessionId) => callbacksRef.current.onSessionIdChange?.(sessionId),
|
|
1196
1248
|
onUserActionRequired: (request) => {
|
|
1197
|
-
|
|
1249
|
+
storeAwareSetUserActionState((prev) => ({
|
|
1198
1250
|
...prev,
|
|
1199
1251
|
prompts: upsertPrompt(prev.prompts, request)
|
|
1200
1252
|
}));
|
|
1201
1253
|
callbacksRef.current.onUserActionRequired?.(request);
|
|
1202
1254
|
},
|
|
1203
1255
|
onUserNotification: (notification) => {
|
|
1204
|
-
|
|
1256
|
+
storeAwareSetUserActionState(
|
|
1205
1257
|
(prev) => prev.notifications.some((n) => n.id === notification.id) ? prev : { ...prev, notifications: [...prev.notifications, notification] }
|
|
1206
1258
|
);
|
|
1207
1259
|
callbacksRef.current.onUserNotification?.(notification);
|
|
@@ -1214,7 +1266,7 @@ function useChatV2(config, callbacks = {}) {
|
|
|
1214
1266
|
storeAwareSetMessages,
|
|
1215
1267
|
storeAwareSetIsWaiting
|
|
1216
1268
|
);
|
|
1217
|
-
const sendMessage =
|
|
1269
|
+
const sendMessage = react.useCallback(
|
|
1218
1270
|
async (userMessage, options) => {
|
|
1219
1271
|
if (!userMessage.trim()) return;
|
|
1220
1272
|
if (!sessionIdRef.current && configRef.current.autoGenerateSessionId !== false) {
|
|
@@ -1274,16 +1326,16 @@ function useChatV2(config, callbacks = {}) {
|
|
|
1274
1326
|
},
|
|
1275
1327
|
[startStream]
|
|
1276
1328
|
);
|
|
1277
|
-
const clearMessages =
|
|
1329
|
+
const clearMessages = react.useCallback(() => {
|
|
1278
1330
|
if (configRef.current.userId) {
|
|
1279
1331
|
chatStore.delete(configRef.current.userId);
|
|
1280
1332
|
}
|
|
1281
1333
|
setMessages([]);
|
|
1282
1334
|
}, []);
|
|
1283
|
-
const prependMessages =
|
|
1335
|
+
const prependMessages = react.useCallback((msgs) => {
|
|
1284
1336
|
setMessages((prev) => [...msgs, ...prev]);
|
|
1285
1337
|
}, []);
|
|
1286
|
-
const cancelStream =
|
|
1338
|
+
const cancelStream = react.useCallback(() => {
|
|
1287
1339
|
const streamUserId = streamUserIdRef.current ?? configRef.current.userId;
|
|
1288
1340
|
if (streamUserId) {
|
|
1289
1341
|
activeStreamStore.abort(streamUserId);
|
|
@@ -1291,7 +1343,7 @@ function useChatV2(config, callbacks = {}) {
|
|
|
1291
1343
|
streamUserIdRef.current = void 0;
|
|
1292
1344
|
cancelStreamManager();
|
|
1293
1345
|
setIsWaitingForResponse(false);
|
|
1294
|
-
|
|
1346
|
+
storeAwareSetUserActionState((prev) => ({ ...prev, prompts: [] }));
|
|
1295
1347
|
setMessages(
|
|
1296
1348
|
(prev) => prev.map((msg) => {
|
|
1297
1349
|
if (msg.isStreaming) {
|
|
@@ -1306,8 +1358,8 @@ function useChatV2(config, callbacks = {}) {
|
|
|
1306
1358
|
return msg;
|
|
1307
1359
|
})
|
|
1308
1360
|
);
|
|
1309
|
-
}, [cancelStreamManager]);
|
|
1310
|
-
const resetSession =
|
|
1361
|
+
}, [cancelStreamManager, storeAwareSetUserActionState]);
|
|
1362
|
+
const resetSession = react.useCallback(() => {
|
|
1311
1363
|
const streamUserId = streamUserIdRef.current ?? configRef.current.userId;
|
|
1312
1364
|
if (streamUserId) {
|
|
1313
1365
|
activeStreamStore.abort(streamUserId);
|
|
@@ -1320,32 +1372,32 @@ function useChatV2(config, callbacks = {}) {
|
|
|
1320
1372
|
sessionIdRef.current = void 0;
|
|
1321
1373
|
abortControllerRef.current?.abort();
|
|
1322
1374
|
setIsWaitingForResponse(false);
|
|
1323
|
-
|
|
1375
|
+
storeAwareSetUserActionState(EMPTY_USER_ACTION_STATE2);
|
|
1324
1376
|
}, []);
|
|
1325
|
-
const getSessionId =
|
|
1377
|
+
const getSessionId = react.useCallback(() => {
|
|
1326
1378
|
return sessionIdRef.current;
|
|
1327
1379
|
}, []);
|
|
1328
|
-
const getMessages =
|
|
1380
|
+
const getMessages = react.useCallback(() => {
|
|
1329
1381
|
return messages;
|
|
1330
1382
|
}, [messages]);
|
|
1331
|
-
const setPromptStatus =
|
|
1383
|
+
const setPromptStatus = react.useCallback(
|
|
1332
1384
|
(userActionId, status) => {
|
|
1333
|
-
|
|
1385
|
+
storeAwareSetUserActionState((prev) => ({
|
|
1334
1386
|
...prev,
|
|
1335
1387
|
prompts: prev.prompts.map(
|
|
1336
1388
|
(p) => p.userActionId === userActionId ? { ...p, status } : p
|
|
1337
1389
|
)
|
|
1338
1390
|
}));
|
|
1339
1391
|
},
|
|
1340
|
-
[]
|
|
1392
|
+
[storeAwareSetUserActionState]
|
|
1341
1393
|
);
|
|
1342
|
-
const removePrompt =
|
|
1343
|
-
|
|
1394
|
+
const removePrompt = react.useCallback((userActionId) => {
|
|
1395
|
+
storeAwareSetUserActionState((prev) => ({
|
|
1344
1396
|
...prev,
|
|
1345
1397
|
prompts: prev.prompts.filter((p) => p.userActionId !== userActionId)
|
|
1346
1398
|
}));
|
|
1347
|
-
}, []);
|
|
1348
|
-
const submitUserAction2 =
|
|
1399
|
+
}, [storeAwareSetUserActionState]);
|
|
1400
|
+
const submitUserAction2 = react.useCallback(
|
|
1349
1401
|
async (userActionId, content) => {
|
|
1350
1402
|
setPromptStatus(userActionId, "submitting");
|
|
1351
1403
|
try {
|
|
@@ -1363,7 +1415,7 @@ function useChatV2(config, callbacks = {}) {
|
|
|
1363
1415
|
},
|
|
1364
1416
|
[removePrompt, setPromptStatus]
|
|
1365
1417
|
);
|
|
1366
|
-
const cancelUserAction2 =
|
|
1418
|
+
const cancelUserAction2 = react.useCallback(
|
|
1367
1419
|
async (userActionId) => {
|
|
1368
1420
|
setPromptStatus(userActionId, "submitting");
|
|
1369
1421
|
try {
|
|
@@ -1381,7 +1433,7 @@ function useChatV2(config, callbacks = {}) {
|
|
|
1381
1433
|
},
|
|
1382
1434
|
[removePrompt, setPromptStatus]
|
|
1383
1435
|
);
|
|
1384
|
-
const resendUserAction2 =
|
|
1436
|
+
const resendUserAction2 = react.useCallback(
|
|
1385
1437
|
async (userActionId) => {
|
|
1386
1438
|
setPromptStatus(userActionId, "submitting");
|
|
1387
1439
|
try {
|
|
@@ -1399,7 +1451,7 @@ function useChatV2(config, callbacks = {}) {
|
|
|
1399
1451
|
},
|
|
1400
1452
|
[setPromptStatus]
|
|
1401
1453
|
);
|
|
1402
|
-
const expireUserAction2 =
|
|
1454
|
+
const expireUserAction2 = react.useCallback(
|
|
1403
1455
|
async (userActionId) => {
|
|
1404
1456
|
setPromptStatus(userActionId, "expired");
|
|
1405
1457
|
try {
|
|
@@ -1412,13 +1464,13 @@ function useChatV2(config, callbacks = {}) {
|
|
|
1412
1464
|
},
|
|
1413
1465
|
[setPromptStatus]
|
|
1414
1466
|
);
|
|
1415
|
-
const dismissNotification =
|
|
1416
|
-
|
|
1467
|
+
const dismissNotification = react.useCallback((id) => {
|
|
1468
|
+
storeAwareSetUserActionState((prev) => ({
|
|
1417
1469
|
...prev,
|
|
1418
1470
|
notifications: prev.notifications.filter((n) => n.id !== id)
|
|
1419
1471
|
}));
|
|
1420
|
-
}, []);
|
|
1421
|
-
|
|
1472
|
+
}, [storeAwareSetUserActionState]);
|
|
1473
|
+
react.useEffect(() => {
|
|
1422
1474
|
const prevSubscriptionUserId = subscriptionPrevUserIdRef.current;
|
|
1423
1475
|
subscriptionPrevUserIdRef.current = config.userId;
|
|
1424
1476
|
const { userId } = config;
|
|
@@ -1426,18 +1478,21 @@ function useChatV2(config, callbacks = {}) {
|
|
|
1426
1478
|
if (prevSubscriptionUserId && prevSubscriptionUserId !== userId && streamUserIdRef.current === prevSubscriptionUserId && !activeStreamStore.has(prevSubscriptionUserId) && activeStreamStore.has(userId)) {
|
|
1427
1479
|
streamUserIdRef.current = userId;
|
|
1428
1480
|
}
|
|
1429
|
-
const unsubscribe = activeStreamStore.subscribe(userId, (msgs, isWaiting) => {
|
|
1481
|
+
const unsubscribe = activeStreamStore.subscribe(userId, (msgs, isWaiting, actions) => {
|
|
1430
1482
|
setMessages(msgs);
|
|
1431
1483
|
setIsWaitingForResponse(isWaiting);
|
|
1484
|
+
setUserActionState(actions);
|
|
1432
1485
|
});
|
|
1433
1486
|
const active = activeStreamStore.get(userId);
|
|
1434
1487
|
if (active) {
|
|
1488
|
+
streamUserIdRef.current = userId;
|
|
1435
1489
|
setMessages(active.messages);
|
|
1436
1490
|
setIsWaitingForResponse(active.isWaiting);
|
|
1491
|
+
setUserActionState(active.userActionState);
|
|
1437
1492
|
}
|
|
1438
1493
|
return unsubscribe;
|
|
1439
1494
|
}, [config.userId]);
|
|
1440
|
-
|
|
1495
|
+
react.useEffect(() => {
|
|
1441
1496
|
if (!config.userId) return;
|
|
1442
1497
|
if (prevUserIdRef.current !== config.userId) return;
|
|
1443
1498
|
const toSave = messages.filter((m) => !m.isStreaming);
|
|
@@ -1445,14 +1500,14 @@ function useChatV2(config, callbacks = {}) {
|
|
|
1445
1500
|
chatStore.set(config.userId, toSave);
|
|
1446
1501
|
}
|
|
1447
1502
|
}, [messages, config.userId]);
|
|
1448
|
-
|
|
1503
|
+
react.useEffect(() => {
|
|
1449
1504
|
if (!config.userId || activeStreamStore.has(config.userId)) return;
|
|
1450
1505
|
if (!config.initialMessages?.length || messagesRef.current.length > 0) return;
|
|
1451
1506
|
chatStore.set(config.userId, config.initialMessages);
|
|
1452
1507
|
setMessages(config.initialMessages);
|
|
1453
1508
|
sessionIdRef.current = getSessionIdFromMessages(config.initialMessages) ?? config.initialSessionId;
|
|
1454
1509
|
}, [config.initialMessages, config.initialSessionId, config.userId]);
|
|
1455
|
-
|
|
1510
|
+
react.useEffect(() => {
|
|
1456
1511
|
const prevUserId = prevUserIdRef.current;
|
|
1457
1512
|
prevUserIdRef.current = config.userId;
|
|
1458
1513
|
if (prevUserId === config.userId) return;
|
|
@@ -1461,12 +1516,14 @@ function useChatV2(config, callbacks = {}) {
|
|
|
1461
1516
|
setMessages([]);
|
|
1462
1517
|
sessionIdRef.current = void 0;
|
|
1463
1518
|
setIsWaitingForResponse(false);
|
|
1464
|
-
setUserActionState(
|
|
1519
|
+
setUserActionState(EMPTY_USER_ACTION_STATE2);
|
|
1465
1520
|
} else if (config.userId) {
|
|
1466
1521
|
const active = activeStreamStore.get(config.userId);
|
|
1467
1522
|
if (active) {
|
|
1523
|
+
streamUserIdRef.current = config.userId;
|
|
1468
1524
|
setMessages(active.messages);
|
|
1469
1525
|
setIsWaitingForResponse(active.isWaiting);
|
|
1526
|
+
setUserActionState(active.userActionState);
|
|
1470
1527
|
sessionIdRef.current = getSessionIdFromMessages(active.messages) ?? config.initialSessionId;
|
|
1471
1528
|
return;
|
|
1472
1529
|
}
|
|
@@ -1500,12 +1557,12 @@ function getSpeechRecognition() {
|
|
|
1500
1557
|
return window.SpeechRecognition || window.webkitSpeechRecognition || null;
|
|
1501
1558
|
}
|
|
1502
1559
|
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 =
|
|
1560
|
+
const [voiceState, setVoiceState] = react.useState("idle");
|
|
1561
|
+
const [transcribedText, setTranscribedText] = react.useState("");
|
|
1562
|
+
const [isAvailable, setIsAvailable] = react.useState(false);
|
|
1563
|
+
const [isRecording, setIsRecording] = react.useState(false);
|
|
1564
|
+
const recognitionRef = react.useRef(null);
|
|
1565
|
+
const autoStopTimerRef = react.useRef(null);
|
|
1509
1566
|
const {
|
|
1510
1567
|
lang = "en-US",
|
|
1511
1568
|
interimResults = true,
|
|
@@ -1514,14 +1571,14 @@ function useVoice(config = {}, callbacks = {}) {
|
|
|
1514
1571
|
autoStopAfterSilence
|
|
1515
1572
|
} = config;
|
|
1516
1573
|
const { onStart, onEnd, onResult, onError, onStateChange } = callbacks;
|
|
1517
|
-
|
|
1574
|
+
react.useEffect(() => {
|
|
1518
1575
|
const SpeechRecognitionAPI = getSpeechRecognition();
|
|
1519
1576
|
setIsAvailable(SpeechRecognitionAPI !== null);
|
|
1520
1577
|
}, []);
|
|
1521
|
-
|
|
1578
|
+
react.useEffect(() => {
|
|
1522
1579
|
onStateChange?.(voiceState);
|
|
1523
1580
|
}, [voiceState, onStateChange]);
|
|
1524
|
-
const requestPermissions =
|
|
1581
|
+
const requestPermissions = react.useCallback(async () => {
|
|
1525
1582
|
try {
|
|
1526
1583
|
const result = await navigator.mediaDevices.getUserMedia({
|
|
1527
1584
|
audio: true
|
|
@@ -1538,7 +1595,7 @@ function useVoice(config = {}, callbacks = {}) {
|
|
|
1538
1595
|
};
|
|
1539
1596
|
}
|
|
1540
1597
|
}, []);
|
|
1541
|
-
const getPermissions =
|
|
1598
|
+
const getPermissions = react.useCallback(async () => {
|
|
1542
1599
|
if (typeof navigator === "undefined" || !navigator.permissions) {
|
|
1543
1600
|
return {
|
|
1544
1601
|
granted: false,
|
|
@@ -1560,13 +1617,13 @@ function useVoice(config = {}, callbacks = {}) {
|
|
|
1560
1617
|
};
|
|
1561
1618
|
}
|
|
1562
1619
|
}, []);
|
|
1563
|
-
const clearAutoStopTimer =
|
|
1620
|
+
const clearAutoStopTimer = react.useCallback(() => {
|
|
1564
1621
|
if (autoStopTimerRef.current) {
|
|
1565
1622
|
clearTimeout(autoStopTimerRef.current);
|
|
1566
1623
|
autoStopTimerRef.current = null;
|
|
1567
1624
|
}
|
|
1568
1625
|
}, []);
|
|
1569
|
-
const resetAutoStopTimer =
|
|
1626
|
+
const resetAutoStopTimer = react.useCallback(() => {
|
|
1570
1627
|
clearAutoStopTimer();
|
|
1571
1628
|
if (autoStopAfterSilence && autoStopAfterSilence > 0) {
|
|
1572
1629
|
autoStopTimerRef.current = setTimeout(() => {
|
|
@@ -1576,7 +1633,7 @@ function useVoice(config = {}, callbacks = {}) {
|
|
|
1576
1633
|
}, autoStopAfterSilence);
|
|
1577
1634
|
}
|
|
1578
1635
|
}, [autoStopAfterSilence, clearAutoStopTimer, isRecording]);
|
|
1579
|
-
const stopRecording =
|
|
1636
|
+
const stopRecording = react.useCallback(() => {
|
|
1580
1637
|
if (recognitionRef.current) {
|
|
1581
1638
|
try {
|
|
1582
1639
|
recognitionRef.current.stop();
|
|
@@ -1588,7 +1645,7 @@ function useVoice(config = {}, callbacks = {}) {
|
|
|
1588
1645
|
setIsRecording(false);
|
|
1589
1646
|
setVoiceState("idle");
|
|
1590
1647
|
}, [clearAutoStopTimer]);
|
|
1591
|
-
const startRecording =
|
|
1648
|
+
const startRecording = react.useCallback(async () => {
|
|
1592
1649
|
const SpeechRecognitionAPI = getSpeechRecognition();
|
|
1593
1650
|
if (!SpeechRecognitionAPI) {
|
|
1594
1651
|
onError?.("Speech recognition not supported in this browser");
|
|
@@ -1678,15 +1735,15 @@ function useVoice(config = {}, callbacks = {}) {
|
|
|
1678
1735
|
resetAutoStopTimer,
|
|
1679
1736
|
clearAutoStopTimer
|
|
1680
1737
|
]);
|
|
1681
|
-
const clearTranscript =
|
|
1738
|
+
const clearTranscript = react.useCallback(() => {
|
|
1682
1739
|
setTranscribedText("");
|
|
1683
1740
|
}, []);
|
|
1684
|
-
const reset =
|
|
1741
|
+
const reset = react.useCallback(() => {
|
|
1685
1742
|
stopRecording();
|
|
1686
1743
|
setTranscribedText("");
|
|
1687
1744
|
setVoiceState("idle");
|
|
1688
1745
|
}, [stopRecording]);
|
|
1689
|
-
|
|
1746
|
+
react.useEffect(() => {
|
|
1690
1747
|
return () => {
|
|
1691
1748
|
if (recognitionRef.current) {
|
|
1692
1749
|
try {
|
|
@@ -1826,9 +1883,9 @@ function buildContent(schema, values) {
|
|
|
1826
1883
|
}
|
|
1827
1884
|
return content;
|
|
1828
1885
|
}
|
|
1829
|
-
var PaymanChatContext =
|
|
1886
|
+
var PaymanChatContext = react.createContext(void 0);
|
|
1830
1887
|
function usePaymanChat() {
|
|
1831
|
-
const context =
|
|
1888
|
+
const context = react.useContext(PaymanChatContext);
|
|
1832
1889
|
if (!context) {
|
|
1833
1890
|
throw new Error("usePaymanChat must be used within a PaymanChat component");
|
|
1834
1891
|
}
|
|
@@ -2086,8 +2143,8 @@ function ImageLightbox({
|
|
|
2086
2143
|
alt = "",
|
|
2087
2144
|
onClose
|
|
2088
2145
|
}) {
|
|
2089
|
-
const [isMounted, setIsMounted] =
|
|
2090
|
-
const [isImageLoaded, setIsImageLoaded] =
|
|
2146
|
+
const [isMounted, setIsMounted] = react.useState(false);
|
|
2147
|
+
const [isImageLoaded, setIsImageLoaded] = react.useState(false);
|
|
2091
2148
|
const overlayStyle = {
|
|
2092
2149
|
position: "fixed",
|
|
2093
2150
|
inset: 0,
|
|
@@ -2108,14 +2165,14 @@ function ImageLightbox({
|
|
|
2108
2165
|
justifyContent: "center",
|
|
2109
2166
|
overflow: "hidden"
|
|
2110
2167
|
};
|
|
2111
|
-
|
|
2168
|
+
react.useEffect(() => {
|
|
2112
2169
|
setIsMounted(true);
|
|
2113
2170
|
return () => setIsMounted(false);
|
|
2114
2171
|
}, []);
|
|
2115
|
-
|
|
2172
|
+
react.useEffect(() => {
|
|
2116
2173
|
setIsImageLoaded(false);
|
|
2117
2174
|
}, [src]);
|
|
2118
|
-
|
|
2175
|
+
react.useEffect(() => {
|
|
2119
2176
|
if (typeof document === "undefined") return;
|
|
2120
2177
|
const previousOverflow = document.body.style.overflow;
|
|
2121
2178
|
document.body.style.overflow = "hidden";
|
|
@@ -2123,7 +2180,7 @@ function ImageLightbox({
|
|
|
2123
2180
|
document.body.style.overflow = previousOverflow;
|
|
2124
2181
|
};
|
|
2125
2182
|
}, []);
|
|
2126
|
-
|
|
2183
|
+
react.useEffect(() => {
|
|
2127
2184
|
if (typeof document === "undefined") return;
|
|
2128
2185
|
const handleKeyDown = (event) => {
|
|
2129
2186
|
if (event.key === "Escape") {
|
|
@@ -2219,15 +2276,15 @@ function MarkdownImage({
|
|
|
2219
2276
|
maxHeight: "18rem",
|
|
2220
2277
|
objectFit: "contain"
|
|
2221
2278
|
};
|
|
2222
|
-
const [isLoaded, setIsLoaded] =
|
|
2223
|
-
const [hasError, setHasError] =
|
|
2224
|
-
const [isLightboxOpen, setIsLightboxOpen] =
|
|
2225
|
-
const isUnresolvedRagImage =
|
|
2279
|
+
const [isLoaded, setIsLoaded] = react.useState(false);
|
|
2280
|
+
const [hasError, setHasError] = react.useState(false);
|
|
2281
|
+
const [isLightboxOpen, setIsLightboxOpen] = react.useState(false);
|
|
2282
|
+
const isUnresolvedRagImage = react.useMemo(
|
|
2226
2283
|
() => src ? isUnresolvedRagImageSource(src) : false,
|
|
2227
2284
|
[src]
|
|
2228
2285
|
);
|
|
2229
2286
|
const isResolvingRagImage = isResolving && isUnresolvedRagImage;
|
|
2230
|
-
|
|
2287
|
+
react.useEffect(() => {
|
|
2231
2288
|
setIsLoaded(false);
|
|
2232
2289
|
setHasError(false);
|
|
2233
2290
|
setIsLightboxOpen(false);
|
|
@@ -2296,7 +2353,7 @@ function createMarkdownComponents(options = {}) {
|
|
|
2296
2353
|
},
|
|
2297
2354
|
pre: ({ children }) => /* @__PURE__ */ jsxRuntime.jsx("pre", { className: "my-2 max-w-full overflow-x-auto rounded-lg", children }),
|
|
2298
2355
|
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 }),
|
|
2356
|
+
ol: ({ children, start }) => /* @__PURE__ */ jsxRuntime.jsx("ol", { className: "mb-3 ml-4 list-decimal space-y-1 text-sm", start, children }),
|
|
2300
2357
|
li: ({ children }) => /* @__PURE__ */ jsxRuntime.jsx("li", { className: "text-sm leading-relaxed", children }),
|
|
2301
2358
|
h1: ({ children }) => /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "mt-4 mb-2 text-lg font-semibold first:mt-0", children }),
|
|
2302
2359
|
h2: ({ children }) => /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "mt-3 mb-2 text-base font-semibold first:mt-0", children }),
|
|
@@ -2354,9 +2411,9 @@ function AgentMessage({
|
|
|
2354
2411
|
const hasTraceData = !!(message.tracingData || message.executionId) && !isStreaming;
|
|
2355
2412
|
const isCancelled = message.isCancelled ?? false;
|
|
2356
2413
|
const currentExecutingStepId = message.currentExecutingStepId;
|
|
2357
|
-
const [isStepsExpanded, setIsStepsExpanded] =
|
|
2358
|
-
const wasStreamingRef =
|
|
2359
|
-
|
|
2414
|
+
const [isStepsExpanded, setIsStepsExpanded] = react.useState(false);
|
|
2415
|
+
const wasStreamingRef = react.useRef(isStreaming);
|
|
2416
|
+
react.useEffect(() => {
|
|
2360
2417
|
if (isStreaming && hasSteps) {
|
|
2361
2418
|
setIsStepsExpanded(true);
|
|
2362
2419
|
}
|
|
@@ -2365,7 +2422,7 @@ function AgentMessage({
|
|
|
2365
2422
|
}
|
|
2366
2423
|
wasStreamingRef.current = isStreaming;
|
|
2367
2424
|
}, [isStreaming, hasSteps]);
|
|
2368
|
-
const totalElapsedMs = hasSteps ? message.steps.reduce((sum,
|
|
2425
|
+
const totalElapsedMs = hasSteps ? message.steps.reduce((sum, step2) => sum + (step2.elapsedMs || 0), 0) : 0;
|
|
2369
2426
|
const currentMessage = message.currentMessage;
|
|
2370
2427
|
const rawContent = message.streamingContent || message.content || "";
|
|
2371
2428
|
const content = rawContent.replace(/\\n/g, "\n");
|
|
@@ -2373,13 +2430,13 @@ function AgentMessage({
|
|
|
2373
2430
|
const completedWithNoContent = !isStreaming && !isCancelled && content.length === 0 && (message.streamProgress === "completed" || message.streamProgress === "error");
|
|
2374
2431
|
const conflictErrorMessage = getConflictErrorMessage(message.errorDetails);
|
|
2375
2432
|
const isError = !!conflictErrorMessage || (isFriendlyWorkflowError(message.errorDetails) || looksLikeRawError(content)) && !hasMeaningfulContent || completedWithNoContent;
|
|
2376
|
-
const currentStep =
|
|
2433
|
+
const currentStep = react.useMemo(
|
|
2377
2434
|
() => message.steps?.find(
|
|
2378
2435
|
(s) => s.id === currentExecutingStepId && s.status === "in_progress"
|
|
2379
2436
|
),
|
|
2380
2437
|
[message.steps, currentExecutingStepId]
|
|
2381
2438
|
);
|
|
2382
|
-
const markdownRenderers =
|
|
2439
|
+
const markdownRenderers = react.useMemo(
|
|
2383
2440
|
() => createMarkdownComponents({
|
|
2384
2441
|
isResolvingImages: message.isResolvingImages
|
|
2385
2442
|
}),
|
|
@@ -2393,25 +2450,25 @@ function AgentMessage({
|
|
|
2393
2450
|
}
|
|
2394
2451
|
return `${count} ${stepWord} completed`;
|
|
2395
2452
|
};
|
|
2396
|
-
const renderStepIcon = (
|
|
2453
|
+
const renderStepIcon = (step2, isCurrentlyExecuting) => {
|
|
2397
2454
|
const wrapper = "h-4 w-4 flex items-center justify-center shrink-0";
|
|
2398
2455
|
if (isCurrentlyExecuting)
|
|
2399
2456
|
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 (
|
|
2457
|
+
if (step2.status === "pending" && isCancelled)
|
|
2401
2458
|
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 (
|
|
2459
|
+
if (step2.status === "pending" || step2.status === "in_progress")
|
|
2403
2460
|
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 (
|
|
2461
|
+
if (step2.status === "completed")
|
|
2405
2462
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: wrapper, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2406
2463
|
lucideReact.Check,
|
|
2407
2464
|
{
|
|
2408
2465
|
className: cn(
|
|
2409
2466
|
"h-3.5 w-3.5",
|
|
2410
|
-
|
|
2467
|
+
step2.eventType === "USER_ACTION_SUCCESS" ? "payman-agent-step-icon--success" : "payman-agent-step-icon--success-dim"
|
|
2411
2468
|
)
|
|
2412
2469
|
}
|
|
2413
2470
|
) });
|
|
2414
|
-
if (
|
|
2471
|
+
if (step2.status === "error")
|
|
2415
2472
|
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
2473
|
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
2474
|
};
|
|
@@ -2423,38 +2480,38 @@ function AgentMessage({
|
|
|
2423
2480
|
exit: { height: 0, opacity: 0 },
|
|
2424
2481
|
transition: { duration: 0.2, ease: "easeInOut" },
|
|
2425
2482
|
className: "overflow-hidden",
|
|
2426
|
-
children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pt-1.5", children: message.steps.map((
|
|
2427
|
-
const isCurrentlyExecuting =
|
|
2428
|
-
const hasTime =
|
|
2483
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pt-1.5", children: message.steps.map((step2) => {
|
|
2484
|
+
const isCurrentlyExecuting = step2.id === currentExecutingStepId && step2.status === "in_progress" && isStreaming && !isCancelled;
|
|
2485
|
+
const hasTime = step2.elapsedMs != null && step2.elapsedMs > 0;
|
|
2429
2486
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-1.5", children: [
|
|
2430
2487
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-1.5 items-start", children: [
|
|
2431
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-px", children: renderStepIcon(
|
|
2488
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-px", children: renderStepIcon(step2, isCurrentlyExecuting) }),
|
|
2432
2489
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2433
2490
|
"span",
|
|
2434
2491
|
{
|
|
2435
2492
|
className: cn(
|
|
2436
2493
|
"text-xs leading-relaxed min-w-0 break-words",
|
|
2437
2494
|
isCurrentlyExecuting && "shimmer-text font-medium",
|
|
2438
|
-
!isCurrentlyExecuting &&
|
|
2439
|
-
!isCurrentlyExecuting &&
|
|
2440
|
-
!isCurrentlyExecuting &&
|
|
2441
|
-
!isCurrentlyExecuting &&
|
|
2442
|
-
!isCurrentlyExecuting &&
|
|
2495
|
+
!isCurrentlyExecuting && step2.status === "error" && "payman-agent-step-text--error",
|
|
2496
|
+
!isCurrentlyExecuting && step2.eventType === "USER_ACTION_SUCCESS" && "payman-agent-step-text--success",
|
|
2497
|
+
!isCurrentlyExecuting && step2.status === "completed" && "payman-agent-step-text--completed",
|
|
2498
|
+
!isCurrentlyExecuting && step2.status === "pending" && "payman-agent-step-text--pending",
|
|
2499
|
+
!isCurrentlyExecuting && step2.status === "in_progress" && "payman-agent-step-text--in-progress"
|
|
2443
2500
|
),
|
|
2444
|
-
children:
|
|
2501
|
+
children: step2.message
|
|
2445
2502
|
}
|
|
2446
2503
|
)
|
|
2447
2504
|
] }),
|
|
2448
2505
|
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
2506
|
/* @__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(
|
|
2507
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] font-mono payman-agent-step-time-text", children: formatElapsedTime(step2.elapsedMs) })
|
|
2451
2508
|
] }) })
|
|
2452
|
-
] },
|
|
2509
|
+
] }, step2.id);
|
|
2453
2510
|
}) })
|
|
2454
2511
|
}
|
|
2455
2512
|
) });
|
|
2456
|
-
const stepsToggleRef =
|
|
2457
|
-
const handleStepsToggle =
|
|
2513
|
+
const stepsToggleRef = react.useRef(null);
|
|
2514
|
+
const handleStepsToggle = react.useCallback(() => {
|
|
2458
2515
|
setIsStepsExpanded((prev) => {
|
|
2459
2516
|
const next = !prev;
|
|
2460
2517
|
if (next) {
|
|
@@ -2782,23 +2839,23 @@ function MessageList({
|
|
|
2782
2839
|
isLoadingMoreMessages = false,
|
|
2783
2840
|
hasMoreMessages = false
|
|
2784
2841
|
}) {
|
|
2785
|
-
const scrollRef =
|
|
2786
|
-
const isNearBottomRef =
|
|
2787
|
-
const [showScrollBtn, setShowScrollBtn] =
|
|
2788
|
-
const prevMessageCountRef =
|
|
2789
|
-
const scrollHeightBeforePrependRef =
|
|
2790
|
-
const firstMessageIdRef =
|
|
2791
|
-
const getDistanceFromBottom =
|
|
2842
|
+
const scrollRef = react.useRef(null);
|
|
2843
|
+
const isNearBottomRef = react.useRef(true);
|
|
2844
|
+
const [showScrollBtn, setShowScrollBtn] = react.useState(false);
|
|
2845
|
+
const prevMessageCountRef = react.useRef(messages.length);
|
|
2846
|
+
const scrollHeightBeforePrependRef = react.useRef(null);
|
|
2847
|
+
const firstMessageIdRef = react.useRef(messages[0]?.id);
|
|
2848
|
+
const getDistanceFromBottom = react.useCallback(() => {
|
|
2792
2849
|
const el = scrollRef.current;
|
|
2793
2850
|
if (!el) return 0;
|
|
2794
2851
|
return el.scrollHeight - el.scrollTop - el.clientHeight;
|
|
2795
2852
|
}, []);
|
|
2796
|
-
const scrollToBottom =
|
|
2853
|
+
const scrollToBottom = react.useCallback((behavior = "smooth") => {
|
|
2797
2854
|
const el = scrollRef.current;
|
|
2798
2855
|
if (!el) return;
|
|
2799
2856
|
el.scrollTo({ top: el.scrollHeight, behavior });
|
|
2800
2857
|
}, []);
|
|
2801
|
-
const handleScroll =
|
|
2858
|
+
const handleScroll = react.useCallback(() => {
|
|
2802
2859
|
const el = scrollRef.current;
|
|
2803
2860
|
if (!el) return;
|
|
2804
2861
|
const distance = getDistanceFromBottom();
|
|
@@ -2810,7 +2867,7 @@ function MessageList({
|
|
|
2810
2867
|
onLoadMoreMessages();
|
|
2811
2868
|
}
|
|
2812
2869
|
}, [getDistanceFromBottom, hasMoreMessages, isLoadingMoreMessages, onLoadMoreMessages]);
|
|
2813
|
-
|
|
2870
|
+
react.useLayoutEffect(() => {
|
|
2814
2871
|
const el = scrollRef.current;
|
|
2815
2872
|
const prevHeight = scrollHeightBeforePrependRef.current;
|
|
2816
2873
|
const newFirstId = messages[0]?.id;
|
|
@@ -2820,25 +2877,25 @@ function MessageList({
|
|
|
2820
2877
|
}
|
|
2821
2878
|
firstMessageIdRef.current = newFirstId;
|
|
2822
2879
|
}, [messages]);
|
|
2823
|
-
|
|
2880
|
+
react.useEffect(() => {
|
|
2824
2881
|
const prevCount = prevMessageCountRef.current;
|
|
2825
2882
|
prevMessageCountRef.current = messages.length;
|
|
2826
2883
|
if (messages.length > prevCount && isNearBottomRef.current) {
|
|
2827
2884
|
requestAnimationFrame(() => scrollToBottom());
|
|
2828
2885
|
}
|
|
2829
2886
|
}, [messages.length, scrollToBottom]);
|
|
2830
|
-
|
|
2887
|
+
react.useEffect(() => {
|
|
2831
2888
|
const lastMsg = messages[messages.length - 1];
|
|
2832
2889
|
if (!lastMsg?.isStreaming) return;
|
|
2833
2890
|
if (!isNearBottomRef.current) return;
|
|
2834
2891
|
requestAnimationFrame(() => scrollToBottom());
|
|
2835
2892
|
});
|
|
2836
|
-
|
|
2893
|
+
react.useEffect(() => {
|
|
2837
2894
|
if (messages.length > 0) {
|
|
2838
2895
|
setTimeout(() => scrollToBottom("instant"), 50);
|
|
2839
2896
|
}
|
|
2840
2897
|
}, []);
|
|
2841
|
-
|
|
2898
|
+
react.useEffect(() => {
|
|
2842
2899
|
const handleStepsToggle = () => {
|
|
2843
2900
|
requestAnimationFrame(() => {
|
|
2844
2901
|
requestAnimationFrame(() => {
|
|
@@ -2855,7 +2912,7 @@ function MessageList({
|
|
|
2855
2912
|
return () => el.removeEventListener("payman-steps-toggle", handleStepsToggle);
|
|
2856
2913
|
}
|
|
2857
2914
|
}, [getDistanceFromBottom, scrollToBottom]);
|
|
2858
|
-
const handleScrollToBottom =
|
|
2915
|
+
const handleScrollToBottom = react.useCallback(() => {
|
|
2859
2916
|
scrollToBottom();
|
|
2860
2917
|
}, [scrollToBottom]);
|
|
2861
2918
|
if (isLoading) {
|
|
@@ -2988,7 +3045,7 @@ function ResetSessionConfirmModal({
|
|
|
2988
3045
|
onClose,
|
|
2989
3046
|
onConfirm
|
|
2990
3047
|
}) {
|
|
2991
|
-
const handleKeyDown =
|
|
3048
|
+
const handleKeyDown = react.useCallback(
|
|
2992
3049
|
(event) => {
|
|
2993
3050
|
if (event.key === "Escape") {
|
|
2994
3051
|
onClose();
|
|
@@ -2996,7 +3053,7 @@ function ResetSessionConfirmModal({
|
|
|
2996
3053
|
},
|
|
2997
3054
|
[onClose]
|
|
2998
3055
|
);
|
|
2999
|
-
|
|
3056
|
+
react.useEffect(() => {
|
|
3000
3057
|
if (!isOpen || typeof document === "undefined") return;
|
|
3001
3058
|
document.addEventListener("keydown", handleKeyDown);
|
|
3002
3059
|
const previousOverflow = document.body.style.overflow;
|
|
@@ -3102,14 +3159,14 @@ function UserMessageV2({
|
|
|
3102
3159
|
retryDisabled = false,
|
|
3103
3160
|
actions
|
|
3104
3161
|
}) {
|
|
3105
|
-
const [copied, setCopied] =
|
|
3106
|
-
const [toast, setToast] =
|
|
3107
|
-
const copyResetTimerRef =
|
|
3108
|
-
const toastTimerRef =
|
|
3162
|
+
const [copied, setCopied] = react.useState(false);
|
|
3163
|
+
const [toast, setToast] = react.useState(null);
|
|
3164
|
+
const copyResetTimerRef = react.useRef(null);
|
|
3165
|
+
const toastTimerRef = react.useRef(null);
|
|
3109
3166
|
const showCopyAction = actions?.copy ?? true;
|
|
3110
3167
|
const showEditAction = actions?.edit ?? false;
|
|
3111
3168
|
const showRetryAction = actions?.retry ?? false;
|
|
3112
|
-
|
|
3169
|
+
react.useEffect(() => {
|
|
3113
3170
|
return () => {
|
|
3114
3171
|
if (copyResetTimerRef.current) clearTimeout(copyResetTimerRef.current);
|
|
3115
3172
|
if (toastTimerRef.current) clearTimeout(toastTimerRef.current);
|
|
@@ -3265,18 +3322,18 @@ function MarkdownImageV2({
|
|
|
3265
3322
|
onImageClick
|
|
3266
3323
|
}) {
|
|
3267
3324
|
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 =
|
|
3325
|
+
const [isVisible, setIsVisible] = react.useState(cachedAlready);
|
|
3326
|
+
const [isLoaded, setIsLoaded] = react.useState(cachedAlready);
|
|
3327
|
+
const [hasError, setHasError] = react.useState(false);
|
|
3328
|
+
const [retryCount, setRetryCount] = react.useState(0);
|
|
3329
|
+
const sentinelRef = react.useRef(null);
|
|
3330
|
+
const prevLoadedRef = react.useRef(cachedAlready);
|
|
3331
|
+
const isUnresolvedRag = react.useMemo(
|
|
3275
3332
|
() => src ? isUnresolvedRagImageSource2(src) : false,
|
|
3276
3333
|
[src]
|
|
3277
3334
|
);
|
|
3278
3335
|
const isResolvingRag = Boolean(isResolving && isUnresolvedRag);
|
|
3279
|
-
|
|
3336
|
+
react.useEffect(() => {
|
|
3280
3337
|
if (src && loadedImageCache.has(src)) {
|
|
3281
3338
|
setIsLoaded(true);
|
|
3282
3339
|
setIsVisible(true);
|
|
@@ -3285,7 +3342,7 @@ function MarkdownImageV2({
|
|
|
3285
3342
|
setHasError(false);
|
|
3286
3343
|
setRetryCount(0);
|
|
3287
3344
|
}, [src]);
|
|
3288
|
-
|
|
3345
|
+
react.useEffect(() => {
|
|
3289
3346
|
const el = sentinelRef.current;
|
|
3290
3347
|
if (!el || !src) return;
|
|
3291
3348
|
const rect = el.getBoundingClientRect();
|
|
@@ -3406,92 +3463,13 @@ function MarkdownImageV2({
|
|
|
3406
3463
|
}
|
|
3407
3464
|
) });
|
|
3408
3465
|
}
|
|
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) {
|
|
3466
|
+
function buildComponents(onImageClick, isResolvingRef) {
|
|
3483
3467
|
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
|
-
},
|
|
3468
|
+
p: ({ children }) => /* @__PURE__ */ jsxRuntime.jsx("p", { children }),
|
|
3491
3469
|
code: ({ children }) => /* @__PURE__ */ jsxRuntime.jsx("code", { children }),
|
|
3492
3470
|
pre: ({ children }) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "payman-v2-markdown-pre", children: /* @__PURE__ */ jsxRuntime.jsx("pre", { children }) }),
|
|
3493
3471
|
ul: ({ children }) => /* @__PURE__ */ jsxRuntime.jsx("ul", { children }),
|
|
3494
|
-
ol: ({ children }) => /* @__PURE__ */ jsxRuntime.jsx("ol", { children }),
|
|
3472
|
+
ol: ({ children, start }) => /* @__PURE__ */ jsxRuntime.jsx("ol", { start, children }),
|
|
3495
3473
|
li: ({ children }) => /* @__PURE__ */ jsxRuntime.jsx("li", { children }),
|
|
3496
3474
|
h1: ({ children }) => /* @__PURE__ */ jsxRuntime.jsx("h1", { children }),
|
|
3497
3475
|
h2: ({ children }) => /* @__PURE__ */ jsxRuntime.jsx("h2", { children }),
|
|
@@ -3523,15 +3501,10 @@ function MarkdownRendererV2({
|
|
|
3523
3501
|
isResolvingImages,
|
|
3524
3502
|
onImageClick
|
|
3525
3503
|
}) {
|
|
3526
|
-
const isResolvingRef =
|
|
3504
|
+
const isResolvingRef = react.useRef(isResolvingImages);
|
|
3527
3505
|
isResolvingRef.current = isResolvingImages;
|
|
3528
|
-
const
|
|
3529
|
-
|
|
3530
|
-
() => extractRagParagraphTexts(content),
|
|
3531
|
-
[content]
|
|
3532
|
-
);
|
|
3533
|
-
const components = React.useMemo(
|
|
3534
|
-
() => buildComponents(onImageClick, isResolvingRef, ragParagraphsRef),
|
|
3506
|
+
const components = react.useMemo(
|
|
3507
|
+
() => buildComponents(onImageClick, isResolvingRef),
|
|
3535
3508
|
[onImageClick]
|
|
3536
3509
|
);
|
|
3537
3510
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -3588,14 +3561,14 @@ function FeedbackReasonModal({
|
|
|
3588
3561
|
onClose,
|
|
3589
3562
|
onSubmit
|
|
3590
3563
|
}) {
|
|
3591
|
-
const [reason, setReason] =
|
|
3564
|
+
const [reason, setReason] = react.useState(
|
|
3592
3565
|
NEGATIVE_FEEDBACK_REASONS[0].value
|
|
3593
3566
|
);
|
|
3594
|
-
const [details, setDetails] =
|
|
3595
|
-
const [submitting, setSubmitting] =
|
|
3596
|
-
const [error, setError] =
|
|
3597
|
-
const [reasonOpen, setReasonOpen] =
|
|
3598
|
-
|
|
3567
|
+
const [details, setDetails] = react.useState("");
|
|
3568
|
+
const [submitting, setSubmitting] = react.useState(false);
|
|
3569
|
+
const [error, setError] = react.useState(null);
|
|
3570
|
+
const [reasonOpen, setReasonOpen] = react.useState(false);
|
|
3571
|
+
react.useEffect(() => {
|
|
3599
3572
|
if (open) {
|
|
3600
3573
|
setReason(NEGATIVE_FEEDBACK_REASONS[0].value);
|
|
3601
3574
|
setDetails("");
|
|
@@ -3604,7 +3577,7 @@ function FeedbackReasonModal({
|
|
|
3604
3577
|
setReasonOpen(false);
|
|
3605
3578
|
}
|
|
3606
3579
|
}, [open]);
|
|
3607
|
-
const handleKeyDown =
|
|
3580
|
+
const handleKeyDown = react.useCallback(
|
|
3608
3581
|
(event) => {
|
|
3609
3582
|
if (event.key !== "Escape") return;
|
|
3610
3583
|
if (reasonOpen) {
|
|
@@ -3615,7 +3588,7 @@ function FeedbackReasonModal({
|
|
|
3615
3588
|
},
|
|
3616
3589
|
[onClose, reasonOpen]
|
|
3617
3590
|
);
|
|
3618
|
-
|
|
3591
|
+
react.useEffect(() => {
|
|
3619
3592
|
if (!open || typeof document === "undefined") return;
|
|
3620
3593
|
document.addEventListener("keydown", handleKeyDown);
|
|
3621
3594
|
const previousOverflow = document.body.style.overflow;
|
|
@@ -3797,6 +3770,87 @@ function FeedbackReasonModal({
|
|
|
3797
3770
|
}
|
|
3798
3771
|
) : null });
|
|
3799
3772
|
}
|
|
3773
|
+
|
|
3774
|
+
// src/utils/markdownImageToken.ts
|
|
3775
|
+
function step(text, i) {
|
|
3776
|
+
if (text[i] === "\\" && i + 1 < text.length) return i + 2;
|
|
3777
|
+
return i + 1;
|
|
3778
|
+
}
|
|
3779
|
+
function scanAltText(text, start) {
|
|
3780
|
+
let i = start;
|
|
3781
|
+
while (i < text.length) {
|
|
3782
|
+
if (text[i] === "]") return i;
|
|
3783
|
+
i = step(text, i);
|
|
3784
|
+
}
|
|
3785
|
+
return -1;
|
|
3786
|
+
}
|
|
3787
|
+
function scanOptionalTitle(text, start) {
|
|
3788
|
+
let i = start;
|
|
3789
|
+
while (i < text.length && /[\t\n ]/.test(text[i])) i++;
|
|
3790
|
+
if (i >= text.length) return i;
|
|
3791
|
+
const quote = text[i];
|
|
3792
|
+
if (quote !== '"' && quote !== "'") return i;
|
|
3793
|
+
i++;
|
|
3794
|
+
while (i < text.length) {
|
|
3795
|
+
if (text[i] === quote) return i + 1;
|
|
3796
|
+
i = step(text, i);
|
|
3797
|
+
}
|
|
3798
|
+
return -1;
|
|
3799
|
+
}
|
|
3800
|
+
function scanAngleBracketDestination(text, start) {
|
|
3801
|
+
let i = start + 1;
|
|
3802
|
+
while (i < text.length) {
|
|
3803
|
+
if (text[i] === ">") return i + 1;
|
|
3804
|
+
i = step(text, i);
|
|
3805
|
+
}
|
|
3806
|
+
return -1;
|
|
3807
|
+
}
|
|
3808
|
+
function scanRawDestination(text, start) {
|
|
3809
|
+
let i = start;
|
|
3810
|
+
let depth = 1;
|
|
3811
|
+
while (i < text.length) {
|
|
3812
|
+
const char = text[i];
|
|
3813
|
+
if (char === "\\") {
|
|
3814
|
+
if (i + 1 >= text.length) return -1;
|
|
3815
|
+
i += 2;
|
|
3816
|
+
continue;
|
|
3817
|
+
}
|
|
3818
|
+
if (char === "(") depth++;
|
|
3819
|
+
else if (char === ")") {
|
|
3820
|
+
depth--;
|
|
3821
|
+
if (depth === 0) return i + 1;
|
|
3822
|
+
}
|
|
3823
|
+
i++;
|
|
3824
|
+
}
|
|
3825
|
+
return -1;
|
|
3826
|
+
}
|
|
3827
|
+
function completeMarkdownImageTokenLength(text) {
|
|
3828
|
+
if (!text.startsWith("![")) return 0;
|
|
3829
|
+
const altEnd = scanAltText(text, 2);
|
|
3830
|
+
if (altEnd === -1 || altEnd + 1 >= text.length || text[altEnd + 1] !== "(") {
|
|
3831
|
+
return 0;
|
|
3832
|
+
}
|
|
3833
|
+
let i = altEnd + 2;
|
|
3834
|
+
if (i >= text.length) return 0;
|
|
3835
|
+
if (text[i] === "<") {
|
|
3836
|
+
i = scanAngleBracketDestination(text, i);
|
|
3837
|
+
if (i === -1) return 0;
|
|
3838
|
+
i = scanOptionalTitle(text, i);
|
|
3839
|
+
if (i === -1 || i >= text.length || text[i] !== ")") return 0;
|
|
3840
|
+
return i + 1;
|
|
3841
|
+
}
|
|
3842
|
+
i = scanRawDestination(text, i);
|
|
3843
|
+
return i === -1 ? 0 : i;
|
|
3844
|
+
}
|
|
3845
|
+
function stripIncompleteImageToken(text) {
|
|
3846
|
+
const lastBang = text.lastIndexOf("![");
|
|
3847
|
+
if (lastBang === -1) return text;
|
|
3848
|
+
const suffix = text.slice(lastBang);
|
|
3849
|
+
if (completeMarkdownImageTokenLength(suffix) > 0) return text;
|
|
3850
|
+
return text.slice(0, lastBang);
|
|
3851
|
+
}
|
|
3852
|
+
|
|
3853
|
+
// src/components/v2/useTypingEffect.ts
|
|
3800
3854
|
var RESPONSE_SPEED = {
|
|
3801
3855
|
normal: [2, 4],
|
|
3802
3856
|
fast: 1,
|
|
@@ -3804,7 +3858,6 @@ var RESPONSE_SPEED = {
|
|
|
3804
3858
|
newline: [4, 6],
|
|
3805
3859
|
idle: 15
|
|
3806
3860
|
};
|
|
3807
|
-
var MARKDOWN_IMAGE_REGEX = /^!\[[^\]]*\]\([^)]*\)/;
|
|
3808
3861
|
function charDelay(char, speed, multiplier) {
|
|
3809
3862
|
const raw = (() => {
|
|
3810
3863
|
if (char === "*") return speed.fast;
|
|
@@ -3819,17 +3872,17 @@ function charDelay(char, speed, multiplier) {
|
|
|
3819
3872
|
function useTypingEffect(targetText, enabled, speed = RESPONSE_SPEED, initialDisplayedText, speedMultiplier = 1) {
|
|
3820
3873
|
const instant = speedMultiplier === 0;
|
|
3821
3874
|
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 =
|
|
3875
|
+
const [displayedText, setDisplayedText] = react.useState("");
|
|
3876
|
+
const displayedRef = react.useRef("");
|
|
3877
|
+
const targetRef = react.useRef(targetText);
|
|
3878
|
+
const enabledRef = react.useRef(enabled);
|
|
3879
|
+
const initialDisplayedRef = react.useRef(initialDisplayedText);
|
|
3880
|
+
const timerRef = react.useRef(null);
|
|
3881
|
+
const runningRef = react.useRef(false);
|
|
3829
3882
|
targetRef.current = targetText;
|
|
3830
3883
|
enabledRef.current = enabled;
|
|
3831
3884
|
initialDisplayedRef.current = initialDisplayedText;
|
|
3832
|
-
|
|
3885
|
+
react.useEffect(() => {
|
|
3833
3886
|
if (!enabled || instant) {
|
|
3834
3887
|
if (timerRef.current) {
|
|
3835
3888
|
clearTimeout(timerRef.current);
|
|
@@ -3863,9 +3916,9 @@ function useTypingEffect(targetText, enabled, speed = RESPONSE_SPEED, initialDis
|
|
|
3863
3916
|
}
|
|
3864
3917
|
if (displayedRef.current.length < targetRef.current.length) {
|
|
3865
3918
|
const remaining = targetRef.current.slice(displayedRef.current.length);
|
|
3866
|
-
const
|
|
3867
|
-
if (
|
|
3868
|
-
displayedRef.current +=
|
|
3919
|
+
const imageTokenLength = completeMarkdownImageTokenLength(remaining);
|
|
3920
|
+
if (imageTokenLength > 0) {
|
|
3921
|
+
displayedRef.current += remaining.slice(0, imageTokenLength);
|
|
3869
3922
|
setDisplayedText(displayedRef.current);
|
|
3870
3923
|
timerRef.current = setTimeout(tick, 0);
|
|
3871
3924
|
return;
|
|
@@ -3894,13 +3947,6 @@ function useTypingEffect(targetText, enabled, speed = RESPONSE_SPEED, initialDis
|
|
|
3894
3947
|
isTyping
|
|
3895
3948
|
};
|
|
3896
3949
|
}
|
|
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
3950
|
function getFeedbackState(message) {
|
|
3905
3951
|
const feedback = message.feedback;
|
|
3906
3952
|
if (feedback === "up" || feedback === "down") return feedback;
|
|
@@ -3919,26 +3965,26 @@ function AssistantMessageV2({
|
|
|
3919
3965
|
actions,
|
|
3920
3966
|
typingSpeed = 4
|
|
3921
3967
|
}) {
|
|
3922
|
-
const [copied, setCopied] =
|
|
3923
|
-
const [activeFeedback, setActiveFeedback] =
|
|
3968
|
+
const [copied, setCopied] = react.useState(false);
|
|
3969
|
+
const [activeFeedback, setActiveFeedback] = react.useState(
|
|
3924
3970
|
() => getFeedbackState(message)
|
|
3925
3971
|
);
|
|
3926
|
-
const [reasonModalOpen, setReasonModalOpen] =
|
|
3972
|
+
const [reasonModalOpen, setReasonModalOpen] = react.useState(false);
|
|
3927
3973
|
const canSubmitFeedback = !!onSubmitFeedback && !!message.executionId;
|
|
3928
|
-
const [toast, setToast] =
|
|
3929
|
-
const copyResetTimerRef =
|
|
3930
|
-
const toastTimerRef =
|
|
3974
|
+
const [toast, setToast] = react.useState(null);
|
|
3975
|
+
const copyResetTimerRef = react.useRef(null);
|
|
3976
|
+
const toastTimerRef = react.useRef(null);
|
|
3931
3977
|
const showCopyAction = actions?.copy ?? true;
|
|
3932
3978
|
const showTraceAction = (actions?.trace ?? true) && !!onExecutionTraceClick;
|
|
3933
3979
|
const showThumbsUp = actions?.thumbsUp ?? true;
|
|
3934
3980
|
const showThumbsDown = actions?.thumbsDown ?? true;
|
|
3935
3981
|
const hydratedFeedback = message.feedback;
|
|
3936
|
-
const hasEverStreamed =
|
|
3982
|
+
const hasEverStreamed = react.useRef(!!message.isStreaming);
|
|
3937
3983
|
if (message.isStreaming) hasEverStreamed.current = true;
|
|
3938
|
-
|
|
3984
|
+
react.useEffect(() => {
|
|
3939
3985
|
setActiveFeedback(getFeedbackState(message));
|
|
3940
3986
|
}, [hydratedFeedback, message.id]);
|
|
3941
|
-
|
|
3987
|
+
react.useEffect(() => {
|
|
3942
3988
|
return () => {
|
|
3943
3989
|
if (copyResetTimerRef.current) clearTimeout(copyResetTimerRef.current);
|
|
3944
3990
|
if (toastTimerRef.current) clearTimeout(toastTimerRef.current);
|
|
@@ -4232,10 +4278,10 @@ function OtpInputV2({
|
|
|
4232
4278
|
disabled = false,
|
|
4233
4279
|
error = false
|
|
4234
4280
|
}) {
|
|
4235
|
-
const inputRefs =
|
|
4281
|
+
const inputRefs = react.useRef([]);
|
|
4236
4282
|
const safeMaxLength = Number.isInteger(maxLength) && maxLength > 0 ? Math.min(maxLength, MAX_SUPPORTED_LENGTH) : DEFAULT_MAX_LENGTH;
|
|
4237
4283
|
const digits = value.split("").concat(Array(safeMaxLength).fill("")).slice(0, safeMaxLength);
|
|
4238
|
-
|
|
4284
|
+
react.useEffect(() => {
|
|
4239
4285
|
if (disabled) return;
|
|
4240
4286
|
const timer = window.setTimeout(() => {
|
|
4241
4287
|
inputRefs.current[0]?.focus();
|
|
@@ -4334,31 +4380,31 @@ function VerificationInline({
|
|
|
4334
4380
|
onResend
|
|
4335
4381
|
}) {
|
|
4336
4382
|
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 =
|
|
4383
|
+
const codeLen = react.useMemo(() => codeLengthFromSchema(prompt), [prompt]);
|
|
4384
|
+
const [code, setCode] = react.useState("");
|
|
4385
|
+
const [errored, setErrored] = react.useState(false);
|
|
4386
|
+
const [resendSec, setResendSec] = react.useState(0);
|
|
4387
|
+
const [hiddenAfterResend, setHiddenAfterResend] = react.useState(false);
|
|
4388
|
+
const lastSubmittedRef = react.useRef(null);
|
|
4389
|
+
const resendTimerRef = react.useRef(void 0);
|
|
4344
4390
|
const status = prompt.status;
|
|
4345
4391
|
const busy = status === "submitting";
|
|
4346
4392
|
const stale = status === "stale";
|
|
4347
4393
|
const locked = busy || stale || expired;
|
|
4348
|
-
|
|
4394
|
+
react.useEffect(() => {
|
|
4349
4395
|
if (prompt.subAction === "SubmissionInvalid") {
|
|
4350
4396
|
setErrored(true);
|
|
4351
4397
|
setCode("");
|
|
4352
4398
|
lastSubmittedRef.current = null;
|
|
4353
4399
|
}
|
|
4354
4400
|
}, [prompt.subAction, prompt.userActionId]);
|
|
4355
|
-
|
|
4401
|
+
react.useEffect(() => {
|
|
4356
4402
|
setHiddenAfterResend(false);
|
|
4357
4403
|
}, [prompt.expirySeconds, prompt.message, prompt.subAction, prompt.userActionId]);
|
|
4358
|
-
|
|
4404
|
+
react.useEffect(() => {
|
|
4359
4405
|
if (code.length < codeLen) lastSubmittedRef.current = null;
|
|
4360
4406
|
}, [code, codeLen]);
|
|
4361
|
-
const doSubmit =
|
|
4407
|
+
const doSubmit = react.useCallback(
|
|
4362
4408
|
(value) => {
|
|
4363
4409
|
if (locked || !value) return;
|
|
4364
4410
|
if (lastSubmittedRef.current === value) return;
|
|
@@ -4370,20 +4416,20 @@ function VerificationInline({
|
|
|
4370
4416
|
},
|
|
4371
4417
|
[locked, onSubmit, prompt.userActionId]
|
|
4372
4418
|
);
|
|
4373
|
-
|
|
4419
|
+
react.useEffect(() => {
|
|
4374
4420
|
if (!isNumeric || locked) return;
|
|
4375
4421
|
if (code.length === codeLen && /^\d+$/.test(code)) {
|
|
4376
4422
|
doSubmit(code);
|
|
4377
4423
|
}
|
|
4378
4424
|
}, [code, codeLen, doSubmit, isNumeric, locked]);
|
|
4379
|
-
|
|
4425
|
+
react.useEffect(() => {
|
|
4380
4426
|
return () => {
|
|
4381
4427
|
if (typeof resendTimerRef.current === "number") {
|
|
4382
4428
|
window.clearInterval(resendTimerRef.current);
|
|
4383
4429
|
}
|
|
4384
4430
|
};
|
|
4385
4431
|
}, []);
|
|
4386
|
-
const startResendCooldown =
|
|
4432
|
+
const startResendCooldown = react.useCallback(() => {
|
|
4387
4433
|
setResendSec(RESEND_COOLDOWN_S);
|
|
4388
4434
|
if (typeof resendTimerRef.current === "number") {
|
|
4389
4435
|
window.clearInterval(resendTimerRef.current);
|
|
@@ -4401,7 +4447,7 @@ function VerificationInline({
|
|
|
4401
4447
|
});
|
|
4402
4448
|
}, 1e3);
|
|
4403
4449
|
}, []);
|
|
4404
|
-
const handleResend =
|
|
4450
|
+
const handleResend = react.useCallback(async () => {
|
|
4405
4451
|
if (locked || resendSec > 0) return;
|
|
4406
4452
|
setErrored(false);
|
|
4407
4453
|
setCode("");
|
|
@@ -4414,7 +4460,7 @@ function VerificationInline({
|
|
|
4414
4460
|
setHiddenAfterResend(false);
|
|
4415
4461
|
}
|
|
4416
4462
|
}, [locked, onResend, prompt.userActionId, resendSec, startResendCooldown]);
|
|
4417
|
-
const handleCancel =
|
|
4463
|
+
const handleCancel = react.useCallback(() => {
|
|
4418
4464
|
if (busy) return;
|
|
4419
4465
|
void onCancel(prompt.userActionId);
|
|
4420
4466
|
}, [busy, onCancel, prompt.userActionId]);
|
|
@@ -4504,13 +4550,13 @@ function SchemaFormInline({
|
|
|
4504
4550
|
onCancel
|
|
4505
4551
|
}) {
|
|
4506
4552
|
const schema = prompt.requestedSchema;
|
|
4507
|
-
const fields =
|
|
4508
|
-
const [values, setValues] =
|
|
4553
|
+
const fields = react.useMemo(() => renderableFields(schema), [schema]);
|
|
4554
|
+
const [values, setValues] = react.useState(() => {
|
|
4509
4555
|
const init2 = {};
|
|
4510
4556
|
for (const [key, field] of fields) init2[key] = defaultValueFor(field);
|
|
4511
4557
|
return init2;
|
|
4512
4558
|
});
|
|
4513
|
-
const [errors, setErrors] =
|
|
4559
|
+
const [errors, setErrors] = react.useState({});
|
|
4514
4560
|
const status = prompt.status;
|
|
4515
4561
|
const busy = status === "submitting";
|
|
4516
4562
|
const stale = status === "stale";
|
|
@@ -4650,14 +4696,15 @@ function NotificationInline({ notification, onDismiss }) {
|
|
|
4650
4696
|
] });
|
|
4651
4697
|
}
|
|
4652
4698
|
function useExpiryCountdown(prompt) {
|
|
4653
|
-
const
|
|
4654
|
-
const [secondsLeft, setSecondsLeft] =
|
|
4655
|
-
|
|
4656
|
-
|
|
4699
|
+
const deadlineMs = typeof prompt.expiresAt === "number" && prompt.expiresAt > 0 ? prompt.expiresAt : typeof prompt.expirySeconds === "number" && prompt.expirySeconds > 0 ? Date.now() + Math.floor(prompt.expirySeconds) * 1e3 : void 0;
|
|
4700
|
+
const [secondsLeft, setSecondsLeft] = react.useState(
|
|
4701
|
+
() => deadlineMs !== void 0 ? Math.max(0, Math.ceil((deadlineMs - Date.now()) / 1e3)) : void 0
|
|
4702
|
+
);
|
|
4703
|
+
react.useEffect(() => {
|
|
4704
|
+
if (deadlineMs === void 0) {
|
|
4657
4705
|
setSecondsLeft(void 0);
|
|
4658
4706
|
return;
|
|
4659
4707
|
}
|
|
4660
|
-
const deadlineMs = Date.now() + initial * 1e3;
|
|
4661
4708
|
let intervalId;
|
|
4662
4709
|
const remaining = () => Math.max(0, Math.ceil((deadlineMs - Date.now()) / 1e3));
|
|
4663
4710
|
const sync = () => {
|
|
@@ -4679,8 +4726,8 @@ function useExpiryCountdown(prompt) {
|
|
|
4679
4726
|
window.removeEventListener("focus", sync);
|
|
4680
4727
|
window.removeEventListener("pageshow", sync);
|
|
4681
4728
|
};
|
|
4682
|
-
}, [prompt.userActionId, prompt.subAction,
|
|
4683
|
-
const expired =
|
|
4729
|
+
}, [prompt.userActionId, prompt.subAction, deadlineMs]);
|
|
4730
|
+
const expired = deadlineMs !== void 0 && (getUserActionSecondsLeft(prompt) ?? secondsLeft ?? 0) <= 0;
|
|
4684
4731
|
return [secondsLeft, expired];
|
|
4685
4732
|
}
|
|
4686
4733
|
function UserActionInline({
|
|
@@ -4691,7 +4738,7 @@ function UserActionInline({
|
|
|
4691
4738
|
onExpired
|
|
4692
4739
|
}) {
|
|
4693
4740
|
const [secondsLeft, expired] = useExpiryCountdown(prompt);
|
|
4694
|
-
|
|
4741
|
+
react.useEffect(() => {
|
|
4695
4742
|
if (expired && prompt.kind !== "notification") onExpired?.();
|
|
4696
4743
|
}, [expired, onExpired, prompt.kind]);
|
|
4697
4744
|
let body;
|
|
@@ -4754,7 +4801,7 @@ function getPromptViewKey(prompt) {
|
|
|
4754
4801
|
prompt.message ?? ""
|
|
4755
4802
|
].join(PROMPT_KEY_SEPARATOR);
|
|
4756
4803
|
}
|
|
4757
|
-
var MessageListV2 =
|
|
4804
|
+
var MessageListV2 = react.forwardRef(
|
|
4758
4805
|
function MessageListV22({
|
|
4759
4806
|
messages,
|
|
4760
4807
|
isStreaming = false,
|
|
@@ -4774,25 +4821,25 @@ var MessageListV2 = React.forwardRef(
|
|
|
4774
4821
|
onSubmitFeedback,
|
|
4775
4822
|
typingSpeed = 4
|
|
4776
4823
|
}, ref) {
|
|
4777
|
-
const noop =
|
|
4824
|
+
const noop = react.useCallback(async () => {
|
|
4778
4825
|
}, []);
|
|
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 =
|
|
4826
|
+
const scrollRef = react.useRef(null);
|
|
4827
|
+
const scrollInnerRef = react.useRef(null);
|
|
4828
|
+
const isNearBottomRef = react.useRef(true);
|
|
4829
|
+
const [showScrollBtn, setShowScrollBtn] = react.useState(false);
|
|
4830
|
+
const [expiredPromptViewState, setExpiredPromptViewState] = react.useState({});
|
|
4831
|
+
const expiredUserActionIdsRef = react.useRef(/* @__PURE__ */ new Set());
|
|
4832
|
+
const prevCountRef = react.useRef(messages.length);
|
|
4833
|
+
const pauseStickUntilUserMessageRef = react.useRef(false);
|
|
4834
|
+
const followingBottomRef = react.useRef(true);
|
|
4835
|
+
const lastPinAtRef = react.useRef(0);
|
|
4836
|
+
const prevScrollTopRef = react.useRef(0);
|
|
4837
|
+
const getDistanceFromBottom = react.useCallback(() => {
|
|
4791
4838
|
const el = scrollRef.current;
|
|
4792
4839
|
if (!el) return 0;
|
|
4793
4840
|
return el.scrollHeight - el.scrollTop - el.clientHeight;
|
|
4794
4841
|
}, []);
|
|
4795
|
-
const messageActivityFingerprint =
|
|
4842
|
+
const messageActivityFingerprint = react.useMemo(() => {
|
|
4796
4843
|
const last = messages[messages.length - 1];
|
|
4797
4844
|
const promptFingerprint = (userActionPrompts ?? []).map((prompt) => `${getPromptViewKey(prompt)}:${prompt.status}`).join(PROMPT_KEY_SEPARATOR);
|
|
4798
4845
|
const notificationFingerprint = (notifications ?? []).map((notification) => notification.id).join(PROMPT_KEY_SEPARATOR);
|
|
@@ -4818,7 +4865,7 @@ var MessageListV2 = React.forwardRef(
|
|
|
4818
4865
|
notificationFingerprint
|
|
4819
4866
|
].join(PROMPT_KEY_SEPARATOR);
|
|
4820
4867
|
}, [isStreaming, messages, notifications, userActionPrompts]);
|
|
4821
|
-
const handleUserActionExpired =
|
|
4868
|
+
const handleUserActionExpired = react.useCallback(
|
|
4822
4869
|
(promptKey, userActionId) => {
|
|
4823
4870
|
setExpiredPromptViewState((prev) => {
|
|
4824
4871
|
if (prev[promptKey]) return prev;
|
|
@@ -4835,7 +4882,7 @@ var MessageListV2 = React.forwardRef(
|
|
|
4835
4882
|
},
|
|
4836
4883
|
[messageActivityFingerprint, onExpireUserAction]
|
|
4837
4884
|
);
|
|
4838
|
-
|
|
4885
|
+
react.useEffect(() => {
|
|
4839
4886
|
setExpiredPromptViewState((prev) => {
|
|
4840
4887
|
let changed = false;
|
|
4841
4888
|
const next = {};
|
|
@@ -4850,7 +4897,7 @@ var MessageListV2 = React.forwardRef(
|
|
|
4850
4897
|
return changed ? next : prev;
|
|
4851
4898
|
});
|
|
4852
4899
|
}, [messageActivityFingerprint]);
|
|
4853
|
-
|
|
4900
|
+
react.useEffect(() => {
|
|
4854
4901
|
const livePromptKeys = new Set((userActionPrompts ?? []).map(getPromptViewKey));
|
|
4855
4902
|
const liveUserActionIds = new Set((userActionPrompts ?? []).map((p) => p.userActionId));
|
|
4856
4903
|
for (const userActionId of expiredUserActionIdsRef.current) {
|
|
@@ -4871,21 +4918,21 @@ var MessageListV2 = React.forwardRef(
|
|
|
4871
4918
|
return changed ? next : prev;
|
|
4872
4919
|
});
|
|
4873
4920
|
}, [userActionPrompts]);
|
|
4874
|
-
const visibleUserActionPrompts =
|
|
4921
|
+
const visibleUserActionPrompts = react.useMemo(
|
|
4875
4922
|
() => userActionPrompts?.filter((prompt) => {
|
|
4876
4923
|
const promptKey = getPromptViewKey(prompt);
|
|
4877
4924
|
return !expiredPromptViewState[promptKey]?.hidden;
|
|
4878
4925
|
}),
|
|
4879
4926
|
[expiredPromptViewState, userActionPrompts]
|
|
4880
4927
|
);
|
|
4881
|
-
const pinToBottom =
|
|
4928
|
+
const pinToBottom = react.useCallback((behavior = "instant") => {
|
|
4882
4929
|
const el = scrollRef.current;
|
|
4883
4930
|
if (!el) return;
|
|
4884
4931
|
lastPinAtRef.current = performance.now();
|
|
4885
4932
|
el.scrollTo({ top: el.scrollHeight, behavior });
|
|
4886
4933
|
prevScrollTopRef.current = el.scrollHeight;
|
|
4887
4934
|
}, []);
|
|
4888
|
-
const scrollToBottom =
|
|
4935
|
+
const scrollToBottom = react.useCallback(
|
|
4889
4936
|
(behavior = "smooth") => {
|
|
4890
4937
|
const el = scrollRef.current;
|
|
4891
4938
|
if (!el) return;
|
|
@@ -4895,7 +4942,7 @@ var MessageListV2 = React.forwardRef(
|
|
|
4895
4942
|
},
|
|
4896
4943
|
[pinToBottom]
|
|
4897
4944
|
);
|
|
4898
|
-
|
|
4945
|
+
react.useImperativeHandle(
|
|
4899
4946
|
ref,
|
|
4900
4947
|
() => ({
|
|
4901
4948
|
scrollToBottom: (behavior = "smooth") => {
|
|
@@ -4908,7 +4955,7 @@ var MessageListV2 = React.forwardRef(
|
|
|
4908
4955
|
}),
|
|
4909
4956
|
[scrollToBottom]
|
|
4910
4957
|
);
|
|
4911
|
-
const handleScroll =
|
|
4958
|
+
const handleScroll = react.useCallback(() => {
|
|
4912
4959
|
const el = scrollRef.current;
|
|
4913
4960
|
if (!el) return;
|
|
4914
4961
|
const currentScrollTop = el.scrollTop;
|
|
@@ -4929,7 +4976,7 @@ var MessageListV2 = React.forwardRef(
|
|
|
4929
4976
|
pauseStickUntilUserMessageRef.current = false;
|
|
4930
4977
|
}
|
|
4931
4978
|
}, [getDistanceFromBottom]);
|
|
4932
|
-
|
|
4979
|
+
react.useEffect(() => {
|
|
4933
4980
|
const prevCount = prevCountRef.current;
|
|
4934
4981
|
prevCountRef.current = messages.length;
|
|
4935
4982
|
if (messages.length > prevCount) {
|
|
@@ -4943,7 +4990,7 @@ var MessageListV2 = React.forwardRef(
|
|
|
4943
4990
|
}
|
|
4944
4991
|
}
|
|
4945
4992
|
}, [messages.length, scrollToBottom]);
|
|
4946
|
-
|
|
4993
|
+
react.useEffect(() => {
|
|
4947
4994
|
const inner = scrollInnerRef.current;
|
|
4948
4995
|
if (!inner) return;
|
|
4949
4996
|
const pinIfFollowing = () => {
|
|
@@ -4968,7 +5015,7 @@ var MessageListV2 = React.forwardRef(
|
|
|
4968
5015
|
mo.disconnect();
|
|
4969
5016
|
};
|
|
4970
5017
|
}, [pinToBottom]);
|
|
4971
|
-
|
|
5018
|
+
react.useEffect(() => {
|
|
4972
5019
|
if (messages.length > 0) {
|
|
4973
5020
|
setTimeout(() => scrollToBottom("instant"), 50);
|
|
4974
5021
|
}
|
|
@@ -5057,7 +5104,7 @@ var MessageListV2 = React.forwardRef(
|
|
|
5057
5104
|
] });
|
|
5058
5105
|
}
|
|
5059
5106
|
);
|
|
5060
|
-
var ChatInputV2 =
|
|
5107
|
+
var ChatInputV2 = react.forwardRef(
|
|
5061
5108
|
function ChatInputV22({
|
|
5062
5109
|
onSend,
|
|
5063
5110
|
disabled = false,
|
|
@@ -5081,20 +5128,20 @@ var ChatInputV2 = React.forwardRef(
|
|
|
5081
5128
|
onAnalysisModeChange,
|
|
5082
5129
|
slashCommands = []
|
|
5083
5130
|
}, 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 =
|
|
5131
|
+
const [value, setValue] = react.useState("");
|
|
5132
|
+
const [isFocused, setIsFocused] = react.useState(false);
|
|
5133
|
+
const [showActions, setShowActions] = react.useState(false);
|
|
5134
|
+
const [showVoiceTooltip, setShowVoiceTooltip] = react.useState(false);
|
|
5135
|
+
const [selectedCommandIndex, setSelectedCommandIndex] = react.useState(0);
|
|
5136
|
+
const [inlineHint, setInlineHint] = react.useState(null);
|
|
5137
|
+
const [commandMenuDismissed, setCommandMenuDismissed] = react.useState(false);
|
|
5138
|
+
const textareaRef = react.useRef(null);
|
|
5139
|
+
const actionsRef = react.useRef(null);
|
|
5140
|
+
const preRecordTextRef = react.useRef("");
|
|
5141
|
+
const voiceTooltipTimerRef = react.useRef(
|
|
5095
5142
|
null
|
|
5096
5143
|
);
|
|
5097
|
-
const voiceDraftSyncActiveRef =
|
|
5144
|
+
const voiceDraftSyncActiveRef = react.useRef(false);
|
|
5098
5145
|
const isInputLocked = disabled || isRecording;
|
|
5099
5146
|
const hasAttachmentOptions = showUploadImageButton || showAttachFileButton;
|
|
5100
5147
|
const showAttachmentMenuButton = showAttachmentButton && hasAttachmentOptions;
|
|
@@ -5105,14 +5152,14 @@ var ChatInputV2 = React.forwardRef(
|
|
|
5105
5152
|
(command) => command.name.toLowerCase().startsWith(commandQuery)
|
|
5106
5153
|
);
|
|
5107
5154
|
const showCommandSuggestions = !commandMenuDismissed && !isRecording && !disabled && commandSuggestions.length > 0;
|
|
5108
|
-
|
|
5155
|
+
react.useEffect(() => {
|
|
5109
5156
|
if (textareaRef.current) {
|
|
5110
5157
|
textareaRef.current.style.height = "auto";
|
|
5111
5158
|
const scrollHeight = textareaRef.current.scrollHeight;
|
|
5112
5159
|
textareaRef.current.style.height = `${Math.min(scrollHeight, 200)}px`;
|
|
5113
5160
|
}
|
|
5114
5161
|
}, [value]);
|
|
5115
|
-
|
|
5162
|
+
react.useEffect(() => {
|
|
5116
5163
|
if (disabled) {
|
|
5117
5164
|
setIsFocused(false);
|
|
5118
5165
|
setShowActions(false);
|
|
@@ -5122,7 +5169,7 @@ var ChatInputV2 = React.forwardRef(
|
|
|
5122
5169
|
const frameId = requestAnimationFrame(() => textareaRef.current?.focus());
|
|
5123
5170
|
return () => cancelAnimationFrame(frameId);
|
|
5124
5171
|
}, [disabled]);
|
|
5125
|
-
|
|
5172
|
+
react.useImperativeHandle(
|
|
5126
5173
|
ref,
|
|
5127
5174
|
() => ({
|
|
5128
5175
|
setDraft: (message) => {
|
|
@@ -5139,7 +5186,7 @@ var ChatInputV2 = React.forwardRef(
|
|
|
5139
5186
|
}),
|
|
5140
5187
|
[disabled]
|
|
5141
5188
|
);
|
|
5142
|
-
|
|
5189
|
+
react.useEffect(() => {
|
|
5143
5190
|
if (!showActions) return;
|
|
5144
5191
|
const handleClickOutside = (e) => {
|
|
5145
5192
|
if (actionsRef.current && !actionsRef.current.contains(e.target)) {
|
|
@@ -5149,29 +5196,29 @@ var ChatInputV2 = React.forwardRef(
|
|
|
5149
5196
|
document.addEventListener("mousedown", handleClickOutside);
|
|
5150
5197
|
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
5151
5198
|
}, [showActions]);
|
|
5152
|
-
|
|
5199
|
+
react.useEffect(() => {
|
|
5153
5200
|
if (!showAttachmentMenuButton) {
|
|
5154
5201
|
setShowActions(false);
|
|
5155
5202
|
}
|
|
5156
5203
|
}, [showAttachmentMenuButton]);
|
|
5157
|
-
|
|
5204
|
+
react.useEffect(() => {
|
|
5158
5205
|
setSelectedCommandIndex(0);
|
|
5159
5206
|
setCommandMenuDismissed(false);
|
|
5160
5207
|
}, [commandQuery]);
|
|
5161
|
-
|
|
5208
|
+
react.useEffect(() => {
|
|
5162
5209
|
return () => {
|
|
5163
5210
|
if (voiceTooltipTimerRef.current) {
|
|
5164
5211
|
clearTimeout(voiceTooltipTimerRef.current);
|
|
5165
5212
|
}
|
|
5166
5213
|
};
|
|
5167
5214
|
}, []);
|
|
5168
|
-
|
|
5215
|
+
react.useEffect(() => {
|
|
5169
5216
|
if (!voiceDraftSyncActiveRef.current) return;
|
|
5170
5217
|
const base = preRecordTextRef.current;
|
|
5171
5218
|
const separator = base && !base.endsWith(" ") && transcribedText ? " " : "";
|
|
5172
5219
|
setValue(`${base}${separator}${transcribedText}`);
|
|
5173
5220
|
}, [isRecording, transcribedText]);
|
|
5174
|
-
const handleSend =
|
|
5221
|
+
const handleSend = react.useCallback(() => {
|
|
5175
5222
|
if (!value.trim() || disabled) return;
|
|
5176
5223
|
const commandHint = getSlashCommandValidationHint(value);
|
|
5177
5224
|
if (commandHint) {
|
|
@@ -5191,7 +5238,7 @@ var ChatInputV2 = React.forwardRef(
|
|
|
5191
5238
|
}
|
|
5192
5239
|
});
|
|
5193
5240
|
}, [value, disabled, onClearEditing, onSend]);
|
|
5194
|
-
const selectCommand =
|
|
5241
|
+
const selectCommand = react.useCallback(
|
|
5195
5242
|
(command) => {
|
|
5196
5243
|
const insertText = command.insertText ?? `${command.name} `;
|
|
5197
5244
|
setValue(insertText);
|
|
@@ -5247,14 +5294,14 @@ var ChatInputV2 = React.forwardRef(
|
|
|
5247
5294
|
onAttachFileClick?.();
|
|
5248
5295
|
setShowActions(false);
|
|
5249
5296
|
};
|
|
5250
|
-
const hideVoiceTooltip =
|
|
5297
|
+
const hideVoiceTooltip = react.useCallback(() => {
|
|
5251
5298
|
if (voiceTooltipTimerRef.current) {
|
|
5252
5299
|
clearTimeout(voiceTooltipTimerRef.current);
|
|
5253
5300
|
voiceTooltipTimerRef.current = null;
|
|
5254
5301
|
}
|
|
5255
5302
|
setShowVoiceTooltip(false);
|
|
5256
5303
|
}, []);
|
|
5257
|
-
const startVoiceTooltipTimer =
|
|
5304
|
+
const startVoiceTooltipTimer = react.useCallback(() => {
|
|
5258
5305
|
if (isVoiceButtonDisabled || isRecording) return;
|
|
5259
5306
|
if (voiceTooltipTimerRef.current) {
|
|
5260
5307
|
clearTimeout(voiceTooltipTimerRef.current);
|
|
@@ -5576,9 +5623,9 @@ var ChatInputV2 = React.forwardRef(
|
|
|
5576
5623
|
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
5624
|
var DEFAULT_SIZE = 36;
|
|
5578
5625
|
function useElapsedSeconds(isStreaming) {
|
|
5579
|
-
const [elapsed, setElapsed] =
|
|
5580
|
-
const startRef =
|
|
5581
|
-
|
|
5626
|
+
const [elapsed, setElapsed] = react.useState(0);
|
|
5627
|
+
const startRef = react.useRef(null);
|
|
5628
|
+
react.useEffect(() => {
|
|
5582
5629
|
if (!isStreaming) {
|
|
5583
5630
|
startRef.current = null;
|
|
5584
5631
|
setElapsed(0);
|
|
@@ -5637,22 +5684,22 @@ function StreamingIndicatorV2({
|
|
|
5637
5684
|
) });
|
|
5638
5685
|
}
|
|
5639
5686
|
function ImageLightboxV2({ src, alt, onClose }) {
|
|
5640
|
-
const [isMounted, setIsMounted] =
|
|
5641
|
-
const [isImageLoaded, setIsImageLoaded] =
|
|
5642
|
-
|
|
5687
|
+
const [isMounted, setIsMounted] = react.useState(false);
|
|
5688
|
+
const [isImageLoaded, setIsImageLoaded] = react.useState(false);
|
|
5689
|
+
react.useEffect(() => {
|
|
5643
5690
|
setIsMounted(true);
|
|
5644
5691
|
return () => setIsMounted(false);
|
|
5645
5692
|
}, []);
|
|
5646
|
-
|
|
5693
|
+
react.useEffect(() => {
|
|
5647
5694
|
setIsImageLoaded(false);
|
|
5648
5695
|
}, [src]);
|
|
5649
|
-
const handleKeyDown =
|
|
5696
|
+
const handleKeyDown = react.useCallback(
|
|
5650
5697
|
(e) => {
|
|
5651
5698
|
if (e.key === "Escape") onClose();
|
|
5652
5699
|
},
|
|
5653
5700
|
[onClose]
|
|
5654
5701
|
);
|
|
5655
|
-
|
|
5702
|
+
react.useEffect(() => {
|
|
5656
5703
|
if (!src || typeof document === "undefined") return;
|
|
5657
5704
|
document.addEventListener("keydown", handleKeyDown);
|
|
5658
5705
|
const previousOverflow = document.body.style.overflow;
|
|
@@ -5784,9 +5831,9 @@ var PRE_PIPELINE_STEPS = /* @__PURE__ */ new Set([
|
|
|
5784
5831
|
"build_pipeline",
|
|
5785
5832
|
"load_skill_index"
|
|
5786
5833
|
]);
|
|
5787
|
-
function stepColor(
|
|
5788
|
-
if (
|
|
5789
|
-
if (PRE_PIPELINE_STEPS.has(
|
|
5834
|
+
function stepColor(step2) {
|
|
5835
|
+
if (step2.status === "failed") return "#ef4444";
|
|
5836
|
+
if (PRE_PIPELINE_STEPS.has(step2.step)) return "#f59e0b";
|
|
5790
5837
|
return "#3b82f6";
|
|
5791
5838
|
}
|
|
5792
5839
|
function formatMs(ms) {
|
|
@@ -5801,10 +5848,10 @@ function TraceTimelineModal({
|
|
|
5801
5848
|
apiBaseUrl,
|
|
5802
5849
|
apiHeaders
|
|
5803
5850
|
}) {
|
|
5804
|
-
const [trace, setTrace] =
|
|
5805
|
-
const [loading, setLoading] =
|
|
5806
|
-
const [error, setError] =
|
|
5807
|
-
|
|
5851
|
+
const [trace, setTrace] = react.useState(null);
|
|
5852
|
+
const [loading, setLoading] = react.useState(false);
|
|
5853
|
+
const [error, setError] = react.useState(null);
|
|
5854
|
+
react.useEffect(() => {
|
|
5808
5855
|
if (!open || !executionId) return;
|
|
5809
5856
|
const ctrl = new AbortController();
|
|
5810
5857
|
setLoading(true);
|
|
@@ -5826,7 +5873,7 @@ function TraceTimelineModal({
|
|
|
5826
5873
|
}).finally(() => setLoading(false));
|
|
5827
5874
|
return () => ctrl.abort();
|
|
5828
5875
|
}, [open, executionId, apiBaseUrl, apiHeaders]);
|
|
5829
|
-
const totalMs =
|
|
5876
|
+
const totalMs = react.useMemo(() => {
|
|
5830
5877
|
if (!trace) return 0;
|
|
5831
5878
|
const meta = trace.runMetadata?.totalTimeMs;
|
|
5832
5879
|
if (typeof meta === "number" && meta > 0) return meta;
|
|
@@ -5835,7 +5882,7 @@ function TraceTimelineModal({
|
|
|
5835
5882
|
if (starts.length === 0 || ends.length === 0) return 0;
|
|
5836
5883
|
return Math.max(...ends) - Math.min(...starts);
|
|
5837
5884
|
}, [trace]);
|
|
5838
|
-
const accountedMs =
|
|
5885
|
+
const accountedMs = react.useMemo(
|
|
5839
5886
|
() => (trace?.pipelineSteps ?? []).reduce(
|
|
5840
5887
|
(sum, s) => sum + (s.durationMs ?? 0),
|
|
5841
5888
|
0
|
|
@@ -5963,10 +6010,10 @@ function TimelineBars({
|
|
|
5963
6010
|
totalMs,
|
|
5964
6011
|
unaccountedMs
|
|
5965
6012
|
}) {
|
|
5966
|
-
const bars = trace.pipelineSteps.map((
|
|
5967
|
-
const duration =
|
|
6013
|
+
const bars = trace.pipelineSteps.map((step2) => {
|
|
6014
|
+
const duration = step2.durationMs ?? 0;
|
|
5968
6015
|
const widthPct = totalMs > 0 ? duration / totalMs * 100 : 0;
|
|
5969
|
-
const llmMs =
|
|
6016
|
+
const llmMs = step2.llmCall?.durationMs ?? null;
|
|
5970
6017
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { marginBottom: 8 }, children: [
|
|
5971
6018
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
5972
6019
|
"div",
|
|
@@ -5980,8 +6027,8 @@ function TimelineBars({
|
|
|
5980
6027
|
},
|
|
5981
6028
|
children: [
|
|
5982
6029
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
5983
|
-
|
|
5984
|
-
|
|
6030
|
+
step2.step,
|
|
6031
|
+
step2.status === "failed" && /* @__PURE__ */ jsxRuntime.jsx("span", { style: { color: "#fca5a5", marginLeft: 6 }, children: "(failed)" })
|
|
5985
6032
|
] }),
|
|
5986
6033
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { style: { opacity: 0.75 }, children: [
|
|
5987
6034
|
formatMs(duration),
|
|
@@ -6009,14 +6056,14 @@ function TimelineBars({
|
|
|
6009
6056
|
style: {
|
|
6010
6057
|
height: "100%",
|
|
6011
6058
|
width: `${Math.max(widthPct, 0.3)}%`,
|
|
6012
|
-
background: stepColor(
|
|
6059
|
+
background: stepColor(step2),
|
|
6013
6060
|
transition: "width 0.2s ease"
|
|
6014
6061
|
}
|
|
6015
6062
|
}
|
|
6016
6063
|
)
|
|
6017
6064
|
}
|
|
6018
6065
|
)
|
|
6019
|
-
] }, `${
|
|
6066
|
+
] }, `${step2.step}-${step2.startTime}`);
|
|
6020
6067
|
});
|
|
6021
6068
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
6022
6069
|
bars,
|
|
@@ -6096,12 +6143,12 @@ var NOOP_ASYNC = async () => {
|
|
|
6096
6143
|
var NOOP = () => {
|
|
6097
6144
|
};
|
|
6098
6145
|
function useSentryChatCallbacks(callbacks, config) {
|
|
6099
|
-
const sentryCtxRef =
|
|
6100
|
-
const callbacksRef =
|
|
6146
|
+
const sentryCtxRef = react.useRef({});
|
|
6147
|
+
const callbacksRef = react.useRef(callbacks);
|
|
6101
6148
|
callbacksRef.current = callbacks;
|
|
6102
6149
|
const initialSessionId = config.initialSessionId;
|
|
6103
6150
|
const apiHeaders = config.api.headers;
|
|
6104
|
-
|
|
6151
|
+
react.useEffect(() => {
|
|
6105
6152
|
sentryCtxRef.current.agentId = config.agentId;
|
|
6106
6153
|
sentryCtxRef.current.sessionOwnerId = config.sessionParams?.id;
|
|
6107
6154
|
if (initialSessionId) {
|
|
@@ -6117,13 +6164,13 @@ function useSentryChatCallbacks(callbacks, config) {
|
|
|
6117
6164
|
initialSessionId,
|
|
6118
6165
|
apiHeaders
|
|
6119
6166
|
]);
|
|
6120
|
-
|
|
6167
|
+
react.useEffect(() => {
|
|
6121
6168
|
const endpoint = config.api.streamEndpoint || "/api/playground/ask/stream";
|
|
6122
6169
|
return subscribeToCfRay(endpoint, (cfRay) => {
|
|
6123
6170
|
sentryCtxRef.current.cfRay = cfRay;
|
|
6124
6171
|
});
|
|
6125
6172
|
}, [config.api.streamEndpoint]);
|
|
6126
|
-
return
|
|
6173
|
+
return react.useMemo(
|
|
6127
6174
|
() => ({
|
|
6128
6175
|
onMessageSent: (msg) => callbacksRef.current?.onMessageSent?.(msg),
|
|
6129
6176
|
onStreamStart: () => callbacksRef.current?.onStreamStart?.(),
|
|
@@ -6172,7 +6219,7 @@ function useSentryChatCallbacks(callbacks, config) {
|
|
|
6172
6219
|
[]
|
|
6173
6220
|
);
|
|
6174
6221
|
}
|
|
6175
|
-
var PaymanChatInner =
|
|
6222
|
+
var PaymanChatInner = react.forwardRef(function PaymanChatInner2({
|
|
6176
6223
|
config,
|
|
6177
6224
|
callbacks = {},
|
|
6178
6225
|
className,
|
|
@@ -6183,18 +6230,18 @@ var PaymanChatInner = React.forwardRef(function PaymanChatInner2({
|
|
|
6183
6230
|
hasMoreMessages = false,
|
|
6184
6231
|
chat
|
|
6185
6232
|
}, 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
|
-
|
|
6233
|
+
const [inputValue, setInputValue] = react.useState("");
|
|
6234
|
+
const prevInputValueRef = react.useRef(inputValue);
|
|
6235
|
+
const [hasEverSentMessage, setHasEverSentMessage] = react.useState(false);
|
|
6236
|
+
const [lightboxSrc, setLightboxSrc] = react.useState(null);
|
|
6237
|
+
const [lightboxAlt, setLightboxAlt] = react.useState("");
|
|
6238
|
+
const [editingMessageId, setEditingMessageId] = react.useState(null);
|
|
6239
|
+
const [isResetSessionConfirmOpen, setIsResetSessionConfirmOpen] = react.useState(false);
|
|
6240
|
+
const [analysisMode, setAnalysisMode] = react.useState("fast");
|
|
6241
|
+
const chatInputV2Ref = react.useRef(null);
|
|
6242
|
+
const messageListV2Ref = react.useRef(null);
|
|
6243
|
+
const resetToEmptyStateRef = react.useRef(false);
|
|
6244
|
+
react.useEffect(() => {
|
|
6198
6245
|
if (config.sentryDsn) {
|
|
6199
6246
|
initSentryIfNeeded(config.sentryDsn);
|
|
6200
6247
|
}
|
|
@@ -6210,7 +6257,7 @@ var PaymanChatInner = React.forwardRef(function PaymanChatInner2({
|
|
|
6210
6257
|
getSessionId,
|
|
6211
6258
|
getMessages
|
|
6212
6259
|
} = chat;
|
|
6213
|
-
|
|
6260
|
+
react.useEffect(() => {
|
|
6214
6261
|
if (resetToEmptyStateRef.current) {
|
|
6215
6262
|
if (messages.length === 0) {
|
|
6216
6263
|
setHasEverSentMessage(false);
|
|
@@ -6222,7 +6269,7 @@ var PaymanChatInner = React.forwardRef(function PaymanChatInner2({
|
|
|
6222
6269
|
setHasEverSentMessage(true);
|
|
6223
6270
|
}
|
|
6224
6271
|
}, [messages.length, hasEverSentMessage]);
|
|
6225
|
-
|
|
6272
|
+
react.useEffect(() => {
|
|
6226
6273
|
if (!editingMessageId) return;
|
|
6227
6274
|
const editingMessageStillExists = messages.some(
|
|
6228
6275
|
(message) => message.id === editingMessageId && message.role === "user"
|
|
@@ -6261,7 +6308,7 @@ var PaymanChatInner = React.forwardRef(function PaymanChatInner2({
|
|
|
6261
6308
|
}
|
|
6262
6309
|
}
|
|
6263
6310
|
);
|
|
6264
|
-
const contextValue =
|
|
6311
|
+
const contextValue = react.useMemo(
|
|
6265
6312
|
() => ({
|
|
6266
6313
|
resetSession,
|
|
6267
6314
|
clearMessages,
|
|
@@ -6288,8 +6335,8 @@ var PaymanChatInner = React.forwardRef(function PaymanChatInner2({
|
|
|
6288
6335
|
onAttachFileClick,
|
|
6289
6336
|
onMessageFeedback
|
|
6290
6337
|
} = callbacks;
|
|
6291
|
-
const [debugTraceExecutionId, setDebugTraceExecutionId] =
|
|
6292
|
-
const handleSubmitFeedback =
|
|
6338
|
+
const [debugTraceExecutionId, setDebugTraceExecutionId] = react.useState(null);
|
|
6339
|
+
const handleSubmitFeedback = react.useCallback(
|
|
6293
6340
|
async ({ messageId, executionId, feedback, details }) => {
|
|
6294
6341
|
if (!executionId) {
|
|
6295
6342
|
throw new Error("Cannot submit feedback before the response completes");
|
|
@@ -6320,14 +6367,14 @@ var PaymanChatInner = React.forwardRef(function PaymanChatInner2({
|
|
|
6320
6367
|
onMessageFeedback
|
|
6321
6368
|
]
|
|
6322
6369
|
);
|
|
6323
|
-
const onExecutionTraceClick =
|
|
6370
|
+
const onExecutionTraceClick = react.useMemo(() => {
|
|
6324
6371
|
if (!config.debug) return rawOnExecutionTraceClick;
|
|
6325
6372
|
return (data) => {
|
|
6326
6373
|
rawOnExecutionTraceClick?.(data);
|
|
6327
6374
|
if (data.executionId) setDebugTraceExecutionId(data.executionId);
|
|
6328
6375
|
};
|
|
6329
6376
|
}, [config.debug, rawOnExecutionTraceClick]);
|
|
6330
|
-
const performResetSession =
|
|
6377
|
+
const performResetSession = react.useCallback(() => {
|
|
6331
6378
|
resetToEmptyStateRef.current = true;
|
|
6332
6379
|
setEditingMessageId(null);
|
|
6333
6380
|
setIsResetSessionConfirmOpen(false);
|
|
@@ -6348,13 +6395,13 @@ var PaymanChatInner = React.forwardRef(function PaymanChatInner2({
|
|
|
6348
6395
|
resetSession,
|
|
6349
6396
|
stopRecording
|
|
6350
6397
|
]);
|
|
6351
|
-
const requestResetSession =
|
|
6398
|
+
const requestResetSession = react.useCallback(() => {
|
|
6352
6399
|
setIsResetSessionConfirmOpen(true);
|
|
6353
6400
|
}, []);
|
|
6354
|
-
const closeResetSessionConfirm =
|
|
6401
|
+
const closeResetSessionConfirm = react.useCallback(() => {
|
|
6355
6402
|
setIsResetSessionConfirmOpen(false);
|
|
6356
6403
|
}, []);
|
|
6357
|
-
|
|
6404
|
+
react.useImperativeHandle(ref, () => ({
|
|
6358
6405
|
resetSession: performResetSession,
|
|
6359
6406
|
clearMessages,
|
|
6360
6407
|
cancelStream,
|
|
@@ -6393,7 +6440,7 @@ var PaymanChatInner = React.forwardRef(function PaymanChatInner2({
|
|
|
6393
6440
|
slashCommands: slashCommandsConfig,
|
|
6394
6441
|
commandPermissions
|
|
6395
6442
|
} = config;
|
|
6396
|
-
const messageActions =
|
|
6443
|
+
const messageActions = react.useMemo(
|
|
6397
6444
|
() => ({
|
|
6398
6445
|
userMessageActions: {
|
|
6399
6446
|
copy: messageActionsConfig?.userMessageActions?.copy ?? true,
|
|
@@ -6409,18 +6456,18 @@ var PaymanChatInner = React.forwardRef(function PaymanChatInner2({
|
|
|
6409
6456
|
}),
|
|
6410
6457
|
[messageActionsConfig]
|
|
6411
6458
|
);
|
|
6412
|
-
const slashCommands =
|
|
6459
|
+
const slashCommands = react.useMemo(
|
|
6413
6460
|
() => enableSlashCommands ? filterSlashCommands(
|
|
6414
6461
|
slashCommandsConfig ?? DEFAULT_SLASH_COMMANDS,
|
|
6415
6462
|
commandPermissions
|
|
6416
6463
|
) : [],
|
|
6417
6464
|
[commandPermissions, enableSlashCommands, slashCommandsConfig]
|
|
6418
6465
|
);
|
|
6419
|
-
const isSessionParamsConfigured =
|
|
6466
|
+
const isSessionParamsConfigured = react.useMemo(() => {
|
|
6420
6467
|
if (!sessionParams) return false;
|
|
6421
6468
|
return !!(sessionParams.id?.trim() && sessionParams.name?.trim());
|
|
6422
6469
|
}, [sessionParams?.id, sessionParams?.name]);
|
|
6423
|
-
|
|
6470
|
+
react.useEffect(() => {
|
|
6424
6471
|
const wasEmpty = prevInputValueRef.current.trim() === "";
|
|
6425
6472
|
const isEmpty2 = inputValue.trim() === "";
|
|
6426
6473
|
prevInputValueRef.current = inputValue;
|
|
@@ -6487,7 +6534,7 @@ var PaymanChatInner = React.forwardRef(function PaymanChatInner2({
|
|
|
6487
6534
|
void sendMessage(text.trim(), { analysisMode: effectiveAnalysisMode });
|
|
6488
6535
|
}
|
|
6489
6536
|
};
|
|
6490
|
-
const handleVoicePress =
|
|
6537
|
+
const handleVoicePress = react.useCallback(async () => {
|
|
6491
6538
|
if (!voiceAvailable) return;
|
|
6492
6539
|
if (isRecording) {
|
|
6493
6540
|
stopRecording();
|
|
@@ -6496,7 +6543,7 @@ var PaymanChatInner = React.forwardRef(function PaymanChatInner2({
|
|
|
6496
6543
|
clearTranscript();
|
|
6497
6544
|
await startRecording();
|
|
6498
6545
|
}, [clearTranscript, isRecording, startRecording, stopRecording, voiceAvailable]);
|
|
6499
|
-
const handleEditMessageDraft =
|
|
6546
|
+
const handleEditMessageDraft = react.useCallback((messageId) => {
|
|
6500
6547
|
const targetMessage = messages.find((message) => message.id === messageId);
|
|
6501
6548
|
if (!targetMessage?.content.trim()) return;
|
|
6502
6549
|
setEditingMessageId(messageId);
|
|
@@ -6505,7 +6552,7 @@ var PaymanChatInner = React.forwardRef(function PaymanChatInner2({
|
|
|
6505
6552
|
messageListV2Ref.current?.scrollToBottom("smooth");
|
|
6506
6553
|
});
|
|
6507
6554
|
}, [messages]);
|
|
6508
|
-
const handleRetryUserMessage =
|
|
6555
|
+
const handleRetryUserMessage = react.useCallback((messageId) => {
|
|
6509
6556
|
if (isWaitingForResponse) return;
|
|
6510
6557
|
const targetMessage = messages.find(
|
|
6511
6558
|
(message) => message.id === messageId && message.role === "user"
|
|
@@ -6522,7 +6569,7 @@ var PaymanChatInner = React.forwardRef(function PaymanChatInner2({
|
|
|
6522
6569
|
});
|
|
6523
6570
|
});
|
|
6524
6571
|
}, [isWaitingForResponse, messages, sendMessage, effectiveAnalysisMode]);
|
|
6525
|
-
const handleClearEditing =
|
|
6572
|
+
const handleClearEditing = react.useCallback(() => {
|
|
6526
6573
|
setEditingMessageId(null);
|
|
6527
6574
|
}, []);
|
|
6528
6575
|
return /* @__PURE__ */ jsxRuntime.jsx(PaymanChatContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
@@ -6712,7 +6759,7 @@ var PaymanChatInner = React.forwardRef(function PaymanChatInner2({
|
|
|
6712
6759
|
}
|
|
6713
6760
|
) });
|
|
6714
6761
|
});
|
|
6715
|
-
var PaymanChat =
|
|
6762
|
+
var PaymanChat = react.forwardRef(
|
|
6716
6763
|
function PaymanChat2(props, ref) {
|
|
6717
6764
|
const mergedCallbacks = useSentryChatCallbacks(props.callbacks, props.config);
|
|
6718
6765
|
const chat = useChatV2(props.config, mergedCallbacks);
|