@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.
@@ -731,8 +731,7 @@ function buildRequestBody(config, userMessage, sessionId, options) {
731
731
  sessionAttributes,
732
732
  analysisMode: options?.analysisMode,
733
733
  locale: resolveLocale(config.locale),
734
- timezone: resolveTimezone(config.timezone),
735
- ...options?.attachments?.length ? { attachments: options.attachments } : {}
734
+ timezone: resolveTimezone(config.timezone)
736
735
  };
737
736
  }
738
737
  function resolveLocale(configured) {
@@ -777,7 +776,6 @@ function buildResolveImagesUrl(config) {
777
776
  const basePath = normalizedEndpointPath.endsWith("/stream") ? normalizedEndpointPath.slice(0, -"/stream".length) : normalizedEndpointPath;
778
777
  return `${config.api.baseUrl}${basePath}/resolve-image-urls`;
779
778
  }
780
- var NGROK_SKIP_BROWSER_WARNING = "ngrok-skip-browser-warning";
781
779
  function buildRequestHeaders(config) {
782
780
  const headers = {
783
781
  ...config.api.headers
@@ -785,9 +783,6 @@ function buildRequestHeaders(config) {
785
783
  if (config.api.authToken) {
786
784
  headers.Authorization = `Bearer ${config.api.authToken}`;
787
785
  }
788
- if (!headers[NGROK_SKIP_BROWSER_WARNING]) {
789
- headers[NGROK_SKIP_BROWSER_WARNING] = "true";
790
- }
791
786
  return headers;
792
787
  }
793
788
  var RAG_IMAGE_REGEX = /\/api\/rag\/chunks\/[^"'\s]+\/image/;
@@ -1068,81 +1063,6 @@ function createCancelledMessageUpdate(steps, currentMessage) {
1068
1063
  currentMessage: currentMessage || "Thinking..."
1069
1064
  };
1070
1065
  }
1071
- var DEFAULT_SIGNED_URL_ENDPOINT = "/api/files/signed-url";
1072
- function fileExtension(filename) {
1073
- const ext = filename.split(".").pop()?.toLowerCase().replace(/^\./, "");
1074
- return ext && ext.length > 0 ? ext : "bin";
1075
- }
1076
- function resolveMimeType(file) {
1077
- if (file.type && file.type.trim().length > 0) return file.type;
1078
- const ext = fileExtension(file.name);
1079
- const byExt = {
1080
- pdf: "application/pdf",
1081
- png: "image/png",
1082
- jpg: "image/jpeg",
1083
- jpeg: "image/jpeg",
1084
- gif: "image/gif",
1085
- webp: "image/webp"
1086
- };
1087
- return byExt[ext] ?? "application/octet-stream";
1088
- }
1089
- function buildSignedUrlEndpoint(config, ext) {
1090
- const endpoint = config.api.signedUrlEndpoint || DEFAULT_SIGNED_URL_ENDPOINT;
1091
- const queryParams = new URLSearchParams({ extn: ext.replace(/^\./, "") });
1092
- return `${config.api.baseUrl}${endpoint}?${queryParams.toString()}`;
1093
- }
1094
- async function requestSignedUrl(config, ext, signal) {
1095
- const url = buildSignedUrlEndpoint(config, ext);
1096
- const headers = buildRequestHeaders(config);
1097
- const response = await fetch(url, {
1098
- method: "GET",
1099
- headers,
1100
- signal
1101
- });
1102
- if (!response.ok) {
1103
- const errorText = await response.text().catch(() => "");
1104
- throw new Error(
1105
- errorText ? `Failed to get upload URL (${response.status}): ${errorText}` : `Failed to get upload URL (${response.status})`
1106
- );
1107
- }
1108
- const data = await response.json();
1109
- if (!data.key || !data.url) {
1110
- throw new Error("Signed URL response missing key or url");
1111
- }
1112
- return { key: data.key, url: data.url };
1113
- }
1114
- async function uploadToSignedUrl(signedUrl, file, mimeType, signal) {
1115
- const response = await fetch(signedUrl, {
1116
- method: "PUT",
1117
- headers: {
1118
- "Content-Type": mimeType,
1119
- "x-ms-blob-type": "BlockBlob"
1120
- },
1121
- body: file,
1122
- signal
1123
- });
1124
- if (!response.ok) {
1125
- const errorText = await response.text().catch(() => "");
1126
- throw new Error(
1127
- errorText ? `Failed to upload file (${response.status}): ${errorText}` : `Failed to upload file (${response.status})`
1128
- );
1129
- }
1130
- }
1131
- async function uploadAttachment(config, file, signal) {
1132
- const ext = fileExtension(file.name);
1133
- const mimeType = resolveMimeType(file);
1134
- const { key, url } = await requestSignedUrl(config, ext, signal);
1135
- await uploadToSignedUrl(url, file, mimeType, signal);
1136
- return {
1137
- tempKey: key,
1138
- filename: file.name,
1139
- mimeType
1140
- };
1141
- }
1142
- async function uploadAttachments(config, files, signal) {
1143
- const uploads = files.map((file) => uploadAttachment(config, file, signal));
1144
- return Promise.all(uploads);
1145
- }
1146
1066
  var UserActionStaleError = class extends Error {
1147
1067
  constructor(userActionId, message = "User action is no longer actionable") {
1148
1068
  super(message);
@@ -1179,6 +1099,9 @@ async function cancelUserAction(config, userActionId) {
1179
1099
  async function resendUserAction(config, userActionId) {
1180
1100
  return sendUserActionRequest(config, userActionId, "resend");
1181
1101
  }
1102
+ async function expireUserAction(config, userActionId) {
1103
+ return sendUserActionRequest(config, userActionId, "expired");
1104
+ }
1182
1105
  var EMPTY_USER_ACTION_STATE = { prompts: [], notifications: [] };
1183
1106
  function upsertPrompt(prompts, req) {
1184
1107
  const active = { ...req, status: "pending" };
@@ -1207,32 +1130,12 @@ function getStoredOrInitialMessages(config) {
1207
1130
  function getSessionIdFromMessages(messages) {
1208
1131
  return messages.find((message) => message.sessionId)?.sessionId;
1209
1132
  }
1210
- var IMAGE_EXTENSIONS = /* @__PURE__ */ new Set(["jpg", "jpeg", "png", "gif", "webp", "avif"]);
1211
- function attachmentKindFromFile(file) {
1212
- const ext = file.name.split(".").pop()?.toLowerCase() ?? "";
1213
- if (IMAGE_EXTENSIONS.has(ext) || file.type.startsWith("image/")) return "image";
1214
- return "file";
1215
- }
1216
- function buildMessageAttachments(files) {
1217
- return files.map((file, index) => {
1218
- const kind = attachmentKindFromFile(file);
1219
- return {
1220
- id: `att-${Date.now()}-${index}`,
1221
- filename: file.name,
1222
- mimeType: file.type || "application/octet-stream",
1223
- // Blob URL for all local files so PDFs/docs stay previewable after send.
1224
- previewUrl: URL.createObjectURL(file),
1225
- kind
1226
- };
1227
- });
1228
- }
1229
1133
  function useChatV2(config, callbacks = {}) {
1230
1134
  const [messages, setMessages] = react.useState(() => getStoredOrInitialMessages(config));
1231
1135
  const [isWaitingForResponse, setIsWaitingForResponse] = react.useState(() => {
1232
1136
  if (!config.userId) return false;
1233
1137
  return activeStreamStore.get(config.userId)?.isWaiting ?? false;
1234
1138
  });
1235
- const [isUploadingAttachments, setIsUploadingAttachments] = react.useState(false);
1236
1139
  const sessionIdRef = react.useRef(
1237
1140
  getSessionIdFromMessages(getStoredOrInitialMessages(config)) ?? config.initialSessionId ?? void 0
1238
1141
  );
@@ -1307,45 +1210,21 @@ function useChatV2(config, callbacks = {}) {
1307
1210
  );
1308
1211
  const sendMessage = react.useCallback(
1309
1212
  async (userMessage, options) => {
1310
- const trimmedMessage = userMessage.trim();
1311
- const files = options?.files ?? [];
1312
- const hasPreuploadedAttachments = (options?.attachments?.length ?? 0) > 0;
1313
- if (!trimmedMessage && files.length === 0 && !hasPreuploadedAttachments) return;
1314
- let streamAttachments = options?.attachments;
1315
- if (!streamAttachments && files.length > 0) {
1316
- setIsUploadingAttachments(true);
1317
- try {
1318
- streamAttachments = await uploadAttachments(configRef.current, files);
1319
- } catch (error) {
1320
- if (error.name !== "AbortError") {
1321
- callbacksRef.current.onError?.(error);
1322
- }
1323
- throw error;
1324
- } finally {
1325
- setIsUploadingAttachments(false);
1326
- }
1327
- }
1213
+ if (!userMessage.trim()) return;
1328
1214
  if (!sessionIdRef.current && configRef.current.autoGenerateSessionId !== false) {
1329
1215
  sessionIdRef.current = generateId();
1330
1216
  callbacksRef.current.onSessionIdChange?.(sessionIdRef.current);
1331
1217
  }
1332
- const messageAttachments = files.length > 0 ? buildMessageAttachments(files) : streamAttachments?.length ? streamAttachments.map((attachment, index) => ({
1333
- id: `att-${Date.now()}-${index}`,
1334
- filename: attachment.filename,
1335
- mimeType: attachment.mimeType,
1336
- kind: attachment.mimeType.startsWith("image/") ? "image" : "file"
1337
- })) : void 0;
1338
1218
  const userMessageId = `user-${Date.now()}`;
1339
1219
  const userMsg = {
1340
1220
  id: userMessageId,
1341
1221
  sessionId: sessionIdRef.current,
1342
1222
  role: "user",
1343
- content: trimmedMessage,
1344
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1345
- attachments: messageAttachments
1223
+ content: userMessage,
1224
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
1346
1225
  };
1347
1226
  setMessages((prev) => [...prev, userMsg]);
1348
- callbacksRef.current.onMessageSent?.(trimmedMessage);
1227
+ callbacksRef.current.onMessageSent?.(userMessage);
1349
1228
  setIsWaitingForResponse(true);
1350
1229
  callbacksRef.current.onStreamStart?.();
1351
1230
  const streamingId = `assistant-${Date.now()}`;
@@ -1372,14 +1251,11 @@ function useChatV2(config, callbacks = {}) {
1372
1251
  activeStreamStore.start(userId, abortController, initialMessages);
1373
1252
  }
1374
1253
  const newSessionId = await startStream(
1375
- trimmedMessage,
1254
+ userMessage,
1376
1255
  streamingId,
1377
1256
  sessionIdRef.current,
1378
1257
  abortController,
1379
- {
1380
- analysisMode: options?.analysisMode,
1381
- attachments: streamAttachments
1382
- }
1258
+ options
1383
1259
  );
1384
1260
  const finalStreamUserId = streamUserIdRef.current ?? userId;
1385
1261
  if (finalStreamUserId) {
@@ -1517,6 +1393,19 @@ function useChatV2(config, callbacks = {}) {
1517
1393
  },
1518
1394
  [setPromptStatus]
1519
1395
  );
1396
+ const expireUserAction2 = react.useCallback(
1397
+ async (userActionId) => {
1398
+ setPromptStatus(userActionId, "expired");
1399
+ try {
1400
+ await expireUserAction(configRef.current, userActionId);
1401
+ } catch (error) {
1402
+ if (error instanceof UserActionStaleError) return;
1403
+ callbacksRef.current.onError?.(error);
1404
+ throw error;
1405
+ }
1406
+ },
1407
+ [setPromptStatus]
1408
+ );
1520
1409
  const dismissNotification = react.useCallback((id) => {
1521
1410
  setUserActionState((prev) => ({
1522
1411
  ...prev,
@@ -1557,18 +1446,6 @@ function useChatV2(config, callbacks = {}) {
1557
1446
  setMessages(config.initialMessages);
1558
1447
  sessionIdRef.current = getSessionIdFromMessages(config.initialMessages) ?? config.initialSessionId;
1559
1448
  }, [config.initialMessages, config.initialSessionId, config.userId]);
1560
- const hydratedSessionIdRef = react.useRef(void 0);
1561
- react.useEffect(() => {
1562
- if (config.userId) return;
1563
- if (!config.initialMessages?.length) return;
1564
- const sessionId = config.initialSessionId;
1565
- if (hydratedSessionIdRef.current === sessionId && messagesRef.current.length > 0) {
1566
- return;
1567
- }
1568
- hydratedSessionIdRef.current = sessionId;
1569
- setMessages(config.initialMessages);
1570
- sessionIdRef.current = getSessionIdFromMessages(config.initialMessages) ?? sessionId;
1571
- }, [config.initialMessages, config.initialSessionId, config.userId]);
1572
1449
  react.useEffect(() => {
1573
1450
  const prevUserId = prevUserIdRef.current;
1574
1451
  prevUserIdRef.current = config.userId;
@@ -1603,12 +1480,12 @@ function useChatV2(config, callbacks = {}) {
1603
1480
  getSessionId,
1604
1481
  getMessages,
1605
1482
  isWaitingForResponse,
1606
- isUploadingAttachments,
1607
1483
  sessionId: sessionIdRef.current,
1608
1484
  userActionState,
1609
1485
  submitUserAction: submitUserAction2,
1610
1486
  cancelUserAction: cancelUserAction2,
1611
1487
  resendUserAction: resendUserAction2,
1488
+ expireUserAction: expireUserAction2,
1612
1489
  dismissNotification
1613
1490
  };
1614
1491
  }