@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.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 { messages: entry.messages, isWaiting: entry.isWaiting };
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
- var EMPTY_USER_ACTION_STATE = { prompts: [], notifications: [] };
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(EMPTY_USER_ACTION_STATE);
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
- setUserActionState((prev) => ({
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
- setUserActionState(
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
- const trimmedMessage = userMessage.trim();
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: trimmedMessage,
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?.(trimmedMessage);
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
- trimmedMessage,
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
- setUserActionState((prev) => ({ ...prev, prompts: [] }));
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
- setUserActionState(EMPTY_USER_ACTION_STATE);
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
- setUserActionState((prev) => ({
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
- setUserActionState((prev) => ({
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
- setUserActionState((prev) => ({
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(EMPTY_USER_ACTION_STATE);
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 initial = typeof prompt.expirySeconds === "number" && prompt.expirySeconds > 0 ? Math.floor(prompt.expirySeconds) : void 0;
4738
- const [secondsLeft, setSecondsLeft] = useState(initial);
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 (initial === void 0) {
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, initial]);
4767
- const expired = initial !== void 0 && secondsLeft === 0;
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 expireUserAction = chat.expireUserAction ?? NOOP_ASYNC;
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 ? expireUserAction : void 0,
6659
+ onExpireUserAction: isUserActionSupported ? expireUserAction2 : void 0,
6724
6660
  onDismissNotification: dismissNotification,
6725
6661
  onSubmitFeedback: handleSubmitFeedback
6726
6662
  }