@paymanai/payman-ask-sdk 4.0.24 → 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 +111 -175
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +111 -175
- package/dist/index.mjs.map +1 -1
- package/dist/index.native.js +129 -188
- package/dist/index.native.js.map +1 -1
- package/package.json +3 -2
package/dist/index.mjs
CHANGED
|
@@ -33,6 +33,7 @@ var chatStore = {
|
|
|
33
33
|
memoryStore.delete(key);
|
|
34
34
|
}
|
|
35
35
|
};
|
|
36
|
+
var EMPTY_USER_ACTION_STATE = { prompts: [], notifications: [] };
|
|
36
37
|
var streams = /* @__PURE__ */ new Map();
|
|
37
38
|
var activeStreamStore = {
|
|
38
39
|
has(key) {
|
|
@@ -41,7 +42,11 @@ var activeStreamStore = {
|
|
|
41
42
|
get(key) {
|
|
42
43
|
const entry = streams.get(key);
|
|
43
44
|
if (!entry) return null;
|
|
44
|
-
return {
|
|
45
|
+
return {
|
|
46
|
+
messages: entry.messages,
|
|
47
|
+
isWaiting: entry.isWaiting,
|
|
48
|
+
userActionState: entry.userActionState
|
|
49
|
+
};
|
|
45
50
|
},
|
|
46
51
|
// Called before startStream — registers the controller and initial messages
|
|
47
52
|
start(key, abortController, initialMessages) {
|
|
@@ -49,6 +54,7 @@ var activeStreamStore = {
|
|
|
49
54
|
streams.set(key, {
|
|
50
55
|
messages: initialMessages,
|
|
51
56
|
isWaiting: true,
|
|
57
|
+
userActionState: EMPTY_USER_ACTION_STATE,
|
|
52
58
|
abortController,
|
|
53
59
|
listeners: existing?.listeners ?? /* @__PURE__ */ new Set()
|
|
54
60
|
});
|
|
@@ -59,20 +65,27 @@ var activeStreamStore = {
|
|
|
59
65
|
if (!entry) return;
|
|
60
66
|
const next = typeof updater === "function" ? updater(entry.messages) : updater;
|
|
61
67
|
entry.messages = next;
|
|
62
|
-
entry.listeners.forEach((l) => l(next, entry.isWaiting));
|
|
68
|
+
entry.listeners.forEach((l) => l(next, entry.isWaiting, entry.userActionState));
|
|
63
69
|
},
|
|
64
70
|
setWaiting(key, waiting) {
|
|
65
71
|
const entry = streams.get(key);
|
|
66
72
|
if (!entry) return;
|
|
67
73
|
entry.isWaiting = waiting;
|
|
68
|
-
entry.listeners.forEach((l) => l(entry.messages, waiting));
|
|
74
|
+
entry.listeners.forEach((l) => l(entry.messages, waiting, entry.userActionState));
|
|
75
|
+
},
|
|
76
|
+
applyUserActionState(key, updater) {
|
|
77
|
+
const entry = streams.get(key);
|
|
78
|
+
if (!entry) return;
|
|
79
|
+
const next = typeof updater === "function" ? updater(entry.userActionState) : updater;
|
|
80
|
+
entry.userActionState = next;
|
|
81
|
+
entry.listeners.forEach((l) => l(entry.messages, entry.isWaiting, next));
|
|
69
82
|
},
|
|
70
83
|
// Called when stream completes — persists to chatStore and cleans up
|
|
71
84
|
complete(key) {
|
|
72
85
|
const entry = streams.get(key);
|
|
73
86
|
if (!entry) return;
|
|
74
87
|
entry.isWaiting = false;
|
|
75
|
-
entry.listeners.forEach((l) => l(entry.messages, false));
|
|
88
|
+
entry.listeners.forEach((l) => l(entry.messages, false, entry.userActionState));
|
|
76
89
|
const toSave = entry.messages.filter((m) => !m.isStreaming);
|
|
77
90
|
if (toSave.length > 0) chatStore.set(key, toSave);
|
|
78
91
|
streams.delete(key);
|
|
@@ -709,8 +722,7 @@ function buildRequestBody(config, userMessage, sessionId, options) {
|
|
|
709
722
|
sessionAttributes,
|
|
710
723
|
analysisMode: options?.analysisMode,
|
|
711
724
|
locale: resolveLocale(config.locale),
|
|
712
|
-
timezone: resolveTimezone(config.timezone)
|
|
713
|
-
...options?.attachments?.length ? { attachments: options.attachments } : {}
|
|
725
|
+
timezone: resolveTimezone(config.timezone)
|
|
714
726
|
};
|
|
715
727
|
}
|
|
716
728
|
function resolveLocale(configured) {
|
|
@@ -755,7 +767,6 @@ function buildResolveImagesUrl(config) {
|
|
|
755
767
|
const basePath = normalizedEndpointPath.endsWith("/stream") ? normalizedEndpointPath.slice(0, -"/stream".length) : normalizedEndpointPath;
|
|
756
768
|
return `${config.api.baseUrl}${basePath}/resolve-image-urls`;
|
|
757
769
|
}
|
|
758
|
-
var NGROK_SKIP_BROWSER_WARNING = "ngrok-skip-browser-warning";
|
|
759
770
|
function buildRequestHeaders(config) {
|
|
760
771
|
const headers = {
|
|
761
772
|
...config.api.headers
|
|
@@ -763,9 +774,6 @@ function buildRequestHeaders(config) {
|
|
|
763
774
|
if (config.api.authToken) {
|
|
764
775
|
headers.Authorization = `Bearer ${config.api.authToken}`;
|
|
765
776
|
}
|
|
766
|
-
if (!headers[NGROK_SKIP_BROWSER_WARNING]) {
|
|
767
|
-
headers[NGROK_SKIP_BROWSER_WARNING] = "true";
|
|
768
|
-
}
|
|
769
777
|
return headers;
|
|
770
778
|
}
|
|
771
779
|
var RAG_IMAGE_REGEX = /\/api\/rag\/chunks\/[^"'\s]+\/image/;
|
|
@@ -1046,81 +1054,6 @@ function createCancelledMessageUpdate(steps, currentMessage) {
|
|
|
1046
1054
|
currentMessage: currentMessage || "Thinking..."
|
|
1047
1055
|
};
|
|
1048
1056
|
}
|
|
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
1057
|
var UserActionStaleError = class extends Error {
|
|
1125
1058
|
constructor(userActionId, message = "User action is no longer actionable") {
|
|
1126
1059
|
super(message);
|
|
@@ -1157,12 +1090,34 @@ async function cancelUserAction(config, userActionId) {
|
|
|
1157
1090
|
async function resendUserAction(config, userActionId) {
|
|
1158
1091
|
return sendUserActionRequest(config, userActionId, "resend");
|
|
1159
1092
|
}
|
|
1160
|
-
|
|
1093
|
+
async function expireUserAction(config, userActionId) {
|
|
1094
|
+
return sendUserActionRequest(config, userActionId, "expired");
|
|
1095
|
+
}
|
|
1096
|
+
function resolveUserActionExpiresAt(req, existing) {
|
|
1097
|
+
if (typeof req.expirySeconds !== "number" || req.expirySeconds <= 0) {
|
|
1098
|
+
return void 0;
|
|
1099
|
+
}
|
|
1100
|
+
if (existing?.expiresAt && existing.userActionId === req.userActionId) {
|
|
1101
|
+
return existing.expiresAt;
|
|
1102
|
+
}
|
|
1103
|
+
return Date.now() + Math.floor(req.expirySeconds) * 1e3;
|
|
1104
|
+
}
|
|
1105
|
+
function getUserActionSecondsLeft(prompt) {
|
|
1106
|
+
if (typeof prompt.expiresAt === "number" && prompt.expiresAt > 0) {
|
|
1107
|
+
return Math.max(0, Math.ceil((prompt.expiresAt - Date.now()) / 1e3));
|
|
1108
|
+
}
|
|
1109
|
+
if (typeof prompt.expirySeconds === "number" && prompt.expirySeconds > 0) {
|
|
1110
|
+
return Math.floor(prompt.expirySeconds);
|
|
1111
|
+
}
|
|
1112
|
+
return void 0;
|
|
1113
|
+
}
|
|
1114
|
+
var EMPTY_USER_ACTION_STATE2 = { prompts: [], notifications: [] };
|
|
1161
1115
|
function upsertPrompt(prompts, req) {
|
|
1162
|
-
const active = { ...req, status: "pending" };
|
|
1163
1116
|
const idx = prompts.findIndex(
|
|
1164
1117
|
(p) => req.toolCallId ? p.toolCallId === req.toolCallId : p.userActionId === req.userActionId
|
|
1165
1118
|
);
|
|
1119
|
+
const expiresAt = resolveUserActionExpiresAt(req, idx >= 0 ? prompts[idx] : void 0);
|
|
1120
|
+
const active = { ...req, status: "pending", expiresAt };
|
|
1166
1121
|
if (idx >= 0) {
|
|
1167
1122
|
const next = prompts.slice();
|
|
1168
1123
|
next[idx] = active;
|
|
@@ -1185,32 +1140,12 @@ function getStoredOrInitialMessages(config) {
|
|
|
1185
1140
|
function getSessionIdFromMessages(messages) {
|
|
1186
1141
|
return messages.find((message) => message.sessionId)?.sessionId;
|
|
1187
1142
|
}
|
|
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
1143
|
function useChatV2(config, callbacks = {}) {
|
|
1208
1144
|
const [messages, setMessages] = useState(() => getStoredOrInitialMessages(config));
|
|
1209
1145
|
const [isWaitingForResponse, setIsWaitingForResponse] = useState(() => {
|
|
1210
1146
|
if (!config.userId) return false;
|
|
1211
1147
|
return activeStreamStore.get(config.userId)?.isWaiting ?? false;
|
|
1212
1148
|
});
|
|
1213
|
-
const [isUploadingAttachments, setIsUploadingAttachments] = useState(false);
|
|
1214
1149
|
const sessionIdRef = useRef(
|
|
1215
1150
|
getSessionIdFromMessages(getStoredOrInitialMessages(config)) ?? config.initialSessionId ?? void 0
|
|
1216
1151
|
);
|
|
@@ -1253,7 +1188,28 @@ function useChatV2(config, callbacks = {}) {
|
|
|
1253
1188
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
1254
1189
|
[]
|
|
1255
1190
|
);
|
|
1256
|
-
const [userActionState, setUserActionState] = useState(
|
|
1191
|
+
const [userActionState, setUserActionState] = useState(() => {
|
|
1192
|
+
if (!config.userId) return EMPTY_USER_ACTION_STATE2;
|
|
1193
|
+
return activeStreamStore.get(config.userId)?.userActionState ?? EMPTY_USER_ACTION_STATE2;
|
|
1194
|
+
});
|
|
1195
|
+
const storeAwareSetUserActionState = useCallback(
|
|
1196
|
+
(updater) => {
|
|
1197
|
+
const streamUserId = streamUserIdRef.current;
|
|
1198
|
+
const currentUserId = configRef.current.userId;
|
|
1199
|
+
const storeKey = streamUserId ?? currentUserId;
|
|
1200
|
+
if (storeKey && activeStreamStore.has(storeKey)) {
|
|
1201
|
+
activeStreamStore.applyUserActionState(
|
|
1202
|
+
storeKey,
|
|
1203
|
+
updater
|
|
1204
|
+
);
|
|
1205
|
+
}
|
|
1206
|
+
if (!streamUserId || streamUserId === currentUserId) {
|
|
1207
|
+
setUserActionState(updater);
|
|
1208
|
+
}
|
|
1209
|
+
},
|
|
1210
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
1211
|
+
[]
|
|
1212
|
+
);
|
|
1257
1213
|
const wrappedCallbacks = useMemo(() => ({
|
|
1258
1214
|
...callbacksRef.current,
|
|
1259
1215
|
onMessageSent: (message) => callbacksRef.current.onMessageSent?.(message),
|
|
@@ -1263,14 +1219,14 @@ function useChatV2(config, callbacks = {}) {
|
|
|
1263
1219
|
onExecutionTraceClick: (data) => callbacksRef.current.onExecutionTraceClick?.(data),
|
|
1264
1220
|
onSessionIdChange: (sessionId) => callbacksRef.current.onSessionIdChange?.(sessionId),
|
|
1265
1221
|
onUserActionRequired: (request) => {
|
|
1266
|
-
|
|
1222
|
+
storeAwareSetUserActionState((prev) => ({
|
|
1267
1223
|
...prev,
|
|
1268
1224
|
prompts: upsertPrompt(prev.prompts, request)
|
|
1269
1225
|
}));
|
|
1270
1226
|
callbacksRef.current.onUserActionRequired?.(request);
|
|
1271
1227
|
},
|
|
1272
1228
|
onUserNotification: (notification) => {
|
|
1273
|
-
|
|
1229
|
+
storeAwareSetUserActionState(
|
|
1274
1230
|
(prev) => prev.notifications.some((n) => n.id === notification.id) ? prev : { ...prev, notifications: [...prev.notifications, notification] }
|
|
1275
1231
|
);
|
|
1276
1232
|
callbacksRef.current.onUserNotification?.(notification);
|
|
@@ -1285,45 +1241,21 @@ function useChatV2(config, callbacks = {}) {
|
|
|
1285
1241
|
);
|
|
1286
1242
|
const sendMessage = useCallback(
|
|
1287
1243
|
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
|
-
}
|
|
1244
|
+
if (!userMessage.trim()) return;
|
|
1306
1245
|
if (!sessionIdRef.current && configRef.current.autoGenerateSessionId !== false) {
|
|
1307
1246
|
sessionIdRef.current = generateId();
|
|
1308
1247
|
callbacksRef.current.onSessionIdChange?.(sessionIdRef.current);
|
|
1309
1248
|
}
|
|
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
1249
|
const userMessageId = `user-${Date.now()}`;
|
|
1317
1250
|
const userMsg = {
|
|
1318
1251
|
id: userMessageId,
|
|
1319
1252
|
sessionId: sessionIdRef.current,
|
|
1320
1253
|
role: "user",
|
|
1321
|
-
content:
|
|
1322
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
1323
|
-
attachments: messageAttachments
|
|
1254
|
+
content: userMessage,
|
|
1255
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
1324
1256
|
};
|
|
1325
1257
|
setMessages((prev) => [...prev, userMsg]);
|
|
1326
|
-
callbacksRef.current.onMessageSent?.(
|
|
1258
|
+
callbacksRef.current.onMessageSent?.(userMessage);
|
|
1327
1259
|
setIsWaitingForResponse(true);
|
|
1328
1260
|
callbacksRef.current.onStreamStart?.();
|
|
1329
1261
|
const streamingId = `assistant-${Date.now()}`;
|
|
@@ -1350,14 +1282,11 @@ function useChatV2(config, callbacks = {}) {
|
|
|
1350
1282
|
activeStreamStore.start(userId, abortController, initialMessages);
|
|
1351
1283
|
}
|
|
1352
1284
|
const newSessionId = await startStream(
|
|
1353
|
-
|
|
1285
|
+
userMessage,
|
|
1354
1286
|
streamingId,
|
|
1355
1287
|
sessionIdRef.current,
|
|
1356
1288
|
abortController,
|
|
1357
|
-
|
|
1358
|
-
analysisMode: options?.analysisMode,
|
|
1359
|
-
attachments: streamAttachments
|
|
1360
|
-
}
|
|
1289
|
+
options
|
|
1361
1290
|
);
|
|
1362
1291
|
const finalStreamUserId = streamUserIdRef.current ?? userId;
|
|
1363
1292
|
if (finalStreamUserId) {
|
|
@@ -1387,7 +1316,7 @@ function useChatV2(config, callbacks = {}) {
|
|
|
1387
1316
|
streamUserIdRef.current = void 0;
|
|
1388
1317
|
cancelStreamManager();
|
|
1389
1318
|
setIsWaitingForResponse(false);
|
|
1390
|
-
|
|
1319
|
+
storeAwareSetUserActionState((prev) => ({ ...prev, prompts: [] }));
|
|
1391
1320
|
setMessages(
|
|
1392
1321
|
(prev) => prev.map((msg) => {
|
|
1393
1322
|
if (msg.isStreaming) {
|
|
@@ -1402,7 +1331,7 @@ function useChatV2(config, callbacks = {}) {
|
|
|
1402
1331
|
return msg;
|
|
1403
1332
|
})
|
|
1404
1333
|
);
|
|
1405
|
-
}, [cancelStreamManager]);
|
|
1334
|
+
}, [cancelStreamManager, storeAwareSetUserActionState]);
|
|
1406
1335
|
const resetSession = useCallback(() => {
|
|
1407
1336
|
const streamUserId = streamUserIdRef.current ?? configRef.current.userId;
|
|
1408
1337
|
if (streamUserId) {
|
|
@@ -1416,7 +1345,7 @@ function useChatV2(config, callbacks = {}) {
|
|
|
1416
1345
|
sessionIdRef.current = void 0;
|
|
1417
1346
|
abortControllerRef.current?.abort();
|
|
1418
1347
|
setIsWaitingForResponse(false);
|
|
1419
|
-
|
|
1348
|
+
storeAwareSetUserActionState(EMPTY_USER_ACTION_STATE2);
|
|
1420
1349
|
}, []);
|
|
1421
1350
|
const getSessionId = useCallback(() => {
|
|
1422
1351
|
return sessionIdRef.current;
|
|
@@ -1426,21 +1355,21 @@ function useChatV2(config, callbacks = {}) {
|
|
|
1426
1355
|
}, [messages]);
|
|
1427
1356
|
const setPromptStatus = useCallback(
|
|
1428
1357
|
(userActionId, status) => {
|
|
1429
|
-
|
|
1358
|
+
storeAwareSetUserActionState((prev) => ({
|
|
1430
1359
|
...prev,
|
|
1431
1360
|
prompts: prev.prompts.map(
|
|
1432
1361
|
(p) => p.userActionId === userActionId ? { ...p, status } : p
|
|
1433
1362
|
)
|
|
1434
1363
|
}));
|
|
1435
1364
|
},
|
|
1436
|
-
[]
|
|
1365
|
+
[storeAwareSetUserActionState]
|
|
1437
1366
|
);
|
|
1438
1367
|
const removePrompt = useCallback((userActionId) => {
|
|
1439
|
-
|
|
1368
|
+
storeAwareSetUserActionState((prev) => ({
|
|
1440
1369
|
...prev,
|
|
1441
1370
|
prompts: prev.prompts.filter((p) => p.userActionId !== userActionId)
|
|
1442
1371
|
}));
|
|
1443
|
-
}, []);
|
|
1372
|
+
}, [storeAwareSetUserActionState]);
|
|
1444
1373
|
const submitUserAction2 = useCallback(
|
|
1445
1374
|
async (userActionId, content) => {
|
|
1446
1375
|
setPromptStatus(userActionId, "submitting");
|
|
@@ -1495,12 +1424,25 @@ function useChatV2(config, callbacks = {}) {
|
|
|
1495
1424
|
},
|
|
1496
1425
|
[setPromptStatus]
|
|
1497
1426
|
);
|
|
1427
|
+
const expireUserAction2 = useCallback(
|
|
1428
|
+
async (userActionId) => {
|
|
1429
|
+
setPromptStatus(userActionId, "expired");
|
|
1430
|
+
try {
|
|
1431
|
+
await expireUserAction(configRef.current, userActionId);
|
|
1432
|
+
} catch (error) {
|
|
1433
|
+
if (error instanceof UserActionStaleError) return;
|
|
1434
|
+
callbacksRef.current.onError?.(error);
|
|
1435
|
+
throw error;
|
|
1436
|
+
}
|
|
1437
|
+
},
|
|
1438
|
+
[setPromptStatus]
|
|
1439
|
+
);
|
|
1498
1440
|
const dismissNotification = useCallback((id) => {
|
|
1499
|
-
|
|
1441
|
+
storeAwareSetUserActionState((prev) => ({
|
|
1500
1442
|
...prev,
|
|
1501
1443
|
notifications: prev.notifications.filter((n) => n.id !== id)
|
|
1502
1444
|
}));
|
|
1503
|
-
}, []);
|
|
1445
|
+
}, [storeAwareSetUserActionState]);
|
|
1504
1446
|
useEffect(() => {
|
|
1505
1447
|
const prevSubscriptionUserId = subscriptionPrevUserIdRef.current;
|
|
1506
1448
|
subscriptionPrevUserIdRef.current = config.userId;
|
|
@@ -1509,14 +1451,17 @@ function useChatV2(config, callbacks = {}) {
|
|
|
1509
1451
|
if (prevSubscriptionUserId && prevSubscriptionUserId !== userId && streamUserIdRef.current === prevSubscriptionUserId && !activeStreamStore.has(prevSubscriptionUserId) && activeStreamStore.has(userId)) {
|
|
1510
1452
|
streamUserIdRef.current = userId;
|
|
1511
1453
|
}
|
|
1512
|
-
const unsubscribe = activeStreamStore.subscribe(userId, (msgs, isWaiting) => {
|
|
1454
|
+
const unsubscribe = activeStreamStore.subscribe(userId, (msgs, isWaiting, actions) => {
|
|
1513
1455
|
setMessages(msgs);
|
|
1514
1456
|
setIsWaitingForResponse(isWaiting);
|
|
1457
|
+
setUserActionState(actions);
|
|
1515
1458
|
});
|
|
1516
1459
|
const active = activeStreamStore.get(userId);
|
|
1517
1460
|
if (active) {
|
|
1461
|
+
streamUserIdRef.current = userId;
|
|
1518
1462
|
setMessages(active.messages);
|
|
1519
1463
|
setIsWaitingForResponse(active.isWaiting);
|
|
1464
|
+
setUserActionState(active.userActionState);
|
|
1520
1465
|
}
|
|
1521
1466
|
return unsubscribe;
|
|
1522
1467
|
}, [config.userId]);
|
|
@@ -1535,18 +1480,6 @@ function useChatV2(config, callbacks = {}) {
|
|
|
1535
1480
|
setMessages(config.initialMessages);
|
|
1536
1481
|
sessionIdRef.current = getSessionIdFromMessages(config.initialMessages) ?? config.initialSessionId;
|
|
1537
1482
|
}, [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
1483
|
useEffect(() => {
|
|
1551
1484
|
const prevUserId = prevUserIdRef.current;
|
|
1552
1485
|
prevUserIdRef.current = config.userId;
|
|
@@ -1556,12 +1489,14 @@ function useChatV2(config, callbacks = {}) {
|
|
|
1556
1489
|
setMessages([]);
|
|
1557
1490
|
sessionIdRef.current = void 0;
|
|
1558
1491
|
setIsWaitingForResponse(false);
|
|
1559
|
-
setUserActionState(
|
|
1492
|
+
setUserActionState(EMPTY_USER_ACTION_STATE2);
|
|
1560
1493
|
} else if (config.userId) {
|
|
1561
1494
|
const active = activeStreamStore.get(config.userId);
|
|
1562
1495
|
if (active) {
|
|
1496
|
+
streamUserIdRef.current = config.userId;
|
|
1563
1497
|
setMessages(active.messages);
|
|
1564
1498
|
setIsWaitingForResponse(active.isWaiting);
|
|
1499
|
+
setUserActionState(active.userActionState);
|
|
1565
1500
|
sessionIdRef.current = getSessionIdFromMessages(active.messages) ?? config.initialSessionId;
|
|
1566
1501
|
return;
|
|
1567
1502
|
}
|
|
@@ -1581,12 +1516,12 @@ function useChatV2(config, callbacks = {}) {
|
|
|
1581
1516
|
getSessionId,
|
|
1582
1517
|
getMessages,
|
|
1583
1518
|
isWaitingForResponse,
|
|
1584
|
-
isUploadingAttachments,
|
|
1585
1519
|
sessionId: sessionIdRef.current,
|
|
1586
1520
|
userActionState,
|
|
1587
1521
|
submitUserAction: submitUserAction2,
|
|
1588
1522
|
cancelUserAction: cancelUserAction2,
|
|
1589
1523
|
resendUserAction: resendUserAction2,
|
|
1524
|
+
expireUserAction: expireUserAction2,
|
|
1590
1525
|
dismissNotification
|
|
1591
1526
|
};
|
|
1592
1527
|
}
|
|
@@ -4734,14 +4669,15 @@ function NotificationInline({ notification, onDismiss }) {
|
|
|
4734
4669
|
] });
|
|
4735
4670
|
}
|
|
4736
4671
|
function useExpiryCountdown(prompt) {
|
|
4737
|
-
const
|
|
4738
|
-
const [secondsLeft, setSecondsLeft] = useState(
|
|
4672
|
+
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;
|
|
4673
|
+
const [secondsLeft, setSecondsLeft] = useState(
|
|
4674
|
+
() => deadlineMs !== void 0 ? Math.max(0, Math.ceil((deadlineMs - Date.now()) / 1e3)) : void 0
|
|
4675
|
+
);
|
|
4739
4676
|
useEffect(() => {
|
|
4740
|
-
if (
|
|
4677
|
+
if (deadlineMs === void 0) {
|
|
4741
4678
|
setSecondsLeft(void 0);
|
|
4742
4679
|
return;
|
|
4743
4680
|
}
|
|
4744
|
-
const deadlineMs = Date.now() + initial * 1e3;
|
|
4745
4681
|
let intervalId;
|
|
4746
4682
|
const remaining = () => Math.max(0, Math.ceil((deadlineMs - Date.now()) / 1e3));
|
|
4747
4683
|
const sync = () => {
|
|
@@ -4763,8 +4699,8 @@ function useExpiryCountdown(prompt) {
|
|
|
4763
4699
|
window.removeEventListener("focus", sync);
|
|
4764
4700
|
window.removeEventListener("pageshow", sync);
|
|
4765
4701
|
};
|
|
4766
|
-
}, [prompt.userActionId, prompt.subAction,
|
|
4767
|
-
const expired =
|
|
4702
|
+
}, [prompt.userActionId, prompt.subAction, deadlineMs]);
|
|
4703
|
+
const expired = deadlineMs !== void 0 && (getUserActionSecondsLeft(prompt) ?? secondsLeft ?? 0) <= 0;
|
|
4768
4704
|
return [secondsLeft, expired];
|
|
4769
4705
|
}
|
|
4770
4706
|
function UserActionInline({
|
|
@@ -6319,7 +6255,7 @@ var PaymanChatInner = forwardRef(function PaymanChatInner2({
|
|
|
6319
6255
|
const submitUserAction2 = chat.submitUserAction ?? NOOP_ASYNC;
|
|
6320
6256
|
const cancelUserAction2 = chat.cancelUserAction ?? NOOP_ASYNC;
|
|
6321
6257
|
const resendUserAction2 = chat.resendUserAction ?? NOOP_ASYNC;
|
|
6322
|
-
const
|
|
6258
|
+
const expireUserAction2 = chat.expireUserAction ?? NOOP_ASYNC;
|
|
6323
6259
|
const dismissNotification = chat.dismissNotification ?? NOOP;
|
|
6324
6260
|
const isUserActionSupported = typeof chat.submitUserAction === "function" && typeof chat.cancelUserAction === "function" && typeof chat.resendUserAction === "function";
|
|
6325
6261
|
const {
|
|
@@ -6720,7 +6656,7 @@ var PaymanChatInner = forwardRef(function PaymanChatInner2({
|
|
|
6720
6656
|
onSubmitUserAction: isUserActionSupported ? submitUserAction2 : void 0,
|
|
6721
6657
|
onCancelUserAction: isUserActionSupported ? cancelUserAction2 : void 0,
|
|
6722
6658
|
onResendUserAction: isUserActionSupported ? resendUserAction2 : void 0,
|
|
6723
|
-
onExpireUserAction: isUserActionSupported ?
|
|
6659
|
+
onExpireUserAction: isUserActionSupported ? expireUserAction2 : void 0,
|
|
6724
6660
|
onDismissNotification: dismissNotification,
|
|
6725
6661
|
onSubmitFeedback: handleSubmitFeedback
|
|
6726
6662
|
}
|