@paymanai/payman-ask-sdk 4.0.21 → 4.0.22

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
@@ -736,8 +736,7 @@ function buildRequestBody(config, userMessage, sessionId, options) {
736
736
  sessionAttributes,
737
737
  analysisMode: options?.analysisMode,
738
738
  locale: resolveLocale(config.locale),
739
- timezone: resolveTimezone(config.timezone),
740
- ...options?.attachments?.length ? { attachments: options.attachments } : {}
739
+ timezone: resolveTimezone(config.timezone)
741
740
  };
742
741
  }
743
742
  function resolveLocale(configured) {
@@ -782,7 +781,6 @@ function buildResolveImagesUrl(config) {
782
781
  const basePath = normalizedEndpointPath.endsWith("/stream") ? normalizedEndpointPath.slice(0, -"/stream".length) : normalizedEndpointPath;
783
782
  return `${config.api.baseUrl}${basePath}/resolve-image-urls`;
784
783
  }
785
- var NGROK_SKIP_BROWSER_WARNING = "ngrok-skip-browser-warning";
786
784
  function buildRequestHeaders(config) {
787
785
  const headers = {
788
786
  ...config.api.headers
@@ -790,9 +788,6 @@ function buildRequestHeaders(config) {
790
788
  if (config.api.authToken) {
791
789
  headers.Authorization = `Bearer ${config.api.authToken}`;
792
790
  }
793
- if (!headers[NGROK_SKIP_BROWSER_WARNING]) {
794
- headers[NGROK_SKIP_BROWSER_WARNING] = "true";
795
- }
796
791
  return headers;
797
792
  }
798
793
  var RAG_IMAGE_REGEX = /\/api\/rag\/chunks\/[^"'\s]+\/image/;
@@ -1073,81 +1068,6 @@ function createCancelledMessageUpdate(steps, currentMessage) {
1073
1068
  currentMessage: currentMessage || "Thinking..."
1074
1069
  };
1075
1070
  }
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
1071
  var UserActionStaleError = class extends Error {
1152
1072
  constructor(userActionId, message = "User action is no longer actionable") {
1153
1073
  super(message);
@@ -1184,6 +1104,9 @@ async function cancelUserAction(config, userActionId) {
1184
1104
  async function resendUserAction(config, userActionId) {
1185
1105
  return sendUserActionRequest(config, userActionId, "resend");
1186
1106
  }
1107
+ async function expireUserAction(config, userActionId) {
1108
+ return sendUserActionRequest(config, userActionId, "expired");
1109
+ }
1187
1110
  var EMPTY_USER_ACTION_STATE = { prompts: [], notifications: [] };
1188
1111
  function upsertPrompt(prompts, req) {
1189
1112
  const active = { ...req, status: "pending" };
@@ -1212,32 +1135,12 @@ function getStoredOrInitialMessages(config) {
1212
1135
  function getSessionIdFromMessages(messages) {
1213
1136
  return messages.find((message) => message.sessionId)?.sessionId;
1214
1137
  }
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
1138
  function useChatV2(config, callbacks = {}) {
1235
1139
  const [messages, setMessages] = react.useState(() => getStoredOrInitialMessages(config));
1236
1140
  const [isWaitingForResponse, setIsWaitingForResponse] = react.useState(() => {
1237
1141
  if (!config.userId) return false;
1238
1142
  return activeStreamStore.get(config.userId)?.isWaiting ?? false;
1239
1143
  });
1240
- const [isUploadingAttachments, setIsUploadingAttachments] = react.useState(false);
1241
1144
  const sessionIdRef = react.useRef(
1242
1145
  getSessionIdFromMessages(getStoredOrInitialMessages(config)) ?? config.initialSessionId ?? void 0
1243
1146
  );
@@ -1312,45 +1215,21 @@ function useChatV2(config, callbacks = {}) {
1312
1215
  );
1313
1216
  const sendMessage = react.useCallback(
1314
1217
  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
- }
1218
+ if (!userMessage.trim()) return;
1333
1219
  if (!sessionIdRef.current && configRef.current.autoGenerateSessionId !== false) {
1334
1220
  sessionIdRef.current = generateId();
1335
1221
  callbacksRef.current.onSessionIdChange?.(sessionIdRef.current);
1336
1222
  }
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
1223
  const userMessageId = `user-${Date.now()}`;
1344
1224
  const userMsg = {
1345
1225
  id: userMessageId,
1346
1226
  sessionId: sessionIdRef.current,
1347
1227
  role: "user",
1348
- content: trimmedMessage,
1349
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1350
- attachments: messageAttachments
1228
+ content: userMessage,
1229
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
1351
1230
  };
1352
1231
  setMessages((prev) => [...prev, userMsg]);
1353
- callbacksRef.current.onMessageSent?.(trimmedMessage);
1232
+ callbacksRef.current.onMessageSent?.(userMessage);
1354
1233
  setIsWaitingForResponse(true);
1355
1234
  callbacksRef.current.onStreamStart?.();
1356
1235
  const streamingId = `assistant-${Date.now()}`;
@@ -1377,14 +1256,11 @@ function useChatV2(config, callbacks = {}) {
1377
1256
  activeStreamStore.start(userId, abortController, initialMessages);
1378
1257
  }
1379
1258
  const newSessionId = await startStream(
1380
- trimmedMessage,
1259
+ userMessage,
1381
1260
  streamingId,
1382
1261
  sessionIdRef.current,
1383
1262
  abortController,
1384
- {
1385
- analysisMode: options?.analysisMode,
1386
- attachments: streamAttachments
1387
- }
1263
+ options
1388
1264
  );
1389
1265
  const finalStreamUserId = streamUserIdRef.current ?? userId;
1390
1266
  if (finalStreamUserId) {
@@ -1522,6 +1398,19 @@ function useChatV2(config, callbacks = {}) {
1522
1398
  },
1523
1399
  [setPromptStatus]
1524
1400
  );
1401
+ const expireUserAction2 = react.useCallback(
1402
+ async (userActionId) => {
1403
+ setPromptStatus(userActionId, "expired");
1404
+ try {
1405
+ await expireUserAction(configRef.current, userActionId);
1406
+ } catch (error) {
1407
+ if (error instanceof UserActionStaleError) return;
1408
+ callbacksRef.current.onError?.(error);
1409
+ throw error;
1410
+ }
1411
+ },
1412
+ [setPromptStatus]
1413
+ );
1525
1414
  const dismissNotification = react.useCallback((id) => {
1526
1415
  setUserActionState((prev) => ({
1527
1416
  ...prev,
@@ -1562,18 +1451,6 @@ function useChatV2(config, callbacks = {}) {
1562
1451
  setMessages(config.initialMessages);
1563
1452
  sessionIdRef.current = getSessionIdFromMessages(config.initialMessages) ?? config.initialSessionId;
1564
1453
  }, [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
1454
  react.useEffect(() => {
1578
1455
  const prevUserId = prevUserIdRef.current;
1579
1456
  prevUserIdRef.current = config.userId;
@@ -1608,12 +1485,12 @@ function useChatV2(config, callbacks = {}) {
1608
1485
  getSessionId,
1609
1486
  getMessages,
1610
1487
  isWaitingForResponse,
1611
- isUploadingAttachments,
1612
1488
  sessionId: sessionIdRef.current,
1613
1489
  userActionState,
1614
1490
  submitUserAction: submitUserAction2,
1615
1491
  cancelUserAction: cancelUserAction2,
1616
1492
  resendUserAction: resendUserAction2,
1493
+ expireUserAction: expireUserAction2,
1617
1494
  dismissNotification
1618
1495
  };
1619
1496
  }
@@ -4695,18 +4572,28 @@ function useExpiryCountdown(prompt) {
4695
4572
  setSecondsLeft(void 0);
4696
4573
  return;
4697
4574
  }
4698
- setSecondsLeft(initial);
4699
- const id = window.setInterval(() => {
4700
- setSecondsLeft((s) => {
4701
- if (s === void 0) return s;
4702
- if (s <= 1) {
4703
- window.clearInterval(id);
4704
- return 0;
4705
- }
4706
- return s - 1;
4707
- });
4708
- }, 1e3);
4709
- return () => window.clearInterval(id);
4575
+ const deadlineMs = Date.now() + initial * 1e3;
4576
+ let intervalId;
4577
+ const remaining = () => Math.max(0, Math.ceil((deadlineMs - Date.now()) / 1e3));
4578
+ const sync = () => {
4579
+ const next = remaining();
4580
+ setSecondsLeft(next);
4581
+ if (next === 0 && intervalId !== void 0) {
4582
+ window.clearInterval(intervalId);
4583
+ intervalId = void 0;
4584
+ }
4585
+ };
4586
+ sync();
4587
+ intervalId = window.setInterval(sync, 1e3);
4588
+ document.addEventListener("visibilitychange", sync);
4589
+ window.addEventListener("focus", sync);
4590
+ window.addEventListener("pageshow", sync);
4591
+ return () => {
4592
+ if (intervalId !== void 0) window.clearInterval(intervalId);
4593
+ document.removeEventListener("visibilitychange", sync);
4594
+ window.removeEventListener("focus", sync);
4595
+ window.removeEventListener("pageshow", sync);
4596
+ };
4710
4597
  }, [prompt.userActionId, prompt.subAction, initial]);
4711
4598
  const expired = initial !== void 0 && secondsLeft === 0;
4712
4599
  return [secondsLeft, expired];
@@ -6263,7 +6150,7 @@ var PaymanChatInner = react.forwardRef(function PaymanChatInner2({
6263
6150
  const submitUserAction2 = chat.submitUserAction ?? NOOP_ASYNC;
6264
6151
  const cancelUserAction2 = chat.cancelUserAction ?? NOOP_ASYNC;
6265
6152
  const resendUserAction2 = chat.resendUserAction ?? NOOP_ASYNC;
6266
- const expireUserAction = chat.expireUserAction ?? NOOP_ASYNC;
6153
+ const expireUserAction2 = chat.expireUserAction ?? NOOP_ASYNC;
6267
6154
  const dismissNotification = chat.dismissNotification ?? NOOP;
6268
6155
  const isUserActionSupported = typeof chat.submitUserAction === "function" && typeof chat.cancelUserAction === "function" && typeof chat.resendUserAction === "function";
6269
6156
  const {
@@ -6664,7 +6551,7 @@ var PaymanChatInner = react.forwardRef(function PaymanChatInner2({
6664
6551
  onSubmitUserAction: isUserActionSupported ? submitUserAction2 : void 0,
6665
6552
  onCancelUserAction: isUserActionSupported ? cancelUserAction2 : void 0,
6666
6553
  onResendUserAction: isUserActionSupported ? resendUserAction2 : void 0,
6667
- onExpireUserAction: isUserActionSupported ? expireUserAction : void 0,
6554
+ onExpireUserAction: isUserActionSupported ? expireUserAction2 : void 0,
6668
6555
  onDismissNotification: dismissNotification,
6669
6556
  onSubmitFeedback: handleSubmitFeedback
6670
6557
  }