@paymanai/payman-ask-sdk 4.0.24 → 4.0.26

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
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var react = require('react');
3
+ var React = require('react');
4
4
  var framerMotion = require('framer-motion');
5
5
  var clsx = require('clsx');
6
6
  var tailwindMerge = require('tailwind-merge');
@@ -33,6 +33,7 @@ function _interopNamespace(e) {
33
33
  return Object.freeze(n);
34
34
  }
35
35
 
36
+ var React__namespace = /*#__PURE__*/_interopNamespace(React);
36
37
  var Sentry__namespace = /*#__PURE__*/_interopNamespace(Sentry);
37
38
  var ReactMarkdown__default = /*#__PURE__*/_interopDefault(ReactMarkdown);
38
39
  var remarkGfm__default = /*#__PURE__*/_interopDefault(remarkGfm);
@@ -60,6 +61,7 @@ var chatStore = {
60
61
  memoryStore.delete(key);
61
62
  }
62
63
  };
64
+ var EMPTY_USER_ACTION_STATE = { prompts: [], notifications: [] };
63
65
  var streams = /* @__PURE__ */ new Map();
64
66
  var activeStreamStore = {
65
67
  has(key) {
@@ -68,7 +70,11 @@ var activeStreamStore = {
68
70
  get(key) {
69
71
  const entry = streams.get(key);
70
72
  if (!entry) return null;
71
- return { messages: entry.messages, isWaiting: entry.isWaiting };
73
+ return {
74
+ messages: entry.messages,
75
+ isWaiting: entry.isWaiting,
76
+ userActionState: entry.userActionState
77
+ };
72
78
  },
73
79
  // Called before startStream — registers the controller and initial messages
74
80
  start(key, abortController, initialMessages) {
@@ -76,6 +82,7 @@ var activeStreamStore = {
76
82
  streams.set(key, {
77
83
  messages: initialMessages,
78
84
  isWaiting: true,
85
+ userActionState: EMPTY_USER_ACTION_STATE,
79
86
  abortController,
80
87
  listeners: existing?.listeners ?? /* @__PURE__ */ new Set()
81
88
  });
@@ -86,20 +93,27 @@ var activeStreamStore = {
86
93
  if (!entry) return;
87
94
  const next = typeof updater === "function" ? updater(entry.messages) : updater;
88
95
  entry.messages = next;
89
- entry.listeners.forEach((l) => l(next, entry.isWaiting));
96
+ entry.listeners.forEach((l) => l(next, entry.isWaiting, entry.userActionState));
90
97
  },
91
98
  setWaiting(key, waiting) {
92
99
  const entry = streams.get(key);
93
100
  if (!entry) return;
94
101
  entry.isWaiting = waiting;
95
- entry.listeners.forEach((l) => l(entry.messages, waiting));
102
+ entry.listeners.forEach((l) => l(entry.messages, waiting, entry.userActionState));
103
+ },
104
+ applyUserActionState(key, updater) {
105
+ const entry = streams.get(key);
106
+ if (!entry) return;
107
+ const next = typeof updater === "function" ? updater(entry.userActionState) : updater;
108
+ entry.userActionState = next;
109
+ entry.listeners.forEach((l) => l(entry.messages, entry.isWaiting, next));
96
110
  },
97
111
  // Called when stream completes — persists to chatStore and cleans up
98
112
  complete(key) {
99
113
  const entry = streams.get(key);
100
114
  if (!entry) return;
101
115
  entry.isWaiting = false;
102
- entry.listeners.forEach((l) => l(entry.messages, false));
116
+ entry.listeners.forEach((l) => l(entry.messages, false, entry.userActionState));
103
117
  const toSave = entry.messages.filter((m) => !m.isStreaming);
104
118
  if (toSave.length > 0) chatStore.set(key, toSave);
105
119
  streams.delete(key);
@@ -287,6 +301,8 @@ function getEventMessage(event) {
287
301
  }
288
302
  case "RUN_IN_PROGRESS":
289
303
  return event.partialText || "Thinking...";
304
+ case "LLM_CALL_STARTED":
305
+ return event.description || "";
290
306
  case "RUN_COMPLETED":
291
307
  return "Agent run completed";
292
308
  case "RUN_FAILED":
@@ -424,7 +440,8 @@ function createInitialV2State() {
424
440
  finalData: void 0,
425
441
  steps: [],
426
442
  stepCounter: 0,
427
- currentExecutingStepId: void 0
443
+ currentExecutingStepId: void 0,
444
+ trailingActivity: false
428
445
  };
429
446
  }
430
447
  function upsertUserAction(state, req) {
@@ -446,6 +463,7 @@ function processStreamEventV2(rawEvent, state) {
446
463
  if (typeof eventType === "string" && eventType.toUpperCase() === "KEEP_ALIVE") {
447
464
  if (event.executionId) state.executionId = event.executionId;
448
465
  if (event.sessionId) state.sessionId = event.sessionId;
466
+ if (state.finalResponse) state.trailingActivity = true;
449
467
  const description = typeof event.description === "string" ? event.description : "";
450
468
  if (description) {
451
469
  for (let i = state.steps.length - 1; i >= 0; i--) {
@@ -480,7 +498,12 @@ function processStreamEventV2(rawEvent, state) {
480
498
  state.lastEventType = eventType;
481
499
  break;
482
500
  }
501
+ case "LLM_CALL_STARTED":
502
+ if (state.finalResponse) state.trailingActivity = true;
503
+ state.lastEventType = eventType;
504
+ break;
483
505
  case "INTENT_STARTED": {
506
+ if (state.finalResponse) state.trailingActivity = true;
484
507
  const stepId = `step-${state.stepCounter++}`;
485
508
  state.steps.push({
486
509
  id: stepId,
@@ -496,6 +519,7 @@ function processStreamEventV2(rawEvent, state) {
496
519
  break;
497
520
  }
498
521
  case "INTENT_COMPLETED": {
522
+ if (state.finalResponse) state.trailingActivity = true;
499
523
  const intentStep = state.steps.find((s) => s.eventType === "INTENT_STARTED" && s.status === "in_progress");
500
524
  if (intentStep) {
501
525
  intentStep.status = "completed";
@@ -527,6 +551,7 @@ function processStreamEventV2(rawEvent, state) {
527
551
  step2.status = "completed";
528
552
  }
529
553
  });
554
+ state.trailingActivity = false;
530
555
  state.lastEventType = eventType;
531
556
  break;
532
557
  }
@@ -598,6 +623,7 @@ function processStreamEventV2(rawEvent, state) {
598
623
  case "WORKFLOW_ERROR":
599
624
  state.hasError = true;
600
625
  state.errorMessage = event.errorMessage || event.message || "Workflow error";
626
+ state.trailingActivity = false;
601
627
  state.lastEventType = eventType;
602
628
  break;
603
629
  // ---- K2 pipeline stage lifecycle events ----
@@ -736,8 +762,7 @@ function buildRequestBody(config, userMessage, sessionId, options) {
736
762
  sessionAttributes,
737
763
  analysisMode: options?.analysisMode,
738
764
  locale: resolveLocale(config.locale),
739
- timezone: resolveTimezone(config.timezone),
740
- ...options?.attachments?.length ? { attachments: options.attachments } : {}
765
+ timezone: resolveTimezone(config.timezone)
741
766
  };
742
767
  }
743
768
  function resolveLocale(configured) {
@@ -782,7 +807,6 @@ function buildResolveImagesUrl(config) {
782
807
  const basePath = normalizedEndpointPath.endsWith("/stream") ? normalizedEndpointPath.slice(0, -"/stream".length) : normalizedEndpointPath;
783
808
  return `${config.api.baseUrl}${basePath}/resolve-image-urls`;
784
809
  }
785
- var NGROK_SKIP_BROWSER_WARNING = "ngrok-skip-browser-warning";
786
810
  function buildRequestHeaders(config) {
787
811
  const headers = {
788
812
  ...config.api.headers
@@ -790,9 +814,6 @@ function buildRequestHeaders(config) {
790
814
  if (config.api.authToken) {
791
815
  headers.Authorization = `Bearer ${config.api.authToken}`;
792
816
  }
793
- if (!headers[NGROK_SKIP_BROWSER_WARNING]) {
794
- headers[NGROK_SKIP_BROWSER_WARNING] = "true";
795
- }
796
817
  return headers;
797
818
  }
798
819
  var RAG_IMAGE_REGEX = /\/api\/rag\/chunks\/[^"'\s]+\/image/;
@@ -845,12 +866,12 @@ async function resolveRagImageUrls(config, content, signal) {
845
866
  }
846
867
  var FRIENDLY_ERROR_MESSAGE = "Oops, something went wrong. Please try again.";
847
868
  function useStreamManagerV2(config, callbacks, setMessages, setIsWaitingForResponse) {
848
- const abortControllerRef = react.useRef(null);
849
- const configRef = react.useRef(config);
869
+ const abortControllerRef = React.useRef(null);
870
+ const configRef = React.useRef(config);
850
871
  configRef.current = config;
851
- const callbacksRef = react.useRef(callbacks);
872
+ const callbacksRef = React.useRef(callbacks);
852
873
  callbacksRef.current = callbacks;
853
- const startStream = react.useCallback(
874
+ const startStream = React.useCallback(
854
875
  async (userMessage, streamingId, sessionId, externalAbortController, options) => {
855
876
  abortControllerRef.current?.abort();
856
877
  const abortController = externalAbortController ?? new AbortController();
@@ -891,7 +912,9 @@ function useStreamManagerV2(config, callbacks, setMessages, setIsWaitingForRespo
891
912
  const latestUsefulStep = [...state.steps].reverse().find(
892
913
  (s) => s.message && !isBlandStatus(s.message)
893
914
  );
894
- const currentMessage = useful(activeStep?.message) ?? useful(lastInProgressStep?.message) ?? latestUsefulStep?.message ?? useful(getEventMessage(event)) ?? // Last-resort: every candidate is bland (very first event,
915
+ const eventTypeUpper = typeof event.eventType === "string" ? event.eventType.toUpperCase() : "";
916
+ const liveEventLabel = eventTypeUpper === "KEEP_ALIVE" || eventTypeUpper === "LLM_CALL_STARTED" ? useful(getEventMessage(event)) : void 0;
917
+ const currentMessage = useful(activeStep?.message) ?? useful(lastInProgressStep?.message) ?? liveEventLabel ?? latestUsefulStep?.message ?? useful(getEventMessage(event)) ?? // Last-resort: every candidate is bland (very first event,
895
918
  // nothing useful seen yet). Render the bland label so the
896
919
  // bubble isn't blank.
897
920
  activeStep?.message ?? lastInProgressStep?.message ?? getEventMessage(event);
@@ -916,6 +939,7 @@ function useStreamManagerV2(config, callbacks, setMessages, setIsWaitingForRespo
916
939
  streamingContent: state.finalResponse,
917
940
  content: "",
918
941
  currentMessage,
942
+ hasTrailingActivity: state.trailingActivity,
919
943
  streamProgress: "processing",
920
944
  isError: false,
921
945
  steps: [...state.steps],
@@ -1049,7 +1073,7 @@ function useStreamManagerV2(config, callbacks, setMessages, setIsWaitingForRespo
1049
1073
  },
1050
1074
  [setMessages, setIsWaitingForResponse]
1051
1075
  );
1052
- const cancelStream = react.useCallback(() => {
1076
+ const cancelStream = React.useCallback(() => {
1053
1077
  abortControllerRef.current?.abort();
1054
1078
  }, []);
1055
1079
  return {
@@ -1073,81 +1097,6 @@ function createCancelledMessageUpdate(steps, currentMessage) {
1073
1097
  currentMessage: currentMessage || "Thinking..."
1074
1098
  };
1075
1099
  }
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
1100
  var UserActionStaleError = class extends Error {
1152
1101
  constructor(userActionId, message = "User action is no longer actionable") {
1153
1102
  super(message);
@@ -1184,12 +1133,34 @@ async function cancelUserAction(config, userActionId) {
1184
1133
  async function resendUserAction(config, userActionId) {
1185
1134
  return sendUserActionRequest(config, userActionId, "resend");
1186
1135
  }
1187
- var EMPTY_USER_ACTION_STATE = { prompts: [], notifications: [] };
1136
+ async function expireUserAction(config, userActionId) {
1137
+ return sendUserActionRequest(config, userActionId, "expired");
1138
+ }
1139
+ function resolveUserActionExpiresAt(req, existing) {
1140
+ if (typeof req.expirySeconds !== "number" || req.expirySeconds <= 0) {
1141
+ return void 0;
1142
+ }
1143
+ if (existing?.expiresAt && existing.userActionId === req.userActionId) {
1144
+ return existing.expiresAt;
1145
+ }
1146
+ return Date.now() + Math.floor(req.expirySeconds) * 1e3;
1147
+ }
1148
+ function getUserActionSecondsLeft(prompt) {
1149
+ if (typeof prompt.expiresAt === "number" && prompt.expiresAt > 0) {
1150
+ return Math.max(0, Math.ceil((prompt.expiresAt - Date.now()) / 1e3));
1151
+ }
1152
+ if (typeof prompt.expirySeconds === "number" && prompt.expirySeconds > 0) {
1153
+ return Math.floor(prompt.expirySeconds);
1154
+ }
1155
+ return void 0;
1156
+ }
1157
+ var EMPTY_USER_ACTION_STATE2 = { prompts: [], notifications: [] };
1188
1158
  function upsertPrompt(prompts, req) {
1189
- const active = { ...req, status: "pending" };
1190
1159
  const idx = prompts.findIndex(
1191
1160
  (p) => req.toolCallId ? p.toolCallId === req.toolCallId : p.userActionId === req.userActionId
1192
1161
  );
1162
+ const expiresAt = resolveUserActionExpiresAt(req, idx >= 0 ? prompts[idx] : void 0);
1163
+ const active = { ...req, status: "pending", expiresAt };
1193
1164
  if (idx >= 0) {
1194
1165
  const next = prompts.slice();
1195
1166
  next[idx] = active;
@@ -1212,45 +1183,25 @@ function getStoredOrInitialMessages(config) {
1212
1183
  function getSessionIdFromMessages(messages) {
1213
1184
  return messages.find((message) => message.sessionId)?.sessionId;
1214
1185
  }
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
1186
  function useChatV2(config, callbacks = {}) {
1235
- const [messages, setMessages] = react.useState(() => getStoredOrInitialMessages(config));
1236
- const [isWaitingForResponse, setIsWaitingForResponse] = react.useState(() => {
1187
+ const [messages, setMessages] = React.useState(() => getStoredOrInitialMessages(config));
1188
+ const [isWaitingForResponse, setIsWaitingForResponse] = React.useState(() => {
1237
1189
  if (!config.userId) return false;
1238
1190
  return activeStreamStore.get(config.userId)?.isWaiting ?? false;
1239
1191
  });
1240
- const [isUploadingAttachments, setIsUploadingAttachments] = react.useState(false);
1241
- const sessionIdRef = react.useRef(
1192
+ const sessionIdRef = React.useRef(
1242
1193
  getSessionIdFromMessages(getStoredOrInitialMessages(config)) ?? config.initialSessionId ?? void 0
1243
1194
  );
1244
- const prevUserIdRef = react.useRef(config.userId);
1245
- const streamUserIdRef = react.useRef(void 0);
1246
- const subscriptionPrevUserIdRef = react.useRef(config.userId);
1247
- const callbacksRef = react.useRef(callbacks);
1195
+ const prevUserIdRef = React.useRef(config.userId);
1196
+ const streamUserIdRef = React.useRef(void 0);
1197
+ const subscriptionPrevUserIdRef = React.useRef(config.userId);
1198
+ const callbacksRef = React.useRef(callbacks);
1248
1199
  callbacksRef.current = callbacks;
1249
- const configRef = react.useRef(config);
1200
+ const configRef = React.useRef(config);
1250
1201
  configRef.current = config;
1251
- const messagesRef = react.useRef(messages);
1202
+ const messagesRef = React.useRef(messages);
1252
1203
  messagesRef.current = messages;
1253
- const storeAwareSetMessages = react.useCallback(
1204
+ const storeAwareSetMessages = React.useCallback(
1254
1205
  (updater) => {
1255
1206
  const streamUserId = streamUserIdRef.current;
1256
1207
  const currentUserId = configRef.current.userId;
@@ -1265,7 +1216,7 @@ function useChatV2(config, callbacks = {}) {
1265
1216
  // eslint-disable-next-line react-hooks/exhaustive-deps
1266
1217
  []
1267
1218
  );
1268
- const storeAwareSetIsWaiting = react.useCallback(
1219
+ const storeAwareSetIsWaiting = React.useCallback(
1269
1220
  (waiting) => {
1270
1221
  const streamUserId = streamUserIdRef.current;
1271
1222
  const currentUserId = configRef.current.userId;
@@ -1280,8 +1231,29 @@ function useChatV2(config, callbacks = {}) {
1280
1231
  // eslint-disable-next-line react-hooks/exhaustive-deps
1281
1232
  []
1282
1233
  );
1283
- const [userActionState, setUserActionState] = react.useState(EMPTY_USER_ACTION_STATE);
1284
- const wrappedCallbacks = react.useMemo(() => ({
1234
+ const [userActionState, setUserActionState] = React.useState(() => {
1235
+ if (!config.userId) return EMPTY_USER_ACTION_STATE2;
1236
+ return activeStreamStore.get(config.userId)?.userActionState ?? EMPTY_USER_ACTION_STATE2;
1237
+ });
1238
+ const storeAwareSetUserActionState = React.useCallback(
1239
+ (updater) => {
1240
+ const streamUserId = streamUserIdRef.current;
1241
+ const currentUserId = configRef.current.userId;
1242
+ const storeKey = streamUserId ?? currentUserId;
1243
+ if (storeKey && activeStreamStore.has(storeKey)) {
1244
+ activeStreamStore.applyUserActionState(
1245
+ storeKey,
1246
+ updater
1247
+ );
1248
+ }
1249
+ if (!streamUserId || streamUserId === currentUserId) {
1250
+ setUserActionState(updater);
1251
+ }
1252
+ },
1253
+ // eslint-disable-next-line react-hooks/exhaustive-deps
1254
+ []
1255
+ );
1256
+ const wrappedCallbacks = React.useMemo(() => ({
1285
1257
  ...callbacksRef.current,
1286
1258
  onMessageSent: (message) => callbacksRef.current.onMessageSent?.(message),
1287
1259
  onStreamStart: () => callbacksRef.current.onStreamStart?.(),
@@ -1290,14 +1262,14 @@ function useChatV2(config, callbacks = {}) {
1290
1262
  onExecutionTraceClick: (data) => callbacksRef.current.onExecutionTraceClick?.(data),
1291
1263
  onSessionIdChange: (sessionId) => callbacksRef.current.onSessionIdChange?.(sessionId),
1292
1264
  onUserActionRequired: (request) => {
1293
- setUserActionState((prev) => ({
1265
+ storeAwareSetUserActionState((prev) => ({
1294
1266
  ...prev,
1295
1267
  prompts: upsertPrompt(prev.prompts, request)
1296
1268
  }));
1297
1269
  callbacksRef.current.onUserActionRequired?.(request);
1298
1270
  },
1299
1271
  onUserNotification: (notification) => {
1300
- setUserActionState(
1272
+ storeAwareSetUserActionState(
1301
1273
  (prev) => prev.notifications.some((n) => n.id === notification.id) ? prev : { ...prev, notifications: [...prev.notifications, notification] }
1302
1274
  );
1303
1275
  callbacksRef.current.onUserNotification?.(notification);
@@ -1310,47 +1282,23 @@ function useChatV2(config, callbacks = {}) {
1310
1282
  storeAwareSetMessages,
1311
1283
  storeAwareSetIsWaiting
1312
1284
  );
1313
- const sendMessage = react.useCallback(
1285
+ const sendMessage = React.useCallback(
1314
1286
  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
- }
1287
+ if (!userMessage.trim()) return;
1333
1288
  if (!sessionIdRef.current && configRef.current.autoGenerateSessionId !== false) {
1334
1289
  sessionIdRef.current = generateId();
1335
1290
  callbacksRef.current.onSessionIdChange?.(sessionIdRef.current);
1336
1291
  }
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
1292
  const userMessageId = `user-${Date.now()}`;
1344
1293
  const userMsg = {
1345
1294
  id: userMessageId,
1346
1295
  sessionId: sessionIdRef.current,
1347
1296
  role: "user",
1348
- content: trimmedMessage,
1349
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1350
- attachments: messageAttachments
1297
+ content: userMessage,
1298
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
1351
1299
  };
1352
1300
  setMessages((prev) => [...prev, userMsg]);
1353
- callbacksRef.current.onMessageSent?.(trimmedMessage);
1301
+ callbacksRef.current.onMessageSent?.(userMessage);
1354
1302
  setIsWaitingForResponse(true);
1355
1303
  callbacksRef.current.onStreamStart?.();
1356
1304
  const streamingId = `assistant-${Date.now()}`;
@@ -1377,14 +1325,11 @@ function useChatV2(config, callbacks = {}) {
1377
1325
  activeStreamStore.start(userId, abortController, initialMessages);
1378
1326
  }
1379
1327
  const newSessionId = await startStream(
1380
- trimmedMessage,
1328
+ userMessage,
1381
1329
  streamingId,
1382
1330
  sessionIdRef.current,
1383
1331
  abortController,
1384
- {
1385
- analysisMode: options?.analysisMode,
1386
- attachments: streamAttachments
1387
- }
1332
+ options
1388
1333
  );
1389
1334
  const finalStreamUserId = streamUserIdRef.current ?? userId;
1390
1335
  if (finalStreamUserId) {
@@ -1397,16 +1342,16 @@ function useChatV2(config, callbacks = {}) {
1397
1342
  },
1398
1343
  [startStream]
1399
1344
  );
1400
- const clearMessages = react.useCallback(() => {
1345
+ const clearMessages = React.useCallback(() => {
1401
1346
  if (configRef.current.userId) {
1402
1347
  chatStore.delete(configRef.current.userId);
1403
1348
  }
1404
1349
  setMessages([]);
1405
1350
  }, []);
1406
- const prependMessages = react.useCallback((msgs) => {
1351
+ const prependMessages = React.useCallback((msgs) => {
1407
1352
  setMessages((prev) => [...msgs, ...prev]);
1408
1353
  }, []);
1409
- const cancelStream = react.useCallback(() => {
1354
+ const cancelStream = React.useCallback(() => {
1410
1355
  const streamUserId = streamUserIdRef.current ?? configRef.current.userId;
1411
1356
  if (streamUserId) {
1412
1357
  activeStreamStore.abort(streamUserId);
@@ -1414,7 +1359,7 @@ function useChatV2(config, callbacks = {}) {
1414
1359
  streamUserIdRef.current = void 0;
1415
1360
  cancelStreamManager();
1416
1361
  setIsWaitingForResponse(false);
1417
- setUserActionState((prev) => ({ ...prev, prompts: [] }));
1362
+ storeAwareSetUserActionState((prev) => ({ ...prev, prompts: [] }));
1418
1363
  setMessages(
1419
1364
  (prev) => prev.map((msg) => {
1420
1365
  if (msg.isStreaming) {
@@ -1429,8 +1374,8 @@ function useChatV2(config, callbacks = {}) {
1429
1374
  return msg;
1430
1375
  })
1431
1376
  );
1432
- }, [cancelStreamManager]);
1433
- const resetSession = react.useCallback(() => {
1377
+ }, [cancelStreamManager, storeAwareSetUserActionState]);
1378
+ const resetSession = React.useCallback(() => {
1434
1379
  const streamUserId = streamUserIdRef.current ?? configRef.current.userId;
1435
1380
  if (streamUserId) {
1436
1381
  activeStreamStore.abort(streamUserId);
@@ -1443,32 +1388,32 @@ function useChatV2(config, callbacks = {}) {
1443
1388
  sessionIdRef.current = void 0;
1444
1389
  abortControllerRef.current?.abort();
1445
1390
  setIsWaitingForResponse(false);
1446
- setUserActionState(EMPTY_USER_ACTION_STATE);
1391
+ storeAwareSetUserActionState(EMPTY_USER_ACTION_STATE2);
1447
1392
  }, []);
1448
- const getSessionId = react.useCallback(() => {
1393
+ const getSessionId = React.useCallback(() => {
1449
1394
  return sessionIdRef.current;
1450
1395
  }, []);
1451
- const getMessages = react.useCallback(() => {
1396
+ const getMessages = React.useCallback(() => {
1452
1397
  return messages;
1453
1398
  }, [messages]);
1454
- const setPromptStatus = react.useCallback(
1399
+ const setPromptStatus = React.useCallback(
1455
1400
  (userActionId, status) => {
1456
- setUserActionState((prev) => ({
1401
+ storeAwareSetUserActionState((prev) => ({
1457
1402
  ...prev,
1458
1403
  prompts: prev.prompts.map(
1459
1404
  (p) => p.userActionId === userActionId ? { ...p, status } : p
1460
1405
  )
1461
1406
  }));
1462
1407
  },
1463
- []
1408
+ [storeAwareSetUserActionState]
1464
1409
  );
1465
- const removePrompt = react.useCallback((userActionId) => {
1466
- setUserActionState((prev) => ({
1410
+ const removePrompt = React.useCallback((userActionId) => {
1411
+ storeAwareSetUserActionState((prev) => ({
1467
1412
  ...prev,
1468
1413
  prompts: prev.prompts.filter((p) => p.userActionId !== userActionId)
1469
1414
  }));
1470
- }, []);
1471
- const submitUserAction2 = react.useCallback(
1415
+ }, [storeAwareSetUserActionState]);
1416
+ const submitUserAction2 = React.useCallback(
1472
1417
  async (userActionId, content) => {
1473
1418
  setPromptStatus(userActionId, "submitting");
1474
1419
  try {
@@ -1486,7 +1431,7 @@ function useChatV2(config, callbacks = {}) {
1486
1431
  },
1487
1432
  [removePrompt, setPromptStatus]
1488
1433
  );
1489
- const cancelUserAction2 = react.useCallback(
1434
+ const cancelUserAction2 = React.useCallback(
1490
1435
  async (userActionId) => {
1491
1436
  setPromptStatus(userActionId, "submitting");
1492
1437
  try {
@@ -1504,7 +1449,7 @@ function useChatV2(config, callbacks = {}) {
1504
1449
  },
1505
1450
  [removePrompt, setPromptStatus]
1506
1451
  );
1507
- const resendUserAction2 = react.useCallback(
1452
+ const resendUserAction2 = React.useCallback(
1508
1453
  async (userActionId) => {
1509
1454
  setPromptStatus(userActionId, "submitting");
1510
1455
  try {
@@ -1522,13 +1467,26 @@ function useChatV2(config, callbacks = {}) {
1522
1467
  },
1523
1468
  [setPromptStatus]
1524
1469
  );
1525
- const dismissNotification = react.useCallback((id) => {
1526
- setUserActionState((prev) => ({
1470
+ const expireUserAction2 = React.useCallback(
1471
+ async (userActionId) => {
1472
+ setPromptStatus(userActionId, "expired");
1473
+ try {
1474
+ await expireUserAction(configRef.current, userActionId);
1475
+ } catch (error) {
1476
+ if (error instanceof UserActionStaleError) return;
1477
+ callbacksRef.current.onError?.(error);
1478
+ throw error;
1479
+ }
1480
+ },
1481
+ [setPromptStatus]
1482
+ );
1483
+ const dismissNotification = React.useCallback((id) => {
1484
+ storeAwareSetUserActionState((prev) => ({
1527
1485
  ...prev,
1528
1486
  notifications: prev.notifications.filter((n) => n.id !== id)
1529
1487
  }));
1530
- }, []);
1531
- react.useEffect(() => {
1488
+ }, [storeAwareSetUserActionState]);
1489
+ React.useEffect(() => {
1532
1490
  const prevSubscriptionUserId = subscriptionPrevUserIdRef.current;
1533
1491
  subscriptionPrevUserIdRef.current = config.userId;
1534
1492
  const { userId } = config;
@@ -1536,18 +1494,21 @@ function useChatV2(config, callbacks = {}) {
1536
1494
  if (prevSubscriptionUserId && prevSubscriptionUserId !== userId && streamUserIdRef.current === prevSubscriptionUserId && !activeStreamStore.has(prevSubscriptionUserId) && activeStreamStore.has(userId)) {
1537
1495
  streamUserIdRef.current = userId;
1538
1496
  }
1539
- const unsubscribe = activeStreamStore.subscribe(userId, (msgs, isWaiting) => {
1497
+ const unsubscribe = activeStreamStore.subscribe(userId, (msgs, isWaiting, actions) => {
1540
1498
  setMessages(msgs);
1541
1499
  setIsWaitingForResponse(isWaiting);
1500
+ setUserActionState(actions);
1542
1501
  });
1543
1502
  const active = activeStreamStore.get(userId);
1544
1503
  if (active) {
1504
+ streamUserIdRef.current = userId;
1545
1505
  setMessages(active.messages);
1546
1506
  setIsWaitingForResponse(active.isWaiting);
1507
+ setUserActionState(active.userActionState);
1547
1508
  }
1548
1509
  return unsubscribe;
1549
1510
  }, [config.userId]);
1550
- react.useEffect(() => {
1511
+ React.useEffect(() => {
1551
1512
  if (!config.userId) return;
1552
1513
  if (prevUserIdRef.current !== config.userId) return;
1553
1514
  const toSave = messages.filter((m) => !m.isStreaming);
@@ -1555,26 +1516,14 @@ function useChatV2(config, callbacks = {}) {
1555
1516
  chatStore.set(config.userId, toSave);
1556
1517
  }
1557
1518
  }, [messages, config.userId]);
1558
- react.useEffect(() => {
1519
+ React.useEffect(() => {
1559
1520
  if (!config.userId || activeStreamStore.has(config.userId)) return;
1560
1521
  if (!config.initialMessages?.length || messagesRef.current.length > 0) return;
1561
1522
  chatStore.set(config.userId, config.initialMessages);
1562
1523
  setMessages(config.initialMessages);
1563
1524
  sessionIdRef.current = getSessionIdFromMessages(config.initialMessages) ?? config.initialSessionId;
1564
1525
  }, [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
- react.useEffect(() => {
1526
+ React.useEffect(() => {
1578
1527
  const prevUserId = prevUserIdRef.current;
1579
1528
  prevUserIdRef.current = config.userId;
1580
1529
  if (prevUserId === config.userId) return;
@@ -1583,12 +1532,14 @@ function useChatV2(config, callbacks = {}) {
1583
1532
  setMessages([]);
1584
1533
  sessionIdRef.current = void 0;
1585
1534
  setIsWaitingForResponse(false);
1586
- setUserActionState(EMPTY_USER_ACTION_STATE);
1535
+ setUserActionState(EMPTY_USER_ACTION_STATE2);
1587
1536
  } else if (config.userId) {
1588
1537
  const active = activeStreamStore.get(config.userId);
1589
1538
  if (active) {
1539
+ streamUserIdRef.current = config.userId;
1590
1540
  setMessages(active.messages);
1591
1541
  setIsWaitingForResponse(active.isWaiting);
1542
+ setUserActionState(active.userActionState);
1592
1543
  sessionIdRef.current = getSessionIdFromMessages(active.messages) ?? config.initialSessionId;
1593
1544
  return;
1594
1545
  }
@@ -1608,12 +1559,12 @@ function useChatV2(config, callbacks = {}) {
1608
1559
  getSessionId,
1609
1560
  getMessages,
1610
1561
  isWaitingForResponse,
1611
- isUploadingAttachments,
1612
1562
  sessionId: sessionIdRef.current,
1613
1563
  userActionState,
1614
1564
  submitUserAction: submitUserAction2,
1615
1565
  cancelUserAction: cancelUserAction2,
1616
1566
  resendUserAction: resendUserAction2,
1567
+ expireUserAction: expireUserAction2,
1617
1568
  dismissNotification
1618
1569
  };
1619
1570
  }
@@ -1622,12 +1573,12 @@ function getSpeechRecognition() {
1622
1573
  return window.SpeechRecognition || window.webkitSpeechRecognition || null;
1623
1574
  }
1624
1575
  function useVoice(config = {}, callbacks = {}) {
1625
- const [voiceState, setVoiceState] = react.useState("idle");
1626
- const [transcribedText, setTranscribedText] = react.useState("");
1627
- const [isAvailable, setIsAvailable] = react.useState(false);
1628
- const [isRecording, setIsRecording] = react.useState(false);
1629
- const recognitionRef = react.useRef(null);
1630
- const autoStopTimerRef = react.useRef(null);
1576
+ const [voiceState, setVoiceState] = React.useState("idle");
1577
+ const [transcribedText, setTranscribedText] = React.useState("");
1578
+ const [isAvailable, setIsAvailable] = React.useState(false);
1579
+ const [isRecording, setIsRecording] = React.useState(false);
1580
+ const recognitionRef = React.useRef(null);
1581
+ const autoStopTimerRef = React.useRef(null);
1631
1582
  const {
1632
1583
  lang = "en-US",
1633
1584
  interimResults = true,
@@ -1636,14 +1587,14 @@ function useVoice(config = {}, callbacks = {}) {
1636
1587
  autoStopAfterSilence
1637
1588
  } = config;
1638
1589
  const { onStart, onEnd, onResult, onError, onStateChange } = callbacks;
1639
- react.useEffect(() => {
1590
+ React.useEffect(() => {
1640
1591
  const SpeechRecognitionAPI = getSpeechRecognition();
1641
1592
  setIsAvailable(SpeechRecognitionAPI !== null);
1642
1593
  }, []);
1643
- react.useEffect(() => {
1594
+ React.useEffect(() => {
1644
1595
  onStateChange?.(voiceState);
1645
1596
  }, [voiceState, onStateChange]);
1646
- const requestPermissions = react.useCallback(async () => {
1597
+ const requestPermissions = React.useCallback(async () => {
1647
1598
  try {
1648
1599
  const result = await navigator.mediaDevices.getUserMedia({
1649
1600
  audio: true
@@ -1660,7 +1611,7 @@ function useVoice(config = {}, callbacks = {}) {
1660
1611
  };
1661
1612
  }
1662
1613
  }, []);
1663
- const getPermissions = react.useCallback(async () => {
1614
+ const getPermissions = React.useCallback(async () => {
1664
1615
  if (typeof navigator === "undefined" || !navigator.permissions) {
1665
1616
  return {
1666
1617
  granted: false,
@@ -1682,13 +1633,13 @@ function useVoice(config = {}, callbacks = {}) {
1682
1633
  };
1683
1634
  }
1684
1635
  }, []);
1685
- const clearAutoStopTimer = react.useCallback(() => {
1636
+ const clearAutoStopTimer = React.useCallback(() => {
1686
1637
  if (autoStopTimerRef.current) {
1687
1638
  clearTimeout(autoStopTimerRef.current);
1688
1639
  autoStopTimerRef.current = null;
1689
1640
  }
1690
1641
  }, []);
1691
- const resetAutoStopTimer = react.useCallback(() => {
1642
+ const resetAutoStopTimer = React.useCallback(() => {
1692
1643
  clearAutoStopTimer();
1693
1644
  if (autoStopAfterSilence && autoStopAfterSilence > 0) {
1694
1645
  autoStopTimerRef.current = setTimeout(() => {
@@ -1698,7 +1649,7 @@ function useVoice(config = {}, callbacks = {}) {
1698
1649
  }, autoStopAfterSilence);
1699
1650
  }
1700
1651
  }, [autoStopAfterSilence, clearAutoStopTimer, isRecording]);
1701
- const stopRecording = react.useCallback(() => {
1652
+ const stopRecording = React.useCallback(() => {
1702
1653
  if (recognitionRef.current) {
1703
1654
  try {
1704
1655
  recognitionRef.current.stop();
@@ -1710,7 +1661,7 @@ function useVoice(config = {}, callbacks = {}) {
1710
1661
  setIsRecording(false);
1711
1662
  setVoiceState("idle");
1712
1663
  }, [clearAutoStopTimer]);
1713
- const startRecording = react.useCallback(async () => {
1664
+ const startRecording = React.useCallback(async () => {
1714
1665
  const SpeechRecognitionAPI = getSpeechRecognition();
1715
1666
  if (!SpeechRecognitionAPI) {
1716
1667
  onError?.("Speech recognition not supported in this browser");
@@ -1800,15 +1751,15 @@ function useVoice(config = {}, callbacks = {}) {
1800
1751
  resetAutoStopTimer,
1801
1752
  clearAutoStopTimer
1802
1753
  ]);
1803
- const clearTranscript = react.useCallback(() => {
1754
+ const clearTranscript = React.useCallback(() => {
1804
1755
  setTranscribedText("");
1805
1756
  }, []);
1806
- const reset = react.useCallback(() => {
1757
+ const reset = React.useCallback(() => {
1807
1758
  stopRecording();
1808
1759
  setTranscribedText("");
1809
1760
  setVoiceState("idle");
1810
1761
  }, [stopRecording]);
1811
- react.useEffect(() => {
1762
+ React.useEffect(() => {
1812
1763
  return () => {
1813
1764
  if (recognitionRef.current) {
1814
1765
  try {
@@ -1948,9 +1899,9 @@ function buildContent(schema, values) {
1948
1899
  }
1949
1900
  return content;
1950
1901
  }
1951
- var PaymanChatContext = react.createContext(void 0);
1902
+ var PaymanChatContext = React.createContext(void 0);
1952
1903
  function usePaymanChat() {
1953
- const context = react.useContext(PaymanChatContext);
1904
+ const context = React.useContext(PaymanChatContext);
1954
1905
  if (!context) {
1955
1906
  throw new Error("usePaymanChat must be used within a PaymanChat component");
1956
1907
  }
@@ -2147,6 +2098,9 @@ function getConflictErrorMessage(errorDetails) {
2147
2098
  }
2148
2099
  function initSentryIfNeeded(dsn) {
2149
2100
  if (!dsn) return;
2101
+ if (typeof window !== "undefined" && (window.location.hostname === "localhost" || window.location.hostname === "127.0.0.1")) {
2102
+ return;
2103
+ }
2150
2104
  if (Sentry__namespace.getClient()) return;
2151
2105
  Sentry__namespace.init({
2152
2106
  dsn,
@@ -2208,8 +2162,8 @@ function ImageLightbox({
2208
2162
  alt = "",
2209
2163
  onClose
2210
2164
  }) {
2211
- const [isMounted, setIsMounted] = react.useState(false);
2212
- const [isImageLoaded, setIsImageLoaded] = react.useState(false);
2165
+ const [isMounted, setIsMounted] = React.useState(false);
2166
+ const [isImageLoaded, setIsImageLoaded] = React.useState(false);
2213
2167
  const overlayStyle = {
2214
2168
  position: "fixed",
2215
2169
  inset: 0,
@@ -2230,14 +2184,14 @@ function ImageLightbox({
2230
2184
  justifyContent: "center",
2231
2185
  overflow: "hidden"
2232
2186
  };
2233
- react.useEffect(() => {
2187
+ React.useEffect(() => {
2234
2188
  setIsMounted(true);
2235
2189
  return () => setIsMounted(false);
2236
2190
  }, []);
2237
- react.useEffect(() => {
2191
+ React.useEffect(() => {
2238
2192
  setIsImageLoaded(false);
2239
2193
  }, [src]);
2240
- react.useEffect(() => {
2194
+ React.useEffect(() => {
2241
2195
  if (typeof document === "undefined") return;
2242
2196
  const previousOverflow = document.body.style.overflow;
2243
2197
  document.body.style.overflow = "hidden";
@@ -2245,7 +2199,7 @@ function ImageLightbox({
2245
2199
  document.body.style.overflow = previousOverflow;
2246
2200
  };
2247
2201
  }, []);
2248
- react.useEffect(() => {
2202
+ React.useEffect(() => {
2249
2203
  if (typeof document === "undefined") return;
2250
2204
  const handleKeyDown = (event) => {
2251
2205
  if (event.key === "Escape") {
@@ -2341,15 +2295,15 @@ function MarkdownImage({
2341
2295
  maxHeight: "18rem",
2342
2296
  objectFit: "contain"
2343
2297
  };
2344
- const [isLoaded, setIsLoaded] = react.useState(false);
2345
- const [hasError, setHasError] = react.useState(false);
2346
- const [isLightboxOpen, setIsLightboxOpen] = react.useState(false);
2347
- const isUnresolvedRagImage = react.useMemo(
2298
+ const [isLoaded, setIsLoaded] = React.useState(false);
2299
+ const [hasError, setHasError] = React.useState(false);
2300
+ const [isLightboxOpen, setIsLightboxOpen] = React.useState(false);
2301
+ const isUnresolvedRagImage = React.useMemo(
2348
2302
  () => src ? isUnresolvedRagImageSource(src) : false,
2349
2303
  [src]
2350
2304
  );
2351
2305
  const isResolvingRagImage = isResolving && isUnresolvedRagImage;
2352
- react.useEffect(() => {
2306
+ React.useEffect(() => {
2353
2307
  setIsLoaded(false);
2354
2308
  setHasError(false);
2355
2309
  setIsLightboxOpen(false);
@@ -2476,9 +2430,9 @@ function AgentMessage({
2476
2430
  const hasTraceData = !!(message.tracingData || message.executionId) && !isStreaming;
2477
2431
  const isCancelled = message.isCancelled ?? false;
2478
2432
  const currentExecutingStepId = message.currentExecutingStepId;
2479
- const [isStepsExpanded, setIsStepsExpanded] = react.useState(false);
2480
- const wasStreamingRef = react.useRef(isStreaming);
2481
- react.useEffect(() => {
2433
+ const [isStepsExpanded, setIsStepsExpanded] = React.useState(false);
2434
+ const wasStreamingRef = React.useRef(isStreaming);
2435
+ React.useEffect(() => {
2482
2436
  if (isStreaming && hasSteps) {
2483
2437
  setIsStepsExpanded(true);
2484
2438
  }
@@ -2495,13 +2449,13 @@ function AgentMessage({
2495
2449
  const completedWithNoContent = !isStreaming && !isCancelled && content.length === 0 && (message.streamProgress === "completed" || message.streamProgress === "error");
2496
2450
  const conflictErrorMessage = getConflictErrorMessage(message.errorDetails);
2497
2451
  const isError = !!conflictErrorMessage || (isFriendlyWorkflowError(message.errorDetails) || looksLikeRawError(content)) && !hasMeaningfulContent || completedWithNoContent;
2498
- const currentStep = react.useMemo(
2452
+ const currentStep = React.useMemo(
2499
2453
  () => message.steps?.find(
2500
2454
  (s) => s.id === currentExecutingStepId && s.status === "in_progress"
2501
2455
  ),
2502
2456
  [message.steps, currentExecutingStepId]
2503
2457
  );
2504
- const markdownRenderers = react.useMemo(
2458
+ const markdownRenderers = React.useMemo(
2505
2459
  () => createMarkdownComponents({
2506
2460
  isResolvingImages: message.isResolvingImages
2507
2461
  }),
@@ -2575,8 +2529,8 @@ function AgentMessage({
2575
2529
  }) })
2576
2530
  }
2577
2531
  ) });
2578
- const stepsToggleRef = react.useRef(null);
2579
- const handleStepsToggle = react.useCallback(() => {
2532
+ const stepsToggleRef = React.useRef(null);
2533
+ const handleStepsToggle = React.useCallback(() => {
2580
2534
  setIsStepsExpanded((prev) => {
2581
2535
  const next = !prev;
2582
2536
  if (next) {
@@ -2904,23 +2858,23 @@ function MessageList({
2904
2858
  isLoadingMoreMessages = false,
2905
2859
  hasMoreMessages = false
2906
2860
  }) {
2907
- const scrollRef = react.useRef(null);
2908
- const isNearBottomRef = react.useRef(true);
2909
- const [showScrollBtn, setShowScrollBtn] = react.useState(false);
2910
- const prevMessageCountRef = react.useRef(messages.length);
2911
- const scrollHeightBeforePrependRef = react.useRef(null);
2912
- const firstMessageIdRef = react.useRef(messages[0]?.id);
2913
- const getDistanceFromBottom = react.useCallback(() => {
2861
+ const scrollRef = React.useRef(null);
2862
+ const isNearBottomRef = React.useRef(true);
2863
+ const [showScrollBtn, setShowScrollBtn] = React.useState(false);
2864
+ const prevMessageCountRef = React.useRef(messages.length);
2865
+ const scrollHeightBeforePrependRef = React.useRef(null);
2866
+ const firstMessageIdRef = React.useRef(messages[0]?.id);
2867
+ const getDistanceFromBottom = React.useCallback(() => {
2914
2868
  const el = scrollRef.current;
2915
2869
  if (!el) return 0;
2916
2870
  return el.scrollHeight - el.scrollTop - el.clientHeight;
2917
2871
  }, []);
2918
- const scrollToBottom = react.useCallback((behavior = "smooth") => {
2872
+ const scrollToBottom = React.useCallback((behavior = "smooth") => {
2919
2873
  const el = scrollRef.current;
2920
2874
  if (!el) return;
2921
2875
  el.scrollTo({ top: el.scrollHeight, behavior });
2922
2876
  }, []);
2923
- const handleScroll = react.useCallback(() => {
2877
+ const handleScroll = React.useCallback(() => {
2924
2878
  const el = scrollRef.current;
2925
2879
  if (!el) return;
2926
2880
  const distance = getDistanceFromBottom();
@@ -2932,7 +2886,7 @@ function MessageList({
2932
2886
  onLoadMoreMessages();
2933
2887
  }
2934
2888
  }, [getDistanceFromBottom, hasMoreMessages, isLoadingMoreMessages, onLoadMoreMessages]);
2935
- react.useLayoutEffect(() => {
2889
+ React.useLayoutEffect(() => {
2936
2890
  const el = scrollRef.current;
2937
2891
  const prevHeight = scrollHeightBeforePrependRef.current;
2938
2892
  const newFirstId = messages[0]?.id;
@@ -2942,25 +2896,25 @@ function MessageList({
2942
2896
  }
2943
2897
  firstMessageIdRef.current = newFirstId;
2944
2898
  }, [messages]);
2945
- react.useEffect(() => {
2899
+ React.useEffect(() => {
2946
2900
  const prevCount = prevMessageCountRef.current;
2947
2901
  prevMessageCountRef.current = messages.length;
2948
2902
  if (messages.length > prevCount && isNearBottomRef.current) {
2949
2903
  requestAnimationFrame(() => scrollToBottom());
2950
2904
  }
2951
2905
  }, [messages.length, scrollToBottom]);
2952
- react.useEffect(() => {
2906
+ React.useEffect(() => {
2953
2907
  const lastMsg = messages[messages.length - 1];
2954
2908
  if (!lastMsg?.isStreaming) return;
2955
2909
  if (!isNearBottomRef.current) return;
2956
2910
  requestAnimationFrame(() => scrollToBottom());
2957
2911
  });
2958
- react.useEffect(() => {
2912
+ React.useEffect(() => {
2959
2913
  if (messages.length > 0) {
2960
2914
  setTimeout(() => scrollToBottom("instant"), 50);
2961
2915
  }
2962
2916
  }, []);
2963
- react.useEffect(() => {
2917
+ React.useEffect(() => {
2964
2918
  const handleStepsToggle = () => {
2965
2919
  requestAnimationFrame(() => {
2966
2920
  requestAnimationFrame(() => {
@@ -2977,7 +2931,7 @@ function MessageList({
2977
2931
  return () => el.removeEventListener("payman-steps-toggle", handleStepsToggle);
2978
2932
  }
2979
2933
  }, [getDistanceFromBottom, scrollToBottom]);
2980
- const handleScrollToBottom = react.useCallback(() => {
2934
+ const handleScrollToBottom = React.useCallback(() => {
2981
2935
  scrollToBottom();
2982
2936
  }, [scrollToBottom]);
2983
2937
  if (isLoading) {
@@ -3110,7 +3064,7 @@ function ResetSessionConfirmModal({
3110
3064
  onClose,
3111
3065
  onConfirm
3112
3066
  }) {
3113
- const handleKeyDown = react.useCallback(
3067
+ const handleKeyDown = React.useCallback(
3114
3068
  (event) => {
3115
3069
  if (event.key === "Escape") {
3116
3070
  onClose();
@@ -3118,7 +3072,7 @@ function ResetSessionConfirmModal({
3118
3072
  },
3119
3073
  [onClose]
3120
3074
  );
3121
- react.useEffect(() => {
3075
+ React.useEffect(() => {
3122
3076
  if (!isOpen || typeof document === "undefined") return;
3123
3077
  document.addEventListener("keydown", handleKeyDown);
3124
3078
  const previousOverflow = document.body.style.overflow;
@@ -3224,14 +3178,14 @@ function UserMessageV2({
3224
3178
  retryDisabled = false,
3225
3179
  actions
3226
3180
  }) {
3227
- const [copied, setCopied] = react.useState(false);
3228
- const [toast, setToast] = react.useState(null);
3229
- const copyResetTimerRef = react.useRef(null);
3230
- const toastTimerRef = react.useRef(null);
3181
+ const [copied, setCopied] = React.useState(false);
3182
+ const [toast, setToast] = React.useState(null);
3183
+ const copyResetTimerRef = React.useRef(null);
3184
+ const toastTimerRef = React.useRef(null);
3231
3185
  const showCopyAction = actions?.copy ?? true;
3232
3186
  const showEditAction = actions?.edit ?? false;
3233
3187
  const showRetryAction = actions?.retry ?? false;
3234
- react.useEffect(() => {
3188
+ React.useEffect(() => {
3235
3189
  return () => {
3236
3190
  if (copyResetTimerRef.current) clearTimeout(copyResetTimerRef.current);
3237
3191
  if (toastTimerRef.current) clearTimeout(toastTimerRef.current);
@@ -3387,18 +3341,18 @@ function MarkdownImageV2({
3387
3341
  onImageClick
3388
3342
  }) {
3389
3343
  const cachedAlready = src ? loadedImageCache.has(src) : false;
3390
- const [isVisible, setIsVisible] = react.useState(cachedAlready);
3391
- const [isLoaded, setIsLoaded] = react.useState(cachedAlready);
3392
- const [hasError, setHasError] = react.useState(false);
3393
- const [retryCount, setRetryCount] = react.useState(0);
3394
- const sentinelRef = react.useRef(null);
3395
- const prevLoadedRef = react.useRef(cachedAlready);
3396
- const isUnresolvedRag = react.useMemo(
3344
+ const [isVisible, setIsVisible] = React.useState(cachedAlready);
3345
+ const [isLoaded, setIsLoaded] = React.useState(cachedAlready);
3346
+ const [hasError, setHasError] = React.useState(false);
3347
+ const [retryCount, setRetryCount] = React.useState(0);
3348
+ const sentinelRef = React.useRef(null);
3349
+ const prevLoadedRef = React.useRef(cachedAlready);
3350
+ const isUnresolvedRag = React.useMemo(
3397
3351
  () => src ? isUnresolvedRagImageSource2(src) : false,
3398
3352
  [src]
3399
3353
  );
3400
3354
  const isResolvingRag = Boolean(isResolving && isUnresolvedRag);
3401
- react.useEffect(() => {
3355
+ React.useEffect(() => {
3402
3356
  if (src && loadedImageCache.has(src)) {
3403
3357
  setIsLoaded(true);
3404
3358
  setIsVisible(true);
@@ -3407,7 +3361,7 @@ function MarkdownImageV2({
3407
3361
  setHasError(false);
3408
3362
  setRetryCount(0);
3409
3363
  }, [src]);
3410
- react.useEffect(() => {
3364
+ React.useEffect(() => {
3411
3365
  const el = sentinelRef.current;
3412
3366
  if (!el || !src) return;
3413
3367
  const rect = el.getBoundingClientRect();
@@ -3528,9 +3482,88 @@ function MarkdownImageV2({
3528
3482
  }
3529
3483
  ) });
3530
3484
  }
3531
- function buildComponents(onImageClick, isResolvingRef) {
3485
+ var RAG_SOURCE_CLASS = "payman-v2-rag-source";
3486
+ var RAG_FOLLOW_UP_CLASS = "payman-v2-rag-follow-up";
3487
+ var SOURCE_PATTERN = /^Sources?:\s*\S/i;
3488
+ var MAX_FOLLOW_UP_LENGTH = 320;
3489
+ var HR_PATTERN = /^-{3,}$|^_{3,}$|^\*{3,}$/;
3490
+ function normalizeRagParagraphText(text) {
3491
+ return text.replace(/\s+/g, " ").trim();
3492
+ }
3493
+ function isRagSourceParagraph(text) {
3494
+ return SOURCE_PATTERN.test(normalizeRagParagraphText(text));
3495
+ }
3496
+ function isRagFollowUpCandidate(text) {
3497
+ const normalized = normalizeRagParagraphText(text);
3498
+ return normalized.length > 0 && normalized.length <= MAX_FOLLOW_UP_LENGTH && normalized.endsWith("?");
3499
+ }
3500
+ function extractRagParagraphTexts(content) {
3501
+ const paragraphs = [];
3502
+ const currentParagraph = [];
3503
+ const flushParagraph = () => {
3504
+ const paragraph = normalizeRagParagraphText(currentParagraph.join(" "));
3505
+ currentParagraph.length = 0;
3506
+ if (paragraph) paragraphs.push(paragraph);
3507
+ };
3508
+ content.replace(/\\n/g, "\n").split(/\r?\n/).forEach((line) => {
3509
+ const trimmedLine = line.trim();
3510
+ if (!trimmedLine) {
3511
+ flushParagraph();
3512
+ return;
3513
+ }
3514
+ if (HR_PATTERN.test(trimmedLine)) {
3515
+ flushParagraph();
3516
+ return;
3517
+ }
3518
+ currentParagraph.push(trimmedLine);
3519
+ });
3520
+ flushParagraph();
3521
+ return paragraphs;
3522
+ }
3523
+ function getRagAnswerParagraphRoles(paragraphs) {
3524
+ const normalized = paragraphs.map(normalizeRagParagraphText);
3525
+ const roles = normalized.map(() => null);
3526
+ const sourceIndexes = normalized.map((paragraph, index) => isRagSourceParagraph(paragraph) ? index : -1).filter((index) => index >= 0);
3527
+ for (const sourceIndex of sourceIndexes) {
3528
+ roles[sourceIndex] = "source";
3529
+ for (const candidateIndex of [sourceIndex - 1, sourceIndex + 1]) {
3530
+ if (candidateIndex >= 0 && candidateIndex < normalized.length && roles[candidateIndex] == null && isRagFollowUpCandidate(normalized[candidateIndex] ?? "")) {
3531
+ roles[candidateIndex] = "follow-up";
3532
+ }
3533
+ }
3534
+ }
3535
+ return roles;
3536
+ }
3537
+ function getRagAnswerParagraphRole(paragraph, paragraphs) {
3538
+ const normalizedParagraph = normalizeRagParagraphText(paragraph);
3539
+ if (isRagSourceParagraph(normalizedParagraph)) return "source";
3540
+ const roles = getRagAnswerParagraphRoles(paragraphs);
3541
+ return paragraphs.map(normalizeRagParagraphText).some((candidate, index) => {
3542
+ return candidate === normalizedParagraph && roles[index] === "follow-up";
3543
+ }) ? "follow-up" : null;
3544
+ }
3545
+ function ragAnswerRoleClassName(role) {
3546
+ if (role === "source") return RAG_SOURCE_CLASS;
3547
+ if (role === "follow-up") return RAG_FOLLOW_UP_CLASS;
3548
+ return void 0;
3549
+ }
3550
+ function reactNodeText(node) {
3551
+ if (typeof node === "string" || typeof node === "number") return String(node);
3552
+ if (Array.isArray(node)) return node.map(reactNodeText).join("");
3553
+ if (React__namespace.isValidElement(node)) {
3554
+ return reactNodeText(node.props.children);
3555
+ }
3556
+ return "";
3557
+ }
3558
+ function buildComponents(onImageClick, isResolvingRef, ragParagraphsRef) {
3532
3559
  return {
3533
- p: ({ children }) => /* @__PURE__ */ jsxRuntime.jsx("p", { children }),
3560
+ p: ({ children }) => {
3561
+ const role = getRagAnswerParagraphRole(
3562
+ reactNodeText(children),
3563
+ ragParagraphsRef?.current ?? []
3564
+ );
3565
+ return /* @__PURE__ */ jsxRuntime.jsx("p", { className: ragAnswerRoleClassName(role), children });
3566
+ },
3534
3567
  code: ({ children }) => /* @__PURE__ */ jsxRuntime.jsx("code", { children }),
3535
3568
  pre: ({ children }) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "payman-v2-markdown-pre", children: /* @__PURE__ */ jsxRuntime.jsx("pre", { children }) }),
3536
3569
  ul: ({ children }) => /* @__PURE__ */ jsxRuntime.jsx("ul", { children }),
@@ -3566,10 +3599,15 @@ function MarkdownRendererV2({
3566
3599
  isResolvingImages,
3567
3600
  onImageClick
3568
3601
  }) {
3569
- const isResolvingRef = react.useRef(isResolvingImages);
3602
+ const isResolvingRef = React.useRef(isResolvingImages);
3570
3603
  isResolvingRef.current = isResolvingImages;
3571
- const components = react.useMemo(
3572
- () => buildComponents(onImageClick, isResolvingRef),
3604
+ const ragParagraphsRef = React.useRef([]);
3605
+ ragParagraphsRef.current = React.useMemo(
3606
+ () => extractRagParagraphTexts(content),
3607
+ [content]
3608
+ );
3609
+ const components = React.useMemo(
3610
+ () => buildComponents(onImageClick, isResolvingRef, ragParagraphsRef),
3573
3611
  [onImageClick]
3574
3612
  );
3575
3613
  return /* @__PURE__ */ jsxRuntime.jsx(
@@ -3626,14 +3664,14 @@ function FeedbackReasonModal({
3626
3664
  onClose,
3627
3665
  onSubmit
3628
3666
  }) {
3629
- const [reason, setReason] = react.useState(
3667
+ const [reason, setReason] = React.useState(
3630
3668
  NEGATIVE_FEEDBACK_REASONS[0].value
3631
3669
  );
3632
- const [details, setDetails] = react.useState("");
3633
- const [submitting, setSubmitting] = react.useState(false);
3634
- const [error, setError] = react.useState(null);
3635
- const [reasonOpen, setReasonOpen] = react.useState(false);
3636
- react.useEffect(() => {
3670
+ const [details, setDetails] = React.useState("");
3671
+ const [submitting, setSubmitting] = React.useState(false);
3672
+ const [error, setError] = React.useState(null);
3673
+ const [reasonOpen, setReasonOpen] = React.useState(false);
3674
+ React.useEffect(() => {
3637
3675
  if (open) {
3638
3676
  setReason(NEGATIVE_FEEDBACK_REASONS[0].value);
3639
3677
  setDetails("");
@@ -3642,7 +3680,7 @@ function FeedbackReasonModal({
3642
3680
  setReasonOpen(false);
3643
3681
  }
3644
3682
  }, [open]);
3645
- const handleKeyDown = react.useCallback(
3683
+ const handleKeyDown = React.useCallback(
3646
3684
  (event) => {
3647
3685
  if (event.key !== "Escape") return;
3648
3686
  if (reasonOpen) {
@@ -3653,7 +3691,7 @@ function FeedbackReasonModal({
3653
3691
  },
3654
3692
  [onClose, reasonOpen]
3655
3693
  );
3656
- react.useEffect(() => {
3694
+ React.useEffect(() => {
3657
3695
  if (!open || typeof document === "undefined") return;
3658
3696
  document.addEventListener("keydown", handleKeyDown);
3659
3697
  const previousOverflow = document.body.style.overflow;
@@ -3937,17 +3975,17 @@ function charDelay(char, speed, multiplier) {
3937
3975
  function useTypingEffect(targetText, enabled, speed = RESPONSE_SPEED, initialDisplayedText, speedMultiplier = 1) {
3938
3976
  const instant = speedMultiplier === 0;
3939
3977
  const multiplier = instant ? 1 : Math.max(speedMultiplier, 0.1);
3940
- const [displayedText, setDisplayedText] = react.useState("");
3941
- const displayedRef = react.useRef("");
3942
- const targetRef = react.useRef(targetText);
3943
- const enabledRef = react.useRef(enabled);
3944
- const initialDisplayedRef = react.useRef(initialDisplayedText);
3945
- const timerRef = react.useRef(null);
3946
- const runningRef = react.useRef(false);
3978
+ const [displayedText, setDisplayedText] = React.useState("");
3979
+ const displayedRef = React.useRef("");
3980
+ const targetRef = React.useRef(targetText);
3981
+ const enabledRef = React.useRef(enabled);
3982
+ const initialDisplayedRef = React.useRef(initialDisplayedText);
3983
+ const timerRef = React.useRef(null);
3984
+ const runningRef = React.useRef(false);
3947
3985
  targetRef.current = targetText;
3948
3986
  enabledRef.current = enabled;
3949
3987
  initialDisplayedRef.current = initialDisplayedText;
3950
- react.useEffect(() => {
3988
+ React.useEffect(() => {
3951
3989
  if (!enabled || instant) {
3952
3990
  if (timerRef.current) {
3953
3991
  clearTimeout(timerRef.current);
@@ -4030,26 +4068,26 @@ function AssistantMessageV2({
4030
4068
  actions,
4031
4069
  typingSpeed = 4
4032
4070
  }) {
4033
- const [copied, setCopied] = react.useState(false);
4034
- const [activeFeedback, setActiveFeedback] = react.useState(
4071
+ const [copied, setCopied] = React.useState(false);
4072
+ const [activeFeedback, setActiveFeedback] = React.useState(
4035
4073
  () => getFeedbackState(message)
4036
4074
  );
4037
- const [reasonModalOpen, setReasonModalOpen] = react.useState(false);
4075
+ const [reasonModalOpen, setReasonModalOpen] = React.useState(false);
4038
4076
  const canSubmitFeedback = !!onSubmitFeedback && !!message.executionId;
4039
- const [toast, setToast] = react.useState(null);
4040
- const copyResetTimerRef = react.useRef(null);
4041
- const toastTimerRef = react.useRef(null);
4077
+ const [toast, setToast] = React.useState(null);
4078
+ const copyResetTimerRef = React.useRef(null);
4079
+ const toastTimerRef = React.useRef(null);
4042
4080
  const showCopyAction = actions?.copy ?? true;
4043
4081
  const showTraceAction = (actions?.trace ?? true) && !!onExecutionTraceClick;
4044
4082
  const showThumbsUp = actions?.thumbsUp ?? true;
4045
4083
  const showThumbsDown = actions?.thumbsDown ?? true;
4046
4084
  const hydratedFeedback = message.feedback;
4047
- const hasEverStreamed = react.useRef(!!message.isStreaming);
4085
+ const hasEverStreamed = React.useRef(!!message.isStreaming);
4048
4086
  if (message.isStreaming) hasEverStreamed.current = true;
4049
- react.useEffect(() => {
4087
+ React.useEffect(() => {
4050
4088
  setActiveFeedback(getFeedbackState(message));
4051
4089
  }, [hydratedFeedback, message.id]);
4052
- react.useEffect(() => {
4090
+ React.useEffect(() => {
4053
4091
  return () => {
4054
4092
  if (copyResetTimerRef.current) clearTimeout(copyResetTimerRef.current);
4055
4093
  if (toastTimerRef.current) clearTimeout(toastTimerRef.current);
@@ -4062,6 +4100,7 @@ function AssistantMessageV2({
4062
4100
  return message.isStreaming ? stripIncompleteImageToken(normalized) : normalized;
4063
4101
  })();
4064
4102
  const isThinkingStreaming = !!message.isStreaming && !rawResponseContent && !message.isError;
4103
+ const showTrailingProgress = !!message.isStreaming && !!rawResponseContent && !message.isError && !message.isCancelled && !!message.hasTrailingActivity;
4065
4104
  const responseTypingEnabled = hasEverStreamed.current && Boolean(rawResponseContent) && !message.isError;
4066
4105
  const { displayedText: displayContent, isTyping: isResponseTyping } = useTypingEffect(
4067
4106
  rawResponseContent,
@@ -4220,7 +4259,7 @@ function AssistantMessageV2({
4220
4259
  {
4221
4260
  isStreaming: isThinkingStreaming,
4222
4261
  stickyLabel,
4223
- currentStepLabel
4262
+ currentStepLabel: currentStepLabel ?? message.currentMessage
4224
4263
  }
4225
4264
  )
4226
4265
  },
@@ -4235,6 +4274,27 @@ function AssistantMessageV2({
4235
4274
  onImageClick
4236
4275
  }
4237
4276
  ) : !isThinkingStreaming ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "payman-v2-assistant-msg-placeholder", children: "..." }) : null }),
4277
+ /* @__PURE__ */ jsxRuntime.jsx(framerMotion.AnimatePresence, { children: showTrailingProgress && /* @__PURE__ */ jsxRuntime.jsx(
4278
+ framerMotion.motion.div,
4279
+ {
4280
+ initial: { opacity: 0, height: 0 },
4281
+ animate: { opacity: 1, height: "auto" },
4282
+ exit: { opacity: 0, height: 0 },
4283
+ transition: {
4284
+ duration: 0.32,
4285
+ ease: [0.2, 0, 0, 1]
4286
+ },
4287
+ style: { overflow: "hidden" },
4288
+ children: /* @__PURE__ */ jsxRuntime.jsx(
4289
+ ThinkingBlockV2,
4290
+ {
4291
+ isStreaming: true,
4292
+ currentStepLabel: message.currentMessage ?? currentStepLabel
4293
+ }
4294
+ )
4295
+ },
4296
+ "trailing-progress"
4297
+ ) }),
4238
4298
  isCancelled && message.isStreaming && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "payman-v2-assistant-msg-paused", children: [
4239
4299
  /* @__PURE__ */ jsxRuntime.jsx(
4240
4300
  lucideReact.WifiOff,
@@ -4343,10 +4403,10 @@ function OtpInputV2({
4343
4403
  disabled = false,
4344
4404
  error = false
4345
4405
  }) {
4346
- const inputRefs = react.useRef([]);
4406
+ const inputRefs = React.useRef([]);
4347
4407
  const safeMaxLength = Number.isInteger(maxLength) && maxLength > 0 ? Math.min(maxLength, MAX_SUPPORTED_LENGTH) : DEFAULT_MAX_LENGTH;
4348
4408
  const digits = value.split("").concat(Array(safeMaxLength).fill("")).slice(0, safeMaxLength);
4349
- react.useEffect(() => {
4409
+ React.useEffect(() => {
4350
4410
  if (disabled) return;
4351
4411
  const timer = window.setTimeout(() => {
4352
4412
  inputRefs.current[0]?.focus();
@@ -4445,31 +4505,31 @@ function VerificationInline({
4445
4505
  onResend
4446
4506
  }) {
4447
4507
  const isNumeric = prompt.verificationType !== "ALPHANUMERIC_CODE";
4448
- const codeLen = react.useMemo(() => codeLengthFromSchema(prompt), [prompt]);
4449
- const [code, setCode] = react.useState("");
4450
- const [errored, setErrored] = react.useState(false);
4451
- const [resendSec, setResendSec] = react.useState(0);
4452
- const [hiddenAfterResend, setHiddenAfterResend] = react.useState(false);
4453
- const lastSubmittedRef = react.useRef(null);
4454
- const resendTimerRef = react.useRef(void 0);
4508
+ const codeLen = React.useMemo(() => codeLengthFromSchema(prompt), [prompt]);
4509
+ const [code, setCode] = React.useState("");
4510
+ const [errored, setErrored] = React.useState(false);
4511
+ const [resendSec, setResendSec] = React.useState(0);
4512
+ const [hiddenAfterResend, setHiddenAfterResend] = React.useState(false);
4513
+ const lastSubmittedRef = React.useRef(null);
4514
+ const resendTimerRef = React.useRef(void 0);
4455
4515
  const status = prompt.status;
4456
4516
  const busy = status === "submitting";
4457
4517
  const stale = status === "stale";
4458
4518
  const locked = busy || stale || expired;
4459
- react.useEffect(() => {
4519
+ React.useEffect(() => {
4460
4520
  if (prompt.subAction === "SubmissionInvalid") {
4461
4521
  setErrored(true);
4462
4522
  setCode("");
4463
4523
  lastSubmittedRef.current = null;
4464
4524
  }
4465
4525
  }, [prompt.subAction, prompt.userActionId]);
4466
- react.useEffect(() => {
4526
+ React.useEffect(() => {
4467
4527
  setHiddenAfterResend(false);
4468
4528
  }, [prompt.expirySeconds, prompt.message, prompt.subAction, prompt.userActionId]);
4469
- react.useEffect(() => {
4529
+ React.useEffect(() => {
4470
4530
  if (code.length < codeLen) lastSubmittedRef.current = null;
4471
4531
  }, [code, codeLen]);
4472
- const doSubmit = react.useCallback(
4532
+ const doSubmit = React.useCallback(
4473
4533
  (value) => {
4474
4534
  if (locked || !value) return;
4475
4535
  if (lastSubmittedRef.current === value) return;
@@ -4481,20 +4541,20 @@ function VerificationInline({
4481
4541
  },
4482
4542
  [locked, onSubmit, prompt.userActionId]
4483
4543
  );
4484
- react.useEffect(() => {
4544
+ React.useEffect(() => {
4485
4545
  if (!isNumeric || locked) return;
4486
4546
  if (code.length === codeLen && /^\d+$/.test(code)) {
4487
4547
  doSubmit(code);
4488
4548
  }
4489
4549
  }, [code, codeLen, doSubmit, isNumeric, locked]);
4490
- react.useEffect(() => {
4550
+ React.useEffect(() => {
4491
4551
  return () => {
4492
4552
  if (typeof resendTimerRef.current === "number") {
4493
4553
  window.clearInterval(resendTimerRef.current);
4494
4554
  }
4495
4555
  };
4496
4556
  }, []);
4497
- const startResendCooldown = react.useCallback(() => {
4557
+ const startResendCooldown = React.useCallback(() => {
4498
4558
  setResendSec(RESEND_COOLDOWN_S);
4499
4559
  if (typeof resendTimerRef.current === "number") {
4500
4560
  window.clearInterval(resendTimerRef.current);
@@ -4512,7 +4572,7 @@ function VerificationInline({
4512
4572
  });
4513
4573
  }, 1e3);
4514
4574
  }, []);
4515
- const handleResend = react.useCallback(async () => {
4575
+ const handleResend = React.useCallback(async () => {
4516
4576
  if (locked || resendSec > 0) return;
4517
4577
  setErrored(false);
4518
4578
  setCode("");
@@ -4525,11 +4585,14 @@ function VerificationInline({
4525
4585
  setHiddenAfterResend(false);
4526
4586
  }
4527
4587
  }, [locked, onResend, prompt.userActionId, resendSec, startResendCooldown]);
4528
- const handleCancel = react.useCallback(() => {
4588
+ const handleCancel = React.useCallback(() => {
4529
4589
  if (busy) return;
4530
4590
  void onCancel(prompt.userActionId);
4531
4591
  }, [busy, onCancel, prompt.userActionId]);
4532
- const description = prompt.message?.trim() || (isNumeric ? `Enter the ${codeLen}-digit code to continue` : "Enter the verification code to continue");
4592
+ const promptMessage = prompt.message?.trim();
4593
+ const description = promptMessage || (isNumeric ? `Enter the ${codeLen}-digit code to continue` : "Enter the verification code to continue");
4594
+ const messageFormat = prompt.metadata?.["payman/messageFormat"];
4595
+ const renderMarkdown = !!promptMessage && messageFormat === "markdown";
4533
4596
  if (hiddenAfterResend) return null;
4534
4597
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "payman-v2-ua", role: "group", "aria-label": "Verification required", children: [
4535
4598
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "payman-v2-ua-head", children: [
@@ -4537,7 +4600,7 @@ function VerificationInline({
4537
4600
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "payman-v2-ua-title", children: "Verification required" }),
4538
4601
  typeof secondsLeft === "number" && !stale && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "payman-v2-ua-timer", children: expired ? "Expired" : `${secondsLeft}s` })
4539
4602
  ] }),
4540
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "payman-v2-ua-desc", children: description }),
4603
+ renderMarkdown ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "payman-v2-ua-markdown", children: /* @__PURE__ */ jsxRuntime.jsx(MarkdownRendererV2, { content: description }) }) : /* @__PURE__ */ jsxRuntime.jsx("p", { className: "payman-v2-ua-desc", children: description }),
4541
4604
  stale ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "payman-v2-ua-stale", children: "This request is no longer available." }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
4542
4605
  isNumeric ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "payman-v2-ua-field", children: /* @__PURE__ */ jsxRuntime.jsx(
4543
4606
  OtpInputV2,
@@ -4615,13 +4678,13 @@ function SchemaFormInline({
4615
4678
  onCancel
4616
4679
  }) {
4617
4680
  const schema = prompt.requestedSchema;
4618
- const fields = react.useMemo(() => renderableFields(schema), [schema]);
4619
- const [values, setValues] = react.useState(() => {
4681
+ const fields = React.useMemo(() => renderableFields(schema), [schema]);
4682
+ const [values, setValues] = React.useState(() => {
4620
4683
  const init2 = {};
4621
4684
  for (const [key, field] of fields) init2[key] = defaultValueFor(field);
4622
4685
  return init2;
4623
4686
  });
4624
- const [errors, setErrors] = react.useState({});
4687
+ const [errors, setErrors] = React.useState({});
4625
4688
  const status = prompt.status;
4626
4689
  const busy = status === "submitting";
4627
4690
  const stale = status === "stale";
@@ -4761,14 +4824,15 @@ function NotificationInline({ notification, onDismiss }) {
4761
4824
  ] });
4762
4825
  }
4763
4826
  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);
4766
- react.useEffect(() => {
4767
- if (initial === void 0) {
4827
+ 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;
4828
+ const [secondsLeft, setSecondsLeft] = React.useState(
4829
+ () => deadlineMs !== void 0 ? Math.max(0, Math.ceil((deadlineMs - Date.now()) / 1e3)) : void 0
4830
+ );
4831
+ React.useEffect(() => {
4832
+ if (deadlineMs === void 0) {
4768
4833
  setSecondsLeft(void 0);
4769
4834
  return;
4770
4835
  }
4771
- const deadlineMs = Date.now() + initial * 1e3;
4772
4836
  let intervalId;
4773
4837
  const remaining = () => Math.max(0, Math.ceil((deadlineMs - Date.now()) / 1e3));
4774
4838
  const sync = () => {
@@ -4790,8 +4854,8 @@ function useExpiryCountdown(prompt) {
4790
4854
  window.removeEventListener("focus", sync);
4791
4855
  window.removeEventListener("pageshow", sync);
4792
4856
  };
4793
- }, [prompt.userActionId, prompt.subAction, initial]);
4794
- const expired = initial !== void 0 && secondsLeft === 0;
4857
+ }, [prompt.userActionId, prompt.subAction, deadlineMs]);
4858
+ const expired = deadlineMs !== void 0 && (getUserActionSecondsLeft(prompt) ?? secondsLeft ?? 0) <= 0;
4795
4859
  return [secondsLeft, expired];
4796
4860
  }
4797
4861
  function UserActionInline({
@@ -4802,7 +4866,7 @@ function UserActionInline({
4802
4866
  onExpired
4803
4867
  }) {
4804
4868
  const [secondsLeft, expired] = useExpiryCountdown(prompt);
4805
- react.useEffect(() => {
4869
+ React.useEffect(() => {
4806
4870
  if (expired && prompt.kind !== "notification") onExpired?.();
4807
4871
  }, [expired, onExpired, prompt.kind]);
4808
4872
  let body;
@@ -4865,7 +4929,7 @@ function getPromptViewKey(prompt) {
4865
4929
  prompt.message ?? ""
4866
4930
  ].join(PROMPT_KEY_SEPARATOR);
4867
4931
  }
4868
- var MessageListV2 = react.forwardRef(
4932
+ var MessageListV2 = React.forwardRef(
4869
4933
  function MessageListV22({
4870
4934
  messages,
4871
4935
  isStreaming = false,
@@ -4885,25 +4949,25 @@ var MessageListV2 = react.forwardRef(
4885
4949
  onSubmitFeedback,
4886
4950
  typingSpeed = 4
4887
4951
  }, ref) {
4888
- const noop = react.useCallback(async () => {
4952
+ const noop = React.useCallback(async () => {
4889
4953
  }, []);
4890
- const scrollRef = react.useRef(null);
4891
- const scrollInnerRef = react.useRef(null);
4892
- const isNearBottomRef = react.useRef(true);
4893
- const [showScrollBtn, setShowScrollBtn] = react.useState(false);
4894
- const [expiredPromptViewState, setExpiredPromptViewState] = react.useState({});
4895
- const expiredUserActionIdsRef = react.useRef(/* @__PURE__ */ new Set());
4896
- const prevCountRef = react.useRef(messages.length);
4897
- const pauseStickUntilUserMessageRef = react.useRef(false);
4898
- const followingBottomRef = react.useRef(true);
4899
- const lastPinAtRef = react.useRef(0);
4900
- const prevScrollTopRef = react.useRef(0);
4901
- const getDistanceFromBottom = react.useCallback(() => {
4954
+ const scrollRef = React.useRef(null);
4955
+ const scrollInnerRef = React.useRef(null);
4956
+ const isNearBottomRef = React.useRef(true);
4957
+ const [showScrollBtn, setShowScrollBtn] = React.useState(false);
4958
+ const [expiredPromptViewState, setExpiredPromptViewState] = React.useState({});
4959
+ const expiredUserActionIdsRef = React.useRef(/* @__PURE__ */ new Set());
4960
+ const prevCountRef = React.useRef(messages.length);
4961
+ const pauseStickUntilUserMessageRef = React.useRef(false);
4962
+ const followingBottomRef = React.useRef(true);
4963
+ const lastPinAtRef = React.useRef(0);
4964
+ const prevScrollTopRef = React.useRef(0);
4965
+ const getDistanceFromBottom = React.useCallback(() => {
4902
4966
  const el = scrollRef.current;
4903
4967
  if (!el) return 0;
4904
4968
  return el.scrollHeight - el.scrollTop - el.clientHeight;
4905
4969
  }, []);
4906
- const messageActivityFingerprint = react.useMemo(() => {
4970
+ const messageActivityFingerprint = React.useMemo(() => {
4907
4971
  const last = messages[messages.length - 1];
4908
4972
  const promptFingerprint = (userActionPrompts ?? []).map((prompt) => `${getPromptViewKey(prompt)}:${prompt.status}`).join(PROMPT_KEY_SEPARATOR);
4909
4973
  const notificationFingerprint = (notifications ?? []).map((notification) => notification.id).join(PROMPT_KEY_SEPARATOR);
@@ -4929,7 +4993,7 @@ var MessageListV2 = react.forwardRef(
4929
4993
  notificationFingerprint
4930
4994
  ].join(PROMPT_KEY_SEPARATOR);
4931
4995
  }, [isStreaming, messages, notifications, userActionPrompts]);
4932
- const handleUserActionExpired = react.useCallback(
4996
+ const handleUserActionExpired = React.useCallback(
4933
4997
  (promptKey, userActionId) => {
4934
4998
  setExpiredPromptViewState((prev) => {
4935
4999
  if (prev[promptKey]) return prev;
@@ -4946,7 +5010,7 @@ var MessageListV2 = react.forwardRef(
4946
5010
  },
4947
5011
  [messageActivityFingerprint, onExpireUserAction]
4948
5012
  );
4949
- react.useEffect(() => {
5013
+ React.useEffect(() => {
4950
5014
  setExpiredPromptViewState((prev) => {
4951
5015
  let changed = false;
4952
5016
  const next = {};
@@ -4961,7 +5025,7 @@ var MessageListV2 = react.forwardRef(
4961
5025
  return changed ? next : prev;
4962
5026
  });
4963
5027
  }, [messageActivityFingerprint]);
4964
- react.useEffect(() => {
5028
+ React.useEffect(() => {
4965
5029
  const livePromptKeys = new Set((userActionPrompts ?? []).map(getPromptViewKey));
4966
5030
  const liveUserActionIds = new Set((userActionPrompts ?? []).map((p) => p.userActionId));
4967
5031
  for (const userActionId of expiredUserActionIdsRef.current) {
@@ -4982,21 +5046,21 @@ var MessageListV2 = react.forwardRef(
4982
5046
  return changed ? next : prev;
4983
5047
  });
4984
5048
  }, [userActionPrompts]);
4985
- const visibleUserActionPrompts = react.useMemo(
5049
+ const visibleUserActionPrompts = React.useMemo(
4986
5050
  () => userActionPrompts?.filter((prompt) => {
4987
5051
  const promptKey = getPromptViewKey(prompt);
4988
5052
  return !expiredPromptViewState[promptKey]?.hidden;
4989
5053
  }),
4990
5054
  [expiredPromptViewState, userActionPrompts]
4991
5055
  );
4992
- const pinToBottom = react.useCallback((behavior = "instant") => {
5056
+ const pinToBottom = React.useCallback((behavior = "instant") => {
4993
5057
  const el = scrollRef.current;
4994
5058
  if (!el) return;
4995
5059
  lastPinAtRef.current = performance.now();
4996
5060
  el.scrollTo({ top: el.scrollHeight, behavior });
4997
5061
  prevScrollTopRef.current = el.scrollHeight;
4998
5062
  }, []);
4999
- const scrollToBottom = react.useCallback(
5063
+ const scrollToBottom = React.useCallback(
5000
5064
  (behavior = "smooth") => {
5001
5065
  const el = scrollRef.current;
5002
5066
  if (!el) return;
@@ -5006,7 +5070,7 @@ var MessageListV2 = react.forwardRef(
5006
5070
  },
5007
5071
  [pinToBottom]
5008
5072
  );
5009
- react.useImperativeHandle(
5073
+ React.useImperativeHandle(
5010
5074
  ref,
5011
5075
  () => ({
5012
5076
  scrollToBottom: (behavior = "smooth") => {
@@ -5019,7 +5083,7 @@ var MessageListV2 = react.forwardRef(
5019
5083
  }),
5020
5084
  [scrollToBottom]
5021
5085
  );
5022
- const handleScroll = react.useCallback(() => {
5086
+ const handleScroll = React.useCallback(() => {
5023
5087
  const el = scrollRef.current;
5024
5088
  if (!el) return;
5025
5089
  const currentScrollTop = el.scrollTop;
@@ -5040,7 +5104,7 @@ var MessageListV2 = react.forwardRef(
5040
5104
  pauseStickUntilUserMessageRef.current = false;
5041
5105
  }
5042
5106
  }, [getDistanceFromBottom]);
5043
- react.useEffect(() => {
5107
+ React.useEffect(() => {
5044
5108
  const prevCount = prevCountRef.current;
5045
5109
  prevCountRef.current = messages.length;
5046
5110
  if (messages.length > prevCount) {
@@ -5054,7 +5118,7 @@ var MessageListV2 = react.forwardRef(
5054
5118
  }
5055
5119
  }
5056
5120
  }, [messages.length, scrollToBottom]);
5057
- react.useEffect(() => {
5121
+ React.useEffect(() => {
5058
5122
  const inner = scrollInnerRef.current;
5059
5123
  if (!inner) return;
5060
5124
  const pinIfFollowing = () => {
@@ -5079,7 +5143,7 @@ var MessageListV2 = react.forwardRef(
5079
5143
  mo.disconnect();
5080
5144
  };
5081
5145
  }, [pinToBottom]);
5082
- react.useEffect(() => {
5146
+ React.useEffect(() => {
5083
5147
  if (messages.length > 0) {
5084
5148
  setTimeout(() => scrollToBottom("instant"), 50);
5085
5149
  }
@@ -5168,7 +5232,7 @@ var MessageListV2 = react.forwardRef(
5168
5232
  ] });
5169
5233
  }
5170
5234
  );
5171
- var ChatInputV2 = react.forwardRef(
5235
+ var ChatInputV2 = React.forwardRef(
5172
5236
  function ChatInputV22({
5173
5237
  onSend,
5174
5238
  disabled = false,
@@ -5192,20 +5256,20 @@ var ChatInputV2 = react.forwardRef(
5192
5256
  onAnalysisModeChange,
5193
5257
  slashCommands = []
5194
5258
  }, ref) {
5195
- const [value, setValue] = react.useState("");
5196
- const [isFocused, setIsFocused] = react.useState(false);
5197
- const [showActions, setShowActions] = react.useState(false);
5198
- const [showVoiceTooltip, setShowVoiceTooltip] = react.useState(false);
5199
- const [selectedCommandIndex, setSelectedCommandIndex] = react.useState(0);
5200
- const [inlineHint, setInlineHint] = react.useState(null);
5201
- const [commandMenuDismissed, setCommandMenuDismissed] = react.useState(false);
5202
- const textareaRef = react.useRef(null);
5203
- const actionsRef = react.useRef(null);
5204
- const preRecordTextRef = react.useRef("");
5205
- const voiceTooltipTimerRef = react.useRef(
5259
+ const [value, setValue] = React.useState("");
5260
+ const [isFocused, setIsFocused] = React.useState(false);
5261
+ const [showActions, setShowActions] = React.useState(false);
5262
+ const [showVoiceTooltip, setShowVoiceTooltip] = React.useState(false);
5263
+ const [selectedCommandIndex, setSelectedCommandIndex] = React.useState(0);
5264
+ const [inlineHint, setInlineHint] = React.useState(null);
5265
+ const [commandMenuDismissed, setCommandMenuDismissed] = React.useState(false);
5266
+ const textareaRef = React.useRef(null);
5267
+ const actionsRef = React.useRef(null);
5268
+ const preRecordTextRef = React.useRef("");
5269
+ const voiceTooltipTimerRef = React.useRef(
5206
5270
  null
5207
5271
  );
5208
- const voiceDraftSyncActiveRef = react.useRef(false);
5272
+ const voiceDraftSyncActiveRef = React.useRef(false);
5209
5273
  const isInputLocked = disabled || isRecording;
5210
5274
  const hasAttachmentOptions = showUploadImageButton || showAttachFileButton;
5211
5275
  const showAttachmentMenuButton = showAttachmentButton && hasAttachmentOptions;
@@ -5216,14 +5280,14 @@ var ChatInputV2 = react.forwardRef(
5216
5280
  (command) => command.name.toLowerCase().startsWith(commandQuery)
5217
5281
  );
5218
5282
  const showCommandSuggestions = !commandMenuDismissed && !isRecording && !disabled && commandSuggestions.length > 0;
5219
- react.useEffect(() => {
5283
+ React.useEffect(() => {
5220
5284
  if (textareaRef.current) {
5221
5285
  textareaRef.current.style.height = "auto";
5222
5286
  const scrollHeight = textareaRef.current.scrollHeight;
5223
5287
  textareaRef.current.style.height = `${Math.min(scrollHeight, 200)}px`;
5224
5288
  }
5225
5289
  }, [value]);
5226
- react.useEffect(() => {
5290
+ React.useEffect(() => {
5227
5291
  if (disabled) {
5228
5292
  setIsFocused(false);
5229
5293
  setShowActions(false);
@@ -5233,7 +5297,7 @@ var ChatInputV2 = react.forwardRef(
5233
5297
  const frameId = requestAnimationFrame(() => textareaRef.current?.focus());
5234
5298
  return () => cancelAnimationFrame(frameId);
5235
5299
  }, [disabled]);
5236
- react.useImperativeHandle(
5300
+ React.useImperativeHandle(
5237
5301
  ref,
5238
5302
  () => ({
5239
5303
  setDraft: (message) => {
@@ -5250,7 +5314,7 @@ var ChatInputV2 = react.forwardRef(
5250
5314
  }),
5251
5315
  [disabled]
5252
5316
  );
5253
- react.useEffect(() => {
5317
+ React.useEffect(() => {
5254
5318
  if (!showActions) return;
5255
5319
  const handleClickOutside = (e) => {
5256
5320
  if (actionsRef.current && !actionsRef.current.contains(e.target)) {
@@ -5260,29 +5324,29 @@ var ChatInputV2 = react.forwardRef(
5260
5324
  document.addEventListener("mousedown", handleClickOutside);
5261
5325
  return () => document.removeEventListener("mousedown", handleClickOutside);
5262
5326
  }, [showActions]);
5263
- react.useEffect(() => {
5327
+ React.useEffect(() => {
5264
5328
  if (!showAttachmentMenuButton) {
5265
5329
  setShowActions(false);
5266
5330
  }
5267
5331
  }, [showAttachmentMenuButton]);
5268
- react.useEffect(() => {
5332
+ React.useEffect(() => {
5269
5333
  setSelectedCommandIndex(0);
5270
5334
  setCommandMenuDismissed(false);
5271
5335
  }, [commandQuery]);
5272
- react.useEffect(() => {
5336
+ React.useEffect(() => {
5273
5337
  return () => {
5274
5338
  if (voiceTooltipTimerRef.current) {
5275
5339
  clearTimeout(voiceTooltipTimerRef.current);
5276
5340
  }
5277
5341
  };
5278
5342
  }, []);
5279
- react.useEffect(() => {
5343
+ React.useEffect(() => {
5280
5344
  if (!voiceDraftSyncActiveRef.current) return;
5281
5345
  const base = preRecordTextRef.current;
5282
5346
  const separator = base && !base.endsWith(" ") && transcribedText ? " " : "";
5283
5347
  setValue(`${base}${separator}${transcribedText}`);
5284
5348
  }, [isRecording, transcribedText]);
5285
- const handleSend = react.useCallback(() => {
5349
+ const handleSend = React.useCallback(() => {
5286
5350
  if (!value.trim() || disabled) return;
5287
5351
  const commandHint = getSlashCommandValidationHint(value);
5288
5352
  if (commandHint) {
@@ -5302,7 +5366,7 @@ var ChatInputV2 = react.forwardRef(
5302
5366
  }
5303
5367
  });
5304
5368
  }, [value, disabled, onClearEditing, onSend]);
5305
- const selectCommand = react.useCallback(
5369
+ const selectCommand = React.useCallback(
5306
5370
  (command) => {
5307
5371
  const insertText = command.insertText ?? `${command.name} `;
5308
5372
  setValue(insertText);
@@ -5358,14 +5422,14 @@ var ChatInputV2 = react.forwardRef(
5358
5422
  onAttachFileClick?.();
5359
5423
  setShowActions(false);
5360
5424
  };
5361
- const hideVoiceTooltip = react.useCallback(() => {
5425
+ const hideVoiceTooltip = React.useCallback(() => {
5362
5426
  if (voiceTooltipTimerRef.current) {
5363
5427
  clearTimeout(voiceTooltipTimerRef.current);
5364
5428
  voiceTooltipTimerRef.current = null;
5365
5429
  }
5366
5430
  setShowVoiceTooltip(false);
5367
5431
  }, []);
5368
- const startVoiceTooltipTimer = react.useCallback(() => {
5432
+ const startVoiceTooltipTimer = React.useCallback(() => {
5369
5433
  if (isVoiceButtonDisabled || isRecording) return;
5370
5434
  if (voiceTooltipTimerRef.current) {
5371
5435
  clearTimeout(voiceTooltipTimerRef.current);
@@ -5687,9 +5751,9 @@ var ChatInputV2 = react.forwardRef(
5687
5751
  var thinking_atom_default = "data:application/zip;base64,UEsDBBQAAAAIAMWrkFzFrMWzUgAAAF4AAAANAAAAbWFuaWZlc3QuanNvbqtWKkstKs7Mz1OyUjJS0lFKT81LLUosyS8C8h1S8kty8ktKMlP14SzdrGIHQz0zPZDaxLzM3MQSoN5iJavoaqXMFKAe38TMPIXgZKApSrWxtQBQSwMEFAAAAAgAxauQXLRghFpXBAAA1RwAABEAAABhL01haW4gU2NlbmUuanNvbu1YWW/jNhD+KwafJVWkqMtPbdEDfdiiQIq+GMZCcei1GvmApLRdGP7v/YYiddqbGNumR4wcomZGHM7B76N0ZLstm7N3Wb6b3a3UTjGHPTw8sLnvsA2bCx/X3811q+qMzY/sAx74stjXda7WeaGqL1alyup9OeNeEnmcnRxWZB9VWbH54sjqj2weOI2bH5+KYibhoirZnONSa0f7AzykGOQYkGP4X2dFpbq13ONx0mTVu6x6bNXZXosf4erI9OLwjwRw7Tv4WWLSP+ALa7I2Rs0RkvkzRhEZQdWz8iHCms48Z54RMEAs2gABkcGRYVFHBqXv8Sh2GBKgRzDNW00SIClag1GzugVNShk5OUd9zxMj4cI/2UhoSdUwVBJpn53EGPMTOd0hh8hAUwuodC1UoVZ1ud+9UjWog+jvb6hIv9D9egxT8aK8kfte5tD5kiTYCfpaqvUPyABb7beH9/57zlUi4zBwE+FnrsyUdDOfC/c+iNVqzVOVKoH06vwLLDsr1Y6q+VZLgX7+dxQDW29SDGmKsVNPr1iLSyB1Bkui0CDGAEdkEmmpeXghQwe/Td0slnRzyDQ5NwdH8L05htXHLGFqIWk0fQ+YPhc9P3+3VpvsoDrSYR9KFNHWpKvWdgfdV998/e3sF2w70Nb35f7pAFNdfn0z49QpNLHDVnqh0FL9IUXU1kG1eZmDO1rYzB06+imrN30/hNG9JmkiPLIVm9flE2ZFuRZoFzf0hIyXzkJfqXcgtLJGCSHyi1SR/URF9pNJYP8b2adeaEwwoqc6AQ2XS+obXTi7bdi6eGmWs8MmXyEN3+UFPaOzQGOdBcQ52BeeDGXqgB3jRNIlirBe7Vs2TYNkXeiGsFtcTS0w3XLPAp8x0MQ86uluEVPse66t9R4ZdbVd88Vw4tNpqTcZIZekEUrFQi/2fAS3hqPIwBMXSIqBp6yqVN1shjHH5NejpvUyOtdZzNyX93lNVfwPn+vGrHjDpiuxSXAvFIHDhSdFRNghvcSPnMQLhKRbo3dbg0bvNgYWsZ4xcz7txuIYrGOfOzz0/JiTUZB4acwdVwiNa43abfVGrbVnMA79fCXG3WGvPdLLlM5nc6czWiBpKFXxq07ptqBOudg7hDI49vRUOAJYuJggZiQDrqFSxA6CMgj2/8PCNqDty6oCjqlViaL8XOb0iC4JjWfU51Xb6CiLunz8CiPop0cnnIb6Ryd7YGpf4bqTUmhPSpSSYXxuSsBtk3ztGkQwPAJS7QevkWdOa2SLNLSn378smfqMTZF0yRzV8Ez4SToNf4i5drmWByfHdk1B5PxGQW+Xgix5jMlhTB5jchlS0CeNOiK74GREQROOGVLQhKFuFHSjoH+CgkSELwM3CrqCgjDJGQoKbhT0pikIH0oE+CAMgOmpF3HAof580grxHaWRdt9opjr9wWUyj6UWHnvSD4yZ1N9pBiIXshuF3Cjktd9izmHo61CIxeSAPpWd/gRQSwECFAAUAAAACADFq5BcxazFs1IAAABeAAAADQAAAAAAAAAAAAAAAAAAAAAAbWFuaWZlc3QuanNvblBLAQIUABQAAAAIAMWrkFy0YIRaVwQAANUcAAARAAAAAAAAAAAAAAAAAH0AAABhL01haW4gU2NlbmUuanNvblBLBQYAAAAAAgACAHoAAAADBQAAAAA=";
5688
5752
  var DEFAULT_SIZE = 36;
5689
5753
  function useElapsedSeconds(isStreaming) {
5690
- const [elapsed, setElapsed] = react.useState(0);
5691
- const startRef = react.useRef(null);
5692
- react.useEffect(() => {
5754
+ const [elapsed, setElapsed] = React.useState(0);
5755
+ const startRef = React.useRef(null);
5756
+ React.useEffect(() => {
5693
5757
  if (!isStreaming) {
5694
5758
  startRef.current = null;
5695
5759
  setElapsed(0);
@@ -5748,22 +5812,22 @@ function StreamingIndicatorV2({
5748
5812
  ) });
5749
5813
  }
5750
5814
  function ImageLightboxV2({ src, alt, onClose }) {
5751
- const [isMounted, setIsMounted] = react.useState(false);
5752
- const [isImageLoaded, setIsImageLoaded] = react.useState(false);
5753
- react.useEffect(() => {
5815
+ const [isMounted, setIsMounted] = React.useState(false);
5816
+ const [isImageLoaded, setIsImageLoaded] = React.useState(false);
5817
+ React.useEffect(() => {
5754
5818
  setIsMounted(true);
5755
5819
  return () => setIsMounted(false);
5756
5820
  }, []);
5757
- react.useEffect(() => {
5821
+ React.useEffect(() => {
5758
5822
  setIsImageLoaded(false);
5759
5823
  }, [src]);
5760
- const handleKeyDown = react.useCallback(
5824
+ const handleKeyDown = React.useCallback(
5761
5825
  (e) => {
5762
5826
  if (e.key === "Escape") onClose();
5763
5827
  },
5764
5828
  [onClose]
5765
5829
  );
5766
- react.useEffect(() => {
5830
+ React.useEffect(() => {
5767
5831
  if (!src || typeof document === "undefined") return;
5768
5832
  document.addEventListener("keydown", handleKeyDown);
5769
5833
  const previousOverflow = document.body.style.overflow;
@@ -5912,10 +5976,10 @@ function TraceTimelineModal({
5912
5976
  apiBaseUrl,
5913
5977
  apiHeaders
5914
5978
  }) {
5915
- const [trace, setTrace] = react.useState(null);
5916
- const [loading, setLoading] = react.useState(false);
5917
- const [error, setError] = react.useState(null);
5918
- react.useEffect(() => {
5979
+ const [trace, setTrace] = React.useState(null);
5980
+ const [loading, setLoading] = React.useState(false);
5981
+ const [error, setError] = React.useState(null);
5982
+ React.useEffect(() => {
5919
5983
  if (!open || !executionId) return;
5920
5984
  const ctrl = new AbortController();
5921
5985
  setLoading(true);
@@ -5937,7 +6001,7 @@ function TraceTimelineModal({
5937
6001
  }).finally(() => setLoading(false));
5938
6002
  return () => ctrl.abort();
5939
6003
  }, [open, executionId, apiBaseUrl, apiHeaders]);
5940
- const totalMs = react.useMemo(() => {
6004
+ const totalMs = React.useMemo(() => {
5941
6005
  if (!trace) return 0;
5942
6006
  const meta = trace.runMetadata?.totalTimeMs;
5943
6007
  if (typeof meta === "number" && meta > 0) return meta;
@@ -5946,7 +6010,7 @@ function TraceTimelineModal({
5946
6010
  if (starts.length === 0 || ends.length === 0) return 0;
5947
6011
  return Math.max(...ends) - Math.min(...starts);
5948
6012
  }, [trace]);
5949
- const accountedMs = react.useMemo(
6013
+ const accountedMs = React.useMemo(
5950
6014
  () => (trace?.pipelineSteps ?? []).reduce(
5951
6015
  (sum, s) => sum + (s.durationMs ?? 0),
5952
6016
  0
@@ -6207,12 +6271,12 @@ var NOOP_ASYNC = async () => {
6207
6271
  var NOOP = () => {
6208
6272
  };
6209
6273
  function useSentryChatCallbacks(callbacks, config) {
6210
- const sentryCtxRef = react.useRef({});
6211
- const callbacksRef = react.useRef(callbacks);
6274
+ const sentryCtxRef = React.useRef({});
6275
+ const callbacksRef = React.useRef(callbacks);
6212
6276
  callbacksRef.current = callbacks;
6213
6277
  const initialSessionId = config.initialSessionId;
6214
6278
  const apiHeaders = config.api.headers;
6215
- react.useEffect(() => {
6279
+ React.useEffect(() => {
6216
6280
  sentryCtxRef.current.agentId = config.agentId;
6217
6281
  sentryCtxRef.current.sessionOwnerId = config.sessionParams?.id;
6218
6282
  if (initialSessionId) {
@@ -6228,13 +6292,13 @@ function useSentryChatCallbacks(callbacks, config) {
6228
6292
  initialSessionId,
6229
6293
  apiHeaders
6230
6294
  ]);
6231
- react.useEffect(() => {
6295
+ React.useEffect(() => {
6232
6296
  const endpoint = config.api.streamEndpoint || "/api/playground/ask/stream";
6233
6297
  return subscribeToCfRay(endpoint, (cfRay) => {
6234
6298
  sentryCtxRef.current.cfRay = cfRay;
6235
6299
  });
6236
6300
  }, [config.api.streamEndpoint]);
6237
- return react.useMemo(
6301
+ return React.useMemo(
6238
6302
  () => ({
6239
6303
  onMessageSent: (msg) => callbacksRef.current?.onMessageSent?.(msg),
6240
6304
  onStreamStart: () => callbacksRef.current?.onStreamStart?.(),
@@ -6283,7 +6347,7 @@ function useSentryChatCallbacks(callbacks, config) {
6283
6347
  []
6284
6348
  );
6285
6349
  }
6286
- var PaymanChatInner = react.forwardRef(function PaymanChatInner2({
6350
+ var PaymanChatInner = React.forwardRef(function PaymanChatInner2({
6287
6351
  config,
6288
6352
  callbacks = {},
6289
6353
  className,
@@ -6294,18 +6358,18 @@ var PaymanChatInner = react.forwardRef(function PaymanChatInner2({
6294
6358
  hasMoreMessages = false,
6295
6359
  chat
6296
6360
  }, ref) {
6297
- const [inputValue, setInputValue] = react.useState("");
6298
- const prevInputValueRef = react.useRef(inputValue);
6299
- const [hasEverSentMessage, setHasEverSentMessage] = react.useState(false);
6300
- const [lightboxSrc, setLightboxSrc] = react.useState(null);
6301
- const [lightboxAlt, setLightboxAlt] = react.useState("");
6302
- const [editingMessageId, setEditingMessageId] = react.useState(null);
6303
- const [isResetSessionConfirmOpen, setIsResetSessionConfirmOpen] = react.useState(false);
6304
- const [analysisMode, setAnalysisMode] = react.useState("fast");
6305
- const chatInputV2Ref = react.useRef(null);
6306
- const messageListV2Ref = react.useRef(null);
6307
- const resetToEmptyStateRef = react.useRef(false);
6308
- react.useEffect(() => {
6361
+ const [inputValue, setInputValue] = React.useState("");
6362
+ const prevInputValueRef = React.useRef(inputValue);
6363
+ const [hasEverSentMessage, setHasEverSentMessage] = React.useState(false);
6364
+ const [lightboxSrc, setLightboxSrc] = React.useState(null);
6365
+ const [lightboxAlt, setLightboxAlt] = React.useState("");
6366
+ const [editingMessageId, setEditingMessageId] = React.useState(null);
6367
+ const [isResetSessionConfirmOpen, setIsResetSessionConfirmOpen] = React.useState(false);
6368
+ const [analysisMode, setAnalysisMode] = React.useState("fast");
6369
+ const chatInputV2Ref = React.useRef(null);
6370
+ const messageListV2Ref = React.useRef(null);
6371
+ const resetToEmptyStateRef = React.useRef(false);
6372
+ React.useEffect(() => {
6309
6373
  if (config.sentryDsn) {
6310
6374
  initSentryIfNeeded(config.sentryDsn);
6311
6375
  }
@@ -6321,7 +6385,7 @@ var PaymanChatInner = react.forwardRef(function PaymanChatInner2({
6321
6385
  getSessionId,
6322
6386
  getMessages
6323
6387
  } = chat;
6324
- react.useEffect(() => {
6388
+ React.useEffect(() => {
6325
6389
  if (resetToEmptyStateRef.current) {
6326
6390
  if (messages.length === 0) {
6327
6391
  setHasEverSentMessage(false);
@@ -6333,7 +6397,7 @@ var PaymanChatInner = react.forwardRef(function PaymanChatInner2({
6333
6397
  setHasEverSentMessage(true);
6334
6398
  }
6335
6399
  }, [messages.length, hasEverSentMessage]);
6336
- react.useEffect(() => {
6400
+ React.useEffect(() => {
6337
6401
  if (!editingMessageId) return;
6338
6402
  const editingMessageStillExists = messages.some(
6339
6403
  (message) => message.id === editingMessageId && message.role === "user"
@@ -6346,7 +6410,7 @@ var PaymanChatInner = react.forwardRef(function PaymanChatInner2({
6346
6410
  const submitUserAction2 = chat.submitUserAction ?? NOOP_ASYNC;
6347
6411
  const cancelUserAction2 = chat.cancelUserAction ?? NOOP_ASYNC;
6348
6412
  const resendUserAction2 = chat.resendUserAction ?? NOOP_ASYNC;
6349
- const expireUserAction = chat.expireUserAction ?? NOOP_ASYNC;
6413
+ const expireUserAction2 = chat.expireUserAction ?? NOOP_ASYNC;
6350
6414
  const dismissNotification = chat.dismissNotification ?? NOOP;
6351
6415
  const isUserActionSupported = typeof chat.submitUserAction === "function" && typeof chat.cancelUserAction === "function" && typeof chat.resendUserAction === "function";
6352
6416
  const {
@@ -6372,7 +6436,7 @@ var PaymanChatInner = react.forwardRef(function PaymanChatInner2({
6372
6436
  }
6373
6437
  }
6374
6438
  );
6375
- const contextValue = react.useMemo(
6439
+ const contextValue = React.useMemo(
6376
6440
  () => ({
6377
6441
  resetSession,
6378
6442
  clearMessages,
@@ -6399,8 +6463,8 @@ var PaymanChatInner = react.forwardRef(function PaymanChatInner2({
6399
6463
  onAttachFileClick,
6400
6464
  onMessageFeedback
6401
6465
  } = callbacks;
6402
- const [debugTraceExecutionId, setDebugTraceExecutionId] = react.useState(null);
6403
- const handleSubmitFeedback = react.useCallback(
6466
+ const [debugTraceExecutionId, setDebugTraceExecutionId] = React.useState(null);
6467
+ const handleSubmitFeedback = React.useCallback(
6404
6468
  async ({ messageId, executionId, feedback, details }) => {
6405
6469
  if (!executionId) {
6406
6470
  throw new Error("Cannot submit feedback before the response completes");
@@ -6431,14 +6495,14 @@ var PaymanChatInner = react.forwardRef(function PaymanChatInner2({
6431
6495
  onMessageFeedback
6432
6496
  ]
6433
6497
  );
6434
- const onExecutionTraceClick = react.useMemo(() => {
6498
+ const onExecutionTraceClick = React.useMemo(() => {
6435
6499
  if (!config.debug) return rawOnExecutionTraceClick;
6436
6500
  return (data) => {
6437
6501
  rawOnExecutionTraceClick?.(data);
6438
6502
  if (data.executionId) setDebugTraceExecutionId(data.executionId);
6439
6503
  };
6440
6504
  }, [config.debug, rawOnExecutionTraceClick]);
6441
- const performResetSession = react.useCallback(() => {
6505
+ const performResetSession = React.useCallback(() => {
6442
6506
  resetToEmptyStateRef.current = true;
6443
6507
  setEditingMessageId(null);
6444
6508
  setIsResetSessionConfirmOpen(false);
@@ -6459,13 +6523,13 @@ var PaymanChatInner = react.forwardRef(function PaymanChatInner2({
6459
6523
  resetSession,
6460
6524
  stopRecording
6461
6525
  ]);
6462
- const requestResetSession = react.useCallback(() => {
6526
+ const requestResetSession = React.useCallback(() => {
6463
6527
  setIsResetSessionConfirmOpen(true);
6464
6528
  }, []);
6465
- const closeResetSessionConfirm = react.useCallback(() => {
6529
+ const closeResetSessionConfirm = React.useCallback(() => {
6466
6530
  setIsResetSessionConfirmOpen(false);
6467
6531
  }, []);
6468
- react.useImperativeHandle(ref, () => ({
6532
+ React.useImperativeHandle(ref, () => ({
6469
6533
  resetSession: performResetSession,
6470
6534
  clearMessages,
6471
6535
  cancelStream,
@@ -6504,7 +6568,7 @@ var PaymanChatInner = react.forwardRef(function PaymanChatInner2({
6504
6568
  slashCommands: slashCommandsConfig,
6505
6569
  commandPermissions
6506
6570
  } = config;
6507
- const messageActions = react.useMemo(
6571
+ const messageActions = React.useMemo(
6508
6572
  () => ({
6509
6573
  userMessageActions: {
6510
6574
  copy: messageActionsConfig?.userMessageActions?.copy ?? true,
@@ -6520,18 +6584,18 @@ var PaymanChatInner = react.forwardRef(function PaymanChatInner2({
6520
6584
  }),
6521
6585
  [messageActionsConfig]
6522
6586
  );
6523
- const slashCommands = react.useMemo(
6587
+ const slashCommands = React.useMemo(
6524
6588
  () => enableSlashCommands ? filterSlashCommands(
6525
6589
  slashCommandsConfig ?? DEFAULT_SLASH_COMMANDS,
6526
6590
  commandPermissions
6527
6591
  ) : [],
6528
6592
  [commandPermissions, enableSlashCommands, slashCommandsConfig]
6529
6593
  );
6530
- const isSessionParamsConfigured = react.useMemo(() => {
6594
+ const isSessionParamsConfigured = React.useMemo(() => {
6531
6595
  if (!sessionParams) return false;
6532
6596
  return !!(sessionParams.id?.trim() && sessionParams.name?.trim());
6533
6597
  }, [sessionParams?.id, sessionParams?.name]);
6534
- react.useEffect(() => {
6598
+ React.useEffect(() => {
6535
6599
  const wasEmpty = prevInputValueRef.current.trim() === "";
6536
6600
  const isEmpty2 = inputValue.trim() === "";
6537
6601
  prevInputValueRef.current = inputValue;
@@ -6598,7 +6662,7 @@ var PaymanChatInner = react.forwardRef(function PaymanChatInner2({
6598
6662
  void sendMessage(text.trim(), { analysisMode: effectiveAnalysisMode });
6599
6663
  }
6600
6664
  };
6601
- const handleVoicePress = react.useCallback(async () => {
6665
+ const handleVoicePress = React.useCallback(async () => {
6602
6666
  if (!voiceAvailable) return;
6603
6667
  if (isRecording) {
6604
6668
  stopRecording();
@@ -6607,7 +6671,7 @@ var PaymanChatInner = react.forwardRef(function PaymanChatInner2({
6607
6671
  clearTranscript();
6608
6672
  await startRecording();
6609
6673
  }, [clearTranscript, isRecording, startRecording, stopRecording, voiceAvailable]);
6610
- const handleEditMessageDraft = react.useCallback((messageId) => {
6674
+ const handleEditMessageDraft = React.useCallback((messageId) => {
6611
6675
  const targetMessage = messages.find((message) => message.id === messageId);
6612
6676
  if (!targetMessage?.content.trim()) return;
6613
6677
  setEditingMessageId(messageId);
@@ -6616,7 +6680,7 @@ var PaymanChatInner = react.forwardRef(function PaymanChatInner2({
6616
6680
  messageListV2Ref.current?.scrollToBottom("smooth");
6617
6681
  });
6618
6682
  }, [messages]);
6619
- const handleRetryUserMessage = react.useCallback((messageId) => {
6683
+ const handleRetryUserMessage = React.useCallback((messageId) => {
6620
6684
  if (isWaitingForResponse) return;
6621
6685
  const targetMessage = messages.find(
6622
6686
  (message) => message.id === messageId && message.role === "user"
@@ -6633,7 +6697,7 @@ var PaymanChatInner = react.forwardRef(function PaymanChatInner2({
6633
6697
  });
6634
6698
  });
6635
6699
  }, [isWaitingForResponse, messages, sendMessage, effectiveAnalysisMode]);
6636
- const handleClearEditing = react.useCallback(() => {
6700
+ const handleClearEditing = React.useCallback(() => {
6637
6701
  setEditingMessageId(null);
6638
6702
  }, []);
6639
6703
  return /* @__PURE__ */ jsxRuntime.jsx(PaymanChatContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsxRuntime.jsxs(
@@ -6747,7 +6811,7 @@ var PaymanChatInner = react.forwardRef(function PaymanChatInner2({
6747
6811
  onSubmitUserAction: isUserActionSupported ? submitUserAction2 : void 0,
6748
6812
  onCancelUserAction: isUserActionSupported ? cancelUserAction2 : void 0,
6749
6813
  onResendUserAction: isUserActionSupported ? resendUserAction2 : void 0,
6750
- onExpireUserAction: isUserActionSupported ? expireUserAction : void 0,
6814
+ onExpireUserAction: isUserActionSupported ? expireUserAction2 : void 0,
6751
6815
  onDismissNotification: dismissNotification,
6752
6816
  onSubmitFeedback: handleSubmitFeedback
6753
6817
  }
@@ -6823,7 +6887,7 @@ var PaymanChatInner = react.forwardRef(function PaymanChatInner2({
6823
6887
  }
6824
6888
  ) });
6825
6889
  });
6826
- var PaymanChat = react.forwardRef(
6890
+ var PaymanChat = React.forwardRef(
6827
6891
  function PaymanChat2(props, ref) {
6828
6892
  const mergedCallbacks = useSentryChatCallbacks(props.callbacks, props.config);
6829
6893
  const chat = useChatV2(props.config, mergedCallbacks);