@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 CHANGED
@@ -60,6 +60,7 @@ var chatStore = {
60
60
  memoryStore.delete(key);
61
61
  }
62
62
  };
63
+ var EMPTY_USER_ACTION_STATE = { prompts: [], notifications: [] };
63
64
  var streams = /* @__PURE__ */ new Map();
64
65
  var activeStreamStore = {
65
66
  has(key) {
@@ -68,7 +69,11 @@ var activeStreamStore = {
68
69
  get(key) {
69
70
  const entry = streams.get(key);
70
71
  if (!entry) return null;
71
- return { messages: entry.messages, isWaiting: entry.isWaiting };
72
+ return {
73
+ messages: entry.messages,
74
+ isWaiting: entry.isWaiting,
75
+ userActionState: entry.userActionState
76
+ };
72
77
  },
73
78
  // Called before startStream — registers the controller and initial messages
74
79
  start(key, abortController, initialMessages) {
@@ -76,6 +81,7 @@ var activeStreamStore = {
76
81
  streams.set(key, {
77
82
  messages: initialMessages,
78
83
  isWaiting: true,
84
+ userActionState: EMPTY_USER_ACTION_STATE,
79
85
  abortController,
80
86
  listeners: existing?.listeners ?? /* @__PURE__ */ new Set()
81
87
  });
@@ -86,20 +92,27 @@ var activeStreamStore = {
86
92
  if (!entry) return;
87
93
  const next = typeof updater === "function" ? updater(entry.messages) : updater;
88
94
  entry.messages = next;
89
- entry.listeners.forEach((l) => l(next, entry.isWaiting));
95
+ entry.listeners.forEach((l) => l(next, entry.isWaiting, entry.userActionState));
90
96
  },
91
97
  setWaiting(key, waiting) {
92
98
  const entry = streams.get(key);
93
99
  if (!entry) return;
94
100
  entry.isWaiting = waiting;
95
- entry.listeners.forEach((l) => l(entry.messages, waiting));
101
+ entry.listeners.forEach((l) => l(entry.messages, waiting, entry.userActionState));
102
+ },
103
+ applyUserActionState(key, updater) {
104
+ const entry = streams.get(key);
105
+ if (!entry) return;
106
+ const next = typeof updater === "function" ? updater(entry.userActionState) : updater;
107
+ entry.userActionState = next;
108
+ entry.listeners.forEach((l) => l(entry.messages, entry.isWaiting, next));
96
109
  },
97
110
  // Called when stream completes — persists to chatStore and cleans up
98
111
  complete(key) {
99
112
  const entry = streams.get(key);
100
113
  if (!entry) return;
101
114
  entry.isWaiting = false;
102
- entry.listeners.forEach((l) => l(entry.messages, false));
115
+ entry.listeners.forEach((l) => l(entry.messages, false, entry.userActionState));
103
116
  const toSave = entry.messages.filter((m) => !m.isStreaming);
104
117
  if (toSave.length > 0) chatStore.set(key, toSave);
105
118
  streams.delete(key);
@@ -736,8 +749,7 @@ function buildRequestBody(config, userMessage, sessionId, options) {
736
749
  sessionAttributes,
737
750
  analysisMode: options?.analysisMode,
738
751
  locale: resolveLocale(config.locale),
739
- timezone: resolveTimezone(config.timezone),
740
- ...options?.attachments?.length ? { attachments: options.attachments } : {}
752
+ timezone: resolveTimezone(config.timezone)
741
753
  };
742
754
  }
743
755
  function resolveLocale(configured) {
@@ -782,7 +794,6 @@ function buildResolveImagesUrl(config) {
782
794
  const basePath = normalizedEndpointPath.endsWith("/stream") ? normalizedEndpointPath.slice(0, -"/stream".length) : normalizedEndpointPath;
783
795
  return `${config.api.baseUrl}${basePath}/resolve-image-urls`;
784
796
  }
785
- var NGROK_SKIP_BROWSER_WARNING = "ngrok-skip-browser-warning";
786
797
  function buildRequestHeaders(config) {
787
798
  const headers = {
788
799
  ...config.api.headers
@@ -790,9 +801,6 @@ function buildRequestHeaders(config) {
790
801
  if (config.api.authToken) {
791
802
  headers.Authorization = `Bearer ${config.api.authToken}`;
792
803
  }
793
- if (!headers[NGROK_SKIP_BROWSER_WARNING]) {
794
- headers[NGROK_SKIP_BROWSER_WARNING] = "true";
795
- }
796
804
  return headers;
797
805
  }
798
806
  var RAG_IMAGE_REGEX = /\/api\/rag\/chunks\/[^"'\s]+\/image/;
@@ -1073,81 +1081,6 @@ function createCancelledMessageUpdate(steps, currentMessage) {
1073
1081
  currentMessage: currentMessage || "Thinking..."
1074
1082
  };
1075
1083
  }
1076
- var DEFAULT_SIGNED_URL_ENDPOINT = "/api/files/signed-url";
1077
- function fileExtension(filename) {
1078
- const ext = filename.split(".").pop()?.toLowerCase().replace(/^\./, "");
1079
- return ext && ext.length > 0 ? ext : "bin";
1080
- }
1081
- function resolveMimeType(file) {
1082
- if (file.type && file.type.trim().length > 0) return file.type;
1083
- const ext = fileExtension(file.name);
1084
- const byExt = {
1085
- pdf: "application/pdf",
1086
- png: "image/png",
1087
- jpg: "image/jpeg",
1088
- jpeg: "image/jpeg",
1089
- gif: "image/gif",
1090
- webp: "image/webp"
1091
- };
1092
- return byExt[ext] ?? "application/octet-stream";
1093
- }
1094
- function buildSignedUrlEndpoint(config, ext) {
1095
- const endpoint = config.api.signedUrlEndpoint || DEFAULT_SIGNED_URL_ENDPOINT;
1096
- const queryParams = new URLSearchParams({ extn: ext.replace(/^\./, "") });
1097
- return `${config.api.baseUrl}${endpoint}?${queryParams.toString()}`;
1098
- }
1099
- async function requestSignedUrl(config, ext, signal) {
1100
- const url = buildSignedUrlEndpoint(config, ext);
1101
- const headers = buildRequestHeaders(config);
1102
- const response = await fetch(url, {
1103
- method: "GET",
1104
- headers,
1105
- signal
1106
- });
1107
- if (!response.ok) {
1108
- const errorText = await response.text().catch(() => "");
1109
- throw new Error(
1110
- errorText ? `Failed to get upload URL (${response.status}): ${errorText}` : `Failed to get upload URL (${response.status})`
1111
- );
1112
- }
1113
- const data = await response.json();
1114
- if (!data.key || !data.url) {
1115
- throw new Error("Signed URL response missing key or url");
1116
- }
1117
- return { key: data.key, url: data.url };
1118
- }
1119
- async function uploadToSignedUrl(signedUrl, file, mimeType, signal) {
1120
- const response = await fetch(signedUrl, {
1121
- method: "PUT",
1122
- headers: {
1123
- "Content-Type": mimeType,
1124
- "x-ms-blob-type": "BlockBlob"
1125
- },
1126
- body: file,
1127
- signal
1128
- });
1129
- if (!response.ok) {
1130
- const errorText = await response.text().catch(() => "");
1131
- throw new Error(
1132
- errorText ? `Failed to upload file (${response.status}): ${errorText}` : `Failed to upload file (${response.status})`
1133
- );
1134
- }
1135
- }
1136
- async function uploadAttachment(config, file, signal) {
1137
- const ext = fileExtension(file.name);
1138
- const mimeType = resolveMimeType(file);
1139
- const { key, url } = await requestSignedUrl(config, ext, signal);
1140
- await uploadToSignedUrl(url, file, mimeType, signal);
1141
- return {
1142
- tempKey: key,
1143
- filename: file.name,
1144
- mimeType
1145
- };
1146
- }
1147
- async function uploadAttachments(config, files, signal) {
1148
- const uploads = files.map((file) => uploadAttachment(config, file, signal));
1149
- return Promise.all(uploads);
1150
- }
1151
1084
  var UserActionStaleError = class extends Error {
1152
1085
  constructor(userActionId, message = "User action is no longer actionable") {
1153
1086
  super(message);
@@ -1184,12 +1117,34 @@ async function cancelUserAction(config, userActionId) {
1184
1117
  async function resendUserAction(config, userActionId) {
1185
1118
  return sendUserActionRequest(config, userActionId, "resend");
1186
1119
  }
1187
- var EMPTY_USER_ACTION_STATE = { prompts: [], notifications: [] };
1120
+ async function expireUserAction(config, userActionId) {
1121
+ return sendUserActionRequest(config, userActionId, "expired");
1122
+ }
1123
+ function resolveUserActionExpiresAt(req, existing) {
1124
+ if (typeof req.expirySeconds !== "number" || req.expirySeconds <= 0) {
1125
+ return void 0;
1126
+ }
1127
+ if (existing?.expiresAt && existing.userActionId === req.userActionId) {
1128
+ return existing.expiresAt;
1129
+ }
1130
+ return Date.now() + Math.floor(req.expirySeconds) * 1e3;
1131
+ }
1132
+ function getUserActionSecondsLeft(prompt) {
1133
+ if (typeof prompt.expiresAt === "number" && prompt.expiresAt > 0) {
1134
+ return Math.max(0, Math.ceil((prompt.expiresAt - Date.now()) / 1e3));
1135
+ }
1136
+ if (typeof prompt.expirySeconds === "number" && prompt.expirySeconds > 0) {
1137
+ return Math.floor(prompt.expirySeconds);
1138
+ }
1139
+ return void 0;
1140
+ }
1141
+ var EMPTY_USER_ACTION_STATE2 = { prompts: [], notifications: [] };
1188
1142
  function upsertPrompt(prompts, req) {
1189
- const active = { ...req, status: "pending" };
1190
1143
  const idx = prompts.findIndex(
1191
1144
  (p) => req.toolCallId ? p.toolCallId === req.toolCallId : p.userActionId === req.userActionId
1192
1145
  );
1146
+ const expiresAt = resolveUserActionExpiresAt(req, idx >= 0 ? prompts[idx] : void 0);
1147
+ const active = { ...req, status: "pending", expiresAt };
1193
1148
  if (idx >= 0) {
1194
1149
  const next = prompts.slice();
1195
1150
  next[idx] = active;
@@ -1212,32 +1167,12 @@ function getStoredOrInitialMessages(config) {
1212
1167
  function getSessionIdFromMessages(messages) {
1213
1168
  return messages.find((message) => message.sessionId)?.sessionId;
1214
1169
  }
1215
- var IMAGE_EXTENSIONS = /* @__PURE__ */ new Set(["jpg", "jpeg", "png", "gif", "webp", "avif"]);
1216
- function attachmentKindFromFile(file) {
1217
- const ext = file.name.split(".").pop()?.toLowerCase() ?? "";
1218
- if (IMAGE_EXTENSIONS.has(ext) || file.type.startsWith("image/")) return "image";
1219
- return "file";
1220
- }
1221
- function buildMessageAttachments(files) {
1222
- return files.map((file, index) => {
1223
- const kind = attachmentKindFromFile(file);
1224
- return {
1225
- id: `att-${Date.now()}-${index}`,
1226
- filename: file.name,
1227
- mimeType: file.type || "application/octet-stream",
1228
- // Blob URL for all local files so PDFs/docs stay previewable after send.
1229
- previewUrl: URL.createObjectURL(file),
1230
- kind
1231
- };
1232
- });
1233
- }
1234
1170
  function useChatV2(config, callbacks = {}) {
1235
1171
  const [messages, setMessages] = react.useState(() => getStoredOrInitialMessages(config));
1236
1172
  const [isWaitingForResponse, setIsWaitingForResponse] = react.useState(() => {
1237
1173
  if (!config.userId) return false;
1238
1174
  return activeStreamStore.get(config.userId)?.isWaiting ?? false;
1239
1175
  });
1240
- const [isUploadingAttachments, setIsUploadingAttachments] = react.useState(false);
1241
1176
  const sessionIdRef = react.useRef(
1242
1177
  getSessionIdFromMessages(getStoredOrInitialMessages(config)) ?? config.initialSessionId ?? void 0
1243
1178
  );
@@ -1280,7 +1215,28 @@ function useChatV2(config, callbacks = {}) {
1280
1215
  // eslint-disable-next-line react-hooks/exhaustive-deps
1281
1216
  []
1282
1217
  );
1283
- const [userActionState, setUserActionState] = react.useState(EMPTY_USER_ACTION_STATE);
1218
+ const [userActionState, setUserActionState] = react.useState(() => {
1219
+ if (!config.userId) return EMPTY_USER_ACTION_STATE2;
1220
+ return activeStreamStore.get(config.userId)?.userActionState ?? EMPTY_USER_ACTION_STATE2;
1221
+ });
1222
+ const storeAwareSetUserActionState = react.useCallback(
1223
+ (updater) => {
1224
+ const streamUserId = streamUserIdRef.current;
1225
+ const currentUserId = configRef.current.userId;
1226
+ const storeKey = streamUserId ?? currentUserId;
1227
+ if (storeKey && activeStreamStore.has(storeKey)) {
1228
+ activeStreamStore.applyUserActionState(
1229
+ storeKey,
1230
+ updater
1231
+ );
1232
+ }
1233
+ if (!streamUserId || streamUserId === currentUserId) {
1234
+ setUserActionState(updater);
1235
+ }
1236
+ },
1237
+ // eslint-disable-next-line react-hooks/exhaustive-deps
1238
+ []
1239
+ );
1284
1240
  const wrappedCallbacks = react.useMemo(() => ({
1285
1241
  ...callbacksRef.current,
1286
1242
  onMessageSent: (message) => callbacksRef.current.onMessageSent?.(message),
@@ -1290,14 +1246,14 @@ function useChatV2(config, callbacks = {}) {
1290
1246
  onExecutionTraceClick: (data) => callbacksRef.current.onExecutionTraceClick?.(data),
1291
1247
  onSessionIdChange: (sessionId) => callbacksRef.current.onSessionIdChange?.(sessionId),
1292
1248
  onUserActionRequired: (request) => {
1293
- setUserActionState((prev) => ({
1249
+ storeAwareSetUserActionState((prev) => ({
1294
1250
  ...prev,
1295
1251
  prompts: upsertPrompt(prev.prompts, request)
1296
1252
  }));
1297
1253
  callbacksRef.current.onUserActionRequired?.(request);
1298
1254
  },
1299
1255
  onUserNotification: (notification) => {
1300
- setUserActionState(
1256
+ storeAwareSetUserActionState(
1301
1257
  (prev) => prev.notifications.some((n) => n.id === notification.id) ? prev : { ...prev, notifications: [...prev.notifications, notification] }
1302
1258
  );
1303
1259
  callbacksRef.current.onUserNotification?.(notification);
@@ -1312,45 +1268,21 @@ function useChatV2(config, callbacks = {}) {
1312
1268
  );
1313
1269
  const sendMessage = react.useCallback(
1314
1270
  async (userMessage, options) => {
1315
- const trimmedMessage = userMessage.trim();
1316
- const files = options?.files ?? [];
1317
- const hasPreuploadedAttachments = (options?.attachments?.length ?? 0) > 0;
1318
- if (!trimmedMessage && files.length === 0 && !hasPreuploadedAttachments) return;
1319
- let streamAttachments = options?.attachments;
1320
- if (!streamAttachments && files.length > 0) {
1321
- setIsUploadingAttachments(true);
1322
- try {
1323
- streamAttachments = await uploadAttachments(configRef.current, files);
1324
- } catch (error) {
1325
- if (error.name !== "AbortError") {
1326
- callbacksRef.current.onError?.(error);
1327
- }
1328
- throw error;
1329
- } finally {
1330
- setIsUploadingAttachments(false);
1331
- }
1332
- }
1271
+ if (!userMessage.trim()) return;
1333
1272
  if (!sessionIdRef.current && configRef.current.autoGenerateSessionId !== false) {
1334
1273
  sessionIdRef.current = generateId();
1335
1274
  callbacksRef.current.onSessionIdChange?.(sessionIdRef.current);
1336
1275
  }
1337
- const messageAttachments = files.length > 0 ? buildMessageAttachments(files) : streamAttachments?.length ? streamAttachments.map((attachment, index) => ({
1338
- id: `att-${Date.now()}-${index}`,
1339
- filename: attachment.filename,
1340
- mimeType: attachment.mimeType,
1341
- kind: attachment.mimeType.startsWith("image/") ? "image" : "file"
1342
- })) : void 0;
1343
1276
  const userMessageId = `user-${Date.now()}`;
1344
1277
  const userMsg = {
1345
1278
  id: userMessageId,
1346
1279
  sessionId: sessionIdRef.current,
1347
1280
  role: "user",
1348
- content: trimmedMessage,
1349
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1350
- attachments: messageAttachments
1281
+ content: userMessage,
1282
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
1351
1283
  };
1352
1284
  setMessages((prev) => [...prev, userMsg]);
1353
- callbacksRef.current.onMessageSent?.(trimmedMessage);
1285
+ callbacksRef.current.onMessageSent?.(userMessage);
1354
1286
  setIsWaitingForResponse(true);
1355
1287
  callbacksRef.current.onStreamStart?.();
1356
1288
  const streamingId = `assistant-${Date.now()}`;
@@ -1377,14 +1309,11 @@ function useChatV2(config, callbacks = {}) {
1377
1309
  activeStreamStore.start(userId, abortController, initialMessages);
1378
1310
  }
1379
1311
  const newSessionId = await startStream(
1380
- trimmedMessage,
1312
+ userMessage,
1381
1313
  streamingId,
1382
1314
  sessionIdRef.current,
1383
1315
  abortController,
1384
- {
1385
- analysisMode: options?.analysisMode,
1386
- attachments: streamAttachments
1387
- }
1316
+ options
1388
1317
  );
1389
1318
  const finalStreamUserId = streamUserIdRef.current ?? userId;
1390
1319
  if (finalStreamUserId) {
@@ -1414,7 +1343,7 @@ function useChatV2(config, callbacks = {}) {
1414
1343
  streamUserIdRef.current = void 0;
1415
1344
  cancelStreamManager();
1416
1345
  setIsWaitingForResponse(false);
1417
- setUserActionState((prev) => ({ ...prev, prompts: [] }));
1346
+ storeAwareSetUserActionState((prev) => ({ ...prev, prompts: [] }));
1418
1347
  setMessages(
1419
1348
  (prev) => prev.map((msg) => {
1420
1349
  if (msg.isStreaming) {
@@ -1429,7 +1358,7 @@ function useChatV2(config, callbacks = {}) {
1429
1358
  return msg;
1430
1359
  })
1431
1360
  );
1432
- }, [cancelStreamManager]);
1361
+ }, [cancelStreamManager, storeAwareSetUserActionState]);
1433
1362
  const resetSession = react.useCallback(() => {
1434
1363
  const streamUserId = streamUserIdRef.current ?? configRef.current.userId;
1435
1364
  if (streamUserId) {
@@ -1443,7 +1372,7 @@ function useChatV2(config, callbacks = {}) {
1443
1372
  sessionIdRef.current = void 0;
1444
1373
  abortControllerRef.current?.abort();
1445
1374
  setIsWaitingForResponse(false);
1446
- setUserActionState(EMPTY_USER_ACTION_STATE);
1375
+ storeAwareSetUserActionState(EMPTY_USER_ACTION_STATE2);
1447
1376
  }, []);
1448
1377
  const getSessionId = react.useCallback(() => {
1449
1378
  return sessionIdRef.current;
@@ -1453,21 +1382,21 @@ function useChatV2(config, callbacks = {}) {
1453
1382
  }, [messages]);
1454
1383
  const setPromptStatus = react.useCallback(
1455
1384
  (userActionId, status) => {
1456
- setUserActionState((prev) => ({
1385
+ storeAwareSetUserActionState((prev) => ({
1457
1386
  ...prev,
1458
1387
  prompts: prev.prompts.map(
1459
1388
  (p) => p.userActionId === userActionId ? { ...p, status } : p
1460
1389
  )
1461
1390
  }));
1462
1391
  },
1463
- []
1392
+ [storeAwareSetUserActionState]
1464
1393
  );
1465
1394
  const removePrompt = react.useCallback((userActionId) => {
1466
- setUserActionState((prev) => ({
1395
+ storeAwareSetUserActionState((prev) => ({
1467
1396
  ...prev,
1468
1397
  prompts: prev.prompts.filter((p) => p.userActionId !== userActionId)
1469
1398
  }));
1470
- }, []);
1399
+ }, [storeAwareSetUserActionState]);
1471
1400
  const submitUserAction2 = react.useCallback(
1472
1401
  async (userActionId, content) => {
1473
1402
  setPromptStatus(userActionId, "submitting");
@@ -1522,12 +1451,25 @@ function useChatV2(config, callbacks = {}) {
1522
1451
  },
1523
1452
  [setPromptStatus]
1524
1453
  );
1454
+ const expireUserAction2 = react.useCallback(
1455
+ async (userActionId) => {
1456
+ setPromptStatus(userActionId, "expired");
1457
+ try {
1458
+ await expireUserAction(configRef.current, userActionId);
1459
+ } catch (error) {
1460
+ if (error instanceof UserActionStaleError) return;
1461
+ callbacksRef.current.onError?.(error);
1462
+ throw error;
1463
+ }
1464
+ },
1465
+ [setPromptStatus]
1466
+ );
1525
1467
  const dismissNotification = react.useCallback((id) => {
1526
- setUserActionState((prev) => ({
1468
+ storeAwareSetUserActionState((prev) => ({
1527
1469
  ...prev,
1528
1470
  notifications: prev.notifications.filter((n) => n.id !== id)
1529
1471
  }));
1530
- }, []);
1472
+ }, [storeAwareSetUserActionState]);
1531
1473
  react.useEffect(() => {
1532
1474
  const prevSubscriptionUserId = subscriptionPrevUserIdRef.current;
1533
1475
  subscriptionPrevUserIdRef.current = config.userId;
@@ -1536,14 +1478,17 @@ function useChatV2(config, callbacks = {}) {
1536
1478
  if (prevSubscriptionUserId && prevSubscriptionUserId !== userId && streamUserIdRef.current === prevSubscriptionUserId && !activeStreamStore.has(prevSubscriptionUserId) && activeStreamStore.has(userId)) {
1537
1479
  streamUserIdRef.current = userId;
1538
1480
  }
1539
- const unsubscribe = activeStreamStore.subscribe(userId, (msgs, isWaiting) => {
1481
+ const unsubscribe = activeStreamStore.subscribe(userId, (msgs, isWaiting, actions) => {
1540
1482
  setMessages(msgs);
1541
1483
  setIsWaitingForResponse(isWaiting);
1484
+ setUserActionState(actions);
1542
1485
  });
1543
1486
  const active = activeStreamStore.get(userId);
1544
1487
  if (active) {
1488
+ streamUserIdRef.current = userId;
1545
1489
  setMessages(active.messages);
1546
1490
  setIsWaitingForResponse(active.isWaiting);
1491
+ setUserActionState(active.userActionState);
1547
1492
  }
1548
1493
  return unsubscribe;
1549
1494
  }, [config.userId]);
@@ -1562,18 +1507,6 @@ function useChatV2(config, callbacks = {}) {
1562
1507
  setMessages(config.initialMessages);
1563
1508
  sessionIdRef.current = getSessionIdFromMessages(config.initialMessages) ?? config.initialSessionId;
1564
1509
  }, [config.initialMessages, config.initialSessionId, config.userId]);
1565
- const hydratedSessionIdRef = react.useRef(void 0);
1566
- react.useEffect(() => {
1567
- if (config.userId) return;
1568
- if (!config.initialMessages?.length) return;
1569
- const sessionId = config.initialSessionId;
1570
- if (hydratedSessionIdRef.current === sessionId && messagesRef.current.length > 0) {
1571
- return;
1572
- }
1573
- hydratedSessionIdRef.current = sessionId;
1574
- setMessages(config.initialMessages);
1575
- sessionIdRef.current = getSessionIdFromMessages(config.initialMessages) ?? sessionId;
1576
- }, [config.initialMessages, config.initialSessionId, config.userId]);
1577
1510
  react.useEffect(() => {
1578
1511
  const prevUserId = prevUserIdRef.current;
1579
1512
  prevUserIdRef.current = config.userId;
@@ -1583,12 +1516,14 @@ function useChatV2(config, callbacks = {}) {
1583
1516
  setMessages([]);
1584
1517
  sessionIdRef.current = void 0;
1585
1518
  setIsWaitingForResponse(false);
1586
- setUserActionState(EMPTY_USER_ACTION_STATE);
1519
+ setUserActionState(EMPTY_USER_ACTION_STATE2);
1587
1520
  } else if (config.userId) {
1588
1521
  const active = activeStreamStore.get(config.userId);
1589
1522
  if (active) {
1523
+ streamUserIdRef.current = config.userId;
1590
1524
  setMessages(active.messages);
1591
1525
  setIsWaitingForResponse(active.isWaiting);
1526
+ setUserActionState(active.userActionState);
1592
1527
  sessionIdRef.current = getSessionIdFromMessages(active.messages) ?? config.initialSessionId;
1593
1528
  return;
1594
1529
  }
@@ -1608,12 +1543,12 @@ function useChatV2(config, callbacks = {}) {
1608
1543
  getSessionId,
1609
1544
  getMessages,
1610
1545
  isWaitingForResponse,
1611
- isUploadingAttachments,
1612
1546
  sessionId: sessionIdRef.current,
1613
1547
  userActionState,
1614
1548
  submitUserAction: submitUserAction2,
1615
1549
  cancelUserAction: cancelUserAction2,
1616
1550
  resendUserAction: resendUserAction2,
1551
+ expireUserAction: expireUserAction2,
1617
1552
  dismissNotification
1618
1553
  };
1619
1554
  }
@@ -4761,14 +4696,15 @@ function NotificationInline({ notification, onDismiss }) {
4761
4696
  ] });
4762
4697
  }
4763
4698
  function useExpiryCountdown(prompt) {
4764
- const initial = typeof prompt.expirySeconds === "number" && prompt.expirySeconds > 0 ? Math.floor(prompt.expirySeconds) : void 0;
4765
- const [secondsLeft, setSecondsLeft] = react.useState(initial);
4699
+ const deadlineMs = typeof prompt.expiresAt === "number" && prompt.expiresAt > 0 ? prompt.expiresAt : typeof prompt.expirySeconds === "number" && prompt.expirySeconds > 0 ? Date.now() + Math.floor(prompt.expirySeconds) * 1e3 : void 0;
4700
+ const [secondsLeft, setSecondsLeft] = react.useState(
4701
+ () => deadlineMs !== void 0 ? Math.max(0, Math.ceil((deadlineMs - Date.now()) / 1e3)) : void 0
4702
+ );
4766
4703
  react.useEffect(() => {
4767
- if (initial === void 0) {
4704
+ if (deadlineMs === void 0) {
4768
4705
  setSecondsLeft(void 0);
4769
4706
  return;
4770
4707
  }
4771
- const deadlineMs = Date.now() + initial * 1e3;
4772
4708
  let intervalId;
4773
4709
  const remaining = () => Math.max(0, Math.ceil((deadlineMs - Date.now()) / 1e3));
4774
4710
  const sync = () => {
@@ -4790,8 +4726,8 @@ function useExpiryCountdown(prompt) {
4790
4726
  window.removeEventListener("focus", sync);
4791
4727
  window.removeEventListener("pageshow", sync);
4792
4728
  };
4793
- }, [prompt.userActionId, prompt.subAction, initial]);
4794
- const expired = initial !== void 0 && secondsLeft === 0;
4729
+ }, [prompt.userActionId, prompt.subAction, deadlineMs]);
4730
+ const expired = deadlineMs !== void 0 && (getUserActionSecondsLeft(prompt) ?? secondsLeft ?? 0) <= 0;
4795
4731
  return [secondsLeft, expired];
4796
4732
  }
4797
4733
  function UserActionInline({
@@ -6346,7 +6282,7 @@ var PaymanChatInner = react.forwardRef(function PaymanChatInner2({
6346
6282
  const submitUserAction2 = chat.submitUserAction ?? NOOP_ASYNC;
6347
6283
  const cancelUserAction2 = chat.cancelUserAction ?? NOOP_ASYNC;
6348
6284
  const resendUserAction2 = chat.resendUserAction ?? NOOP_ASYNC;
6349
- const expireUserAction = chat.expireUserAction ?? NOOP_ASYNC;
6285
+ const expireUserAction2 = chat.expireUserAction ?? NOOP_ASYNC;
6350
6286
  const dismissNotification = chat.dismissNotification ?? NOOP;
6351
6287
  const isUserActionSupported = typeof chat.submitUserAction === "function" && typeof chat.cancelUserAction === "function" && typeof chat.resendUserAction === "function";
6352
6288
  const {
@@ -6747,7 +6683,7 @@ var PaymanChatInner = react.forwardRef(function PaymanChatInner2({
6747
6683
  onSubmitUserAction: isUserActionSupported ? submitUserAction2 : void 0,
6748
6684
  onCancelUserAction: isUserActionSupported ? cancelUserAction2 : void 0,
6749
6685
  onResendUserAction: isUserActionSupported ? resendUserAction2 : void 0,
6750
- onExpireUserAction: isUserActionSupported ? expireUserAction : void 0,
6686
+ onExpireUserAction: isUserActionSupported ? expireUserAction2 : void 0,
6751
6687
  onDismissNotification: dismissNotification,
6752
6688
  onSubmitFeedback: handleSubmitFeedback
6753
6689
  }