@paymanai/payman-ask-sdk 4.0.24 → 4.0.26
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 +503 -439
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +247 -183
- package/dist/index.mjs.map +1 -1
- package/dist/index.native.js +154 -192
- package/dist/index.native.js.map +1 -1
- package/dist/styles.css +30 -0
- package/dist/styles.css.map +1 -1
- package/package.json +3 -2
package/dist/index.mjs
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
1
2
|
import { createContext, forwardRef, useCallback, useRef, useState, useMemo, useEffect, useImperativeHandle, useLayoutEffect, useContext } from 'react';
|
|
2
3
|
import { AnimatePresence, motion } from 'framer-motion';
|
|
3
4
|
import { clsx } from 'clsx';
|
|
@@ -33,6 +34,7 @@ var chatStore = {
|
|
|
33
34
|
memoryStore.delete(key);
|
|
34
35
|
}
|
|
35
36
|
};
|
|
37
|
+
var EMPTY_USER_ACTION_STATE = { prompts: [], notifications: [] };
|
|
36
38
|
var streams = /* @__PURE__ */ new Map();
|
|
37
39
|
var activeStreamStore = {
|
|
38
40
|
has(key) {
|
|
@@ -41,7 +43,11 @@ var activeStreamStore = {
|
|
|
41
43
|
get(key) {
|
|
42
44
|
const entry = streams.get(key);
|
|
43
45
|
if (!entry) return null;
|
|
44
|
-
return {
|
|
46
|
+
return {
|
|
47
|
+
messages: entry.messages,
|
|
48
|
+
isWaiting: entry.isWaiting,
|
|
49
|
+
userActionState: entry.userActionState
|
|
50
|
+
};
|
|
45
51
|
},
|
|
46
52
|
// Called before startStream — registers the controller and initial messages
|
|
47
53
|
start(key, abortController, initialMessages) {
|
|
@@ -49,6 +55,7 @@ var activeStreamStore = {
|
|
|
49
55
|
streams.set(key, {
|
|
50
56
|
messages: initialMessages,
|
|
51
57
|
isWaiting: true,
|
|
58
|
+
userActionState: EMPTY_USER_ACTION_STATE,
|
|
52
59
|
abortController,
|
|
53
60
|
listeners: existing?.listeners ?? /* @__PURE__ */ new Set()
|
|
54
61
|
});
|
|
@@ -59,20 +66,27 @@ var activeStreamStore = {
|
|
|
59
66
|
if (!entry) return;
|
|
60
67
|
const next = typeof updater === "function" ? updater(entry.messages) : updater;
|
|
61
68
|
entry.messages = next;
|
|
62
|
-
entry.listeners.forEach((l) => l(next, entry.isWaiting));
|
|
69
|
+
entry.listeners.forEach((l) => l(next, entry.isWaiting, entry.userActionState));
|
|
63
70
|
},
|
|
64
71
|
setWaiting(key, waiting) {
|
|
65
72
|
const entry = streams.get(key);
|
|
66
73
|
if (!entry) return;
|
|
67
74
|
entry.isWaiting = waiting;
|
|
68
|
-
entry.listeners.forEach((l) => l(entry.messages, waiting));
|
|
75
|
+
entry.listeners.forEach((l) => l(entry.messages, waiting, entry.userActionState));
|
|
76
|
+
},
|
|
77
|
+
applyUserActionState(key, updater) {
|
|
78
|
+
const entry = streams.get(key);
|
|
79
|
+
if (!entry) return;
|
|
80
|
+
const next = typeof updater === "function" ? updater(entry.userActionState) : updater;
|
|
81
|
+
entry.userActionState = next;
|
|
82
|
+
entry.listeners.forEach((l) => l(entry.messages, entry.isWaiting, next));
|
|
69
83
|
},
|
|
70
84
|
// Called when stream completes — persists to chatStore and cleans up
|
|
71
85
|
complete(key) {
|
|
72
86
|
const entry = streams.get(key);
|
|
73
87
|
if (!entry) return;
|
|
74
88
|
entry.isWaiting = false;
|
|
75
|
-
entry.listeners.forEach((l) => l(entry.messages, false));
|
|
89
|
+
entry.listeners.forEach((l) => l(entry.messages, false, entry.userActionState));
|
|
76
90
|
const toSave = entry.messages.filter((m) => !m.isStreaming);
|
|
77
91
|
if (toSave.length > 0) chatStore.set(key, toSave);
|
|
78
92
|
streams.delete(key);
|
|
@@ -260,6 +274,8 @@ function getEventMessage(event) {
|
|
|
260
274
|
}
|
|
261
275
|
case "RUN_IN_PROGRESS":
|
|
262
276
|
return event.partialText || "Thinking...";
|
|
277
|
+
case "LLM_CALL_STARTED":
|
|
278
|
+
return event.description || "";
|
|
263
279
|
case "RUN_COMPLETED":
|
|
264
280
|
return "Agent run completed";
|
|
265
281
|
case "RUN_FAILED":
|
|
@@ -397,7 +413,8 @@ function createInitialV2State() {
|
|
|
397
413
|
finalData: void 0,
|
|
398
414
|
steps: [],
|
|
399
415
|
stepCounter: 0,
|
|
400
|
-
currentExecutingStepId: void 0
|
|
416
|
+
currentExecutingStepId: void 0,
|
|
417
|
+
trailingActivity: false
|
|
401
418
|
};
|
|
402
419
|
}
|
|
403
420
|
function upsertUserAction(state, req) {
|
|
@@ -419,6 +436,7 @@ function processStreamEventV2(rawEvent, state) {
|
|
|
419
436
|
if (typeof eventType === "string" && eventType.toUpperCase() === "KEEP_ALIVE") {
|
|
420
437
|
if (event.executionId) state.executionId = event.executionId;
|
|
421
438
|
if (event.sessionId) state.sessionId = event.sessionId;
|
|
439
|
+
if (state.finalResponse) state.trailingActivity = true;
|
|
422
440
|
const description = typeof event.description === "string" ? event.description : "";
|
|
423
441
|
if (description) {
|
|
424
442
|
for (let i = state.steps.length - 1; i >= 0; i--) {
|
|
@@ -453,7 +471,12 @@ function processStreamEventV2(rawEvent, state) {
|
|
|
453
471
|
state.lastEventType = eventType;
|
|
454
472
|
break;
|
|
455
473
|
}
|
|
474
|
+
case "LLM_CALL_STARTED":
|
|
475
|
+
if (state.finalResponse) state.trailingActivity = true;
|
|
476
|
+
state.lastEventType = eventType;
|
|
477
|
+
break;
|
|
456
478
|
case "INTENT_STARTED": {
|
|
479
|
+
if (state.finalResponse) state.trailingActivity = true;
|
|
457
480
|
const stepId = `step-${state.stepCounter++}`;
|
|
458
481
|
state.steps.push({
|
|
459
482
|
id: stepId,
|
|
@@ -469,6 +492,7 @@ function processStreamEventV2(rawEvent, state) {
|
|
|
469
492
|
break;
|
|
470
493
|
}
|
|
471
494
|
case "INTENT_COMPLETED": {
|
|
495
|
+
if (state.finalResponse) state.trailingActivity = true;
|
|
472
496
|
const intentStep = state.steps.find((s) => s.eventType === "INTENT_STARTED" && s.status === "in_progress");
|
|
473
497
|
if (intentStep) {
|
|
474
498
|
intentStep.status = "completed";
|
|
@@ -500,6 +524,7 @@ function processStreamEventV2(rawEvent, state) {
|
|
|
500
524
|
step2.status = "completed";
|
|
501
525
|
}
|
|
502
526
|
});
|
|
527
|
+
state.trailingActivity = false;
|
|
503
528
|
state.lastEventType = eventType;
|
|
504
529
|
break;
|
|
505
530
|
}
|
|
@@ -571,6 +596,7 @@ function processStreamEventV2(rawEvent, state) {
|
|
|
571
596
|
case "WORKFLOW_ERROR":
|
|
572
597
|
state.hasError = true;
|
|
573
598
|
state.errorMessage = event.errorMessage || event.message || "Workflow error";
|
|
599
|
+
state.trailingActivity = false;
|
|
574
600
|
state.lastEventType = eventType;
|
|
575
601
|
break;
|
|
576
602
|
// ---- K2 pipeline stage lifecycle events ----
|
|
@@ -709,8 +735,7 @@ function buildRequestBody(config, userMessage, sessionId, options) {
|
|
|
709
735
|
sessionAttributes,
|
|
710
736
|
analysisMode: options?.analysisMode,
|
|
711
737
|
locale: resolveLocale(config.locale),
|
|
712
|
-
timezone: resolveTimezone(config.timezone)
|
|
713
|
-
...options?.attachments?.length ? { attachments: options.attachments } : {}
|
|
738
|
+
timezone: resolveTimezone(config.timezone)
|
|
714
739
|
};
|
|
715
740
|
}
|
|
716
741
|
function resolveLocale(configured) {
|
|
@@ -755,7 +780,6 @@ function buildResolveImagesUrl(config) {
|
|
|
755
780
|
const basePath = normalizedEndpointPath.endsWith("/stream") ? normalizedEndpointPath.slice(0, -"/stream".length) : normalizedEndpointPath;
|
|
756
781
|
return `${config.api.baseUrl}${basePath}/resolve-image-urls`;
|
|
757
782
|
}
|
|
758
|
-
var NGROK_SKIP_BROWSER_WARNING = "ngrok-skip-browser-warning";
|
|
759
783
|
function buildRequestHeaders(config) {
|
|
760
784
|
const headers = {
|
|
761
785
|
...config.api.headers
|
|
@@ -763,9 +787,6 @@ function buildRequestHeaders(config) {
|
|
|
763
787
|
if (config.api.authToken) {
|
|
764
788
|
headers.Authorization = `Bearer ${config.api.authToken}`;
|
|
765
789
|
}
|
|
766
|
-
if (!headers[NGROK_SKIP_BROWSER_WARNING]) {
|
|
767
|
-
headers[NGROK_SKIP_BROWSER_WARNING] = "true";
|
|
768
|
-
}
|
|
769
790
|
return headers;
|
|
770
791
|
}
|
|
771
792
|
var RAG_IMAGE_REGEX = /\/api\/rag\/chunks\/[^"'\s]+\/image/;
|
|
@@ -864,7 +885,9 @@ function useStreamManagerV2(config, callbacks, setMessages, setIsWaitingForRespo
|
|
|
864
885
|
const latestUsefulStep = [...state.steps].reverse().find(
|
|
865
886
|
(s) => s.message && !isBlandStatus(s.message)
|
|
866
887
|
);
|
|
867
|
-
const
|
|
888
|
+
const eventTypeUpper = typeof event.eventType === "string" ? event.eventType.toUpperCase() : "";
|
|
889
|
+
const liveEventLabel = eventTypeUpper === "KEEP_ALIVE" || eventTypeUpper === "LLM_CALL_STARTED" ? useful(getEventMessage(event)) : void 0;
|
|
890
|
+
const currentMessage = useful(activeStep?.message) ?? useful(lastInProgressStep?.message) ?? liveEventLabel ?? latestUsefulStep?.message ?? useful(getEventMessage(event)) ?? // Last-resort: every candidate is bland (very first event,
|
|
868
891
|
// nothing useful seen yet). Render the bland label so the
|
|
869
892
|
// bubble isn't blank.
|
|
870
893
|
activeStep?.message ?? lastInProgressStep?.message ?? getEventMessage(event);
|
|
@@ -889,6 +912,7 @@ function useStreamManagerV2(config, callbacks, setMessages, setIsWaitingForRespo
|
|
|
889
912
|
streamingContent: state.finalResponse,
|
|
890
913
|
content: "",
|
|
891
914
|
currentMessage,
|
|
915
|
+
hasTrailingActivity: state.trailingActivity,
|
|
892
916
|
streamProgress: "processing",
|
|
893
917
|
isError: false,
|
|
894
918
|
steps: [...state.steps],
|
|
@@ -1046,81 +1070,6 @@ function createCancelledMessageUpdate(steps, currentMessage) {
|
|
|
1046
1070
|
currentMessage: currentMessage || "Thinking..."
|
|
1047
1071
|
};
|
|
1048
1072
|
}
|
|
1049
|
-
var DEFAULT_SIGNED_URL_ENDPOINT = "/api/files/signed-url";
|
|
1050
|
-
function fileExtension(filename) {
|
|
1051
|
-
const ext = filename.split(".").pop()?.toLowerCase().replace(/^\./, "");
|
|
1052
|
-
return ext && ext.length > 0 ? ext : "bin";
|
|
1053
|
-
}
|
|
1054
|
-
function resolveMimeType(file) {
|
|
1055
|
-
if (file.type && file.type.trim().length > 0) return file.type;
|
|
1056
|
-
const ext = fileExtension(file.name);
|
|
1057
|
-
const byExt = {
|
|
1058
|
-
pdf: "application/pdf",
|
|
1059
|
-
png: "image/png",
|
|
1060
|
-
jpg: "image/jpeg",
|
|
1061
|
-
jpeg: "image/jpeg",
|
|
1062
|
-
gif: "image/gif",
|
|
1063
|
-
webp: "image/webp"
|
|
1064
|
-
};
|
|
1065
|
-
return byExt[ext] ?? "application/octet-stream";
|
|
1066
|
-
}
|
|
1067
|
-
function buildSignedUrlEndpoint(config, ext) {
|
|
1068
|
-
const endpoint = config.api.signedUrlEndpoint || DEFAULT_SIGNED_URL_ENDPOINT;
|
|
1069
|
-
const queryParams = new URLSearchParams({ extn: ext.replace(/^\./, "") });
|
|
1070
|
-
return `${config.api.baseUrl}${endpoint}?${queryParams.toString()}`;
|
|
1071
|
-
}
|
|
1072
|
-
async function requestSignedUrl(config, ext, signal) {
|
|
1073
|
-
const url = buildSignedUrlEndpoint(config, ext);
|
|
1074
|
-
const headers = buildRequestHeaders(config);
|
|
1075
|
-
const response = await fetch(url, {
|
|
1076
|
-
method: "GET",
|
|
1077
|
-
headers,
|
|
1078
|
-
signal
|
|
1079
|
-
});
|
|
1080
|
-
if (!response.ok) {
|
|
1081
|
-
const errorText = await response.text().catch(() => "");
|
|
1082
|
-
throw new Error(
|
|
1083
|
-
errorText ? `Failed to get upload URL (${response.status}): ${errorText}` : `Failed to get upload URL (${response.status})`
|
|
1084
|
-
);
|
|
1085
|
-
}
|
|
1086
|
-
const data = await response.json();
|
|
1087
|
-
if (!data.key || !data.url) {
|
|
1088
|
-
throw new Error("Signed URL response missing key or url");
|
|
1089
|
-
}
|
|
1090
|
-
return { key: data.key, url: data.url };
|
|
1091
|
-
}
|
|
1092
|
-
async function uploadToSignedUrl(signedUrl, file, mimeType, signal) {
|
|
1093
|
-
const response = await fetch(signedUrl, {
|
|
1094
|
-
method: "PUT",
|
|
1095
|
-
headers: {
|
|
1096
|
-
"Content-Type": mimeType,
|
|
1097
|
-
"x-ms-blob-type": "BlockBlob"
|
|
1098
|
-
},
|
|
1099
|
-
body: file,
|
|
1100
|
-
signal
|
|
1101
|
-
});
|
|
1102
|
-
if (!response.ok) {
|
|
1103
|
-
const errorText = await response.text().catch(() => "");
|
|
1104
|
-
throw new Error(
|
|
1105
|
-
errorText ? `Failed to upload file (${response.status}): ${errorText}` : `Failed to upload file (${response.status})`
|
|
1106
|
-
);
|
|
1107
|
-
}
|
|
1108
|
-
}
|
|
1109
|
-
async function uploadAttachment(config, file, signal) {
|
|
1110
|
-
const ext = fileExtension(file.name);
|
|
1111
|
-
const mimeType = resolveMimeType(file);
|
|
1112
|
-
const { key, url } = await requestSignedUrl(config, ext, signal);
|
|
1113
|
-
await uploadToSignedUrl(url, file, mimeType, signal);
|
|
1114
|
-
return {
|
|
1115
|
-
tempKey: key,
|
|
1116
|
-
filename: file.name,
|
|
1117
|
-
mimeType
|
|
1118
|
-
};
|
|
1119
|
-
}
|
|
1120
|
-
async function uploadAttachments(config, files, signal) {
|
|
1121
|
-
const uploads = files.map((file) => uploadAttachment(config, file, signal));
|
|
1122
|
-
return Promise.all(uploads);
|
|
1123
|
-
}
|
|
1124
1073
|
var UserActionStaleError = class extends Error {
|
|
1125
1074
|
constructor(userActionId, message = "User action is no longer actionable") {
|
|
1126
1075
|
super(message);
|
|
@@ -1157,12 +1106,34 @@ async function cancelUserAction(config, userActionId) {
|
|
|
1157
1106
|
async function resendUserAction(config, userActionId) {
|
|
1158
1107
|
return sendUserActionRequest(config, userActionId, "resend");
|
|
1159
1108
|
}
|
|
1160
|
-
|
|
1109
|
+
async function expireUserAction(config, userActionId) {
|
|
1110
|
+
return sendUserActionRequest(config, userActionId, "expired");
|
|
1111
|
+
}
|
|
1112
|
+
function resolveUserActionExpiresAt(req, existing) {
|
|
1113
|
+
if (typeof req.expirySeconds !== "number" || req.expirySeconds <= 0) {
|
|
1114
|
+
return void 0;
|
|
1115
|
+
}
|
|
1116
|
+
if (existing?.expiresAt && existing.userActionId === req.userActionId) {
|
|
1117
|
+
return existing.expiresAt;
|
|
1118
|
+
}
|
|
1119
|
+
return Date.now() + Math.floor(req.expirySeconds) * 1e3;
|
|
1120
|
+
}
|
|
1121
|
+
function getUserActionSecondsLeft(prompt) {
|
|
1122
|
+
if (typeof prompt.expiresAt === "number" && prompt.expiresAt > 0) {
|
|
1123
|
+
return Math.max(0, Math.ceil((prompt.expiresAt - Date.now()) / 1e3));
|
|
1124
|
+
}
|
|
1125
|
+
if (typeof prompt.expirySeconds === "number" && prompt.expirySeconds > 0) {
|
|
1126
|
+
return Math.floor(prompt.expirySeconds);
|
|
1127
|
+
}
|
|
1128
|
+
return void 0;
|
|
1129
|
+
}
|
|
1130
|
+
var EMPTY_USER_ACTION_STATE2 = { prompts: [], notifications: [] };
|
|
1161
1131
|
function upsertPrompt(prompts, req) {
|
|
1162
|
-
const active = { ...req, status: "pending" };
|
|
1163
1132
|
const idx = prompts.findIndex(
|
|
1164
1133
|
(p) => req.toolCallId ? p.toolCallId === req.toolCallId : p.userActionId === req.userActionId
|
|
1165
1134
|
);
|
|
1135
|
+
const expiresAt = resolveUserActionExpiresAt(req, idx >= 0 ? prompts[idx] : void 0);
|
|
1136
|
+
const active = { ...req, status: "pending", expiresAt };
|
|
1166
1137
|
if (idx >= 0) {
|
|
1167
1138
|
const next = prompts.slice();
|
|
1168
1139
|
next[idx] = active;
|
|
@@ -1185,32 +1156,12 @@ function getStoredOrInitialMessages(config) {
|
|
|
1185
1156
|
function getSessionIdFromMessages(messages) {
|
|
1186
1157
|
return messages.find((message) => message.sessionId)?.sessionId;
|
|
1187
1158
|
}
|
|
1188
|
-
var IMAGE_EXTENSIONS = /* @__PURE__ */ new Set(["jpg", "jpeg", "png", "gif", "webp", "avif"]);
|
|
1189
|
-
function attachmentKindFromFile(file) {
|
|
1190
|
-
const ext = file.name.split(".").pop()?.toLowerCase() ?? "";
|
|
1191
|
-
if (IMAGE_EXTENSIONS.has(ext) || file.type.startsWith("image/")) return "image";
|
|
1192
|
-
return "file";
|
|
1193
|
-
}
|
|
1194
|
-
function buildMessageAttachments(files) {
|
|
1195
|
-
return files.map((file, index) => {
|
|
1196
|
-
const kind = attachmentKindFromFile(file);
|
|
1197
|
-
return {
|
|
1198
|
-
id: `att-${Date.now()}-${index}`,
|
|
1199
|
-
filename: file.name,
|
|
1200
|
-
mimeType: file.type || "application/octet-stream",
|
|
1201
|
-
// Blob URL for all local files so PDFs/docs stay previewable after send.
|
|
1202
|
-
previewUrl: URL.createObjectURL(file),
|
|
1203
|
-
kind
|
|
1204
|
-
};
|
|
1205
|
-
});
|
|
1206
|
-
}
|
|
1207
1159
|
function useChatV2(config, callbacks = {}) {
|
|
1208
1160
|
const [messages, setMessages] = useState(() => getStoredOrInitialMessages(config));
|
|
1209
1161
|
const [isWaitingForResponse, setIsWaitingForResponse] = useState(() => {
|
|
1210
1162
|
if (!config.userId) return false;
|
|
1211
1163
|
return activeStreamStore.get(config.userId)?.isWaiting ?? false;
|
|
1212
1164
|
});
|
|
1213
|
-
const [isUploadingAttachments, setIsUploadingAttachments] = useState(false);
|
|
1214
1165
|
const sessionIdRef = useRef(
|
|
1215
1166
|
getSessionIdFromMessages(getStoredOrInitialMessages(config)) ?? config.initialSessionId ?? void 0
|
|
1216
1167
|
);
|
|
@@ -1253,7 +1204,28 @@ function useChatV2(config, callbacks = {}) {
|
|
|
1253
1204
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
1254
1205
|
[]
|
|
1255
1206
|
);
|
|
1256
|
-
const [userActionState, setUserActionState] = useState(
|
|
1207
|
+
const [userActionState, setUserActionState] = useState(() => {
|
|
1208
|
+
if (!config.userId) return EMPTY_USER_ACTION_STATE2;
|
|
1209
|
+
return activeStreamStore.get(config.userId)?.userActionState ?? EMPTY_USER_ACTION_STATE2;
|
|
1210
|
+
});
|
|
1211
|
+
const storeAwareSetUserActionState = useCallback(
|
|
1212
|
+
(updater) => {
|
|
1213
|
+
const streamUserId = streamUserIdRef.current;
|
|
1214
|
+
const currentUserId = configRef.current.userId;
|
|
1215
|
+
const storeKey = streamUserId ?? currentUserId;
|
|
1216
|
+
if (storeKey && activeStreamStore.has(storeKey)) {
|
|
1217
|
+
activeStreamStore.applyUserActionState(
|
|
1218
|
+
storeKey,
|
|
1219
|
+
updater
|
|
1220
|
+
);
|
|
1221
|
+
}
|
|
1222
|
+
if (!streamUserId || streamUserId === currentUserId) {
|
|
1223
|
+
setUserActionState(updater);
|
|
1224
|
+
}
|
|
1225
|
+
},
|
|
1226
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
1227
|
+
[]
|
|
1228
|
+
);
|
|
1257
1229
|
const wrappedCallbacks = useMemo(() => ({
|
|
1258
1230
|
...callbacksRef.current,
|
|
1259
1231
|
onMessageSent: (message) => callbacksRef.current.onMessageSent?.(message),
|
|
@@ -1263,14 +1235,14 @@ function useChatV2(config, callbacks = {}) {
|
|
|
1263
1235
|
onExecutionTraceClick: (data) => callbacksRef.current.onExecutionTraceClick?.(data),
|
|
1264
1236
|
onSessionIdChange: (sessionId) => callbacksRef.current.onSessionIdChange?.(sessionId),
|
|
1265
1237
|
onUserActionRequired: (request) => {
|
|
1266
|
-
|
|
1238
|
+
storeAwareSetUserActionState((prev) => ({
|
|
1267
1239
|
...prev,
|
|
1268
1240
|
prompts: upsertPrompt(prev.prompts, request)
|
|
1269
1241
|
}));
|
|
1270
1242
|
callbacksRef.current.onUserActionRequired?.(request);
|
|
1271
1243
|
},
|
|
1272
1244
|
onUserNotification: (notification) => {
|
|
1273
|
-
|
|
1245
|
+
storeAwareSetUserActionState(
|
|
1274
1246
|
(prev) => prev.notifications.some((n) => n.id === notification.id) ? prev : { ...prev, notifications: [...prev.notifications, notification] }
|
|
1275
1247
|
);
|
|
1276
1248
|
callbacksRef.current.onUserNotification?.(notification);
|
|
@@ -1285,45 +1257,21 @@ function useChatV2(config, callbacks = {}) {
|
|
|
1285
1257
|
);
|
|
1286
1258
|
const sendMessage = useCallback(
|
|
1287
1259
|
async (userMessage, options) => {
|
|
1288
|
-
|
|
1289
|
-
const files = options?.files ?? [];
|
|
1290
|
-
const hasPreuploadedAttachments = (options?.attachments?.length ?? 0) > 0;
|
|
1291
|
-
if (!trimmedMessage && files.length === 0 && !hasPreuploadedAttachments) return;
|
|
1292
|
-
let streamAttachments = options?.attachments;
|
|
1293
|
-
if (!streamAttachments && files.length > 0) {
|
|
1294
|
-
setIsUploadingAttachments(true);
|
|
1295
|
-
try {
|
|
1296
|
-
streamAttachments = await uploadAttachments(configRef.current, files);
|
|
1297
|
-
} catch (error) {
|
|
1298
|
-
if (error.name !== "AbortError") {
|
|
1299
|
-
callbacksRef.current.onError?.(error);
|
|
1300
|
-
}
|
|
1301
|
-
throw error;
|
|
1302
|
-
} finally {
|
|
1303
|
-
setIsUploadingAttachments(false);
|
|
1304
|
-
}
|
|
1305
|
-
}
|
|
1260
|
+
if (!userMessage.trim()) return;
|
|
1306
1261
|
if (!sessionIdRef.current && configRef.current.autoGenerateSessionId !== false) {
|
|
1307
1262
|
sessionIdRef.current = generateId();
|
|
1308
1263
|
callbacksRef.current.onSessionIdChange?.(sessionIdRef.current);
|
|
1309
1264
|
}
|
|
1310
|
-
const messageAttachments = files.length > 0 ? buildMessageAttachments(files) : streamAttachments?.length ? streamAttachments.map((attachment, index) => ({
|
|
1311
|
-
id: `att-${Date.now()}-${index}`,
|
|
1312
|
-
filename: attachment.filename,
|
|
1313
|
-
mimeType: attachment.mimeType,
|
|
1314
|
-
kind: attachment.mimeType.startsWith("image/") ? "image" : "file"
|
|
1315
|
-
})) : void 0;
|
|
1316
1265
|
const userMessageId = `user-${Date.now()}`;
|
|
1317
1266
|
const userMsg = {
|
|
1318
1267
|
id: userMessageId,
|
|
1319
1268
|
sessionId: sessionIdRef.current,
|
|
1320
1269
|
role: "user",
|
|
1321
|
-
content:
|
|
1322
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
1323
|
-
attachments: messageAttachments
|
|
1270
|
+
content: userMessage,
|
|
1271
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
1324
1272
|
};
|
|
1325
1273
|
setMessages((prev) => [...prev, userMsg]);
|
|
1326
|
-
callbacksRef.current.onMessageSent?.(
|
|
1274
|
+
callbacksRef.current.onMessageSent?.(userMessage);
|
|
1327
1275
|
setIsWaitingForResponse(true);
|
|
1328
1276
|
callbacksRef.current.onStreamStart?.();
|
|
1329
1277
|
const streamingId = `assistant-${Date.now()}`;
|
|
@@ -1350,14 +1298,11 @@ function useChatV2(config, callbacks = {}) {
|
|
|
1350
1298
|
activeStreamStore.start(userId, abortController, initialMessages);
|
|
1351
1299
|
}
|
|
1352
1300
|
const newSessionId = await startStream(
|
|
1353
|
-
|
|
1301
|
+
userMessage,
|
|
1354
1302
|
streamingId,
|
|
1355
1303
|
sessionIdRef.current,
|
|
1356
1304
|
abortController,
|
|
1357
|
-
|
|
1358
|
-
analysisMode: options?.analysisMode,
|
|
1359
|
-
attachments: streamAttachments
|
|
1360
|
-
}
|
|
1305
|
+
options
|
|
1361
1306
|
);
|
|
1362
1307
|
const finalStreamUserId = streamUserIdRef.current ?? userId;
|
|
1363
1308
|
if (finalStreamUserId) {
|
|
@@ -1387,7 +1332,7 @@ function useChatV2(config, callbacks = {}) {
|
|
|
1387
1332
|
streamUserIdRef.current = void 0;
|
|
1388
1333
|
cancelStreamManager();
|
|
1389
1334
|
setIsWaitingForResponse(false);
|
|
1390
|
-
|
|
1335
|
+
storeAwareSetUserActionState((prev) => ({ ...prev, prompts: [] }));
|
|
1391
1336
|
setMessages(
|
|
1392
1337
|
(prev) => prev.map((msg) => {
|
|
1393
1338
|
if (msg.isStreaming) {
|
|
@@ -1402,7 +1347,7 @@ function useChatV2(config, callbacks = {}) {
|
|
|
1402
1347
|
return msg;
|
|
1403
1348
|
})
|
|
1404
1349
|
);
|
|
1405
|
-
}, [cancelStreamManager]);
|
|
1350
|
+
}, [cancelStreamManager, storeAwareSetUserActionState]);
|
|
1406
1351
|
const resetSession = useCallback(() => {
|
|
1407
1352
|
const streamUserId = streamUserIdRef.current ?? configRef.current.userId;
|
|
1408
1353
|
if (streamUserId) {
|
|
@@ -1416,7 +1361,7 @@ function useChatV2(config, callbacks = {}) {
|
|
|
1416
1361
|
sessionIdRef.current = void 0;
|
|
1417
1362
|
abortControllerRef.current?.abort();
|
|
1418
1363
|
setIsWaitingForResponse(false);
|
|
1419
|
-
|
|
1364
|
+
storeAwareSetUserActionState(EMPTY_USER_ACTION_STATE2);
|
|
1420
1365
|
}, []);
|
|
1421
1366
|
const getSessionId = useCallback(() => {
|
|
1422
1367
|
return sessionIdRef.current;
|
|
@@ -1426,21 +1371,21 @@ function useChatV2(config, callbacks = {}) {
|
|
|
1426
1371
|
}, [messages]);
|
|
1427
1372
|
const setPromptStatus = useCallback(
|
|
1428
1373
|
(userActionId, status) => {
|
|
1429
|
-
|
|
1374
|
+
storeAwareSetUserActionState((prev) => ({
|
|
1430
1375
|
...prev,
|
|
1431
1376
|
prompts: prev.prompts.map(
|
|
1432
1377
|
(p) => p.userActionId === userActionId ? { ...p, status } : p
|
|
1433
1378
|
)
|
|
1434
1379
|
}));
|
|
1435
1380
|
},
|
|
1436
|
-
[]
|
|
1381
|
+
[storeAwareSetUserActionState]
|
|
1437
1382
|
);
|
|
1438
1383
|
const removePrompt = useCallback((userActionId) => {
|
|
1439
|
-
|
|
1384
|
+
storeAwareSetUserActionState((prev) => ({
|
|
1440
1385
|
...prev,
|
|
1441
1386
|
prompts: prev.prompts.filter((p) => p.userActionId !== userActionId)
|
|
1442
1387
|
}));
|
|
1443
|
-
}, []);
|
|
1388
|
+
}, [storeAwareSetUserActionState]);
|
|
1444
1389
|
const submitUserAction2 = useCallback(
|
|
1445
1390
|
async (userActionId, content) => {
|
|
1446
1391
|
setPromptStatus(userActionId, "submitting");
|
|
@@ -1495,12 +1440,25 @@ function useChatV2(config, callbacks = {}) {
|
|
|
1495
1440
|
},
|
|
1496
1441
|
[setPromptStatus]
|
|
1497
1442
|
);
|
|
1443
|
+
const expireUserAction2 = useCallback(
|
|
1444
|
+
async (userActionId) => {
|
|
1445
|
+
setPromptStatus(userActionId, "expired");
|
|
1446
|
+
try {
|
|
1447
|
+
await expireUserAction(configRef.current, userActionId);
|
|
1448
|
+
} catch (error) {
|
|
1449
|
+
if (error instanceof UserActionStaleError) return;
|
|
1450
|
+
callbacksRef.current.onError?.(error);
|
|
1451
|
+
throw error;
|
|
1452
|
+
}
|
|
1453
|
+
},
|
|
1454
|
+
[setPromptStatus]
|
|
1455
|
+
);
|
|
1498
1456
|
const dismissNotification = useCallback((id) => {
|
|
1499
|
-
|
|
1457
|
+
storeAwareSetUserActionState((prev) => ({
|
|
1500
1458
|
...prev,
|
|
1501
1459
|
notifications: prev.notifications.filter((n) => n.id !== id)
|
|
1502
1460
|
}));
|
|
1503
|
-
}, []);
|
|
1461
|
+
}, [storeAwareSetUserActionState]);
|
|
1504
1462
|
useEffect(() => {
|
|
1505
1463
|
const prevSubscriptionUserId = subscriptionPrevUserIdRef.current;
|
|
1506
1464
|
subscriptionPrevUserIdRef.current = config.userId;
|
|
@@ -1509,14 +1467,17 @@ function useChatV2(config, callbacks = {}) {
|
|
|
1509
1467
|
if (prevSubscriptionUserId && prevSubscriptionUserId !== userId && streamUserIdRef.current === prevSubscriptionUserId && !activeStreamStore.has(prevSubscriptionUserId) && activeStreamStore.has(userId)) {
|
|
1510
1468
|
streamUserIdRef.current = userId;
|
|
1511
1469
|
}
|
|
1512
|
-
const unsubscribe = activeStreamStore.subscribe(userId, (msgs, isWaiting) => {
|
|
1470
|
+
const unsubscribe = activeStreamStore.subscribe(userId, (msgs, isWaiting, actions) => {
|
|
1513
1471
|
setMessages(msgs);
|
|
1514
1472
|
setIsWaitingForResponse(isWaiting);
|
|
1473
|
+
setUserActionState(actions);
|
|
1515
1474
|
});
|
|
1516
1475
|
const active = activeStreamStore.get(userId);
|
|
1517
1476
|
if (active) {
|
|
1477
|
+
streamUserIdRef.current = userId;
|
|
1518
1478
|
setMessages(active.messages);
|
|
1519
1479
|
setIsWaitingForResponse(active.isWaiting);
|
|
1480
|
+
setUserActionState(active.userActionState);
|
|
1520
1481
|
}
|
|
1521
1482
|
return unsubscribe;
|
|
1522
1483
|
}, [config.userId]);
|
|
@@ -1535,18 +1496,6 @@ function useChatV2(config, callbacks = {}) {
|
|
|
1535
1496
|
setMessages(config.initialMessages);
|
|
1536
1497
|
sessionIdRef.current = getSessionIdFromMessages(config.initialMessages) ?? config.initialSessionId;
|
|
1537
1498
|
}, [config.initialMessages, config.initialSessionId, config.userId]);
|
|
1538
|
-
const hydratedSessionIdRef = useRef(void 0);
|
|
1539
|
-
useEffect(() => {
|
|
1540
|
-
if (config.userId) return;
|
|
1541
|
-
if (!config.initialMessages?.length) return;
|
|
1542
|
-
const sessionId = config.initialSessionId;
|
|
1543
|
-
if (hydratedSessionIdRef.current === sessionId && messagesRef.current.length > 0) {
|
|
1544
|
-
return;
|
|
1545
|
-
}
|
|
1546
|
-
hydratedSessionIdRef.current = sessionId;
|
|
1547
|
-
setMessages(config.initialMessages);
|
|
1548
|
-
sessionIdRef.current = getSessionIdFromMessages(config.initialMessages) ?? sessionId;
|
|
1549
|
-
}, [config.initialMessages, config.initialSessionId, config.userId]);
|
|
1550
1499
|
useEffect(() => {
|
|
1551
1500
|
const prevUserId = prevUserIdRef.current;
|
|
1552
1501
|
prevUserIdRef.current = config.userId;
|
|
@@ -1556,12 +1505,14 @@ function useChatV2(config, callbacks = {}) {
|
|
|
1556
1505
|
setMessages([]);
|
|
1557
1506
|
sessionIdRef.current = void 0;
|
|
1558
1507
|
setIsWaitingForResponse(false);
|
|
1559
|
-
setUserActionState(
|
|
1508
|
+
setUserActionState(EMPTY_USER_ACTION_STATE2);
|
|
1560
1509
|
} else if (config.userId) {
|
|
1561
1510
|
const active = activeStreamStore.get(config.userId);
|
|
1562
1511
|
if (active) {
|
|
1512
|
+
streamUserIdRef.current = config.userId;
|
|
1563
1513
|
setMessages(active.messages);
|
|
1564
1514
|
setIsWaitingForResponse(active.isWaiting);
|
|
1515
|
+
setUserActionState(active.userActionState);
|
|
1565
1516
|
sessionIdRef.current = getSessionIdFromMessages(active.messages) ?? config.initialSessionId;
|
|
1566
1517
|
return;
|
|
1567
1518
|
}
|
|
@@ -1581,12 +1532,12 @@ function useChatV2(config, callbacks = {}) {
|
|
|
1581
1532
|
getSessionId,
|
|
1582
1533
|
getMessages,
|
|
1583
1534
|
isWaitingForResponse,
|
|
1584
|
-
isUploadingAttachments,
|
|
1585
1535
|
sessionId: sessionIdRef.current,
|
|
1586
1536
|
userActionState,
|
|
1587
1537
|
submitUserAction: submitUserAction2,
|
|
1588
1538
|
cancelUserAction: cancelUserAction2,
|
|
1589
1539
|
resendUserAction: resendUserAction2,
|
|
1540
|
+
expireUserAction: expireUserAction2,
|
|
1590
1541
|
dismissNotification
|
|
1591
1542
|
};
|
|
1592
1543
|
}
|
|
@@ -2120,6 +2071,9 @@ function getConflictErrorMessage(errorDetails) {
|
|
|
2120
2071
|
}
|
|
2121
2072
|
function initSentryIfNeeded(dsn) {
|
|
2122
2073
|
if (!dsn) return;
|
|
2074
|
+
if (typeof window !== "undefined" && (window.location.hostname === "localhost" || window.location.hostname === "127.0.0.1")) {
|
|
2075
|
+
return;
|
|
2076
|
+
}
|
|
2123
2077
|
if (Sentry.getClient()) return;
|
|
2124
2078
|
Sentry.init({
|
|
2125
2079
|
dsn,
|
|
@@ -3501,9 +3455,88 @@ function MarkdownImageV2({
|
|
|
3501
3455
|
}
|
|
3502
3456
|
) });
|
|
3503
3457
|
}
|
|
3504
|
-
|
|
3458
|
+
var RAG_SOURCE_CLASS = "payman-v2-rag-source";
|
|
3459
|
+
var RAG_FOLLOW_UP_CLASS = "payman-v2-rag-follow-up";
|
|
3460
|
+
var SOURCE_PATTERN = /^Sources?:\s*\S/i;
|
|
3461
|
+
var MAX_FOLLOW_UP_LENGTH = 320;
|
|
3462
|
+
var HR_PATTERN = /^-{3,}$|^_{3,}$|^\*{3,}$/;
|
|
3463
|
+
function normalizeRagParagraphText(text) {
|
|
3464
|
+
return text.replace(/\s+/g, " ").trim();
|
|
3465
|
+
}
|
|
3466
|
+
function isRagSourceParagraph(text) {
|
|
3467
|
+
return SOURCE_PATTERN.test(normalizeRagParagraphText(text));
|
|
3468
|
+
}
|
|
3469
|
+
function isRagFollowUpCandidate(text) {
|
|
3470
|
+
const normalized = normalizeRagParagraphText(text);
|
|
3471
|
+
return normalized.length > 0 && normalized.length <= MAX_FOLLOW_UP_LENGTH && normalized.endsWith("?");
|
|
3472
|
+
}
|
|
3473
|
+
function extractRagParagraphTexts(content) {
|
|
3474
|
+
const paragraphs = [];
|
|
3475
|
+
const currentParagraph = [];
|
|
3476
|
+
const flushParagraph = () => {
|
|
3477
|
+
const paragraph = normalizeRagParagraphText(currentParagraph.join(" "));
|
|
3478
|
+
currentParagraph.length = 0;
|
|
3479
|
+
if (paragraph) paragraphs.push(paragraph);
|
|
3480
|
+
};
|
|
3481
|
+
content.replace(/\\n/g, "\n").split(/\r?\n/).forEach((line) => {
|
|
3482
|
+
const trimmedLine = line.trim();
|
|
3483
|
+
if (!trimmedLine) {
|
|
3484
|
+
flushParagraph();
|
|
3485
|
+
return;
|
|
3486
|
+
}
|
|
3487
|
+
if (HR_PATTERN.test(trimmedLine)) {
|
|
3488
|
+
flushParagraph();
|
|
3489
|
+
return;
|
|
3490
|
+
}
|
|
3491
|
+
currentParagraph.push(trimmedLine);
|
|
3492
|
+
});
|
|
3493
|
+
flushParagraph();
|
|
3494
|
+
return paragraphs;
|
|
3495
|
+
}
|
|
3496
|
+
function getRagAnswerParagraphRoles(paragraphs) {
|
|
3497
|
+
const normalized = paragraphs.map(normalizeRagParagraphText);
|
|
3498
|
+
const roles = normalized.map(() => null);
|
|
3499
|
+
const sourceIndexes = normalized.map((paragraph, index) => isRagSourceParagraph(paragraph) ? index : -1).filter((index) => index >= 0);
|
|
3500
|
+
for (const sourceIndex of sourceIndexes) {
|
|
3501
|
+
roles[sourceIndex] = "source";
|
|
3502
|
+
for (const candidateIndex of [sourceIndex - 1, sourceIndex + 1]) {
|
|
3503
|
+
if (candidateIndex >= 0 && candidateIndex < normalized.length && roles[candidateIndex] == null && isRagFollowUpCandidate(normalized[candidateIndex] ?? "")) {
|
|
3504
|
+
roles[candidateIndex] = "follow-up";
|
|
3505
|
+
}
|
|
3506
|
+
}
|
|
3507
|
+
}
|
|
3508
|
+
return roles;
|
|
3509
|
+
}
|
|
3510
|
+
function getRagAnswerParagraphRole(paragraph, paragraphs) {
|
|
3511
|
+
const normalizedParagraph = normalizeRagParagraphText(paragraph);
|
|
3512
|
+
if (isRagSourceParagraph(normalizedParagraph)) return "source";
|
|
3513
|
+
const roles = getRagAnswerParagraphRoles(paragraphs);
|
|
3514
|
+
return paragraphs.map(normalizeRagParagraphText).some((candidate, index) => {
|
|
3515
|
+
return candidate === normalizedParagraph && roles[index] === "follow-up";
|
|
3516
|
+
}) ? "follow-up" : null;
|
|
3517
|
+
}
|
|
3518
|
+
function ragAnswerRoleClassName(role) {
|
|
3519
|
+
if (role === "source") return RAG_SOURCE_CLASS;
|
|
3520
|
+
if (role === "follow-up") return RAG_FOLLOW_UP_CLASS;
|
|
3521
|
+
return void 0;
|
|
3522
|
+
}
|
|
3523
|
+
function reactNodeText(node) {
|
|
3524
|
+
if (typeof node === "string" || typeof node === "number") return String(node);
|
|
3525
|
+
if (Array.isArray(node)) return node.map(reactNodeText).join("");
|
|
3526
|
+
if (React.isValidElement(node)) {
|
|
3527
|
+
return reactNodeText(node.props.children);
|
|
3528
|
+
}
|
|
3529
|
+
return "";
|
|
3530
|
+
}
|
|
3531
|
+
function buildComponents(onImageClick, isResolvingRef, ragParagraphsRef) {
|
|
3505
3532
|
return {
|
|
3506
|
-
p: ({ children }) =>
|
|
3533
|
+
p: ({ children }) => {
|
|
3534
|
+
const role = getRagAnswerParagraphRole(
|
|
3535
|
+
reactNodeText(children),
|
|
3536
|
+
ragParagraphsRef?.current ?? []
|
|
3537
|
+
);
|
|
3538
|
+
return /* @__PURE__ */ jsx("p", { className: ragAnswerRoleClassName(role), children });
|
|
3539
|
+
},
|
|
3507
3540
|
code: ({ children }) => /* @__PURE__ */ jsx("code", { children }),
|
|
3508
3541
|
pre: ({ children }) => /* @__PURE__ */ jsx("div", { className: "payman-v2-markdown-pre", children: /* @__PURE__ */ jsx("pre", { children }) }),
|
|
3509
3542
|
ul: ({ children }) => /* @__PURE__ */ jsx("ul", { children }),
|
|
@@ -3541,8 +3574,13 @@ function MarkdownRendererV2({
|
|
|
3541
3574
|
}) {
|
|
3542
3575
|
const isResolvingRef = useRef(isResolvingImages);
|
|
3543
3576
|
isResolvingRef.current = isResolvingImages;
|
|
3577
|
+
const ragParagraphsRef = useRef([]);
|
|
3578
|
+
ragParagraphsRef.current = useMemo(
|
|
3579
|
+
() => extractRagParagraphTexts(content),
|
|
3580
|
+
[content]
|
|
3581
|
+
);
|
|
3544
3582
|
const components = useMemo(
|
|
3545
|
-
() => buildComponents(onImageClick, isResolvingRef),
|
|
3583
|
+
() => buildComponents(onImageClick, isResolvingRef, ragParagraphsRef),
|
|
3546
3584
|
[onImageClick]
|
|
3547
3585
|
);
|
|
3548
3586
|
return /* @__PURE__ */ jsx(
|
|
@@ -4035,6 +4073,7 @@ function AssistantMessageV2({
|
|
|
4035
4073
|
return message.isStreaming ? stripIncompleteImageToken(normalized) : normalized;
|
|
4036
4074
|
})();
|
|
4037
4075
|
const isThinkingStreaming = !!message.isStreaming && !rawResponseContent && !message.isError;
|
|
4076
|
+
const showTrailingProgress = !!message.isStreaming && !!rawResponseContent && !message.isError && !message.isCancelled && !!message.hasTrailingActivity;
|
|
4038
4077
|
const responseTypingEnabled = hasEverStreamed.current && Boolean(rawResponseContent) && !message.isError;
|
|
4039
4078
|
const { displayedText: displayContent, isTyping: isResponseTyping } = useTypingEffect(
|
|
4040
4079
|
rawResponseContent,
|
|
@@ -4193,7 +4232,7 @@ function AssistantMessageV2({
|
|
|
4193
4232
|
{
|
|
4194
4233
|
isStreaming: isThinkingStreaming,
|
|
4195
4234
|
stickyLabel,
|
|
4196
|
-
currentStepLabel
|
|
4235
|
+
currentStepLabel: currentStepLabel ?? message.currentMessage
|
|
4197
4236
|
}
|
|
4198
4237
|
)
|
|
4199
4238
|
},
|
|
@@ -4208,6 +4247,27 @@ function AssistantMessageV2({
|
|
|
4208
4247
|
onImageClick
|
|
4209
4248
|
}
|
|
4210
4249
|
) : !isThinkingStreaming ? /* @__PURE__ */ jsx("span", { className: "payman-v2-assistant-msg-placeholder", children: "..." }) : null }),
|
|
4250
|
+
/* @__PURE__ */ jsx(AnimatePresence, { children: showTrailingProgress && /* @__PURE__ */ jsx(
|
|
4251
|
+
motion.div,
|
|
4252
|
+
{
|
|
4253
|
+
initial: { opacity: 0, height: 0 },
|
|
4254
|
+
animate: { opacity: 1, height: "auto" },
|
|
4255
|
+
exit: { opacity: 0, height: 0 },
|
|
4256
|
+
transition: {
|
|
4257
|
+
duration: 0.32,
|
|
4258
|
+
ease: [0.2, 0, 0, 1]
|
|
4259
|
+
},
|
|
4260
|
+
style: { overflow: "hidden" },
|
|
4261
|
+
children: /* @__PURE__ */ jsx(
|
|
4262
|
+
ThinkingBlockV2,
|
|
4263
|
+
{
|
|
4264
|
+
isStreaming: true,
|
|
4265
|
+
currentStepLabel: message.currentMessage ?? currentStepLabel
|
|
4266
|
+
}
|
|
4267
|
+
)
|
|
4268
|
+
},
|
|
4269
|
+
"trailing-progress"
|
|
4270
|
+
) }),
|
|
4211
4271
|
isCancelled && message.isStreaming && /* @__PURE__ */ jsxs("div", { className: "payman-v2-assistant-msg-paused", children: [
|
|
4212
4272
|
/* @__PURE__ */ jsx(
|
|
4213
4273
|
WifiOff,
|
|
@@ -4502,7 +4562,10 @@ function VerificationInline({
|
|
|
4502
4562
|
if (busy) return;
|
|
4503
4563
|
void onCancel(prompt.userActionId);
|
|
4504
4564
|
}, [busy, onCancel, prompt.userActionId]);
|
|
4505
|
-
const
|
|
4565
|
+
const promptMessage = prompt.message?.trim();
|
|
4566
|
+
const description = promptMessage || (isNumeric ? `Enter the ${codeLen}-digit code to continue` : "Enter the verification code to continue");
|
|
4567
|
+
const messageFormat = prompt.metadata?.["payman/messageFormat"];
|
|
4568
|
+
const renderMarkdown = !!promptMessage && messageFormat === "markdown";
|
|
4506
4569
|
if (hiddenAfterResend) return null;
|
|
4507
4570
|
return /* @__PURE__ */ jsxs("div", { className: "payman-v2-ua", role: "group", "aria-label": "Verification required", children: [
|
|
4508
4571
|
/* @__PURE__ */ jsxs("div", { className: "payman-v2-ua-head", children: [
|
|
@@ -4510,7 +4573,7 @@ function VerificationInline({
|
|
|
4510
4573
|
/* @__PURE__ */ jsx("span", { className: "payman-v2-ua-title", children: "Verification required" }),
|
|
4511
4574
|
typeof secondsLeft === "number" && !stale && /* @__PURE__ */ jsx("span", { className: "payman-v2-ua-timer", children: expired ? "Expired" : `${secondsLeft}s` })
|
|
4512
4575
|
] }),
|
|
4513
|
-
/* @__PURE__ */ jsx("p", { className: "payman-v2-ua-desc", children: description }),
|
|
4576
|
+
renderMarkdown ? /* @__PURE__ */ jsx("div", { className: "payman-v2-ua-markdown", children: /* @__PURE__ */ jsx(MarkdownRendererV2, { content: description }) }) : /* @__PURE__ */ jsx("p", { className: "payman-v2-ua-desc", children: description }),
|
|
4514
4577
|
stale ? /* @__PURE__ */ jsx("p", { className: "payman-v2-ua-stale", children: "This request is no longer available." }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
4515
4578
|
isNumeric ? /* @__PURE__ */ jsx("div", { className: "payman-v2-ua-field", children: /* @__PURE__ */ jsx(
|
|
4516
4579
|
OtpInputV2,
|
|
@@ -4734,14 +4797,15 @@ function NotificationInline({ notification, onDismiss }) {
|
|
|
4734
4797
|
] });
|
|
4735
4798
|
}
|
|
4736
4799
|
function useExpiryCountdown(prompt) {
|
|
4737
|
-
const
|
|
4738
|
-
const [secondsLeft, setSecondsLeft] = useState(
|
|
4800
|
+
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;
|
|
4801
|
+
const [secondsLeft, setSecondsLeft] = useState(
|
|
4802
|
+
() => deadlineMs !== void 0 ? Math.max(0, Math.ceil((deadlineMs - Date.now()) / 1e3)) : void 0
|
|
4803
|
+
);
|
|
4739
4804
|
useEffect(() => {
|
|
4740
|
-
if (
|
|
4805
|
+
if (deadlineMs === void 0) {
|
|
4741
4806
|
setSecondsLeft(void 0);
|
|
4742
4807
|
return;
|
|
4743
4808
|
}
|
|
4744
|
-
const deadlineMs = Date.now() + initial * 1e3;
|
|
4745
4809
|
let intervalId;
|
|
4746
4810
|
const remaining = () => Math.max(0, Math.ceil((deadlineMs - Date.now()) / 1e3));
|
|
4747
4811
|
const sync = () => {
|
|
@@ -4763,8 +4827,8 @@ function useExpiryCountdown(prompt) {
|
|
|
4763
4827
|
window.removeEventListener("focus", sync);
|
|
4764
4828
|
window.removeEventListener("pageshow", sync);
|
|
4765
4829
|
};
|
|
4766
|
-
}, [prompt.userActionId, prompt.subAction,
|
|
4767
|
-
const expired =
|
|
4830
|
+
}, [prompt.userActionId, prompt.subAction, deadlineMs]);
|
|
4831
|
+
const expired = deadlineMs !== void 0 && (getUserActionSecondsLeft(prompt) ?? secondsLeft ?? 0) <= 0;
|
|
4768
4832
|
return [secondsLeft, expired];
|
|
4769
4833
|
}
|
|
4770
4834
|
function UserActionInline({
|
|
@@ -6319,7 +6383,7 @@ var PaymanChatInner = forwardRef(function PaymanChatInner2({
|
|
|
6319
6383
|
const submitUserAction2 = chat.submitUserAction ?? NOOP_ASYNC;
|
|
6320
6384
|
const cancelUserAction2 = chat.cancelUserAction ?? NOOP_ASYNC;
|
|
6321
6385
|
const resendUserAction2 = chat.resendUserAction ?? NOOP_ASYNC;
|
|
6322
|
-
const
|
|
6386
|
+
const expireUserAction2 = chat.expireUserAction ?? NOOP_ASYNC;
|
|
6323
6387
|
const dismissNotification = chat.dismissNotification ?? NOOP;
|
|
6324
6388
|
const isUserActionSupported = typeof chat.submitUserAction === "function" && typeof chat.cancelUserAction === "function" && typeof chat.resendUserAction === "function";
|
|
6325
6389
|
const {
|
|
@@ -6720,7 +6784,7 @@ var PaymanChatInner = forwardRef(function PaymanChatInner2({
|
|
|
6720
6784
|
onSubmitUserAction: isUserActionSupported ? submitUserAction2 : void 0,
|
|
6721
6785
|
onCancelUserAction: isUserActionSupported ? cancelUserAction2 : void 0,
|
|
6722
6786
|
onResendUserAction: isUserActionSupported ? resendUserAction2 : void 0,
|
|
6723
|
-
onExpireUserAction: isUserActionSupported ?
|
|
6787
|
+
onExpireUserAction: isUserActionSupported ? expireUserAction2 : void 0,
|
|
6724
6788
|
onDismissNotification: dismissNotification,
|
|
6725
6789
|
onSubmitFeedback: handleSubmitFeedback
|
|
6726
6790
|
}
|