@paymanai/payman-ask-sdk 4.0.19 → 4.0.20
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.d.mts +93 -26
- package/dist/index.d.ts +93 -26
- package/dist/index.js +1745 -391
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1737 -393
- package/dist/index.mjs.map +1 -1
- package/dist/styles.css +484 -25
- package/dist/styles.css.map +1 -1
- package/package.json +1 -1
- package/dist/index.native.js +0 -3681
- package/dist/index.native.js.map +0 -1
package/dist/index.mjs
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { createContext, forwardRef, useCallback, useRef, useState,
|
|
1
|
+
import { createContext, forwardRef, useCallback, useRef, useState, useImperativeHandle, useEffect, useContext, useMemo, useLayoutEffect, Children, isValidElement } from 'react';
|
|
2
2
|
import { AnimatePresence, motion } from 'framer-motion';
|
|
3
3
|
import { clsx } from 'clsx';
|
|
4
4
|
import { twMerge } from 'tailwind-merge';
|
|
5
5
|
import * as Sentry from '@sentry/react';
|
|
6
|
-
import { ArrowDown,
|
|
6
|
+
import { ArrowDown, Loader2, FileText, X, Pencil, RotateCcw, Telescope, Zap, Plus, ImagePlus, Paperclip, Mic, ArrowUp, Check, AlertCircle, Copy, WifiOff, ThumbsUp, ThumbsDown, Binoculars, Info, Download, ChevronDown, RefreshCw, ExternalLink, User, Clock, Sparkles, ImageOff, Eye, ChevronRight, ShieldCheck } from 'lucide-react';
|
|
7
7
|
import ReactMarkdown from 'react-markdown';
|
|
8
8
|
import remarkGfm from 'remark-gfm';
|
|
9
9
|
import { createPortal } from 'react-dom';
|
|
@@ -13,7 +13,10 @@ import { DotLottieReact } from '@lottiefiles/dotlottie-react';
|
|
|
13
13
|
|
|
14
14
|
var __defProp = Object.defineProperty;
|
|
15
15
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
16
|
-
var __publicField = (obj, key, value) => __defNormalProp(obj, key + "", value);
|
|
16
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
17
|
+
var __defProp2 = Object.defineProperty;
|
|
18
|
+
var __defNormalProp2 = (obj, key, value) => key in obj ? __defProp2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
19
|
+
var __publicField2 = (obj, key, value) => __defNormalProp2(obj, key + "", value);
|
|
17
20
|
function generateId() {
|
|
18
21
|
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
|
|
19
22
|
const r = Math.random() * 16 | 0;
|
|
@@ -709,7 +712,8 @@ function buildRequestBody(config, userMessage, sessionId, options) {
|
|
|
709
712
|
sessionAttributes,
|
|
710
713
|
analysisMode: options?.analysisMode,
|
|
711
714
|
locale: resolveLocale(config.locale),
|
|
712
|
-
timezone: resolveTimezone(config.timezone)
|
|
715
|
+
timezone: resolveTimezone(config.timezone),
|
|
716
|
+
...options?.attachments?.length ? { attachments: options.attachments } : {}
|
|
713
717
|
};
|
|
714
718
|
}
|
|
715
719
|
function resolveLocale(configured) {
|
|
@@ -754,6 +758,7 @@ function buildResolveImagesUrl(config) {
|
|
|
754
758
|
const basePath = normalizedEndpointPath.endsWith("/stream") ? normalizedEndpointPath.slice(0, -"/stream".length) : normalizedEndpointPath;
|
|
755
759
|
return `${config.api.baseUrl}${basePath}/resolve-image-urls`;
|
|
756
760
|
}
|
|
761
|
+
var NGROK_SKIP_BROWSER_WARNING = "ngrok-skip-browser-warning";
|
|
757
762
|
function buildRequestHeaders(config) {
|
|
758
763
|
const headers = {
|
|
759
764
|
...config.api.headers
|
|
@@ -761,6 +766,9 @@ function buildRequestHeaders(config) {
|
|
|
761
766
|
if (config.api.authToken) {
|
|
762
767
|
headers.Authorization = `Bearer ${config.api.authToken}`;
|
|
763
768
|
}
|
|
769
|
+
if (!headers[NGROK_SKIP_BROWSER_WARNING]) {
|
|
770
|
+
headers[NGROK_SKIP_BROWSER_WARNING] = "true";
|
|
771
|
+
}
|
|
764
772
|
return headers;
|
|
765
773
|
}
|
|
766
774
|
var RAG_IMAGE_REGEX = /\/api\/rag\/chunks\/[^"'\s]+\/image/;
|
|
@@ -1041,10 +1049,85 @@ function createCancelledMessageUpdate(steps, currentMessage) {
|
|
|
1041
1049
|
currentMessage: currentMessage || "Thinking..."
|
|
1042
1050
|
};
|
|
1043
1051
|
}
|
|
1052
|
+
var DEFAULT_SIGNED_URL_ENDPOINT = "/api/files/signed-url";
|
|
1053
|
+
function fileExtension(filename) {
|
|
1054
|
+
const ext = filename.split(".").pop()?.toLowerCase().replace(/^\./, "");
|
|
1055
|
+
return ext && ext.length > 0 ? ext : "bin";
|
|
1056
|
+
}
|
|
1057
|
+
function resolveMimeType(file) {
|
|
1058
|
+
if (file.type && file.type.trim().length > 0) return file.type;
|
|
1059
|
+
const ext = fileExtension(file.name);
|
|
1060
|
+
const byExt = {
|
|
1061
|
+
pdf: "application/pdf",
|
|
1062
|
+
png: "image/png",
|
|
1063
|
+
jpg: "image/jpeg",
|
|
1064
|
+
jpeg: "image/jpeg",
|
|
1065
|
+
gif: "image/gif",
|
|
1066
|
+
webp: "image/webp"
|
|
1067
|
+
};
|
|
1068
|
+
return byExt[ext] ?? "application/octet-stream";
|
|
1069
|
+
}
|
|
1070
|
+
function buildSignedUrlEndpoint(config, ext) {
|
|
1071
|
+
const endpoint = config.api.signedUrlEndpoint || DEFAULT_SIGNED_URL_ENDPOINT;
|
|
1072
|
+
const queryParams = new URLSearchParams({ extn: ext.replace(/^\./, "") });
|
|
1073
|
+
return `${config.api.baseUrl}${endpoint}?${queryParams.toString()}`;
|
|
1074
|
+
}
|
|
1075
|
+
async function requestSignedUrl(config, ext, signal) {
|
|
1076
|
+
const url = buildSignedUrlEndpoint(config, ext);
|
|
1077
|
+
const headers = buildRequestHeaders(config);
|
|
1078
|
+
const response = await fetch(url, {
|
|
1079
|
+
method: "GET",
|
|
1080
|
+
headers,
|
|
1081
|
+
signal
|
|
1082
|
+
});
|
|
1083
|
+
if (!response.ok) {
|
|
1084
|
+
const errorText = await response.text().catch(() => "");
|
|
1085
|
+
throw new Error(
|
|
1086
|
+
errorText ? `Failed to get upload URL (${response.status}): ${errorText}` : `Failed to get upload URL (${response.status})`
|
|
1087
|
+
);
|
|
1088
|
+
}
|
|
1089
|
+
const data = await response.json();
|
|
1090
|
+
if (!data.key || !data.url) {
|
|
1091
|
+
throw new Error("Signed URL response missing key or url");
|
|
1092
|
+
}
|
|
1093
|
+
return { key: data.key, url: data.url };
|
|
1094
|
+
}
|
|
1095
|
+
async function uploadToSignedUrl(signedUrl, file, mimeType, signal) {
|
|
1096
|
+
const response = await fetch(signedUrl, {
|
|
1097
|
+
method: "PUT",
|
|
1098
|
+
headers: {
|
|
1099
|
+
"Content-Type": mimeType,
|
|
1100
|
+
"x-ms-blob-type": "BlockBlob"
|
|
1101
|
+
},
|
|
1102
|
+
body: file,
|
|
1103
|
+
signal
|
|
1104
|
+
});
|
|
1105
|
+
if (!response.ok) {
|
|
1106
|
+
const errorText = await response.text().catch(() => "");
|
|
1107
|
+
throw new Error(
|
|
1108
|
+
errorText ? `Failed to upload file (${response.status}): ${errorText}` : `Failed to upload file (${response.status})`
|
|
1109
|
+
);
|
|
1110
|
+
}
|
|
1111
|
+
}
|
|
1112
|
+
async function uploadAttachment(config, file, signal) {
|
|
1113
|
+
const ext = fileExtension(file.name);
|
|
1114
|
+
const mimeType = resolveMimeType(file);
|
|
1115
|
+
const { key, url } = await requestSignedUrl(config, ext, signal);
|
|
1116
|
+
await uploadToSignedUrl(url, file, mimeType, signal);
|
|
1117
|
+
return {
|
|
1118
|
+
tempKey: key,
|
|
1119
|
+
filename: file.name,
|
|
1120
|
+
mimeType
|
|
1121
|
+
};
|
|
1122
|
+
}
|
|
1123
|
+
async function uploadAttachments(config, files, signal) {
|
|
1124
|
+
const uploads = files.map((file) => uploadAttachment(config, file, signal));
|
|
1125
|
+
return Promise.all(uploads);
|
|
1126
|
+
}
|
|
1044
1127
|
var UserActionStaleError = class extends Error {
|
|
1045
1128
|
constructor(userActionId, message = "User action is no longer actionable") {
|
|
1046
1129
|
super(message);
|
|
1047
|
-
|
|
1130
|
+
__publicField2(this, "userActionId");
|
|
1048
1131
|
this.name = "UserActionStaleError";
|
|
1049
1132
|
this.userActionId = userActionId;
|
|
1050
1133
|
}
|
|
@@ -1077,9 +1160,6 @@ async function cancelUserAction(config, userActionId) {
|
|
|
1077
1160
|
async function resendUserAction(config, userActionId) {
|
|
1078
1161
|
return sendUserActionRequest(config, userActionId, "resend");
|
|
1079
1162
|
}
|
|
1080
|
-
async function expireUserAction(config, userActionId) {
|
|
1081
|
-
return sendUserActionRequest(config, userActionId, "expired");
|
|
1082
|
-
}
|
|
1083
1163
|
var EMPTY_USER_ACTION_STATE = { prompts: [], notifications: [] };
|
|
1084
1164
|
function upsertPrompt(prompts, req) {
|
|
1085
1165
|
const active = { ...req, status: "pending" };
|
|
@@ -1108,12 +1188,32 @@ function getStoredOrInitialMessages(config) {
|
|
|
1108
1188
|
function getSessionIdFromMessages(messages) {
|
|
1109
1189
|
return messages.find((message) => message.sessionId)?.sessionId;
|
|
1110
1190
|
}
|
|
1191
|
+
var IMAGE_EXTENSIONS = /* @__PURE__ */ new Set(["jpg", "jpeg", "png", "gif", "webp", "avif"]);
|
|
1192
|
+
function attachmentKindFromFile(file) {
|
|
1193
|
+
const ext = file.name.split(".").pop()?.toLowerCase() ?? "";
|
|
1194
|
+
if (IMAGE_EXTENSIONS.has(ext) || file.type.startsWith("image/")) return "image";
|
|
1195
|
+
return "file";
|
|
1196
|
+
}
|
|
1197
|
+
function buildMessageAttachments(files) {
|
|
1198
|
+
return files.map((file, index) => {
|
|
1199
|
+
const kind = attachmentKindFromFile(file);
|
|
1200
|
+
return {
|
|
1201
|
+
id: `att-${Date.now()}-${index}`,
|
|
1202
|
+
filename: file.name,
|
|
1203
|
+
mimeType: file.type || "application/octet-stream",
|
|
1204
|
+
// Blob URL for all local files so PDFs/docs stay previewable after send.
|
|
1205
|
+
previewUrl: URL.createObjectURL(file),
|
|
1206
|
+
kind
|
|
1207
|
+
};
|
|
1208
|
+
});
|
|
1209
|
+
}
|
|
1111
1210
|
function useChatV2(config, callbacks = {}) {
|
|
1112
1211
|
const [messages, setMessages] = useState(() => getStoredOrInitialMessages(config));
|
|
1113
1212
|
const [isWaitingForResponse, setIsWaitingForResponse] = useState(() => {
|
|
1114
1213
|
if (!config.userId) return false;
|
|
1115
1214
|
return activeStreamStore.get(config.userId)?.isWaiting ?? false;
|
|
1116
1215
|
});
|
|
1216
|
+
const [isUploadingAttachments, setIsUploadingAttachments] = useState(false);
|
|
1117
1217
|
const sessionIdRef = useRef(
|
|
1118
1218
|
getSessionIdFromMessages(getStoredOrInitialMessages(config)) ?? config.initialSessionId ?? void 0
|
|
1119
1219
|
);
|
|
@@ -1188,21 +1288,45 @@ function useChatV2(config, callbacks = {}) {
|
|
|
1188
1288
|
);
|
|
1189
1289
|
const sendMessage = useCallback(
|
|
1190
1290
|
async (userMessage, options) => {
|
|
1191
|
-
|
|
1291
|
+
const trimmedMessage = userMessage.trim();
|
|
1292
|
+
const files = options?.files ?? [];
|
|
1293
|
+
const hasPreuploadedAttachments = (options?.attachments?.length ?? 0) > 0;
|
|
1294
|
+
if (!trimmedMessage && files.length === 0 && !hasPreuploadedAttachments) return;
|
|
1295
|
+
let streamAttachments = options?.attachments;
|
|
1296
|
+
if (!streamAttachments && files.length > 0) {
|
|
1297
|
+
setIsUploadingAttachments(true);
|
|
1298
|
+
try {
|
|
1299
|
+
streamAttachments = await uploadAttachments(configRef.current, files);
|
|
1300
|
+
} catch (error) {
|
|
1301
|
+
if (error.name !== "AbortError") {
|
|
1302
|
+
callbacksRef.current.onError?.(error);
|
|
1303
|
+
}
|
|
1304
|
+
throw error;
|
|
1305
|
+
} finally {
|
|
1306
|
+
setIsUploadingAttachments(false);
|
|
1307
|
+
}
|
|
1308
|
+
}
|
|
1192
1309
|
if (!sessionIdRef.current && configRef.current.autoGenerateSessionId !== false) {
|
|
1193
1310
|
sessionIdRef.current = generateId();
|
|
1194
1311
|
callbacksRef.current.onSessionIdChange?.(sessionIdRef.current);
|
|
1195
1312
|
}
|
|
1313
|
+
const messageAttachments = files.length > 0 ? buildMessageAttachments(files) : streamAttachments?.length ? streamAttachments.map((attachment, index) => ({
|
|
1314
|
+
id: `att-${Date.now()}-${index}`,
|
|
1315
|
+
filename: attachment.filename,
|
|
1316
|
+
mimeType: attachment.mimeType,
|
|
1317
|
+
kind: attachment.mimeType.startsWith("image/") ? "image" : "file"
|
|
1318
|
+
})) : void 0;
|
|
1196
1319
|
const userMessageId = `user-${Date.now()}`;
|
|
1197
1320
|
const userMsg = {
|
|
1198
1321
|
id: userMessageId,
|
|
1199
1322
|
sessionId: sessionIdRef.current,
|
|
1200
1323
|
role: "user",
|
|
1201
|
-
content:
|
|
1202
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
1324
|
+
content: trimmedMessage,
|
|
1325
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1326
|
+
attachments: messageAttachments
|
|
1203
1327
|
};
|
|
1204
1328
|
setMessages((prev) => [...prev, userMsg]);
|
|
1205
|
-
callbacksRef.current.onMessageSent?.(
|
|
1329
|
+
callbacksRef.current.onMessageSent?.(trimmedMessage);
|
|
1206
1330
|
setIsWaitingForResponse(true);
|
|
1207
1331
|
callbacksRef.current.onStreamStart?.();
|
|
1208
1332
|
const streamingId = `assistant-${Date.now()}`;
|
|
@@ -1229,11 +1353,14 @@ function useChatV2(config, callbacks = {}) {
|
|
|
1229
1353
|
activeStreamStore.start(userId, abortController, initialMessages);
|
|
1230
1354
|
}
|
|
1231
1355
|
const newSessionId = await startStream(
|
|
1232
|
-
|
|
1356
|
+
trimmedMessage,
|
|
1233
1357
|
streamingId,
|
|
1234
1358
|
sessionIdRef.current,
|
|
1235
1359
|
abortController,
|
|
1236
|
-
|
|
1360
|
+
{
|
|
1361
|
+
analysisMode: options?.analysisMode,
|
|
1362
|
+
attachments: streamAttachments
|
|
1363
|
+
}
|
|
1237
1364
|
);
|
|
1238
1365
|
const finalStreamUserId = streamUserIdRef.current ?? userId;
|
|
1239
1366
|
if (finalStreamUserId) {
|
|
@@ -1371,19 +1498,6 @@ function useChatV2(config, callbacks = {}) {
|
|
|
1371
1498
|
},
|
|
1372
1499
|
[setPromptStatus]
|
|
1373
1500
|
);
|
|
1374
|
-
const expireUserAction2 = useCallback(
|
|
1375
|
-
async (userActionId) => {
|
|
1376
|
-
setPromptStatus(userActionId, "expired");
|
|
1377
|
-
try {
|
|
1378
|
-
await expireUserAction(configRef.current, userActionId);
|
|
1379
|
-
} catch (error) {
|
|
1380
|
-
if (error instanceof UserActionStaleError) return;
|
|
1381
|
-
callbacksRef.current.onError?.(error);
|
|
1382
|
-
throw error;
|
|
1383
|
-
}
|
|
1384
|
-
},
|
|
1385
|
-
[setPromptStatus]
|
|
1386
|
-
);
|
|
1387
1501
|
const dismissNotification = useCallback((id) => {
|
|
1388
1502
|
setUserActionState((prev) => ({
|
|
1389
1503
|
...prev,
|
|
@@ -1424,6 +1538,18 @@ function useChatV2(config, callbacks = {}) {
|
|
|
1424
1538
|
setMessages(config.initialMessages);
|
|
1425
1539
|
sessionIdRef.current = getSessionIdFromMessages(config.initialMessages) ?? config.initialSessionId;
|
|
1426
1540
|
}, [config.initialMessages, config.initialSessionId, config.userId]);
|
|
1541
|
+
const hydratedSessionIdRef = useRef(void 0);
|
|
1542
|
+
useEffect(() => {
|
|
1543
|
+
if (config.userId) return;
|
|
1544
|
+
if (!config.initialMessages?.length) return;
|
|
1545
|
+
const sessionId = config.initialSessionId;
|
|
1546
|
+
if (hydratedSessionIdRef.current === sessionId && messagesRef.current.length > 0) {
|
|
1547
|
+
return;
|
|
1548
|
+
}
|
|
1549
|
+
hydratedSessionIdRef.current = sessionId;
|
|
1550
|
+
setMessages(config.initialMessages);
|
|
1551
|
+
sessionIdRef.current = getSessionIdFromMessages(config.initialMessages) ?? sessionId;
|
|
1552
|
+
}, [config.initialMessages, config.initialSessionId, config.userId]);
|
|
1427
1553
|
useEffect(() => {
|
|
1428
1554
|
const prevUserId = prevUserIdRef.current;
|
|
1429
1555
|
prevUserIdRef.current = config.userId;
|
|
@@ -1458,12 +1584,12 @@ function useChatV2(config, callbacks = {}) {
|
|
|
1458
1584
|
getSessionId,
|
|
1459
1585
|
getMessages,
|
|
1460
1586
|
isWaitingForResponse,
|
|
1587
|
+
isUploadingAttachments,
|
|
1461
1588
|
sessionId: sessionIdRef.current,
|
|
1462
1589
|
userActionState,
|
|
1463
1590
|
submitUserAction: submitUserAction2,
|
|
1464
1591
|
cancelUserAction: cancelUserAction2,
|
|
1465
1592
|
resendUserAction: resendUserAction2,
|
|
1466
|
-
expireUserAction: expireUserAction2,
|
|
1467
1593
|
dismissNotification
|
|
1468
1594
|
};
|
|
1469
1595
|
}
|
|
@@ -1682,6 +1808,102 @@ function useVoice(config = {}, callbacks = {}) {
|
|
|
1682
1808
|
reset
|
|
1683
1809
|
};
|
|
1684
1810
|
}
|
|
1811
|
+
function useAttachmentUpload(config) {
|
|
1812
|
+
const configRef = useRef(config);
|
|
1813
|
+
configRef.current = config;
|
|
1814
|
+
const [entries, setEntries] = useState(/* @__PURE__ */ new Map());
|
|
1815
|
+
const [orderedIds, setOrderedIds] = useState([]);
|
|
1816
|
+
const abortControllersRef = useRef(/* @__PURE__ */ new Map());
|
|
1817
|
+
const activeIdsRef = useRef(/* @__PURE__ */ new Set());
|
|
1818
|
+
const startUpload = useCallback((id, file) => {
|
|
1819
|
+
if (activeIdsRef.current.has(id)) return;
|
|
1820
|
+
activeIdsRef.current.add(id);
|
|
1821
|
+
const controller = new AbortController();
|
|
1822
|
+
abortControllersRef.current.set(id, controller);
|
|
1823
|
+
setEntries((prev) => {
|
|
1824
|
+
const next = new Map(prev);
|
|
1825
|
+
next.set(id, { id, status: "uploading" });
|
|
1826
|
+
return next;
|
|
1827
|
+
});
|
|
1828
|
+
void uploadAttachment(configRef.current, file, controller.signal).then((payload) => {
|
|
1829
|
+
if (controller.signal.aborted) return;
|
|
1830
|
+
setEntries((prev) => {
|
|
1831
|
+
const next = new Map(prev);
|
|
1832
|
+
next.set(id, { id, status: "done", payload });
|
|
1833
|
+
return next;
|
|
1834
|
+
});
|
|
1835
|
+
}).catch((error) => {
|
|
1836
|
+
if (error.name === "AbortError") return;
|
|
1837
|
+
setEntries((prev) => {
|
|
1838
|
+
const next = new Map(prev);
|
|
1839
|
+
next.set(id, {
|
|
1840
|
+
id,
|
|
1841
|
+
status: "error",
|
|
1842
|
+
error: error.message || "Upload failed"
|
|
1843
|
+
});
|
|
1844
|
+
return next;
|
|
1845
|
+
});
|
|
1846
|
+
}).finally(() => {
|
|
1847
|
+
abortControllersRef.current.delete(id);
|
|
1848
|
+
});
|
|
1849
|
+
}, []);
|
|
1850
|
+
const syncAttachments = useCallback(
|
|
1851
|
+
(attachments) => {
|
|
1852
|
+
const nextIds = attachments.map((attachment) => attachment.id);
|
|
1853
|
+
setOrderedIds(nextIds);
|
|
1854
|
+
const nextIdSet = new Set(nextIds);
|
|
1855
|
+
for (const id of activeIdsRef.current) {
|
|
1856
|
+
if (nextIdSet.has(id)) continue;
|
|
1857
|
+
abortControllersRef.current.get(id)?.abort();
|
|
1858
|
+
abortControllersRef.current.delete(id);
|
|
1859
|
+
activeIdsRef.current.delete(id);
|
|
1860
|
+
}
|
|
1861
|
+
setEntries((prev) => {
|
|
1862
|
+
const next = new Map(prev);
|
|
1863
|
+
for (const id of next.keys()) {
|
|
1864
|
+
if (!nextIdSet.has(id)) next.delete(id);
|
|
1865
|
+
}
|
|
1866
|
+
return next;
|
|
1867
|
+
});
|
|
1868
|
+
for (const attachment of attachments) {
|
|
1869
|
+
startUpload(attachment.id, attachment.file);
|
|
1870
|
+
}
|
|
1871
|
+
},
|
|
1872
|
+
[startUpload]
|
|
1873
|
+
);
|
|
1874
|
+
const clearAll = useCallback(() => {
|
|
1875
|
+
for (const controller of abortControllersRef.current.values()) {
|
|
1876
|
+
controller.abort();
|
|
1877
|
+
}
|
|
1878
|
+
abortControllersRef.current.clear();
|
|
1879
|
+
activeIdsRef.current.clear();
|
|
1880
|
+
setOrderedIds([]);
|
|
1881
|
+
setEntries(/* @__PURE__ */ new Map());
|
|
1882
|
+
}, []);
|
|
1883
|
+
const entryList = useMemo(
|
|
1884
|
+
() => orderedIds.map((id) => entries.get(id)).filter((entry) => entry != null),
|
|
1885
|
+
[entries, orderedIds]
|
|
1886
|
+
);
|
|
1887
|
+
const isUploading = entryList.some((entry) => entry.status === "uploading");
|
|
1888
|
+
const hasErrors = entryList.some((entry) => entry.status === "error");
|
|
1889
|
+
const allReady = orderedIds.length === 0 || orderedIds.every((id) => entries.get(id)?.status === "done");
|
|
1890
|
+
const payloads = entryList.filter((entry) => entry.status === "done" && entry.payload).map((entry) => entry.payload);
|
|
1891
|
+
const statusById = useMemo(
|
|
1892
|
+
() => Object.fromEntries(
|
|
1893
|
+
entryList.map((entry) => [entry.id, entry.status])
|
|
1894
|
+
),
|
|
1895
|
+
[entryList]
|
|
1896
|
+
);
|
|
1897
|
+
return {
|
|
1898
|
+
syncAttachments,
|
|
1899
|
+
clearAll,
|
|
1900
|
+
isUploading,
|
|
1901
|
+
hasErrors,
|
|
1902
|
+
allReady,
|
|
1903
|
+
payloads,
|
|
1904
|
+
statusById
|
|
1905
|
+
};
|
|
1906
|
+
}
|
|
1685
1907
|
function classifyField(field) {
|
|
1686
1908
|
if (!field) return "text";
|
|
1687
1909
|
if (Array.isArray(field.oneOf) && field.oneOf.length > 0) return "select";
|
|
@@ -1798,6 +2020,66 @@ function buildContent(schema, values) {
|
|
|
1798
2020
|
}
|
|
1799
2021
|
return content;
|
|
1800
2022
|
}
|
|
2023
|
+
var ATTACHMENTS_SUFFIX_RE = /\n\n\[Attachments:[^\]]*\]\s*$/;
|
|
2024
|
+
function stripAttachmentsSuffixFromIntent(intent) {
|
|
2025
|
+
return intent.replace(ATTACHMENTS_SUFFIX_RE, "").trimEnd();
|
|
2026
|
+
}
|
|
2027
|
+
function mapFeedback(feedback) {
|
|
2028
|
+
if (!feedback?.feedback) return null;
|
|
2029
|
+
return feedback.feedback === "POSITIVE" ? "up" : "down";
|
|
2030
|
+
}
|
|
2031
|
+
function mapHistoryAttachments(executionId, attachments) {
|
|
2032
|
+
const mapped = (attachments ?? []).map((attachment, index) => ({
|
|
2033
|
+
id: `${executionId}:att:${index}`,
|
|
2034
|
+
filename: attachment.filename,
|
|
2035
|
+
mimeType: attachment.mimeType,
|
|
2036
|
+
url: attachment.url ?? void 0,
|
|
2037
|
+
kind: attachment.mimeType.startsWith("image/") ? "image" : "file"
|
|
2038
|
+
}));
|
|
2039
|
+
return mapped.length > 0 ? mapped : void 0;
|
|
2040
|
+
}
|
|
2041
|
+
function mapExecutionHistoryToChatMessages(message) {
|
|
2042
|
+
const timestamp = message.startTime || message.endTime || (/* @__PURE__ */ new Date()).toISOString();
|
|
2043
|
+
const executionId = message.executionId ?? message.traceId ?? message.id;
|
|
2044
|
+
const attachments = mapHistoryAttachments(message.id, message.attachments);
|
|
2045
|
+
const rows = [
|
|
2046
|
+
{
|
|
2047
|
+
id: `${message.id}:user`,
|
|
2048
|
+
role: "user",
|
|
2049
|
+
content: stripAttachmentsSuffixFromIntent(message.sessionUserIntent),
|
|
2050
|
+
timestamp,
|
|
2051
|
+
attachments
|
|
2052
|
+
}
|
|
2053
|
+
];
|
|
2054
|
+
if (message.agentResponse) {
|
|
2055
|
+
rows.push({
|
|
2056
|
+
id: `${message.id}:assistant`,
|
|
2057
|
+
role: "assistant",
|
|
2058
|
+
content: message.agentResponse,
|
|
2059
|
+
timestamp: message.endTime || timestamp,
|
|
2060
|
+
isError: message.status === "FAILED",
|
|
2061
|
+
executionId,
|
|
2062
|
+
feedback: mapFeedback(message.feedback)
|
|
2063
|
+
});
|
|
2064
|
+
}
|
|
2065
|
+
return rows;
|
|
2066
|
+
}
|
|
2067
|
+
function mapExecutionHistoryPageToChatMessages(messages) {
|
|
2068
|
+
return messages.flatMap(mapExecutionHistoryToChatMessages);
|
|
2069
|
+
}
|
|
2070
|
+
function attachmentDisplayUrl(attachment) {
|
|
2071
|
+
return attachment.previewUrl ?? attachment.url;
|
|
2072
|
+
}
|
|
2073
|
+
function isImageAttachment(attachment) {
|
|
2074
|
+
const displayUrl = attachmentDisplayUrl(attachment);
|
|
2075
|
+
return attachment.kind === "image" || Boolean(displayUrl) && attachment.mimeType.startsWith("image/");
|
|
2076
|
+
}
|
|
2077
|
+
function isPdfAttachmentMeta(attachment) {
|
|
2078
|
+
return attachment.mimeType === "application/pdf" || /\.pdf$/i.test(attachment.filename);
|
|
2079
|
+
}
|
|
2080
|
+
function isPdfFile(file) {
|
|
2081
|
+
return file.type === "application/pdf" || /\.pdf$/i.test(file.name);
|
|
2082
|
+
}
|
|
1801
2083
|
var PaymanChatContext = createContext(void 0);
|
|
1802
2084
|
function usePaymanChat() {
|
|
1803
2085
|
const context = useContext(PaymanChatContext);
|
|
@@ -1908,6 +2190,111 @@ function subscribeToCfRay(urlPattern, listener) {
|
|
|
1908
2190
|
};
|
|
1909
2191
|
}
|
|
1910
2192
|
|
|
2193
|
+
// src/utils/attachmentConfig.ts
|
|
2194
|
+
var DEFAULT_IMAGE_EXTENSIONS = ["png", "jpg", "jpeg", "gif", "webp"];
|
|
2195
|
+
var DEFAULT_DOCUMENT_EXTENSIONS = ["pdf", "docx", "xlsx", "xls"];
|
|
2196
|
+
function resolveChatAttachmentConfig(config) {
|
|
2197
|
+
const nested = config.attachments;
|
|
2198
|
+
const enabled = nested?.enabled ?? config.showAttachmentButton ?? true;
|
|
2199
|
+
const uploadImage = nested?.uploadImage ?? config.showUploadImageButton ?? true;
|
|
2200
|
+
const attachFile = nested?.attachFile ?? config.showAttachFileButton ?? true;
|
|
2201
|
+
return {
|
|
2202
|
+
showAttachmentButton: enabled && (uploadImage || attachFile),
|
|
2203
|
+
showUploadImageButton: enabled && uploadImage,
|
|
2204
|
+
showAttachFileButton: enabled && attachFile,
|
|
2205
|
+
maxCount: nested?.maxCount ?? nested?.maxImages ?? nested?.maxDocuments,
|
|
2206
|
+
maxFileBytes: nested?.maxFileBytes,
|
|
2207
|
+
maxTotalBytes: nested?.maxTotalBytes,
|
|
2208
|
+
allowedImageExtensions: nested?.imageExtensions ?? DEFAULT_IMAGE_EXTENSIONS,
|
|
2209
|
+
allowedFileExtensions: nested?.documentExtensions ?? DEFAULT_DOCUMENT_EXTENSIONS
|
|
2210
|
+
};
|
|
2211
|
+
}
|
|
2212
|
+
|
|
2213
|
+
// src/utils/formatAttachmentBytes.ts
|
|
2214
|
+
function formatAttachmentBytes(bytes) {
|
|
2215
|
+
if (!Number.isFinite(bytes) || bytes <= 0) return "0 B";
|
|
2216
|
+
const units = ["B", "KB", "MB", "GB"];
|
|
2217
|
+
let value = bytes;
|
|
2218
|
+
let unitIndex = 0;
|
|
2219
|
+
while (value >= 1024 && unitIndex < units.length - 1) {
|
|
2220
|
+
value /= 1024;
|
|
2221
|
+
unitIndex += 1;
|
|
2222
|
+
}
|
|
2223
|
+
const rounded = unitIndex === 0 ? String(Math.round(value)) : value >= 10 ? value.toFixed(0) : value.toFixed(1).replace(/\.0$/, "");
|
|
2224
|
+
return `${rounded} ${units[unitIndex]}`;
|
|
2225
|
+
}
|
|
2226
|
+
|
|
2227
|
+
// src/utils/pdfLink.ts
|
|
2228
|
+
function filenameFromContentDisposition(value) {
|
|
2229
|
+
if (!value) return void 0;
|
|
2230
|
+
let decoded = value;
|
|
2231
|
+
try {
|
|
2232
|
+
decoded = decodeURIComponent(value);
|
|
2233
|
+
} catch {
|
|
2234
|
+
decoded = value;
|
|
2235
|
+
}
|
|
2236
|
+
const quoted = decoded.match(/filename\*=(?:UTF-8''([^;]+)|"([^"]+)")/i);
|
|
2237
|
+
if (quoted?.[1] || quoted?.[2]) {
|
|
2238
|
+
return (quoted[1] ?? quoted[2])?.trim();
|
|
2239
|
+
}
|
|
2240
|
+
const unquoted = decoded.match(/filename=([^;]+)/i);
|
|
2241
|
+
return unquoted?.[1]?.replace(/"/g, "").trim();
|
|
2242
|
+
}
|
|
2243
|
+
function filenameFromUrlPath(href) {
|
|
2244
|
+
try {
|
|
2245
|
+
const parts = new URL(href).pathname.split("/").filter(Boolean);
|
|
2246
|
+
const last = parts[parts.length - 1];
|
|
2247
|
+
return last ? decodeURIComponent(last) : void 0;
|
|
2248
|
+
} catch {
|
|
2249
|
+
return void 0;
|
|
2250
|
+
}
|
|
2251
|
+
}
|
|
2252
|
+
function isPdfUrl(href) {
|
|
2253
|
+
if (!href) return false;
|
|
2254
|
+
const lower = href.toLowerCase();
|
|
2255
|
+
if (lower.includes(".pdf")) return true;
|
|
2256
|
+
try {
|
|
2257
|
+
const url = new URL(href);
|
|
2258
|
+
if (url.pathname.toLowerCase().endsWith(".pdf")) return true;
|
|
2259
|
+
const filename = url.searchParams.get("filename");
|
|
2260
|
+
if (filename?.toLowerCase().includes(".pdf")) return true;
|
|
2261
|
+
for (const key of ["rscd", "response-content-disposition"]) {
|
|
2262
|
+
const fromDisposition = filenameFromContentDisposition(
|
|
2263
|
+
url.searchParams.get(key)
|
|
2264
|
+
);
|
|
2265
|
+
if (fromDisposition?.toLowerCase().includes(".pdf")) return true;
|
|
2266
|
+
}
|
|
2267
|
+
} catch {
|
|
2268
|
+
return lower.endsWith(".pdf");
|
|
2269
|
+
}
|
|
2270
|
+
return false;
|
|
2271
|
+
}
|
|
2272
|
+
function getPdfTitleFromUrl(href, linkText) {
|
|
2273
|
+
const text = linkText?.trim();
|
|
2274
|
+
if (text) return text;
|
|
2275
|
+
try {
|
|
2276
|
+
const url = new URL(href);
|
|
2277
|
+
const filename = url.searchParams.get("filename");
|
|
2278
|
+
if (filename) {
|
|
2279
|
+
return filename.replace(/\.pdf$/i, "").replace(/[-_]+/g, " ").trim();
|
|
2280
|
+
}
|
|
2281
|
+
for (const key of ["rscd", "response-content-disposition"]) {
|
|
2282
|
+
const fromDisposition = filenameFromContentDisposition(
|
|
2283
|
+
url.searchParams.get(key)
|
|
2284
|
+
);
|
|
2285
|
+
if (fromDisposition) {
|
|
2286
|
+
return fromDisposition.replace(/\.pdf$/i, "").replace(/[-_]+/g, " ").trim();
|
|
2287
|
+
}
|
|
2288
|
+
}
|
|
2289
|
+
} catch {
|
|
2290
|
+
}
|
|
2291
|
+
const fromPath = filenameFromUrlPath(href);
|
|
2292
|
+
if (fromPath) {
|
|
2293
|
+
return fromPath.replace(/\.pdf$/i, "").replace(/[-_]+/g, " ").trim();
|
|
2294
|
+
}
|
|
2295
|
+
return "Document";
|
|
2296
|
+
}
|
|
2297
|
+
|
|
1911
2298
|
// src/utils/slashCommands.ts
|
|
1912
2299
|
var DEFAULT_SLASH_COMMANDS = [
|
|
1913
2300
|
{
|
|
@@ -3059,6 +3446,108 @@ function ActionTooltipV2({ label, children }) {
|
|
|
3059
3446
|
] }) })
|
|
3060
3447
|
] });
|
|
3061
3448
|
}
|
|
3449
|
+
function FilePreviewShell({
|
|
3450
|
+
filename,
|
|
3451
|
+
typeLabel,
|
|
3452
|
+
onClick,
|
|
3453
|
+
thumbnail,
|
|
3454
|
+
className,
|
|
3455
|
+
"aria-label": ariaLabel
|
|
3456
|
+
}) {
|
|
3457
|
+
const shellClass = cn(
|
|
3458
|
+
"payman-v2-file-preview-shell",
|
|
3459
|
+
"payman-v2-file-preview-shell-sent",
|
|
3460
|
+
onClick && "payman-v2-file-preview-shell-clickable",
|
|
3461
|
+
className
|
|
3462
|
+
);
|
|
3463
|
+
const body = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
3464
|
+
/* @__PURE__ */ jsx("div", { className: "payman-v2-file-preview-thumb", children: thumbnail ?? /* @__PURE__ */ jsx(
|
|
3465
|
+
FileText,
|
|
3466
|
+
{
|
|
3467
|
+
size: 16,
|
|
3468
|
+
strokeWidth: 1.75,
|
|
3469
|
+
className: "payman-v2-file-preview-doc-icon"
|
|
3470
|
+
}
|
|
3471
|
+
) }),
|
|
3472
|
+
/* @__PURE__ */ jsxs("div", { className: "payman-v2-file-preview-info", children: [
|
|
3473
|
+
/* @__PURE__ */ jsx("span", { className: "payman-v2-file-preview-name", children: filename }),
|
|
3474
|
+
/* @__PURE__ */ jsx("span", { className: "payman-v2-file-preview-type", children: typeLabel })
|
|
3475
|
+
] })
|
|
3476
|
+
] });
|
|
3477
|
+
if (onClick) {
|
|
3478
|
+
return /* @__PURE__ */ jsx(
|
|
3479
|
+
"button",
|
|
3480
|
+
{
|
|
3481
|
+
type: "button",
|
|
3482
|
+
className: shellClass,
|
|
3483
|
+
onClick,
|
|
3484
|
+
"aria-label": ariaLabel ?? `Open ${filename}`,
|
|
3485
|
+
children: body
|
|
3486
|
+
}
|
|
3487
|
+
);
|
|
3488
|
+
}
|
|
3489
|
+
return /* @__PURE__ */ jsx("div", { className: shellClass, children: body });
|
|
3490
|
+
}
|
|
3491
|
+
function FilePreviewBlockLayout({
|
|
3492
|
+
children,
|
|
3493
|
+
className,
|
|
3494
|
+
...rest
|
|
3495
|
+
}) {
|
|
3496
|
+
return /* @__PURE__ */ jsx("div", { className: cn("payman-v2-file-preview-item", className), ...rest, children });
|
|
3497
|
+
}
|
|
3498
|
+
function attachmentTypeLabel(attachment) {
|
|
3499
|
+
if (isImageAttachment(attachment)) {
|
|
3500
|
+
return "Image";
|
|
3501
|
+
}
|
|
3502
|
+
const ext = attachment.filename.split(".").pop()?.toUpperCase();
|
|
3503
|
+
return ext || "Document";
|
|
3504
|
+
}
|
|
3505
|
+
function isPdfAttachment(attachment) {
|
|
3506
|
+
const displayUrl = attachmentDisplayUrl(attachment);
|
|
3507
|
+
return isPdfAttachmentMeta(attachment) || Boolean(displayUrl) && isPdfUrl(displayUrl);
|
|
3508
|
+
}
|
|
3509
|
+
function AttachmentPreviewBlock({
|
|
3510
|
+
attachment,
|
|
3511
|
+
onImageClick
|
|
3512
|
+
}) {
|
|
3513
|
+
const chatContext = useContext(PaymanChatContext);
|
|
3514
|
+
const displayUrl = attachmentDisplayUrl(attachment);
|
|
3515
|
+
const typeLabel = attachmentTypeLabel(attachment);
|
|
3516
|
+
const isImage = isImageAttachment(attachment) && displayUrl;
|
|
3517
|
+
const openAttachment = () => {
|
|
3518
|
+
if (!displayUrl) return;
|
|
3519
|
+
if (isImageAttachment(attachment)) {
|
|
3520
|
+
onImageClick?.(displayUrl, attachment.filename);
|
|
3521
|
+
return;
|
|
3522
|
+
}
|
|
3523
|
+
if (isPdfAttachment(attachment)) {
|
|
3524
|
+
chatContext?.openPdfSheet(displayUrl, attachment.filename);
|
|
3525
|
+
return;
|
|
3526
|
+
}
|
|
3527
|
+
window.open(displayUrl, "_blank", "noopener,noreferrer");
|
|
3528
|
+
};
|
|
3529
|
+
if (isImage) {
|
|
3530
|
+
return /* @__PURE__ */ jsx(FilePreviewBlockLayout, { children: /* @__PURE__ */ jsx(
|
|
3531
|
+
FilePreviewShell,
|
|
3532
|
+
{
|
|
3533
|
+
filename: attachment.filename,
|
|
3534
|
+
typeLabel,
|
|
3535
|
+
onClick: openAttachment,
|
|
3536
|
+
"aria-label": `Preview ${attachment.filename}`,
|
|
3537
|
+
thumbnail: /* @__PURE__ */ jsx("img", { src: displayUrl, alt: "", draggable: false })
|
|
3538
|
+
}
|
|
3539
|
+
) });
|
|
3540
|
+
}
|
|
3541
|
+
return /* @__PURE__ */ jsx(FilePreviewBlockLayout, { children: /* @__PURE__ */ jsx(
|
|
3542
|
+
FilePreviewShell,
|
|
3543
|
+
{
|
|
3544
|
+
filename: attachment.filename,
|
|
3545
|
+
typeLabel,
|
|
3546
|
+
onClick: displayUrl ? openAttachment : void 0,
|
|
3547
|
+
"aria-label": `Open ${attachment.filename}`
|
|
3548
|
+
}
|
|
3549
|
+
) });
|
|
3550
|
+
}
|
|
3062
3551
|
function formatMessageTime(timestamp) {
|
|
3063
3552
|
const value = new Date(timestamp);
|
|
3064
3553
|
if (Number.isNaN(value.getTime())) return "";
|
|
@@ -3071,6 +3560,7 @@ function UserMessageV2({
|
|
|
3071
3560
|
message,
|
|
3072
3561
|
onEdit,
|
|
3073
3562
|
onRetry,
|
|
3563
|
+
onImageClick,
|
|
3074
3564
|
retryDisabled = false,
|
|
3075
3565
|
actions
|
|
3076
3566
|
}) {
|
|
@@ -3153,7 +3643,15 @@ function UserMessageV2({
|
|
|
3153
3643
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
3154
3644
|
toastPortal,
|
|
3155
3645
|
/* @__PURE__ */ jsx("div", { className: "payman-v2-user-msg payman-v2-fade-in", children: /* @__PURE__ */ jsxs("div", { className: "payman-v2-user-msg-group", children: [
|
|
3156
|
-
/* @__PURE__ */ jsx("div", { className: "payman-v2-user-msg-
|
|
3646
|
+
message.attachments && message.attachments.length > 0 && /* @__PURE__ */ jsx("div", { className: "payman-v2-file-preview payman-v2-user-msg-attachments", children: message.attachments.map((attachment) => /* @__PURE__ */ jsx(
|
|
3647
|
+
AttachmentPreviewBlock,
|
|
3648
|
+
{
|
|
3649
|
+
attachment,
|
|
3650
|
+
onImageClick
|
|
3651
|
+
},
|
|
3652
|
+
attachment.id
|
|
3653
|
+
)) }),
|
|
3654
|
+
(message.content.trim().length > 0 || !message.attachments?.length) && /* @__PURE__ */ jsx("div", { className: "payman-v2-user-msg-bubble", children: parsedCommand ? /* @__PURE__ */ jsxs("div", { className: "payman-v2-user-msg-command", children: [
|
|
3157
3655
|
/* @__PURE__ */ jsx("span", { className: "payman-v2-user-msg-command-chip", children: parsedCommand.command }),
|
|
3158
3656
|
parsedCommand.body.trim() ? /* @__PURE__ */ jsx("p", { className: "payman-v2-user-msg-text", children: parsedCommand.body }) : null
|
|
3159
3657
|
] }) : /* @__PURE__ */ jsx("p", { className: "payman-v2-user-msg-text", children: message.content }) }),
|
|
@@ -3378,9 +3876,44 @@ function MarkdownImageV2({
|
|
|
3378
3876
|
}
|
|
3379
3877
|
) });
|
|
3380
3878
|
}
|
|
3381
|
-
function
|
|
3879
|
+
function PdfBlockV2({ title, href, onOpen, autoOpen = false }) {
|
|
3880
|
+
const autoOpenedHrefRef = useRef(null);
|
|
3881
|
+
useEffect(() => {
|
|
3882
|
+
if (!autoOpen || autoOpenedHrefRef.current === href) return;
|
|
3883
|
+
autoOpenedHrefRef.current = href;
|
|
3884
|
+
onOpen(href, title, { auto: true });
|
|
3885
|
+
}, [href, autoOpen]);
|
|
3886
|
+
return /* @__PURE__ */ jsx(FilePreviewBlockLayout, { "data-payman-file-block": true, children: /* @__PURE__ */ jsx(
|
|
3887
|
+
FilePreviewShell,
|
|
3888
|
+
{
|
|
3889
|
+
filename: title,
|
|
3890
|
+
typeLabel: "PDF",
|
|
3891
|
+
onClick: () => onOpen(href, title),
|
|
3892
|
+
"aria-label": `Open PDF: ${title}`
|
|
3893
|
+
}
|
|
3894
|
+
) });
|
|
3895
|
+
}
|
|
3896
|
+
function childrenToText(children) {
|
|
3897
|
+
if (typeof children === "string") return children;
|
|
3898
|
+
if (typeof children === "number") return String(children);
|
|
3899
|
+
if (Array.isArray(children)) return children.map(childrenToText).join("");
|
|
3900
|
+
if (children && typeof children === "object" && "props" in children) {
|
|
3901
|
+
return childrenToText(children.props.children);
|
|
3902
|
+
}
|
|
3903
|
+
return "";
|
|
3904
|
+
}
|
|
3905
|
+
function isFileBlockChild(child) {
|
|
3906
|
+
return isValidElement(child) && typeof child.props === "object" && child.props !== null && "data-payman-file-block" in child.props;
|
|
3907
|
+
}
|
|
3908
|
+
function buildComponents(onImageClick, isResolvingRef, onPdfClick, autoOpenPdf) {
|
|
3382
3909
|
return {
|
|
3383
|
-
p: ({ children }) =>
|
|
3910
|
+
p: ({ children }) => {
|
|
3911
|
+
const childArray = Children.toArray(children);
|
|
3912
|
+
if (childArray.length === 1 && isFileBlockChild(childArray[0])) {
|
|
3913
|
+
return childArray[0];
|
|
3914
|
+
}
|
|
3915
|
+
return /* @__PURE__ */ jsx("p", { children });
|
|
3916
|
+
},
|
|
3384
3917
|
code: ({ children }) => /* @__PURE__ */ jsx("code", { children }),
|
|
3385
3918
|
pre: ({ children }) => /* @__PURE__ */ jsx("div", { className: "payman-v2-markdown-pre", children: /* @__PURE__ */ jsx("pre", { children }) }),
|
|
3386
3919
|
ul: ({ children }) => /* @__PURE__ */ jsx("ul", { children }),
|
|
@@ -3393,7 +3926,15 @@ function buildComponents(onImageClick, isResolvingRef) {
|
|
|
3393
3926
|
em: ({ children }) => /* @__PURE__ */ jsx("em", { children }),
|
|
3394
3927
|
blockquote: ({ children }) => /* @__PURE__ */ jsx("blockquote", { children }),
|
|
3395
3928
|
hr: () => /* @__PURE__ */ jsx("hr", {}),
|
|
3396
|
-
a: ({ href, children }) =>
|
|
3929
|
+
a: ({ href, children }) => {
|
|
3930
|
+
const url = href ?? "";
|
|
3931
|
+
if (onPdfClick && isPdfUrl(url)) {
|
|
3932
|
+
const linkText = childrenToText(children).trim();
|
|
3933
|
+
const title = getPdfTitleFromUrl(url, linkText);
|
|
3934
|
+
return /* @__PURE__ */ jsx(PdfBlockV2, { href: url, title, onOpen: onPdfClick, autoOpen: autoOpenPdf });
|
|
3935
|
+
}
|
|
3936
|
+
return /* @__PURE__ */ jsx("a", { href, target: "_blank", rel: "noopener noreferrer", children });
|
|
3937
|
+
},
|
|
3397
3938
|
img: ({ src, alt }) => /* @__PURE__ */ jsx(
|
|
3398
3939
|
MarkdownImageV2,
|
|
3399
3940
|
{
|
|
@@ -3414,13 +3955,15 @@ function MarkdownRendererV2({
|
|
|
3414
3955
|
content,
|
|
3415
3956
|
isStreaming,
|
|
3416
3957
|
isResolvingImages,
|
|
3417
|
-
onImageClick
|
|
3958
|
+
onImageClick,
|
|
3959
|
+
onPdfClick,
|
|
3960
|
+
autoOpenPdf
|
|
3418
3961
|
}) {
|
|
3419
3962
|
const isResolvingRef = useRef(isResolvingImages);
|
|
3420
3963
|
isResolvingRef.current = isResolvingImages;
|
|
3421
3964
|
const components = useMemo(
|
|
3422
|
-
() => buildComponents(onImageClick, isResolvingRef),
|
|
3423
|
-
[onImageClick]
|
|
3965
|
+
() => buildComponents(onImageClick, isResolvingRef, onPdfClick, autoOpenPdf),
|
|
3966
|
+
[onImageClick, onPdfClick, autoOpenPdf]
|
|
3424
3967
|
);
|
|
3425
3968
|
return /* @__PURE__ */ jsx(
|
|
3426
3969
|
"div",
|
|
@@ -3789,6 +4332,17 @@ function stripIncompleteImageToken(text) {
|
|
|
3789
4332
|
if (/^!\[[^\]]*\]\([^)]*\)/.test(after)) return text;
|
|
3790
4333
|
return text.slice(0, lastBang);
|
|
3791
4334
|
}
|
|
4335
|
+
function stripIncompleteLinkToken(text) {
|
|
4336
|
+
const lastBracket = text.lastIndexOf("[");
|
|
4337
|
+
if (lastBracket === -1) return text;
|
|
4338
|
+
if (lastBracket > 0 && text[lastBracket - 1] === "!") return text;
|
|
4339
|
+
const after = text.slice(lastBracket);
|
|
4340
|
+
if (/^\[[^\]]*\]\([^)]*\)/.test(after)) return text;
|
|
4341
|
+
return text.slice(0, lastBracket);
|
|
4342
|
+
}
|
|
4343
|
+
function stripIncompleteMarkdownTokens(text) {
|
|
4344
|
+
return stripIncompleteLinkToken(stripIncompleteImageToken(text));
|
|
4345
|
+
}
|
|
3792
4346
|
function getFeedbackState(message) {
|
|
3793
4347
|
const feedback = message.feedback;
|
|
3794
4348
|
if (feedback === "up" || feedback === "down") return feedback;
|
|
@@ -3812,6 +4366,12 @@ function AssistantMessageV2({
|
|
|
3812
4366
|
() => getFeedbackState(message)
|
|
3813
4367
|
);
|
|
3814
4368
|
const [reasonModalOpen, setReasonModalOpen] = useState(false);
|
|
4369
|
+
const chatContext = useContext(PaymanChatContext);
|
|
4370
|
+
const chatContextRef = useRef(chatContext);
|
|
4371
|
+
chatContextRef.current = chatContext;
|
|
4372
|
+
const handlePdfClick = useCallback((href, title, options) => {
|
|
4373
|
+
chatContextRef.current?.openPdfSheet(href, title, options);
|
|
4374
|
+
}, []);
|
|
3815
4375
|
const canSubmitFeedback = !!onSubmitFeedback && !!message.executionId;
|
|
3816
4376
|
const [toast, setToast] = useState(null);
|
|
3817
4377
|
const copyResetTimerRef = useRef(null);
|
|
@@ -3836,7 +4396,7 @@ function AssistantMessageV2({
|
|
|
3836
4396
|
const raw = message.isStreaming ? message.streamingContent || message.content : message.content;
|
|
3837
4397
|
if (!raw) return "";
|
|
3838
4398
|
const normalized = raw.replace(/\\n/g, "\n");
|
|
3839
|
-
return message.isStreaming ?
|
|
4399
|
+
return message.isStreaming ? stripIncompleteMarkdownTokens(normalized) : normalized;
|
|
3840
4400
|
})();
|
|
3841
4401
|
const isThinkingStreaming = !!message.isStreaming && !rawResponseContent && !message.isError;
|
|
3842
4402
|
const responseTypingEnabled = hasEverStreamed.current && Boolean(rawResponseContent) && !message.isError;
|
|
@@ -4006,10 +4566,12 @@ function AssistantMessageV2({
|
|
|
4006
4566
|
/* @__PURE__ */ jsx("div", { className: "payman-v2-assistant-msg-content-area", children: displayContent ? /* @__PURE__ */ jsx(
|
|
4007
4567
|
MarkdownRendererV2,
|
|
4008
4568
|
{
|
|
4009
|
-
content: displayContent,
|
|
4569
|
+
content: message.isStreaming && !isCancelled || isResponseTyping ? stripIncompleteMarkdownTokens(displayContent) : displayContent,
|
|
4010
4570
|
isStreaming: message.isStreaming && !isCancelled || isResponseTyping,
|
|
4011
4571
|
isResolvingImages: message.isResolvingImages,
|
|
4012
|
-
onImageClick
|
|
4572
|
+
onImageClick,
|
|
4573
|
+
onPdfClick: handlePdfClick,
|
|
4574
|
+
autoOpenPdf: hasEverStreamed.current
|
|
4013
4575
|
}
|
|
4014
4576
|
) : !isThinkingStreaming ? /* @__PURE__ */ jsx("span", { className: "payman-v2-assistant-msg-placeholder", children: "..." }) : null }),
|
|
4015
4577
|
isCancelled && message.isStreaming && /* @__PURE__ */ jsxs("div", { className: "payman-v2-assistant-msg-paused", children: [
|
|
@@ -4226,7 +4788,6 @@ function VerificationInline({
|
|
|
4226
4788
|
const [code, setCode] = useState("");
|
|
4227
4789
|
const [errored, setErrored] = useState(false);
|
|
4228
4790
|
const [resendSec, setResendSec] = useState(0);
|
|
4229
|
-
const [hiddenAfterResend, setHiddenAfterResend] = useState(false);
|
|
4230
4791
|
const lastSubmittedRef = useRef(null);
|
|
4231
4792
|
const resendTimerRef = useRef(void 0);
|
|
4232
4793
|
const status = prompt.status;
|
|
@@ -4240,9 +4801,6 @@ function VerificationInline({
|
|
|
4240
4801
|
lastSubmittedRef.current = null;
|
|
4241
4802
|
}
|
|
4242
4803
|
}, [prompt.subAction, prompt.userActionId]);
|
|
4243
|
-
useEffect(() => {
|
|
4244
|
-
setHiddenAfterResend(false);
|
|
4245
|
-
}, [prompt.expirySeconds, prompt.message, prompt.subAction, prompt.userActionId]);
|
|
4246
4804
|
useEffect(() => {
|
|
4247
4805
|
if (code.length < codeLen) lastSubmittedRef.current = null;
|
|
4248
4806
|
}, [code, codeLen]);
|
|
@@ -4293,13 +4851,11 @@ function VerificationInline({
|
|
|
4293
4851
|
if (locked || resendSec > 0) return;
|
|
4294
4852
|
setErrored(false);
|
|
4295
4853
|
setCode("");
|
|
4296
|
-
setHiddenAfterResend(true);
|
|
4297
4854
|
lastSubmittedRef.current = null;
|
|
4298
4855
|
try {
|
|
4299
4856
|
await onResend(prompt.userActionId);
|
|
4300
4857
|
startResendCooldown();
|
|
4301
4858
|
} catch {
|
|
4302
|
-
setHiddenAfterResend(false);
|
|
4303
4859
|
}
|
|
4304
4860
|
}, [locked, onResend, prompt.userActionId, resendSec, startResendCooldown]);
|
|
4305
4861
|
const handleCancel = useCallback(() => {
|
|
@@ -4307,7 +4863,6 @@ function VerificationInline({
|
|
|
4307
4863
|
void onCancel(prompt.userActionId);
|
|
4308
4864
|
}, [busy, onCancel, prompt.userActionId]);
|
|
4309
4865
|
const description = prompt.message?.trim() || (isNumeric ? `Enter the ${codeLen}-digit code to continue` : "Enter the verification code to continue");
|
|
4310
|
-
if (hiddenAfterResend) return null;
|
|
4311
4866
|
return /* @__PURE__ */ jsxs("div", { className: "payman-v2-ua", role: "group", "aria-label": "Verification required", children: [
|
|
4312
4867
|
/* @__PURE__ */ jsxs("div", { className: "payman-v2-ua-head", children: [
|
|
4313
4868
|
/* @__PURE__ */ jsx(ShieldCheck, { className: "payman-v2-ua-icon", size: 15, strokeWidth: 1.75, "aria-hidden": true }),
|
|
@@ -4403,9 +4958,6 @@ function SchemaFormInline({
|
|
|
4403
4958
|
const busy = status === "submitting";
|
|
4404
4959
|
const stale = status === "stale";
|
|
4405
4960
|
const locked = busy || stale || expired;
|
|
4406
|
-
const isUserConfirmation = prompt.subAction === "UserConfirmation";
|
|
4407
|
-
const messageFormat = prompt.metadata?.["payman/messageFormat"];
|
|
4408
|
-
const renderMarkdown = messageFormat === "markdown";
|
|
4409
4961
|
const setValue = (key, value) => {
|
|
4410
4962
|
setValues((prev) => ({ ...prev, [key]: value }));
|
|
4411
4963
|
setErrors((prev) => {
|
|
@@ -4431,8 +4983,8 @@ function SchemaFormInline({
|
|
|
4431
4983
|
/* @__PURE__ */ jsx("span", { className: "payman-v2-ua-title", children: "Action required" }),
|
|
4432
4984
|
typeof secondsLeft === "number" && !stale && /* @__PURE__ */ jsx("span", { className: "payman-v2-ua-timer", children: expired ? "Expired" : `${secondsLeft}s` })
|
|
4433
4985
|
] }),
|
|
4434
|
-
prompt.message?.trim() &&
|
|
4435
|
-
stale ? /* @__PURE__ */ jsx("p", { className: "payman-v2-ua-stale", children: "This request is no longer available." }) : fields.length === 0 ?
|
|
4986
|
+
prompt.message?.trim() && /* @__PURE__ */ jsx("p", { className: "payman-v2-ua-desc", children: prompt.message }),
|
|
4987
|
+
stale ? /* @__PURE__ */ jsx("p", { className: "payman-v2-ua-stale", children: "This request is no longer available." }) : fields.length === 0 ? /* @__PURE__ */ jsx("p", { className: "payman-v2-ua-desc", children: "This action has no inputs to fill." }) : /* @__PURE__ */ jsx("div", { className: "payman-v2-ua-form", children: fields.map(([key, field]) => {
|
|
4436
4988
|
const widget = classifyField(field);
|
|
4437
4989
|
const label = field.title || key;
|
|
4438
4990
|
const required = isRequired(schema, key);
|
|
@@ -4505,7 +5057,7 @@ function SchemaFormInline({
|
|
|
4505
5057
|
className: "payman-v2-ua-btn payman-v2-ua-btn-primary",
|
|
4506
5058
|
disabled: locked,
|
|
4507
5059
|
onClick: handleSubmit,
|
|
4508
|
-
children: busy ? "Submitting\u2026" :
|
|
5060
|
+
children: busy ? "Submitting\u2026" : "Submit"
|
|
4509
5061
|
}
|
|
4510
5062
|
),
|
|
4511
5063
|
/* @__PURE__ */ jsx(
|
|
@@ -4561,25 +5113,10 @@ function useExpiryCountdown(prompt) {
|
|
|
4561
5113
|
const expired = initial !== void 0 && secondsLeft === 0;
|
|
4562
5114
|
return [secondsLeft, expired];
|
|
4563
5115
|
}
|
|
4564
|
-
function UserActionInline({
|
|
4565
|
-
prompt,
|
|
4566
|
-
onSubmit,
|
|
4567
|
-
onCancel,
|
|
4568
|
-
onResend,
|
|
4569
|
-
onExpired
|
|
4570
|
-
}) {
|
|
5116
|
+
function UserActionInline({ prompt, onSubmit, onCancel, onResend }) {
|
|
4571
5117
|
const [secondsLeft, expired] = useExpiryCountdown(prompt);
|
|
4572
|
-
useEffect(() => {
|
|
4573
|
-
if (expired && prompt.kind !== "notification") onExpired?.();
|
|
4574
|
-
}, [expired, onExpired, prompt.kind]);
|
|
4575
5118
|
let body;
|
|
4576
|
-
if (
|
|
4577
|
-
const note = {
|
|
4578
|
-
id: `${prompt.userActionId}-expired`,
|
|
4579
|
-
message: prompt.kind === "verification" ? "Verification Request Expired" : "User Form Expired"
|
|
4580
|
-
};
|
|
4581
|
-
body = /* @__PURE__ */ jsx(NotificationInline, { notification: note });
|
|
4582
|
-
} else if (prompt.kind === "verification") {
|
|
5119
|
+
if (prompt.kind === "verification") {
|
|
4583
5120
|
body = /* @__PURE__ */ jsx(
|
|
4584
5121
|
VerificationInline,
|
|
4585
5122
|
{
|
|
@@ -4619,23 +5156,10 @@ function UserActionInline({
|
|
|
4619
5156
|
}
|
|
4620
5157
|
var SCROLL_THRESHOLD2 = 100;
|
|
4621
5158
|
var USER_SCROLL_UP_EPSILON = 4;
|
|
4622
|
-
var PROMPT_KEY_SEPARATOR = "";
|
|
4623
|
-
function getPromptSlotKey(prompt) {
|
|
4624
|
-
return prompt.toolCallId || prompt.userActionId;
|
|
4625
|
-
}
|
|
4626
|
-
function getPromptViewKey(prompt) {
|
|
4627
|
-
return [
|
|
4628
|
-
getPromptSlotKey(prompt),
|
|
4629
|
-
prompt.userActionId,
|
|
4630
|
-
prompt.subAction ?? "",
|
|
4631
|
-
prompt.expirySeconds ?? "",
|
|
4632
|
-
prompt.message ?? ""
|
|
4633
|
-
].join(PROMPT_KEY_SEPARATOR);
|
|
4634
|
-
}
|
|
4635
5159
|
var MessageListV2 = forwardRef(
|
|
4636
5160
|
function MessageListV22({
|
|
4637
5161
|
messages,
|
|
4638
|
-
isStreaming = false,
|
|
5162
|
+
isStreaming: _isStreaming = false,
|
|
4639
5163
|
onEditUserMessage,
|
|
4640
5164
|
onRetryUserMessage,
|
|
4641
5165
|
onImageClick,
|
|
@@ -4647,10 +5171,10 @@ var MessageListV2 = forwardRef(
|
|
|
4647
5171
|
onSubmitUserAction,
|
|
4648
5172
|
onCancelUserAction,
|
|
4649
5173
|
onResendUserAction,
|
|
4650
|
-
onExpireUserAction,
|
|
4651
5174
|
onDismissNotification,
|
|
4652
5175
|
onSubmitFeedback,
|
|
4653
|
-
typingSpeed = 4
|
|
5176
|
+
typingSpeed = 4,
|
|
5177
|
+
sidePanelOpen = false
|
|
4654
5178
|
}, ref) {
|
|
4655
5179
|
const noop = useCallback(async () => {
|
|
4656
5180
|
}, []);
|
|
@@ -4658,11 +5182,11 @@ var MessageListV2 = forwardRef(
|
|
|
4658
5182
|
const scrollInnerRef = useRef(null);
|
|
4659
5183
|
const isNearBottomRef = useRef(true);
|
|
4660
5184
|
const [showScrollBtn, setShowScrollBtn] = useState(false);
|
|
4661
|
-
const [expiredPromptViewState, setExpiredPromptViewState] = useState({});
|
|
4662
|
-
const expiredUserActionIdsRef = useRef(/* @__PURE__ */ new Set());
|
|
4663
5185
|
const prevCountRef = useRef(messages.length);
|
|
4664
5186
|
const pauseStickUntilUserMessageRef = useRef(false);
|
|
4665
5187
|
const followingBottomRef = useRef(true);
|
|
5188
|
+
const sidePanelOpenRef = useRef(sidePanelOpen);
|
|
5189
|
+
sidePanelOpenRef.current = sidePanelOpen;
|
|
4666
5190
|
const lastPinAtRef = useRef(0);
|
|
4667
5191
|
const prevScrollTopRef = useRef(0);
|
|
4668
5192
|
const getDistanceFromBottom = useCallback(() => {
|
|
@@ -4670,92 +5194,6 @@ var MessageListV2 = forwardRef(
|
|
|
4670
5194
|
if (!el) return 0;
|
|
4671
5195
|
return el.scrollHeight - el.scrollTop - el.clientHeight;
|
|
4672
5196
|
}, []);
|
|
4673
|
-
const messageActivityFingerprint = useMemo(() => {
|
|
4674
|
-
const last = messages[messages.length - 1];
|
|
4675
|
-
const promptFingerprint = (userActionPrompts ?? []).map((prompt) => `${getPromptViewKey(prompt)}:${prompt.status}`).join(PROMPT_KEY_SEPARATOR);
|
|
4676
|
-
const notificationFingerprint = (notifications ?? []).map((notification) => notification.id).join(PROMPT_KEY_SEPARATOR);
|
|
4677
|
-
if (!last) {
|
|
4678
|
-
return [
|
|
4679
|
-
0,
|
|
4680
|
-
isStreaming ? "streaming" : "idle",
|
|
4681
|
-
promptFingerprint,
|
|
4682
|
-
notificationFingerprint
|
|
4683
|
-
].join(PROMPT_KEY_SEPARATOR);
|
|
4684
|
-
}
|
|
4685
|
-
return [
|
|
4686
|
-
messages.length,
|
|
4687
|
-
isStreaming ? "streaming" : "idle",
|
|
4688
|
-
last.id,
|
|
4689
|
-
last.role,
|
|
4690
|
-
last.content ?? "",
|
|
4691
|
-
last.isStreaming ? "streaming" : "done",
|
|
4692
|
-
last.streamProgress ?? "",
|
|
4693
|
-
last.steps?.length ?? 0,
|
|
4694
|
-
last.errorDetails ?? "",
|
|
4695
|
-
promptFingerprint,
|
|
4696
|
-
notificationFingerprint
|
|
4697
|
-
].join(PROMPT_KEY_SEPARATOR);
|
|
4698
|
-
}, [isStreaming, messages, notifications, userActionPrompts]);
|
|
4699
|
-
const handleUserActionExpired = useCallback(
|
|
4700
|
-
(promptKey, userActionId) => {
|
|
4701
|
-
setExpiredPromptViewState((prev) => {
|
|
4702
|
-
if (prev[promptKey]) return prev;
|
|
4703
|
-
return {
|
|
4704
|
-
...prev,
|
|
4705
|
-
[promptKey]: { baseline: messageActivityFingerprint, hidden: false }
|
|
4706
|
-
};
|
|
4707
|
-
});
|
|
4708
|
-
if (!expiredUserActionIdsRef.current.has(userActionId)) {
|
|
4709
|
-
expiredUserActionIdsRef.current.add(userActionId);
|
|
4710
|
-
void onExpireUserAction?.(userActionId)?.catch(() => {
|
|
4711
|
-
});
|
|
4712
|
-
}
|
|
4713
|
-
},
|
|
4714
|
-
[messageActivityFingerprint, onExpireUserAction]
|
|
4715
|
-
);
|
|
4716
|
-
useEffect(() => {
|
|
4717
|
-
setExpiredPromptViewState((prev) => {
|
|
4718
|
-
let changed = false;
|
|
4719
|
-
const next = {};
|
|
4720
|
-
for (const [key, state] of Object.entries(prev)) {
|
|
4721
|
-
if (!state.hidden && state.baseline !== messageActivityFingerprint) {
|
|
4722
|
-
next[key] = { ...state, hidden: true };
|
|
4723
|
-
changed = true;
|
|
4724
|
-
} else {
|
|
4725
|
-
next[key] = state;
|
|
4726
|
-
}
|
|
4727
|
-
}
|
|
4728
|
-
return changed ? next : prev;
|
|
4729
|
-
});
|
|
4730
|
-
}, [messageActivityFingerprint]);
|
|
4731
|
-
useEffect(() => {
|
|
4732
|
-
const livePromptKeys = new Set((userActionPrompts ?? []).map(getPromptViewKey));
|
|
4733
|
-
const liveUserActionIds = new Set((userActionPrompts ?? []).map((p) => p.userActionId));
|
|
4734
|
-
for (const userActionId of expiredUserActionIdsRef.current) {
|
|
4735
|
-
if (!liveUserActionIds.has(userActionId)) {
|
|
4736
|
-
expiredUserActionIdsRef.current.delete(userActionId);
|
|
4737
|
-
}
|
|
4738
|
-
}
|
|
4739
|
-
setExpiredPromptViewState((prev) => {
|
|
4740
|
-
let changed = false;
|
|
4741
|
-
const next = {};
|
|
4742
|
-
for (const [key, state] of Object.entries(prev)) {
|
|
4743
|
-
if (livePromptKeys.has(key)) {
|
|
4744
|
-
next[key] = state;
|
|
4745
|
-
} else {
|
|
4746
|
-
changed = true;
|
|
4747
|
-
}
|
|
4748
|
-
}
|
|
4749
|
-
return changed ? next : prev;
|
|
4750
|
-
});
|
|
4751
|
-
}, [userActionPrompts]);
|
|
4752
|
-
const visibleUserActionPrompts = useMemo(
|
|
4753
|
-
() => userActionPrompts?.filter((prompt) => {
|
|
4754
|
-
const promptKey = getPromptViewKey(prompt);
|
|
4755
|
-
return !expiredPromptViewState[promptKey]?.hidden;
|
|
4756
|
-
}),
|
|
4757
|
-
[expiredPromptViewState, userActionPrompts]
|
|
4758
|
-
);
|
|
4759
5197
|
const pinToBottom = useCallback((behavior = "instant") => {
|
|
4760
5198
|
const el = scrollRef.current;
|
|
4761
5199
|
if (!el) return;
|
|
@@ -4796,17 +5234,25 @@ var MessageListV2 = forwardRef(
|
|
|
4796
5234
|
const nearBottom = distance <= SCROLL_THRESHOLD2;
|
|
4797
5235
|
isNearBottomRef.current = nearBottom;
|
|
4798
5236
|
setShowScrollBtn(!nearBottom);
|
|
4799
|
-
const sincePin = performance.now() - lastPinAtRef.current;
|
|
4800
|
-
if (sincePin < 250) return;
|
|
4801
5237
|
const scrolledUp = currentScrollTop < prevScrollTop - USER_SCROLL_UP_EPSILON;
|
|
4802
5238
|
if (scrolledUp) {
|
|
4803
5239
|
followingBottomRef.current = false;
|
|
4804
5240
|
pauseStickUntilUserMessageRef.current = true;
|
|
4805
|
-
|
|
5241
|
+
return;
|
|
5242
|
+
}
|
|
5243
|
+
const sincePin = performance.now() - lastPinAtRef.current;
|
|
5244
|
+
if (sincePin < 250) return;
|
|
5245
|
+
if (nearBottom) {
|
|
4806
5246
|
followingBottomRef.current = true;
|
|
4807
5247
|
pauseStickUntilUserMessageRef.current = false;
|
|
4808
5248
|
}
|
|
4809
5249
|
}, [getDistanceFromBottom]);
|
|
5250
|
+
const handleWheel = useCallback((e) => {
|
|
5251
|
+
if (e.deltaY < 0) {
|
|
5252
|
+
followingBottomRef.current = false;
|
|
5253
|
+
pauseStickUntilUserMessageRef.current = true;
|
|
5254
|
+
}
|
|
5255
|
+
}, []);
|
|
4810
5256
|
useEffect(() => {
|
|
4811
5257
|
const prevCount = prevCountRef.current;
|
|
4812
5258
|
prevCountRef.current = messages.length;
|
|
@@ -4816,7 +5262,7 @@ var MessageListV2 = forwardRef(
|
|
|
4816
5262
|
pauseStickUntilUserMessageRef.current = false;
|
|
4817
5263
|
followingBottomRef.current = true;
|
|
4818
5264
|
requestAnimationFrame(() => scrollToBottom());
|
|
4819
|
-
} else if (!pauseStickUntilUserMessageRef.current && followingBottomRef.current) {
|
|
5265
|
+
} else if (!sidePanelOpenRef.current && !pauseStickUntilUserMessageRef.current && followingBottomRef.current) {
|
|
4820
5266
|
requestAnimationFrame(() => scrollToBottom("instant"));
|
|
4821
5267
|
}
|
|
4822
5268
|
}
|
|
@@ -4825,27 +5271,16 @@ var MessageListV2 = forwardRef(
|
|
|
4825
5271
|
const inner = scrollInnerRef.current;
|
|
4826
5272
|
if (!inner) return;
|
|
4827
5273
|
const pinIfFollowing = () => {
|
|
5274
|
+
if (sidePanelOpenRef.current) return;
|
|
4828
5275
|
if (pauseStickUntilUserMessageRef.current) return;
|
|
4829
5276
|
if (!followingBottomRef.current) return;
|
|
5277
|
+
if (getDistanceFromBottom() > SCROLL_THRESHOLD2) return;
|
|
4830
5278
|
pinToBottom("instant");
|
|
4831
5279
|
};
|
|
4832
|
-
const ro = new ResizeObserver(
|
|
4833
|
-
pinIfFollowing();
|
|
4834
|
-
});
|
|
5280
|
+
const ro = new ResizeObserver(pinIfFollowing);
|
|
4835
5281
|
ro.observe(inner);
|
|
4836
|
-
|
|
4837
|
-
|
|
4838
|
-
});
|
|
4839
|
-
mo.observe(inner, {
|
|
4840
|
-
childList: true,
|
|
4841
|
-
subtree: true,
|
|
4842
|
-
characterData: true
|
|
4843
|
-
});
|
|
4844
|
-
return () => {
|
|
4845
|
-
ro.disconnect();
|
|
4846
|
-
mo.disconnect();
|
|
4847
|
-
};
|
|
4848
|
-
}, [pinToBottom]);
|
|
5282
|
+
return () => ro.disconnect();
|
|
5283
|
+
}, [pinToBottom, getDistanceFromBottom]);
|
|
4849
5284
|
useEffect(() => {
|
|
4850
5285
|
if (messages.length > 0) {
|
|
4851
5286
|
setTimeout(() => scrollToBottom("instant"), 50);
|
|
@@ -4857,6 +5292,7 @@ var MessageListV2 = forwardRef(
|
|
|
4857
5292
|
{
|
|
4858
5293
|
ref: scrollRef,
|
|
4859
5294
|
onScroll: handleScroll,
|
|
5295
|
+
onWheel: handleWheel,
|
|
4860
5296
|
className: "payman-v2-message-scroll payman-v2-scrollbar",
|
|
4861
5297
|
children: /* @__PURE__ */ jsxs(
|
|
4862
5298
|
"div",
|
|
@@ -4870,6 +5306,7 @@ var MessageListV2 = forwardRef(
|
|
|
4870
5306
|
message,
|
|
4871
5307
|
onEdit: onEditUserMessage,
|
|
4872
5308
|
onRetry: onRetryUserMessage,
|
|
5309
|
+
onImageClick,
|
|
4873
5310
|
retryDisabled,
|
|
4874
5311
|
actions: messageActions?.userMessageActions
|
|
4875
5312
|
}
|
|
@@ -4892,20 +5329,16 @@ var MessageListV2 = forwardRef(
|
|
|
4892
5329
|
},
|
|
4893
5330
|
note.id
|
|
4894
5331
|
)),
|
|
4895
|
-
|
|
4896
|
-
|
|
4897
|
-
|
|
4898
|
-
|
|
4899
|
-
|
|
4900
|
-
|
|
4901
|
-
|
|
4902
|
-
|
|
4903
|
-
|
|
4904
|
-
|
|
4905
|
-
},
|
|
4906
|
-
promptKey
|
|
4907
|
-
);
|
|
4908
|
-
})
|
|
5332
|
+
userActionPrompts?.map((prompt) => /* @__PURE__ */ jsx(
|
|
5333
|
+
UserActionInline,
|
|
5334
|
+
{
|
|
5335
|
+
prompt,
|
|
5336
|
+
onSubmit: onSubmitUserAction ?? noop,
|
|
5337
|
+
onCancel: onCancelUserAction ?? noop,
|
|
5338
|
+
onResend: onResendUserAction ?? noop
|
|
5339
|
+
},
|
|
5340
|
+
prompt.toolCallId || prompt.userActionId
|
|
5341
|
+
))
|
|
4909
5342
|
]
|
|
4910
5343
|
}
|
|
4911
5344
|
)
|
|
@@ -4935,29 +5368,146 @@ var MessageListV2 = forwardRef(
|
|
|
4935
5368
|
] });
|
|
4936
5369
|
}
|
|
4937
5370
|
);
|
|
4938
|
-
|
|
4939
|
-
|
|
4940
|
-
|
|
4941
|
-
|
|
4942
|
-
|
|
4943
|
-
|
|
4944
|
-
|
|
4945
|
-
|
|
4946
|
-
|
|
4947
|
-
|
|
4948
|
-
|
|
4949
|
-
|
|
4950
|
-
|
|
4951
|
-
|
|
4952
|
-
|
|
4953
|
-
|
|
4954
|
-
|
|
4955
|
-
|
|
4956
|
-
|
|
4957
|
-
|
|
4958
|
-
|
|
4959
|
-
|
|
4960
|
-
|
|
5371
|
+
function FilePreviewModal({ src, name, onClose }) {
|
|
5372
|
+
const [isMounted, setIsMounted] = useState(false);
|
|
5373
|
+
const [isLoaded, setIsLoaded] = useState(false);
|
|
5374
|
+
useEffect(() => {
|
|
5375
|
+
setIsMounted(true);
|
|
5376
|
+
return () => setIsMounted(false);
|
|
5377
|
+
}, []);
|
|
5378
|
+
useEffect(() => {
|
|
5379
|
+
setIsLoaded(false);
|
|
5380
|
+
}, [src]);
|
|
5381
|
+
const handleKeyDown = useCallback(
|
|
5382
|
+
(e) => {
|
|
5383
|
+
if (e.key === "Escape") onClose();
|
|
5384
|
+
},
|
|
5385
|
+
[onClose]
|
|
5386
|
+
);
|
|
5387
|
+
useEffect(() => {
|
|
5388
|
+
if (!src || typeof document === "undefined") return;
|
|
5389
|
+
document.addEventListener("keydown", handleKeyDown);
|
|
5390
|
+
const prev = document.body.style.overflow;
|
|
5391
|
+
document.body.style.overflow = "hidden";
|
|
5392
|
+
return () => {
|
|
5393
|
+
document.removeEventListener("keydown", handleKeyDown);
|
|
5394
|
+
document.body.style.overflow = prev;
|
|
5395
|
+
};
|
|
5396
|
+
}, [src, handleKeyDown]);
|
|
5397
|
+
if (!isMounted || typeof document === "undefined") return null;
|
|
5398
|
+
return createPortal(
|
|
5399
|
+
/* @__PURE__ */ jsx(AnimatePresence, { children: src ? /* @__PURE__ */ jsxs(
|
|
5400
|
+
motion.div,
|
|
5401
|
+
{
|
|
5402
|
+
className: "payman-v2-file-preview-overlay",
|
|
5403
|
+
initial: { opacity: 0 },
|
|
5404
|
+
animate: { opacity: 1 },
|
|
5405
|
+
exit: { opacity: 0 },
|
|
5406
|
+
transition: { duration: 0.18 },
|
|
5407
|
+
onClick: onClose,
|
|
5408
|
+
role: "dialog",
|
|
5409
|
+
"aria-modal": "true",
|
|
5410
|
+
"aria-label": `Preview: ${name}`,
|
|
5411
|
+
children: [
|
|
5412
|
+
/* @__PURE__ */ jsx(
|
|
5413
|
+
"button",
|
|
5414
|
+
{
|
|
5415
|
+
type: "button",
|
|
5416
|
+
className: "payman-v2-file-preview-close",
|
|
5417
|
+
"aria-label": "Close preview",
|
|
5418
|
+
onClick: (e) => {
|
|
5419
|
+
e.stopPropagation();
|
|
5420
|
+
onClose();
|
|
5421
|
+
},
|
|
5422
|
+
children: /* @__PURE__ */ jsx(X, { size: 18, strokeWidth: 2 })
|
|
5423
|
+
}
|
|
5424
|
+
),
|
|
5425
|
+
/* @__PURE__ */ jsx(
|
|
5426
|
+
motion.div,
|
|
5427
|
+
{
|
|
5428
|
+
className: "payman-v2-file-preview-inner",
|
|
5429
|
+
initial: { scale: 0.93, opacity: 0 },
|
|
5430
|
+
animate: { scale: isLoaded ? 1 : 0.93, opacity: isLoaded ? 1 : 0 },
|
|
5431
|
+
exit: { scale: 0.93, opacity: 0 },
|
|
5432
|
+
transition: { duration: 0.2 },
|
|
5433
|
+
onClick: (e) => e.stopPropagation(),
|
|
5434
|
+
children: /* @__PURE__ */ jsx(
|
|
5435
|
+
"img",
|
|
5436
|
+
{
|
|
5437
|
+
src,
|
|
5438
|
+
alt: name,
|
|
5439
|
+
className: "payman-v2-file-preview-img",
|
|
5440
|
+
draggable: false,
|
|
5441
|
+
onLoad: () => setIsLoaded(true)
|
|
5442
|
+
}
|
|
5443
|
+
)
|
|
5444
|
+
}
|
|
5445
|
+
)
|
|
5446
|
+
]
|
|
5447
|
+
},
|
|
5448
|
+
"file-preview"
|
|
5449
|
+
) : null }),
|
|
5450
|
+
document.body
|
|
5451
|
+
);
|
|
5452
|
+
}
|
|
5453
|
+
function normalizeExtension(ext) {
|
|
5454
|
+
return ext.replace(/^\./, "").toLowerCase();
|
|
5455
|
+
}
|
|
5456
|
+
function extOf(filename) {
|
|
5457
|
+
return filename.split(".").pop()?.toLowerCase() ?? "";
|
|
5458
|
+
}
|
|
5459
|
+
function isAllowedImage(file, allowedExtensions) {
|
|
5460
|
+
const allowed = new Set(allowedExtensions.map(normalizeExtension));
|
|
5461
|
+
const ext = extOf(file.name);
|
|
5462
|
+
if (allowed.has(ext)) return true;
|
|
5463
|
+
if (!file.type.startsWith("image/")) return false;
|
|
5464
|
+
const mimeSubtype = file.type.slice("image/".length).toLowerCase();
|
|
5465
|
+
return allowed.has(mimeSubtype) || mimeSubtype === "jpeg" && allowed.has("jpg");
|
|
5466
|
+
}
|
|
5467
|
+
function isAllowedDocument(file, allowedExtensions) {
|
|
5468
|
+
const allowed = new Set(allowedExtensions.map(normalizeExtension));
|
|
5469
|
+
return allowed.has(extOf(file.name));
|
|
5470
|
+
}
|
|
5471
|
+
function fileTypeLabel(file, kind) {
|
|
5472
|
+
if (kind === "image") return "Image";
|
|
5473
|
+
const ext = extOf(file.name);
|
|
5474
|
+
return ext ? ext.toUpperCase() : "Document";
|
|
5475
|
+
}
|
|
5476
|
+
var ChatInputV2 = forwardRef(
|
|
5477
|
+
function ChatInputV22({
|
|
5478
|
+
onSend,
|
|
5479
|
+
disabled = false,
|
|
5480
|
+
isStreaming = false,
|
|
5481
|
+
isUploadingAttachments = false,
|
|
5482
|
+
attachmentsReady = true,
|
|
5483
|
+
hasAttachmentUploadErrors = false,
|
|
5484
|
+
attachmentUploadStatusById = {},
|
|
5485
|
+
uploadedAttachmentPayloads = [],
|
|
5486
|
+
placeholder = "Reply...",
|
|
5487
|
+
enableVoice = false,
|
|
5488
|
+
voiceAvailable = false,
|
|
5489
|
+
isRecording = false,
|
|
5490
|
+
onVoicePress,
|
|
5491
|
+
transcribedText = "",
|
|
5492
|
+
showResetSession = false,
|
|
5493
|
+
onResetSession,
|
|
5494
|
+
showAttachmentButton = true,
|
|
5495
|
+
showUploadImageButton = true,
|
|
5496
|
+
showAttachFileButton = true,
|
|
5497
|
+
onUploadImageClick,
|
|
5498
|
+
onAttachFileClick,
|
|
5499
|
+
allowedImageExtensions = ["png", "jpg", "jpeg", "gif", "webp"],
|
|
5500
|
+
allowedFileExtensions = ["pdf", "docx", "xlsx", "xls"],
|
|
5501
|
+
maxCount,
|
|
5502
|
+
maxFileBytes,
|
|
5503
|
+
maxTotalBytes,
|
|
5504
|
+
onFilesChange,
|
|
5505
|
+
onAttachmentsChange,
|
|
5506
|
+
editingMessageId = null,
|
|
5507
|
+
onClearEditing,
|
|
5508
|
+
analysisMode,
|
|
5509
|
+
onAnalysisModeChange,
|
|
5510
|
+
slashCommands = []
|
|
4961
5511
|
}, ref) {
|
|
4962
5512
|
const [value, setValue] = useState("");
|
|
4963
5513
|
const [isFocused, setIsFocused] = useState(false);
|
|
@@ -4966,14 +5516,133 @@ var ChatInputV2 = forwardRef(
|
|
|
4966
5516
|
const [selectedCommandIndex, setSelectedCommandIndex] = useState(0);
|
|
4967
5517
|
const [inlineHint, setInlineHint] = useState(null);
|
|
4968
5518
|
const [commandMenuDismissed, setCommandMenuDismissed] = useState(false);
|
|
5519
|
+
const [attachedFiles, setAttachedFiles] = useState([]);
|
|
5520
|
+
const [previewFile, setPreviewFile] = useState(null);
|
|
5521
|
+
const [isSending, setIsSending] = useState(false);
|
|
4969
5522
|
const textareaRef = useRef(null);
|
|
4970
5523
|
const actionsRef = useRef(null);
|
|
5524
|
+
const imageInputRef = useRef(null);
|
|
5525
|
+
const fileInputRef = useRef(null);
|
|
4971
5526
|
const preRecordTextRef = useRef("");
|
|
4972
5527
|
const voiceTooltipTimerRef = useRef(
|
|
4973
5528
|
null
|
|
4974
5529
|
);
|
|
4975
5530
|
const voiceDraftSyncActiveRef = useRef(false);
|
|
4976
|
-
const
|
|
5531
|
+
const chatContext = useContext(PaymanChatContext);
|
|
5532
|
+
useEffect(() => {
|
|
5533
|
+
return () => {
|
|
5534
|
+
attachedFiles.forEach((f) => URL.revokeObjectURL(f.objectUrl));
|
|
5535
|
+
};
|
|
5536
|
+
}, []);
|
|
5537
|
+
const notifyAttachmentList = useCallback(
|
|
5538
|
+
(files) => {
|
|
5539
|
+
onFilesChange?.(files.map((f) => f.file));
|
|
5540
|
+
onAttachmentsChange?.(files.map((f) => ({ id: f.id, file: f.file })));
|
|
5541
|
+
},
|
|
5542
|
+
[onAttachmentsChange, onFilesChange]
|
|
5543
|
+
);
|
|
5544
|
+
const clearAttachmentsFromInput = useCallback(() => {
|
|
5545
|
+
setAttachedFiles((prev) => {
|
|
5546
|
+
prev.forEach((f) => URL.revokeObjectURL(f.objectUrl));
|
|
5547
|
+
return [];
|
|
5548
|
+
});
|
|
5549
|
+
setPreviewFile(null);
|
|
5550
|
+
onFilesChange?.([]);
|
|
5551
|
+
onAttachmentsChange?.([]);
|
|
5552
|
+
}, [onAttachmentsChange, onFilesChange]);
|
|
5553
|
+
const addFiles = useCallback(
|
|
5554
|
+
(incoming, source) => {
|
|
5555
|
+
const isImage = source === "image";
|
|
5556
|
+
const allowedExtensions = isImage ? allowedImageExtensions : allowedFileExtensions;
|
|
5557
|
+
const isAllowed = isImage ? isAllowedImage : isAllowedDocument;
|
|
5558
|
+
const kindLabel = isImage ? "image" : "document";
|
|
5559
|
+
setAttachedFiles((prev) => {
|
|
5560
|
+
const accepted = [];
|
|
5561
|
+
let rejectedType = false;
|
|
5562
|
+
let hitCountLimit = false;
|
|
5563
|
+
let hitFileSizeLimit = false;
|
|
5564
|
+
let hitTotalSizeLimit = false;
|
|
5565
|
+
let oversizedName = "";
|
|
5566
|
+
const currentTotalBytes = prev.reduce(
|
|
5567
|
+
(sum, item) => sum + item.file.size,
|
|
5568
|
+
0
|
|
5569
|
+
);
|
|
5570
|
+
let addedBytes = 0;
|
|
5571
|
+
for (const file of incoming) {
|
|
5572
|
+
if (!isAllowed(file, allowedExtensions)) {
|
|
5573
|
+
rejectedType = true;
|
|
5574
|
+
continue;
|
|
5575
|
+
}
|
|
5576
|
+
if (maxFileBytes != null && file.size > maxFileBytes) {
|
|
5577
|
+
hitFileSizeLimit = true;
|
|
5578
|
+
oversizedName = file.name;
|
|
5579
|
+
continue;
|
|
5580
|
+
}
|
|
5581
|
+
if (maxTotalBytes != null && currentTotalBytes + addedBytes + file.size > maxTotalBytes) {
|
|
5582
|
+
hitTotalSizeLimit = true;
|
|
5583
|
+
break;
|
|
5584
|
+
}
|
|
5585
|
+
if (maxCount != null && prev.length + accepted.length >= maxCount) {
|
|
5586
|
+
hitCountLimit = true;
|
|
5587
|
+
break;
|
|
5588
|
+
}
|
|
5589
|
+
accepted.push({
|
|
5590
|
+
id: `${Date.now()}-${Math.random()}`,
|
|
5591
|
+
file,
|
|
5592
|
+
kind: source,
|
|
5593
|
+
objectUrl: URL.createObjectURL(file)
|
|
5594
|
+
});
|
|
5595
|
+
addedBytes += file.size;
|
|
5596
|
+
}
|
|
5597
|
+
if (rejectedType) {
|
|
5598
|
+
setInlineHint(
|
|
5599
|
+
`Unsupported ${kindLabel} type. Allowed: ${allowedExtensions.map(normalizeExtension).join(", ")}.`
|
|
5600
|
+
);
|
|
5601
|
+
} else if (hitFileSizeLimit) {
|
|
5602
|
+
setInlineHint(
|
|
5603
|
+
maxFileBytes != null ? `"${oversizedName}" exceeds the ${formatAttachmentBytes(maxFileBytes)} per-file limit.` : "File exceeds the maximum allowed size."
|
|
5604
|
+
);
|
|
5605
|
+
} else if (hitTotalSizeLimit) {
|
|
5606
|
+
setInlineHint(
|
|
5607
|
+
maxTotalBytes != null ? `Total attachment size would exceed ${formatAttachmentBytes(maxTotalBytes)}.` : "Total attachment size exceeds the limit."
|
|
5608
|
+
);
|
|
5609
|
+
} else if (hitCountLimit) {
|
|
5610
|
+
setInlineHint(
|
|
5611
|
+
maxCount === 1 ? "Only 1 attachment is allowed per message." : `Maximum ${maxCount} attachments allowed per message.`
|
|
5612
|
+
);
|
|
5613
|
+
}
|
|
5614
|
+
if (accepted.length === 0) return prev;
|
|
5615
|
+
const updated = [...prev, ...accepted];
|
|
5616
|
+
notifyAttachmentList(updated);
|
|
5617
|
+
return updated;
|
|
5618
|
+
});
|
|
5619
|
+
},
|
|
5620
|
+
[
|
|
5621
|
+
allowedFileExtensions,
|
|
5622
|
+
allowedImageExtensions,
|
|
5623
|
+
maxCount,
|
|
5624
|
+
maxFileBytes,
|
|
5625
|
+
maxTotalBytes,
|
|
5626
|
+
notifyAttachmentList
|
|
5627
|
+
]
|
|
5628
|
+
);
|
|
5629
|
+
const removeFile = useCallback(
|
|
5630
|
+
(id) => {
|
|
5631
|
+
setAttachedFiles((prev) => {
|
|
5632
|
+
const target = prev.find((f) => f.id === id);
|
|
5633
|
+
if (target) URL.revokeObjectURL(target.objectUrl);
|
|
5634
|
+
const updated = prev.filter((f) => f.id !== id);
|
|
5635
|
+
notifyAttachmentList(updated);
|
|
5636
|
+
return updated;
|
|
5637
|
+
});
|
|
5638
|
+
setPreviewFile((p) => p?.id === id ? null : p);
|
|
5639
|
+
},
|
|
5640
|
+
[notifyAttachmentList]
|
|
5641
|
+
);
|
|
5642
|
+
const imageAccept = allowedImageExtensions.map((e) => `.${e.replace(/^\./, "")}`).join(",");
|
|
5643
|
+
const fileAccept = allowedFileExtensions.map((e) => `.${e.replace(/^\./, "")}`).join(",");
|
|
5644
|
+
const isInputBusy = isSending || isUploadingAttachments;
|
|
5645
|
+
const isInputLocked = disabled || isRecording || isInputBusy;
|
|
4977
5646
|
const hasAttachmentOptions = showUploadImageButton || showAttachFileButton;
|
|
4978
5647
|
const showAttachmentMenuButton = showAttachmentButton && hasAttachmentOptions;
|
|
4979
5648
|
const showVoiceButton = enableVoice && onVoicePress != null;
|
|
@@ -5013,9 +5682,10 @@ var ChatInputV2 = forwardRef(
|
|
|
5013
5682
|
const end = message.length;
|
|
5014
5683
|
textarea.setSelectionRange(end, end);
|
|
5015
5684
|
});
|
|
5016
|
-
}
|
|
5685
|
+
},
|
|
5686
|
+
clearAttachments: clearAttachmentsFromInput
|
|
5017
5687
|
}),
|
|
5018
|
-
[disabled]
|
|
5688
|
+
[disabled, clearAttachmentsFromInput]
|
|
5019
5689
|
);
|
|
5020
5690
|
useEffect(() => {
|
|
5021
5691
|
if (!showActions) return;
|
|
@@ -5049,8 +5719,23 @@ var ChatInputV2 = forwardRef(
|
|
|
5049
5719
|
const separator = base && !base.endsWith(" ") && transcribedText ? " " : "";
|
|
5050
5720
|
setValue(`${base}${separator}${transcribedText}`);
|
|
5051
5721
|
}, [isRecording, transcribedText]);
|
|
5052
|
-
|
|
5053
|
-
if (
|
|
5722
|
+
function uploadStatusLabel(status, file, kind) {
|
|
5723
|
+
if (status === "uploading") return "Uploading\u2026";
|
|
5724
|
+
if (status === "error") return "Upload failed";
|
|
5725
|
+
return fileTypeLabel(file, kind);
|
|
5726
|
+
}
|
|
5727
|
+
const handleSend = useCallback(async () => {
|
|
5728
|
+
const hasText = value.trim().length > 0;
|
|
5729
|
+
const hasFiles = attachedFiles.length > 0;
|
|
5730
|
+
if (!hasText && !hasFiles || disabled || isSending || isUploadingAttachments) return;
|
|
5731
|
+
if (hasFiles && !attachmentsReady) {
|
|
5732
|
+
setInlineHint("Waiting for attachments to finish uploading.");
|
|
5733
|
+
return;
|
|
5734
|
+
}
|
|
5735
|
+
if (hasFiles && hasAttachmentUploadErrors) {
|
|
5736
|
+
setInlineHint("Remove or re-add attachments that failed to upload.");
|
|
5737
|
+
return;
|
|
5738
|
+
}
|
|
5054
5739
|
const commandHint = getSlashCommandValidationHint(value);
|
|
5055
5740
|
if (commandHint) {
|
|
5056
5741
|
setInlineHint(commandHint);
|
|
@@ -5060,15 +5745,38 @@ var ChatInputV2 = forwardRef(
|
|
|
5060
5745
|
preRecordTextRef.current = "";
|
|
5061
5746
|
setInlineHint(null);
|
|
5062
5747
|
onClearEditing?.();
|
|
5063
|
-
|
|
5748
|
+
const textToSend = value.trim();
|
|
5749
|
+
const filesToSend = attachedFiles.map((f) => f.file);
|
|
5750
|
+
const attachmentsToSend = [...uploadedAttachmentPayloads];
|
|
5064
5751
|
setValue("");
|
|
5752
|
+
clearAttachmentsFromInput();
|
|
5065
5753
|
requestAnimationFrame(() => {
|
|
5066
5754
|
if (textareaRef.current) {
|
|
5067
5755
|
textareaRef.current.style.height = "auto";
|
|
5068
5756
|
textareaRef.current.focus();
|
|
5069
5757
|
}
|
|
5070
5758
|
});
|
|
5071
|
-
|
|
5759
|
+
setIsSending(true);
|
|
5760
|
+
try {
|
|
5761
|
+
await onSend(textToSend, filesToSend, attachmentsToSend);
|
|
5762
|
+
} catch {
|
|
5763
|
+
setInlineHint("Failed to send message. Please try again.");
|
|
5764
|
+
} finally {
|
|
5765
|
+
setIsSending(false);
|
|
5766
|
+
}
|
|
5767
|
+
}, [
|
|
5768
|
+
value,
|
|
5769
|
+
attachedFiles,
|
|
5770
|
+
uploadedAttachmentPayloads,
|
|
5771
|
+
disabled,
|
|
5772
|
+
isSending,
|
|
5773
|
+
isUploadingAttachments,
|
|
5774
|
+
attachmentsReady,
|
|
5775
|
+
hasAttachmentUploadErrors,
|
|
5776
|
+
onClearEditing,
|
|
5777
|
+
onSend,
|
|
5778
|
+
clearAttachmentsFromInput
|
|
5779
|
+
]);
|
|
5072
5780
|
const selectCommand = useCallback(
|
|
5073
5781
|
(command) => {
|
|
5074
5782
|
const insertText = command.insertText ?? `${command.name} `;
|
|
@@ -5113,18 +5821,30 @@ var ChatInputV2 = forwardRef(
|
|
|
5113
5821
|
}
|
|
5114
5822
|
if (e.key === "Enter" && !e.shiftKey) {
|
|
5115
5823
|
e.preventDefault();
|
|
5116
|
-
if (isStreaming) return;
|
|
5117
|
-
handleSend();
|
|
5824
|
+
if (isStreaming || isSending || isUploadingAttachments) return;
|
|
5825
|
+
void handleSend();
|
|
5118
5826
|
}
|
|
5119
5827
|
};
|
|
5120
5828
|
const handleUploadImageClick = () => {
|
|
5829
|
+
imageInputRef.current?.click();
|
|
5121
5830
|
onUploadImageClick?.();
|
|
5122
5831
|
setShowActions(false);
|
|
5123
5832
|
};
|
|
5124
5833
|
const handleAttachFileClick = () => {
|
|
5834
|
+
fileInputRef.current?.click();
|
|
5125
5835
|
onAttachFileClick?.();
|
|
5126
5836
|
setShowActions(false);
|
|
5127
5837
|
};
|
|
5838
|
+
const handleImageFilesSelected = (e) => {
|
|
5839
|
+
const files = Array.from(e.target.files ?? []);
|
|
5840
|
+
if (files.length) addFiles(files, "image");
|
|
5841
|
+
e.target.value = "";
|
|
5842
|
+
};
|
|
5843
|
+
const handleDocFilesSelected = (e) => {
|
|
5844
|
+
const files = Array.from(e.target.files ?? []);
|
|
5845
|
+
if (files.length) addFiles(files, "file");
|
|
5846
|
+
e.target.value = "";
|
|
5847
|
+
};
|
|
5128
5848
|
const hideVoiceTooltip = useCallback(() => {
|
|
5129
5849
|
if (voiceTooltipTimerRef.current) {
|
|
5130
5850
|
clearTimeout(voiceTooltipTimerRef.current);
|
|
@@ -5152,9 +5872,39 @@ var ChatInputV2 = forwardRef(
|
|
|
5152
5872
|
}
|
|
5153
5873
|
onVoicePress();
|
|
5154
5874
|
};
|
|
5155
|
-
const canSend = value.trim().length > 0 && !disabled;
|
|
5156
|
-
const sendDisabled = !canSend || isStreaming;
|
|
5875
|
+
const canSend = (value.trim().length > 0 || attachedFiles.length > 0) && !disabled;
|
|
5876
|
+
const sendDisabled = !canSend || isStreaming || isUploadingAttachments || !attachmentsReady || hasAttachmentUploadErrors || isSending;
|
|
5157
5877
|
return /* @__PURE__ */ jsxs("div", { className: "payman-v2-input-container", children: [
|
|
5878
|
+
/* @__PURE__ */ jsx(
|
|
5879
|
+
"input",
|
|
5880
|
+
{
|
|
5881
|
+
ref: imageInputRef,
|
|
5882
|
+
type: "file",
|
|
5883
|
+
accept: imageAccept,
|
|
5884
|
+
multiple: maxCount == null || maxCount > 1,
|
|
5885
|
+
style: { display: "none" },
|
|
5886
|
+
onChange: handleImageFilesSelected
|
|
5887
|
+
}
|
|
5888
|
+
),
|
|
5889
|
+
/* @__PURE__ */ jsx(
|
|
5890
|
+
"input",
|
|
5891
|
+
{
|
|
5892
|
+
ref: fileInputRef,
|
|
5893
|
+
type: "file",
|
|
5894
|
+
accept: fileAccept,
|
|
5895
|
+
multiple: maxCount == null || maxCount > 1,
|
|
5896
|
+
style: { display: "none" },
|
|
5897
|
+
onChange: handleDocFilesSelected
|
|
5898
|
+
}
|
|
5899
|
+
),
|
|
5900
|
+
/* @__PURE__ */ jsx(
|
|
5901
|
+
FilePreviewModal,
|
|
5902
|
+
{
|
|
5903
|
+
src: previewFile?.kind === "image" ? previewFile.objectUrl : null,
|
|
5904
|
+
name: previewFile?.file.name ?? "",
|
|
5905
|
+
onClose: () => setPreviewFile(null)
|
|
5906
|
+
}
|
|
5907
|
+
),
|
|
5158
5908
|
/* @__PURE__ */ jsx(AnimatePresence, { children: showCommandSuggestions && /* @__PURE__ */ jsx(
|
|
5159
5909
|
motion.div,
|
|
5160
5910
|
{
|
|
@@ -5193,6 +5943,115 @@ var ChatInputV2 = forwardRef(
|
|
|
5193
5943
|
),
|
|
5194
5944
|
children: [
|
|
5195
5945
|
/* @__PURE__ */ jsxs("div", { className: "payman-v2-input-body", children: [
|
|
5946
|
+
/* @__PURE__ */ jsx(AnimatePresence, { initial: false, children: attachedFiles.length > 0 && /* @__PURE__ */ jsx(
|
|
5947
|
+
motion.div,
|
|
5948
|
+
{
|
|
5949
|
+
initial: { opacity: 0, height: 0 },
|
|
5950
|
+
animate: { opacity: 1, height: "auto" },
|
|
5951
|
+
exit: { opacity: 0, height: 0 },
|
|
5952
|
+
transition: { duration: 0.15, ease: "easeOut" },
|
|
5953
|
+
className: "payman-v2-file-preview",
|
|
5954
|
+
children: attachedFiles.map((af) => {
|
|
5955
|
+
const uploadStatus = attachmentUploadStatusById[af.id];
|
|
5956
|
+
const isUploadingFile = uploadStatus === "uploading";
|
|
5957
|
+
const hasUploadError = uploadStatus === "error";
|
|
5958
|
+
return /* @__PURE__ */ jsxs("div", { className: "payman-v2-file-preview-item", children: [
|
|
5959
|
+
af.kind === "image" ? /* @__PURE__ */ jsxs(
|
|
5960
|
+
"button",
|
|
5961
|
+
{
|
|
5962
|
+
type: "button",
|
|
5963
|
+
className: cn(
|
|
5964
|
+
"payman-v2-file-preview-shell payman-v2-file-preview-shell-clickable",
|
|
5965
|
+
hasUploadError && "payman-v2-file-preview-shell-error"
|
|
5966
|
+
),
|
|
5967
|
+
onClick: () => setPreviewFile(af),
|
|
5968
|
+
disabled: isUploadingFile,
|
|
5969
|
+
"aria-label": `Preview ${af.file.name}`,
|
|
5970
|
+
children: [
|
|
5971
|
+
/* @__PURE__ */ jsxs("div", { className: "payman-v2-file-preview-thumb", children: [
|
|
5972
|
+
/* @__PURE__ */ jsx(
|
|
5973
|
+
"img",
|
|
5974
|
+
{
|
|
5975
|
+
src: af.objectUrl,
|
|
5976
|
+
alt: "",
|
|
5977
|
+
draggable: false
|
|
5978
|
+
}
|
|
5979
|
+
),
|
|
5980
|
+
isUploadingFile && /* @__PURE__ */ jsx("div", { className: "payman-v2-file-preview-uploading", children: /* @__PURE__ */ jsx(Loader2, { size: 14, className: "payman-v2-spin" }) })
|
|
5981
|
+
] }),
|
|
5982
|
+
/* @__PURE__ */ jsxs("div", { className: "payman-v2-file-preview-info", children: [
|
|
5983
|
+
/* @__PURE__ */ jsx("p", { className: "payman-v2-file-preview-name", children: af.file.name }),
|
|
5984
|
+
/* @__PURE__ */ jsx("p", { className: "payman-v2-file-preview-type", children: uploadStatusLabel(uploadStatus, af.file, af.kind) })
|
|
5985
|
+
] })
|
|
5986
|
+
]
|
|
5987
|
+
}
|
|
5988
|
+
) : isPdfFile(af.file) ? /* @__PURE__ */ jsxs(
|
|
5989
|
+
"button",
|
|
5990
|
+
{
|
|
5991
|
+
type: "button",
|
|
5992
|
+
className: cn(
|
|
5993
|
+
"payman-v2-file-preview-shell payman-v2-file-preview-shell-clickable",
|
|
5994
|
+
hasUploadError && "payman-v2-file-preview-shell-error"
|
|
5995
|
+
),
|
|
5996
|
+
onClick: () => chatContext?.openPdfSheet(
|
|
5997
|
+
af.objectUrl,
|
|
5998
|
+
af.file.name
|
|
5999
|
+
),
|
|
6000
|
+
disabled: isUploadingFile,
|
|
6001
|
+
"aria-label": `Preview ${af.file.name}`,
|
|
6002
|
+
children: [
|
|
6003
|
+
/* @__PURE__ */ jsx("div", { className: "payman-v2-file-preview-thumb", children: isUploadingFile ? /* @__PURE__ */ jsx(Loader2, { size: 16, className: "payman-v2-spin payman-v2-file-preview-doc-icon" }) : /* @__PURE__ */ jsx(
|
|
6004
|
+
FileText,
|
|
6005
|
+
{
|
|
6006
|
+
size: 16,
|
|
6007
|
+
strokeWidth: 1.75,
|
|
6008
|
+
className: "payman-v2-file-preview-doc-icon"
|
|
6009
|
+
}
|
|
6010
|
+
) }),
|
|
6011
|
+
/* @__PURE__ */ jsxs("div", { className: "payman-v2-file-preview-info", children: [
|
|
6012
|
+
/* @__PURE__ */ jsx("p", { className: "payman-v2-file-preview-name", children: af.file.name }),
|
|
6013
|
+
/* @__PURE__ */ jsx("p", { className: "payman-v2-file-preview-type", children: uploadStatusLabel(uploadStatus, af.file, af.kind) })
|
|
6014
|
+
] })
|
|
6015
|
+
]
|
|
6016
|
+
}
|
|
6017
|
+
) : /* @__PURE__ */ jsxs(
|
|
6018
|
+
"div",
|
|
6019
|
+
{
|
|
6020
|
+
className: cn(
|
|
6021
|
+
"payman-v2-file-preview-shell",
|
|
6022
|
+
hasUploadError && "payman-v2-file-preview-shell-error"
|
|
6023
|
+
),
|
|
6024
|
+
children: [
|
|
6025
|
+
/* @__PURE__ */ jsx("div", { className: "payman-v2-file-preview-thumb", children: isUploadingFile ? /* @__PURE__ */ jsx(Loader2, { size: 16, className: "payman-v2-spin payman-v2-file-preview-doc-icon" }) : /* @__PURE__ */ jsx(
|
|
6026
|
+
FileText,
|
|
6027
|
+
{
|
|
6028
|
+
size: 16,
|
|
6029
|
+
strokeWidth: 1.75,
|
|
6030
|
+
className: "payman-v2-file-preview-doc-icon"
|
|
6031
|
+
}
|
|
6032
|
+
) }),
|
|
6033
|
+
/* @__PURE__ */ jsxs("div", { className: "payman-v2-file-preview-info", children: [
|
|
6034
|
+
/* @__PURE__ */ jsx("p", { className: "payman-v2-file-preview-name", children: af.file.name }),
|
|
6035
|
+
/* @__PURE__ */ jsx("p", { className: "payman-v2-file-preview-type", children: uploadStatusLabel(uploadStatus, af.file, af.kind) })
|
|
6036
|
+
] })
|
|
6037
|
+
]
|
|
6038
|
+
}
|
|
6039
|
+
),
|
|
6040
|
+
/* @__PURE__ */ jsx(
|
|
6041
|
+
"button",
|
|
6042
|
+
{
|
|
6043
|
+
type: "button",
|
|
6044
|
+
className: "payman-v2-file-preview-remove",
|
|
6045
|
+
onClick: () => removeFile(af.id),
|
|
6046
|
+
"aria-label": `Remove ${af.file.name}`,
|
|
6047
|
+
children: /* @__PURE__ */ jsx(X, { size: 12, strokeWidth: 2.5 })
|
|
6048
|
+
}
|
|
6049
|
+
)
|
|
6050
|
+
] }, af.id);
|
|
6051
|
+
})
|
|
6052
|
+
},
|
|
6053
|
+
"file-preview"
|
|
6054
|
+
) }),
|
|
5196
6055
|
/* @__PURE__ */ jsx(AnimatePresence, { initial: false, children: editingMessageId && /* @__PURE__ */ jsxs(
|
|
5197
6056
|
motion.div,
|
|
5198
6057
|
{
|
|
@@ -5424,13 +6283,13 @@ var ChatInputV2 = forwardRef(
|
|
|
5424
6283
|
"button",
|
|
5425
6284
|
{
|
|
5426
6285
|
type: "button",
|
|
5427
|
-
onClick: handleSend,
|
|
6286
|
+
onClick: () => void handleSend(),
|
|
5428
6287
|
disabled: sendDisabled,
|
|
5429
6288
|
className: cn(
|
|
5430
6289
|
"payman-v2-input-send-btn",
|
|
5431
6290
|
sendDisabled && "payman-v2-input-send-btn-disabled"
|
|
5432
6291
|
),
|
|
5433
|
-
"aria-label": "Send message",
|
|
6292
|
+
"aria-label": isUploadingAttachments || isSending ? "Uploading attachments" : "Send message",
|
|
5434
6293
|
children: /* @__PURE__ */ jsx(
|
|
5435
6294
|
ArrowUp,
|
|
5436
6295
|
{
|
|
@@ -5965,6 +6824,389 @@ function TimelineBars({
|
|
|
5965
6824
|
)
|
|
5966
6825
|
] });
|
|
5967
6826
|
}
|
|
6827
|
+
|
|
6828
|
+
// src/utils/pdfPreview.ts
|
|
6829
|
+
var PdfPreviewError = class extends Error {
|
|
6830
|
+
constructor(kind, title, userMessage) {
|
|
6831
|
+
super(userMessage);
|
|
6832
|
+
__publicField(this, "kind");
|
|
6833
|
+
__publicField(this, "title");
|
|
6834
|
+
__publicField(this, "userMessage");
|
|
6835
|
+
this.name = "PdfPreviewError";
|
|
6836
|
+
this.kind = kind;
|
|
6837
|
+
this.title = title;
|
|
6838
|
+
this.userMessage = userMessage;
|
|
6839
|
+
}
|
|
6840
|
+
};
|
|
6841
|
+
function classifyErrorBody(body, status) {
|
|
6842
|
+
const text = body.replace(/\s+/g, " ").trim();
|
|
6843
|
+
if (/signed expiry time|must be after signed start time|expired|expir/i.test(text)) {
|
|
6844
|
+
return new PdfPreviewError(
|
|
6845
|
+
"expired",
|
|
6846
|
+
"Link expired",
|
|
6847
|
+
"This download link has expired. Ask the assistant to generate a new copy of the document."
|
|
6848
|
+
);
|
|
6849
|
+
}
|
|
6850
|
+
if (/AuthenticationFailed|authorization header|formed correctly including the signature/i.test(
|
|
6851
|
+
text
|
|
6852
|
+
)) {
|
|
6853
|
+
return new PdfPreviewError(
|
|
6854
|
+
"forbidden",
|
|
6855
|
+
"Link no longer valid",
|
|
6856
|
+
"This preview link is no longer valid. Request a fresh download link and try again."
|
|
6857
|
+
);
|
|
6858
|
+
}
|
|
6859
|
+
if (status === 404 || /BlobNotFound|ResourceNotFound|The specified blob does not exist/i.test(text)) {
|
|
6860
|
+
return new PdfPreviewError(
|
|
6861
|
+
"not_found",
|
|
6862
|
+
"Document not found",
|
|
6863
|
+
"The file is no longer available. It may have been removed or the link is incorrect."
|
|
6864
|
+
);
|
|
6865
|
+
}
|
|
6866
|
+
if (status === 403) {
|
|
6867
|
+
return new PdfPreviewError(
|
|
6868
|
+
"forbidden",
|
|
6869
|
+
"Can't open document",
|
|
6870
|
+
"You may not have access to this file, or the link has expired."
|
|
6871
|
+
);
|
|
6872
|
+
}
|
|
6873
|
+
if (status === 401) {
|
|
6874
|
+
return new PdfPreviewError(
|
|
6875
|
+
"forbidden",
|
|
6876
|
+
"Access denied",
|
|
6877
|
+
"This preview link could not be verified. Request a new download link."
|
|
6878
|
+
);
|
|
6879
|
+
}
|
|
6880
|
+
return new PdfPreviewError(
|
|
6881
|
+
"unknown",
|
|
6882
|
+
"Can't preview document",
|
|
6883
|
+
"Something went wrong while opening this file. Try downloading it or request a new link."
|
|
6884
|
+
);
|
|
6885
|
+
}
|
|
6886
|
+
function normalizePdfPreviewError(error) {
|
|
6887
|
+
if (error instanceof PdfPreviewError) return error;
|
|
6888
|
+
if (error instanceof TypeError) {
|
|
6889
|
+
return new PdfPreviewError(
|
|
6890
|
+
"network",
|
|
6891
|
+
"Connection problem",
|
|
6892
|
+
"Could not load the document. Check your connection and try again."
|
|
6893
|
+
);
|
|
6894
|
+
}
|
|
6895
|
+
return new PdfPreviewError(
|
|
6896
|
+
"unknown",
|
|
6897
|
+
"Can't preview document",
|
|
6898
|
+
"Something went wrong while opening this file. Try downloading it or request a new link."
|
|
6899
|
+
);
|
|
6900
|
+
}
|
|
6901
|
+
async function assertPdfBlob(blob, status) {
|
|
6902
|
+
if (!blob.size) {
|
|
6903
|
+
return Promise.reject(
|
|
6904
|
+
new PdfPreviewError(
|
|
6905
|
+
"empty",
|
|
6906
|
+
"Document unavailable",
|
|
6907
|
+
"The file response was empty. Request a new download link and try again."
|
|
6908
|
+
)
|
|
6909
|
+
);
|
|
6910
|
+
}
|
|
6911
|
+
const head = await blob.slice(0, Math.min(blob.size, 1024)).text();
|
|
6912
|
+
if (head.startsWith("%PDF")) {
|
|
6913
|
+
return blob;
|
|
6914
|
+
}
|
|
6915
|
+
throw classifyErrorBody(head, status);
|
|
6916
|
+
}
|
|
6917
|
+
async function fetchPdfBlob(src) {
|
|
6918
|
+
let response;
|
|
6919
|
+
try {
|
|
6920
|
+
response = await fetch(src, {
|
|
6921
|
+
method: "GET",
|
|
6922
|
+
headers: { Accept: "application/pdf,*/*" }
|
|
6923
|
+
});
|
|
6924
|
+
} catch {
|
|
6925
|
+
throw new PdfPreviewError(
|
|
6926
|
+
"network",
|
|
6927
|
+
"Connection problem",
|
|
6928
|
+
"Could not load the document. Check your connection and try again."
|
|
6929
|
+
);
|
|
6930
|
+
}
|
|
6931
|
+
const blob = await response.blob();
|
|
6932
|
+
if (!response.ok) {
|
|
6933
|
+
const body = await blob.text().catch(() => "");
|
|
6934
|
+
throw classifyErrorBody(body, response.status);
|
|
6935
|
+
}
|
|
6936
|
+
return assertPdfBlob(blob, response.status);
|
|
6937
|
+
}
|
|
6938
|
+
var MIN_WIDTH = 320;
|
|
6939
|
+
var MAX_WIDTH_RATIO = 0.6;
|
|
6940
|
+
var DEFAULT_WIDTH = 520;
|
|
6941
|
+
var SPRING = { type: "spring", stiffness: 340, damping: 34, mass: 0.85 };
|
|
6942
|
+
var SHEET_EXIT = { duration: 0.22, ease: [0.4, 0, 1, 1] };
|
|
6943
|
+
function pdfDownloadName(title) {
|
|
6944
|
+
const base = title.trim() || "document";
|
|
6945
|
+
return base.toLowerCase().endsWith(".pdf") ? base : `${base}.pdf`;
|
|
6946
|
+
}
|
|
6947
|
+
function clampSplitWidth(w) {
|
|
6948
|
+
const maxW = Math.floor(window.innerWidth * MAX_WIDTH_RATIO);
|
|
6949
|
+
return Math.max(MIN_WIDTH, Math.min(maxW, w));
|
|
6950
|
+
}
|
|
6951
|
+
function PdfSheetV2({
|
|
6952
|
+
src,
|
|
6953
|
+
title,
|
|
6954
|
+
onClose,
|
|
6955
|
+
mode = "split"
|
|
6956
|
+
}) {
|
|
6957
|
+
return /* @__PURE__ */ jsx(AnimatePresence, { children: src && /* @__PURE__ */ jsx(
|
|
6958
|
+
PdfSheetPanel,
|
|
6959
|
+
{
|
|
6960
|
+
src,
|
|
6961
|
+
title,
|
|
6962
|
+
onClose,
|
|
6963
|
+
mode
|
|
6964
|
+
},
|
|
6965
|
+
"pdf-panel"
|
|
6966
|
+
) });
|
|
6967
|
+
}
|
|
6968
|
+
function PdfSheetPanel({
|
|
6969
|
+
src,
|
|
6970
|
+
title,
|
|
6971
|
+
onClose,
|
|
6972
|
+
mode
|
|
6973
|
+
}) {
|
|
6974
|
+
const isSheet = mode === "sheet";
|
|
6975
|
+
const [isLoaded, setIsLoaded] = useState(false);
|
|
6976
|
+
const [isDownloading, setIsDownloading] = useState(false);
|
|
6977
|
+
const [previewUrl, setPreviewUrl] = useState(null);
|
|
6978
|
+
const [previewError, setPreviewError] = useState(null);
|
|
6979
|
+
const [loadAttempt, setLoadAttempt] = useState(0);
|
|
6980
|
+
const blobRef = useRef(null);
|
|
6981
|
+
const objectUrlRef = useRef(null);
|
|
6982
|
+
const [panelWidth, setPanelWidth] = useState(DEFAULT_WIDTH);
|
|
6983
|
+
const [splitOpened, setSplitOpened] = useState(false);
|
|
6984
|
+
const [isDragging, setIsDragging] = useState(false);
|
|
6985
|
+
useEffect(() => {
|
|
6986
|
+
setIsLoaded(false);
|
|
6987
|
+
setPreviewUrl(null);
|
|
6988
|
+
setPreviewError(null);
|
|
6989
|
+
setPanelWidth(DEFAULT_WIDTH);
|
|
6990
|
+
setSplitOpened(false);
|
|
6991
|
+
blobRef.current = null;
|
|
6992
|
+
if (objectUrlRef.current) {
|
|
6993
|
+
URL.revokeObjectURL(objectUrlRef.current);
|
|
6994
|
+
objectUrlRef.current = null;
|
|
6995
|
+
}
|
|
6996
|
+
let cancelled = false;
|
|
6997
|
+
const loadPreview = async () => {
|
|
6998
|
+
try {
|
|
6999
|
+
const blob = await fetchPdfBlob(src);
|
|
7000
|
+
if (cancelled) return;
|
|
7001
|
+
blobRef.current = blob;
|
|
7002
|
+
const objectUrl = URL.createObjectURL(blob);
|
|
7003
|
+
objectUrlRef.current = objectUrl;
|
|
7004
|
+
setPreviewUrl(objectUrl);
|
|
7005
|
+
} catch (error) {
|
|
7006
|
+
if (!cancelled) {
|
|
7007
|
+
setPreviewError(normalizePdfPreviewError(error));
|
|
7008
|
+
}
|
|
7009
|
+
}
|
|
7010
|
+
};
|
|
7011
|
+
void loadPreview();
|
|
7012
|
+
return () => {
|
|
7013
|
+
cancelled = true;
|
|
7014
|
+
if (objectUrlRef.current) {
|
|
7015
|
+
URL.revokeObjectURL(objectUrlRef.current);
|
|
7016
|
+
objectUrlRef.current = null;
|
|
7017
|
+
}
|
|
7018
|
+
blobRef.current = null;
|
|
7019
|
+
};
|
|
7020
|
+
}, [src, loadAttempt]);
|
|
7021
|
+
useEffect(() => {
|
|
7022
|
+
if (isSheet) return;
|
|
7023
|
+
const onWindowResize = () => setPanelWidth((size) => clampSplitWidth(size));
|
|
7024
|
+
window.addEventListener("resize", onWindowResize);
|
|
7025
|
+
return () => window.removeEventListener("resize", onWindowResize);
|
|
7026
|
+
}, [isSheet]);
|
|
7027
|
+
const handleKeyDown = useCallback(
|
|
7028
|
+
(e) => {
|
|
7029
|
+
if (e.key === "Escape") onClose();
|
|
7030
|
+
},
|
|
7031
|
+
[onClose]
|
|
7032
|
+
);
|
|
7033
|
+
useEffect(() => {
|
|
7034
|
+
document.addEventListener("keydown", handleKeyDown);
|
|
7035
|
+
return () => document.removeEventListener("keydown", handleKeyDown);
|
|
7036
|
+
}, [handleKeyDown]);
|
|
7037
|
+
const canDownload = isLoaded && previewUrl != null && !previewError;
|
|
7038
|
+
const handleDownload = async () => {
|
|
7039
|
+
const filename = pdfDownloadName(title);
|
|
7040
|
+
setIsDownloading(true);
|
|
7041
|
+
try {
|
|
7042
|
+
const blob = blobRef.current ?? await fetchPdfBlob(src);
|
|
7043
|
+
const objectUrl = URL.createObjectURL(blob);
|
|
7044
|
+
const a = document.createElement("a");
|
|
7045
|
+
a.href = objectUrl;
|
|
7046
|
+
a.download = filename;
|
|
7047
|
+
a.target = "_blank";
|
|
7048
|
+
a.rel = "noopener noreferrer";
|
|
7049
|
+
document.body.appendChild(a);
|
|
7050
|
+
a.click();
|
|
7051
|
+
a.remove();
|
|
7052
|
+
URL.revokeObjectURL(objectUrl);
|
|
7053
|
+
} catch (error) {
|
|
7054
|
+
setPreviewError(normalizePdfPreviewError(error));
|
|
7055
|
+
} finally {
|
|
7056
|
+
setIsDownloading(false);
|
|
7057
|
+
}
|
|
7058
|
+
};
|
|
7059
|
+
const handleRetry = () => {
|
|
7060
|
+
setPreviewError(null);
|
|
7061
|
+
setIsLoaded(false);
|
|
7062
|
+
setPreviewUrl(null);
|
|
7063
|
+
setLoadAttempt((attempt) => attempt + 1);
|
|
7064
|
+
};
|
|
7065
|
+
const handleOpenInNewTab = () => {
|
|
7066
|
+
window.open(src, "_blank", "noopener,noreferrer");
|
|
7067
|
+
};
|
|
7068
|
+
const onResizeMouseDown = (e) => {
|
|
7069
|
+
if (e.button !== 0) return;
|
|
7070
|
+
e.preventDefault();
|
|
7071
|
+
const startX = e.clientX;
|
|
7072
|
+
const startW = panelWidth;
|
|
7073
|
+
setIsDragging(true);
|
|
7074
|
+
const onMove = (ev) => {
|
|
7075
|
+
setPanelWidth(clampSplitWidth(startW + (startX - ev.clientX)));
|
|
7076
|
+
};
|
|
7077
|
+
const onUp = () => {
|
|
7078
|
+
setIsDragging(false);
|
|
7079
|
+
document.removeEventListener("mousemove", onMove);
|
|
7080
|
+
document.removeEventListener("mouseup", onUp);
|
|
7081
|
+
};
|
|
7082
|
+
document.addEventListener("mousemove", onMove);
|
|
7083
|
+
document.addEventListener("mouseup", onUp);
|
|
7084
|
+
};
|
|
7085
|
+
return /* @__PURE__ */ jsxs(
|
|
7086
|
+
motion.div,
|
|
7087
|
+
{
|
|
7088
|
+
className: cn(
|
|
7089
|
+
"payman-v2-root payman-v2-pdf-sheet-panel",
|
|
7090
|
+
isSheet && "payman-v2-pdf-sheet-panel--sheet"
|
|
7091
|
+
),
|
|
7092
|
+
style: { minWidth: 0 },
|
|
7093
|
+
initial: isSheet ? { x: "100%", opacity: 0 } : { width: 0, opacity: 0 },
|
|
7094
|
+
animate: isSheet ? { x: 0, opacity: 1 } : { width: panelWidth, opacity: 1 },
|
|
7095
|
+
exit: isSheet ? { x: "100%", opacity: 0, transition: { x: SHEET_EXIT, opacity: SHEET_EXIT } } : { width: 0, opacity: 0, transition: { width: SHEET_EXIT, opacity: SHEET_EXIT } },
|
|
7096
|
+
transition: isSheet ? { x: SPRING, opacity: SPRING } : {
|
|
7097
|
+
width: splitOpened ? { duration: 0 } : SPRING,
|
|
7098
|
+
opacity: SPRING
|
|
7099
|
+
},
|
|
7100
|
+
onAnimationComplete: () => {
|
|
7101
|
+
if (!isSheet && !splitOpened) setSplitOpened(true);
|
|
7102
|
+
},
|
|
7103
|
+
children: [
|
|
7104
|
+
!isSheet && /* @__PURE__ */ jsx(
|
|
7105
|
+
"div",
|
|
7106
|
+
{
|
|
7107
|
+
className: "payman-v2-pdf-sheet-resize-handle",
|
|
7108
|
+
onMouseDown: onResizeMouseDown,
|
|
7109
|
+
"aria-hidden": "true",
|
|
7110
|
+
children: /* @__PURE__ */ jsx("div", { className: "payman-v2-pdf-sheet-resize-grip" })
|
|
7111
|
+
}
|
|
7112
|
+
),
|
|
7113
|
+
/* @__PURE__ */ jsxs("div", { className: "payman-v2-pdf-sheet-header", children: [
|
|
7114
|
+
/* @__PURE__ */ jsxs("div", { className: "payman-v2-pdf-sheet-header-left", children: [
|
|
7115
|
+
/* @__PURE__ */ jsx("div", { className: "payman-v2-pdf-sheet-file-icon", children: /* @__PURE__ */ jsx(FileText, { size: 14, strokeWidth: 1.75 }) }),
|
|
7116
|
+
/* @__PURE__ */ jsx("span", { className: "payman-v2-pdf-sheet-title", title, children: title || "Document" })
|
|
7117
|
+
] }),
|
|
7118
|
+
/* @__PURE__ */ jsxs("div", { className: "payman-v2-pdf-sheet-header-actions", children: [
|
|
7119
|
+
/* @__PURE__ */ jsxs(
|
|
7120
|
+
"button",
|
|
7121
|
+
{
|
|
7122
|
+
type: "button",
|
|
7123
|
+
className: "payman-v2-pdf-sheet-download-btn",
|
|
7124
|
+
"aria-label": "Download PDF",
|
|
7125
|
+
disabled: !canDownload || isDownloading,
|
|
7126
|
+
onClick: () => void handleDownload(),
|
|
7127
|
+
children: [
|
|
7128
|
+
isDownloading ? /* @__PURE__ */ jsx(Loader2, { size: 13, strokeWidth: 2, style: { animation: "payman-v2-spin 0.65s linear infinite" } }) : /* @__PURE__ */ jsx(Download, { size: 13, strokeWidth: 2 }),
|
|
7129
|
+
/* @__PURE__ */ jsx("span", { children: isDownloading ? "Downloading\u2026" : "Download" })
|
|
7130
|
+
]
|
|
7131
|
+
}
|
|
7132
|
+
),
|
|
7133
|
+
/* @__PURE__ */ jsx(
|
|
7134
|
+
"button",
|
|
7135
|
+
{
|
|
7136
|
+
type: "button",
|
|
7137
|
+
className: "payman-v2-pdf-sheet-close-btn",
|
|
7138
|
+
"aria-label": "Close preview",
|
|
7139
|
+
onClick: (e) => {
|
|
7140
|
+
e.stopPropagation();
|
|
7141
|
+
onClose();
|
|
7142
|
+
},
|
|
7143
|
+
children: /* @__PURE__ */ jsx(X, { size: 15, strokeWidth: 2.25 })
|
|
7144
|
+
}
|
|
7145
|
+
)
|
|
7146
|
+
] })
|
|
7147
|
+
] }),
|
|
7148
|
+
/* @__PURE__ */ jsx("div", { className: "payman-v2-pdf-sheet-body", children: previewError ? /* @__PURE__ */ jsxs("div", { className: "payman-v2-pdf-sheet-error", role: "alert", children: [
|
|
7149
|
+
/* @__PURE__ */ jsx("div", { className: "payman-v2-pdf-sheet-error-icon", children: /* @__PURE__ */ jsx(AlertCircle, { size: 22, strokeWidth: 1.75 }) }),
|
|
7150
|
+
/* @__PURE__ */ jsx("p", { className: "payman-v2-pdf-sheet-error-title", children: previewError.title }),
|
|
7151
|
+
/* @__PURE__ */ jsx("p", { className: "payman-v2-pdf-sheet-error-message", children: previewError.userMessage }),
|
|
7152
|
+
/* @__PURE__ */ jsxs("div", { className: "payman-v2-pdf-sheet-error-actions", children: [
|
|
7153
|
+
previewError.kind === "network" && /* @__PURE__ */ jsxs(
|
|
7154
|
+
"button",
|
|
7155
|
+
{
|
|
7156
|
+
type: "button",
|
|
7157
|
+
className: "payman-v2-pdf-sheet-error-btn",
|
|
7158
|
+
onClick: handleRetry,
|
|
7159
|
+
children: [
|
|
7160
|
+
/* @__PURE__ */ jsx(RefreshCw, { size: 14, strokeWidth: 2 }),
|
|
7161
|
+
/* @__PURE__ */ jsx("span", { children: "Try again" })
|
|
7162
|
+
]
|
|
7163
|
+
}
|
|
7164
|
+
),
|
|
7165
|
+
(previewError.kind === "network" || previewError.kind === "unknown") && /* @__PURE__ */ jsxs(
|
|
7166
|
+
"button",
|
|
7167
|
+
{
|
|
7168
|
+
type: "button",
|
|
7169
|
+
className: "payman-v2-pdf-sheet-error-btn payman-v2-pdf-sheet-error-btn-secondary",
|
|
7170
|
+
onClick: handleOpenInNewTab,
|
|
7171
|
+
children: [
|
|
7172
|
+
/* @__PURE__ */ jsx(ExternalLink, { size: 14, strokeWidth: 2 }),
|
|
7173
|
+
/* @__PURE__ */ jsx("span", { children: "Open link" })
|
|
7174
|
+
]
|
|
7175
|
+
}
|
|
7176
|
+
)
|
|
7177
|
+
] })
|
|
7178
|
+
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
7179
|
+
(!isLoaded || !previewUrl) && /* @__PURE__ */ jsxs("div", { className: "payman-v2-pdf-sheet-loading", children: [
|
|
7180
|
+
/* @__PURE__ */ jsx(
|
|
7181
|
+
Loader2,
|
|
7182
|
+
{
|
|
7183
|
+
size: 20,
|
|
7184
|
+
strokeWidth: 2,
|
|
7185
|
+
style: { animation: "payman-v2-spin 0.65s linear infinite", color: "var(--payman-v2-text-3)" }
|
|
7186
|
+
}
|
|
7187
|
+
),
|
|
7188
|
+
/* @__PURE__ */ jsx("p", { className: "payman-v2-pdf-sheet-loading-text", children: previewUrl ? "Preparing preview\u2026" : "Opening document\u2026" })
|
|
7189
|
+
] }),
|
|
7190
|
+
previewUrl && /* @__PURE__ */ jsx(
|
|
7191
|
+
"iframe",
|
|
7192
|
+
{
|
|
7193
|
+
src: previewUrl,
|
|
7194
|
+
title: title || "PDF Preview",
|
|
7195
|
+
className: "payman-v2-pdf-sheet-iframe",
|
|
7196
|
+
style: {
|
|
7197
|
+
opacity: isLoaded ? 1 : 0,
|
|
7198
|
+
transition: "opacity 0.3s ease",
|
|
7199
|
+
pointerEvents: isDragging ? "none" : "auto"
|
|
7200
|
+
},
|
|
7201
|
+
onLoad: () => setIsLoaded(true)
|
|
7202
|
+
},
|
|
7203
|
+
previewUrl
|
|
7204
|
+
)
|
|
7205
|
+
] }) })
|
|
7206
|
+
]
|
|
7207
|
+
}
|
|
7208
|
+
);
|
|
7209
|
+
}
|
|
5968
7210
|
var DEFAULT_USER_ACTION_STATE = {
|
|
5969
7211
|
prompts: [],
|
|
5970
7212
|
notifications: []
|
|
@@ -6059,7 +7301,8 @@ var PaymanChatInner = forwardRef(function PaymanChatInner2({
|
|
|
6059
7301
|
onLoadMoreMessages,
|
|
6060
7302
|
isLoadingMoreMessages = false,
|
|
6061
7303
|
hasMoreMessages = false,
|
|
6062
|
-
chat
|
|
7304
|
+
chat,
|
|
7305
|
+
attachmentUpload
|
|
6063
7306
|
}, ref) {
|
|
6064
7307
|
const [inputValue, setInputValue] = useState("");
|
|
6065
7308
|
const prevInputValueRef = useRef(inputValue);
|
|
@@ -6113,7 +7356,6 @@ var PaymanChatInner = forwardRef(function PaymanChatInner2({
|
|
|
6113
7356
|
const submitUserAction2 = chat.submitUserAction ?? NOOP_ASYNC;
|
|
6114
7357
|
const cancelUserAction2 = chat.cancelUserAction ?? NOOP_ASYNC;
|
|
6115
7358
|
const resendUserAction2 = chat.resendUserAction ?? NOOP_ASYNC;
|
|
6116
|
-
const expireUserAction2 = chat.expireUserAction ?? NOOP_ASYNC;
|
|
6117
7359
|
const dismissNotification = chat.dismissNotification ?? NOOP;
|
|
6118
7360
|
const isUserActionSupported = typeof chat.submitUserAction === "function" && typeof chat.cancelUserAction === "function" && typeof chat.resendUserAction === "function";
|
|
6119
7361
|
const {
|
|
@@ -6139,6 +7381,19 @@ var PaymanChatInner = forwardRef(function PaymanChatInner2({
|
|
|
6139
7381
|
}
|
|
6140
7382
|
}
|
|
6141
7383
|
);
|
|
7384
|
+
const [pdfSheet, setPdfSheet] = useState(null);
|
|
7385
|
+
const autoOpenedPdfHrefsRef = useRef(/* @__PURE__ */ new Set());
|
|
7386
|
+
const pdfPreviewMode = config.pdfPreviewMode ?? "split";
|
|
7387
|
+
const openPdfSheet = useCallback((href, title, options) => {
|
|
7388
|
+
if (options?.auto) {
|
|
7389
|
+
if (autoOpenedPdfHrefsRef.current.has(href)) return;
|
|
7390
|
+
autoOpenedPdfHrefsRef.current.add(href);
|
|
7391
|
+
}
|
|
7392
|
+
setPdfSheet({ href, title });
|
|
7393
|
+
}, []);
|
|
7394
|
+
const closePdfSheet = useCallback(() => {
|
|
7395
|
+
setPdfSheet(null);
|
|
7396
|
+
}, []);
|
|
6142
7397
|
const contextValue = useMemo(
|
|
6143
7398
|
() => ({
|
|
6144
7399
|
resetSession,
|
|
@@ -6147,7 +7402,8 @@ var PaymanChatInner = forwardRef(function PaymanChatInner2({
|
|
|
6147
7402
|
cancelStream,
|
|
6148
7403
|
getSessionId,
|
|
6149
7404
|
getMessages,
|
|
6150
|
-
isWaitingForResponse
|
|
7405
|
+
isWaitingForResponse,
|
|
7406
|
+
openPdfSheet
|
|
6151
7407
|
}),
|
|
6152
7408
|
[
|
|
6153
7409
|
resetSession,
|
|
@@ -6156,7 +7412,8 @@ var PaymanChatInner = forwardRef(function PaymanChatInner2({
|
|
|
6156
7412
|
cancelStream,
|
|
6157
7413
|
getSessionId,
|
|
6158
7414
|
getMessages,
|
|
6159
|
-
isWaitingForResponse
|
|
7415
|
+
isWaitingForResponse,
|
|
7416
|
+
openPdfSheet
|
|
6160
7417
|
]
|
|
6161
7418
|
);
|
|
6162
7419
|
const {
|
|
@@ -6212,7 +7469,10 @@ var PaymanChatInner = forwardRef(function PaymanChatInner2({
|
|
|
6212
7469
|
setInputValue("");
|
|
6213
7470
|
setLightboxSrc(null);
|
|
6214
7471
|
setLightboxAlt("");
|
|
7472
|
+
setPdfSheet(null);
|
|
7473
|
+
autoOpenedPdfHrefsRef.current.clear();
|
|
6215
7474
|
chatInputV2Ref.current?.setDraft("");
|
|
7475
|
+
chatInputV2Ref.current?.clearAttachments();
|
|
6216
7476
|
clearTranscript();
|
|
6217
7477
|
if (isRecording) {
|
|
6218
7478
|
stopRecording();
|
|
@@ -6263,14 +7523,20 @@ var PaymanChatInner = forwardRef(function PaymanChatInner2({
|
|
|
6263
7523
|
emptyStateComponent,
|
|
6264
7524
|
showResetSession = false,
|
|
6265
7525
|
enableDeepModeToggle = true,
|
|
6266
|
-
showAttachmentButton = true,
|
|
6267
|
-
showUploadImageButton = true,
|
|
6268
|
-
showAttachFileButton = true,
|
|
6269
7526
|
messageActions: messageActionsConfig,
|
|
6270
7527
|
enableSlashCommands = true,
|
|
6271
7528
|
slashCommands: slashCommandsConfig,
|
|
6272
7529
|
commandPermissions
|
|
6273
7530
|
} = config;
|
|
7531
|
+
const attachmentSettings = useMemo(
|
|
7532
|
+
() => resolveChatAttachmentConfig(config),
|
|
7533
|
+
[
|
|
7534
|
+
config.attachments,
|
|
7535
|
+
config.showAttachmentButton,
|
|
7536
|
+
config.showUploadImageButton,
|
|
7537
|
+
config.showAttachFileButton
|
|
7538
|
+
]
|
|
7539
|
+
);
|
|
6274
7540
|
const messageActions = useMemo(
|
|
6275
7541
|
() => ({
|
|
6276
7542
|
userMessageActions: {
|
|
@@ -6358,11 +7624,22 @@ var PaymanChatInner = forwardRef(function PaymanChatInner2({
|
|
|
6358
7624
|
};
|
|
6359
7625
|
const userActionPrompts = isUserActionSupported ? userActionState.prompts : void 0;
|
|
6360
7626
|
const notifications = userActionState.notifications;
|
|
6361
|
-
const
|
|
7627
|
+
const handleAttachmentsChange = useCallback(
|
|
7628
|
+
(attachments) => {
|
|
7629
|
+
attachmentUpload.syncAttachments(attachments);
|
|
7630
|
+
},
|
|
7631
|
+
[attachmentUpload]
|
|
7632
|
+
);
|
|
7633
|
+
const handleV2Send = (text, files = [], attachments = []) => {
|
|
6362
7634
|
if (isRecording) stopRecording();
|
|
6363
|
-
if (text.trim() && !disableInput && isSessionParamsConfigured) {
|
|
7635
|
+
if ((text.trim() || files.length > 0) && !disableInput && isSessionParamsConfigured) {
|
|
7636
|
+
if (files.length > 0 && attachments.length === 0) return;
|
|
6364
7637
|
setEditingMessageId(null);
|
|
6365
|
-
void sendMessage(text.trim(), {
|
|
7638
|
+
void sendMessage(text.trim(), {
|
|
7639
|
+
analysisMode: effectiveAnalysisMode,
|
|
7640
|
+
attachments,
|
|
7641
|
+
files
|
|
7642
|
+
});
|
|
6366
7643
|
}
|
|
6367
7644
|
};
|
|
6368
7645
|
const handleVoicePress = useCallback(async () => {
|
|
@@ -6410,156 +7687,214 @@ var PaymanChatInner = forwardRef(function PaymanChatInner2({
|
|
|
6410
7687
|
style,
|
|
6411
7688
|
children: [
|
|
6412
7689
|
children,
|
|
6413
|
-
/* @__PURE__ */
|
|
6414
|
-
|
|
7690
|
+
/* @__PURE__ */ jsxs(
|
|
7691
|
+
"div",
|
|
6415
7692
|
{
|
|
6416
|
-
|
|
6417
|
-
|
|
6418
|
-
|
|
6419
|
-
|
|
6420
|
-
|
|
6421
|
-
|
|
6422
|
-
/* @__PURE__ */ jsx(
|
|
6423
|
-
MessageList,
|
|
6424
|
-
{
|
|
6425
|
-
messages,
|
|
6426
|
-
isLoading: false,
|
|
6427
|
-
emptyStateText,
|
|
6428
|
-
showEmptyStateIcon,
|
|
6429
|
-
emptyStateComponent,
|
|
6430
|
-
layout,
|
|
6431
|
-
showTimestamps,
|
|
6432
|
-
stage: config.stage || "DEVELOPMENT",
|
|
6433
|
-
animated,
|
|
6434
|
-
showAgentName,
|
|
6435
|
-
agentName,
|
|
6436
|
-
showAvatars,
|
|
6437
|
-
showUserAvatar,
|
|
6438
|
-
showAssistantAvatar,
|
|
6439
|
-
showExecutionSteps,
|
|
6440
|
-
showStreamingDot,
|
|
6441
|
-
streamingStepsText,
|
|
6442
|
-
completedStepsText,
|
|
6443
|
-
onExecutionTraceClick,
|
|
6444
|
-
onLoadMoreMessages,
|
|
6445
|
-
isLoadingMoreMessages,
|
|
6446
|
-
hasMoreMessages
|
|
6447
|
-
}
|
|
6448
|
-
),
|
|
6449
|
-
/* @__PURE__ */ jsx(
|
|
7693
|
+
className: cn(
|
|
7694
|
+
"payman-v2-split-layout",
|
|
7695
|
+
pdfPreviewMode === "sheet" && "payman-v2-split-layout--sheet"
|
|
7696
|
+
),
|
|
7697
|
+
children: [
|
|
7698
|
+
/* @__PURE__ */ jsx("div", { className: "payman-v2-chat-column", children: /* @__PURE__ */ jsx(AnimatePresence, { mode: "wait", children: isEmpty && !hasEverSentMessage ? /* @__PURE__ */ jsx(
|
|
6450
7699
|
motion.div,
|
|
6451
7700
|
{
|
|
6452
|
-
initial: { opacity:
|
|
6453
|
-
|
|
6454
|
-
transition: {
|
|
6455
|
-
|
|
6456
|
-
|
|
6457
|
-
|
|
6458
|
-
|
|
6459
|
-
|
|
6460
|
-
|
|
6461
|
-
|
|
6462
|
-
|
|
6463
|
-
|
|
6464
|
-
|
|
6465
|
-
|
|
6466
|
-
|
|
6467
|
-
|
|
6468
|
-
|
|
6469
|
-
|
|
6470
|
-
|
|
6471
|
-
|
|
6472
|
-
|
|
6473
|
-
|
|
6474
|
-
|
|
6475
|
-
|
|
6476
|
-
|
|
6477
|
-
|
|
6478
|
-
|
|
6479
|
-
|
|
6480
|
-
|
|
6481
|
-
|
|
6482
|
-
|
|
6483
|
-
|
|
6484
|
-
|
|
6485
|
-
|
|
6486
|
-
|
|
6487
|
-
|
|
6488
|
-
|
|
6489
|
-
|
|
6490
|
-
|
|
6491
|
-
|
|
6492
|
-
|
|
6493
|
-
|
|
6494
|
-
|
|
6495
|
-
|
|
6496
|
-
|
|
6497
|
-
|
|
6498
|
-
|
|
6499
|
-
|
|
6500
|
-
|
|
7701
|
+
initial: { opacity: 1 },
|
|
7702
|
+
exit: { opacity: 0 },
|
|
7703
|
+
transition: { duration: 0.3 },
|
|
7704
|
+
className: "payman-v2-chat-layout",
|
|
7705
|
+
style: { justifyContent: "center", alignItems: "center" },
|
|
7706
|
+
children: /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", flex: 1, width: "100%" }, children: [
|
|
7707
|
+
/* @__PURE__ */ jsx(
|
|
7708
|
+
MessageList,
|
|
7709
|
+
{
|
|
7710
|
+
messages,
|
|
7711
|
+
isLoading: false,
|
|
7712
|
+
emptyStateText,
|
|
7713
|
+
showEmptyStateIcon,
|
|
7714
|
+
emptyStateComponent,
|
|
7715
|
+
layout,
|
|
7716
|
+
showTimestamps,
|
|
7717
|
+
stage: config.stage || "DEVELOPMENT",
|
|
7718
|
+
animated,
|
|
7719
|
+
showAgentName,
|
|
7720
|
+
agentName,
|
|
7721
|
+
showAvatars,
|
|
7722
|
+
showUserAvatar,
|
|
7723
|
+
showAssistantAvatar,
|
|
7724
|
+
showExecutionSteps,
|
|
7725
|
+
showStreamingDot,
|
|
7726
|
+
streamingStepsText,
|
|
7727
|
+
completedStepsText,
|
|
7728
|
+
onExecutionTraceClick,
|
|
7729
|
+
onLoadMoreMessages,
|
|
7730
|
+
isLoadingMoreMessages,
|
|
7731
|
+
hasMoreMessages
|
|
7732
|
+
}
|
|
7733
|
+
),
|
|
7734
|
+
/* @__PURE__ */ jsx(
|
|
7735
|
+
motion.div,
|
|
7736
|
+
{
|
|
7737
|
+
initial: { opacity: 0, y: 12 },
|
|
7738
|
+
animate: { opacity: 1, y: 0 },
|
|
7739
|
+
transition: { delay: 0.2, duration: 0.4, ease: [0.25, 0.46, 0.45, 0.94] },
|
|
7740
|
+
style: { width: "100%" },
|
|
7741
|
+
children: hasAskPermission && /* @__PURE__ */ jsx(
|
|
7742
|
+
ChatInputV2,
|
|
7743
|
+
{
|
|
7744
|
+
ref: chatInputV2Ref,
|
|
7745
|
+
onSend: handleV2Send,
|
|
7746
|
+
onCancel: cancelStream,
|
|
7747
|
+
disabled: isV2InputDisabled,
|
|
7748
|
+
isStreaming: isWaitingForResponse,
|
|
7749
|
+
isUploadingAttachments: attachmentUpload.isUploading,
|
|
7750
|
+
attachmentsReady: attachmentUpload.allReady,
|
|
7751
|
+
hasAttachmentUploadErrors: attachmentUpload.hasErrors,
|
|
7752
|
+
attachmentUploadStatusById: attachmentUpload.statusById,
|
|
7753
|
+
uploadedAttachmentPayloads: attachmentUpload.payloads,
|
|
7754
|
+
onAttachmentsChange: handleAttachmentsChange,
|
|
7755
|
+
placeholder: isRecording ? "Listening..." : placeholder,
|
|
7756
|
+
enableVoice: config.enableVoice === true,
|
|
7757
|
+
transcribedText: config.enableVoice === true ? transcribedText : "",
|
|
7758
|
+
voiceAvailable: config.enableVoice === true && voiceAvailable,
|
|
7759
|
+
isRecording,
|
|
7760
|
+
onVoicePress: config.enableVoice === true ? handleVoicePress : void 0,
|
|
7761
|
+
onCancelRecording: handleCancelRecording,
|
|
7762
|
+
onConfirmRecording: handleConfirmRecording,
|
|
7763
|
+
showResetSession,
|
|
7764
|
+
onResetSession: requestResetSession,
|
|
7765
|
+
showAttachmentButton: attachmentSettings.showAttachmentButton,
|
|
7766
|
+
showUploadImageButton: attachmentSettings.showUploadImageButton,
|
|
7767
|
+
showAttachFileButton: attachmentSettings.showAttachFileButton,
|
|
7768
|
+
allowedImageExtensions: attachmentSettings.allowedImageExtensions,
|
|
7769
|
+
allowedFileExtensions: attachmentSettings.allowedFileExtensions,
|
|
7770
|
+
maxCount: attachmentSettings.maxCount,
|
|
7771
|
+
maxFileBytes: attachmentSettings.maxFileBytes,
|
|
7772
|
+
maxTotalBytes: attachmentSettings.maxTotalBytes,
|
|
7773
|
+
onUploadImageClick,
|
|
7774
|
+
onAttachFileClick,
|
|
7775
|
+
editingMessageId,
|
|
7776
|
+
onClearEditing: handleClearEditing,
|
|
7777
|
+
analysisMode: enableDeepModeToggle ? analysisMode : void 0,
|
|
7778
|
+
onAnalysisModeChange: enableDeepModeToggle ? setAnalysisMode : void 0,
|
|
7779
|
+
slashCommands
|
|
7780
|
+
}
|
|
7781
|
+
)
|
|
7782
|
+
}
|
|
7783
|
+
)
|
|
7784
|
+
] })
|
|
7785
|
+
},
|
|
7786
|
+
"v2-empty"
|
|
7787
|
+
) : /* @__PURE__ */ jsxs(
|
|
7788
|
+
motion.div,
|
|
6501
7789
|
{
|
|
6502
|
-
|
|
6503
|
-
|
|
6504
|
-
|
|
6505
|
-
|
|
6506
|
-
|
|
6507
|
-
|
|
6508
|
-
|
|
6509
|
-
|
|
6510
|
-
|
|
6511
|
-
|
|
6512
|
-
|
|
6513
|
-
|
|
6514
|
-
|
|
6515
|
-
|
|
6516
|
-
|
|
6517
|
-
|
|
6518
|
-
|
|
6519
|
-
|
|
6520
|
-
|
|
6521
|
-
|
|
6522
|
-
|
|
6523
|
-
|
|
7790
|
+
initial: hasEverSentMessage ? { opacity: 0 } : false,
|
|
7791
|
+
animate: { opacity: 1 },
|
|
7792
|
+
transition: { duration: 0.3 },
|
|
7793
|
+
className: "payman-v2-chat-layout",
|
|
7794
|
+
children: [
|
|
7795
|
+
/* @__PURE__ */ jsx(
|
|
7796
|
+
MessageListV2,
|
|
7797
|
+
{
|
|
7798
|
+
ref: messageListV2Ref,
|
|
7799
|
+
messages,
|
|
7800
|
+
isStreaming: isWaitingForResponse,
|
|
7801
|
+
sidePanelOpen: !!pdfSheet,
|
|
7802
|
+
onEditUserMessage: handleEditMessageDraft,
|
|
7803
|
+
onRetryUserMessage: handleRetryUserMessage,
|
|
7804
|
+
onImageClick: handleImageClick,
|
|
7805
|
+
onExecutionTraceClick,
|
|
7806
|
+
messageActions,
|
|
7807
|
+
retryDisabled: isWaitingForResponse,
|
|
7808
|
+
typingSpeed: config.typingSpeed ?? 4,
|
|
7809
|
+
userActionPrompts,
|
|
7810
|
+
notifications,
|
|
7811
|
+
onSubmitUserAction: isUserActionSupported ? submitUserAction2 : void 0,
|
|
7812
|
+
onCancelUserAction: isUserActionSupported ? cancelUserAction2 : void 0,
|
|
7813
|
+
onResendUserAction: isUserActionSupported ? resendUserAction2 : void 0,
|
|
7814
|
+
onDismissNotification: dismissNotification,
|
|
7815
|
+
onSubmitFeedback: handleSubmitFeedback
|
|
7816
|
+
}
|
|
7817
|
+
),
|
|
7818
|
+
/* @__PURE__ */ jsx(
|
|
7819
|
+
StreamingIndicatorV2,
|
|
7820
|
+
{
|
|
7821
|
+
isStreaming: isWaitingForResponse,
|
|
7822
|
+
loadingAnimation: config.loadingAnimation
|
|
7823
|
+
}
|
|
7824
|
+
),
|
|
7825
|
+
hasAskPermission && /* @__PURE__ */ jsx(
|
|
7826
|
+
ChatInputV2,
|
|
7827
|
+
{
|
|
7828
|
+
ref: chatInputV2Ref,
|
|
7829
|
+
onSend: handleV2Send,
|
|
7830
|
+
onCancel: cancelStream,
|
|
7831
|
+
disabled: isV2InputDisabled,
|
|
7832
|
+
isStreaming: isWaitingForResponse,
|
|
7833
|
+
isUploadingAttachments: attachmentUpload.isUploading,
|
|
7834
|
+
attachmentsReady: attachmentUpload.allReady,
|
|
7835
|
+
hasAttachmentUploadErrors: attachmentUpload.hasErrors,
|
|
7836
|
+
attachmentUploadStatusById: attachmentUpload.statusById,
|
|
7837
|
+
uploadedAttachmentPayloads: attachmentUpload.payloads,
|
|
7838
|
+
onAttachmentsChange: handleAttachmentsChange,
|
|
7839
|
+
placeholder: isRecording ? "Listening..." : placeholder,
|
|
7840
|
+
enableVoice: config.enableVoice === true,
|
|
7841
|
+
transcribedText: config.enableVoice === true ? transcribedText : "",
|
|
7842
|
+
voiceAvailable: config.enableVoice === true && voiceAvailable,
|
|
7843
|
+
isRecording,
|
|
7844
|
+
onVoicePress: config.enableVoice === true ? handleVoicePress : void 0,
|
|
7845
|
+
onCancelRecording: handleCancelRecording,
|
|
7846
|
+
onConfirmRecording: handleConfirmRecording,
|
|
7847
|
+
showResetSession,
|
|
7848
|
+
onResetSession: requestResetSession,
|
|
7849
|
+
showAttachmentButton: attachmentSettings.showAttachmentButton,
|
|
7850
|
+
showUploadImageButton: attachmentSettings.showUploadImageButton,
|
|
7851
|
+
showAttachFileButton: attachmentSettings.showAttachFileButton,
|
|
7852
|
+
allowedImageExtensions: attachmentSettings.allowedImageExtensions,
|
|
7853
|
+
allowedFileExtensions: attachmentSettings.allowedFileExtensions,
|
|
7854
|
+
maxCount: attachmentSettings.maxCount,
|
|
7855
|
+
maxFileBytes: attachmentSettings.maxFileBytes,
|
|
7856
|
+
maxTotalBytes: attachmentSettings.maxTotalBytes,
|
|
7857
|
+
onUploadImageClick,
|
|
7858
|
+
onAttachFileClick,
|
|
7859
|
+
editingMessageId,
|
|
7860
|
+
onClearEditing: handleClearEditing,
|
|
7861
|
+
analysisMode: enableDeepModeToggle ? analysisMode : void 0,
|
|
7862
|
+
onAnalysisModeChange: enableDeepModeToggle ? setAnalysisMode : void 0,
|
|
7863
|
+
slashCommands
|
|
7864
|
+
}
|
|
7865
|
+
)
|
|
7866
|
+
]
|
|
7867
|
+
},
|
|
7868
|
+
"v2-chat"
|
|
7869
|
+
) }) }),
|
|
7870
|
+
pdfPreviewMode === "split" && /* @__PURE__ */ jsx(
|
|
7871
|
+
PdfSheetV2,
|
|
6524
7872
|
{
|
|
6525
|
-
|
|
6526
|
-
|
|
7873
|
+
src: pdfSheet?.href ?? null,
|
|
7874
|
+
title: pdfSheet?.title ?? "",
|
|
7875
|
+
onClose: closePdfSheet,
|
|
7876
|
+
mode: "split"
|
|
6527
7877
|
}
|
|
6528
7878
|
),
|
|
6529
|
-
|
|
6530
|
-
|
|
7879
|
+
pdfPreviewMode === "sheet" && /* @__PURE__ */ jsx(
|
|
7880
|
+
"div",
|
|
6531
7881
|
{
|
|
6532
|
-
|
|
6533
|
-
|
|
6534
|
-
|
|
6535
|
-
|
|
6536
|
-
|
|
6537
|
-
|
|
6538
|
-
|
|
6539
|
-
|
|
6540
|
-
|
|
6541
|
-
|
|
6542
|
-
|
|
6543
|
-
onCancelRecording: handleCancelRecording,
|
|
6544
|
-
onConfirmRecording: handleConfirmRecording,
|
|
6545
|
-
showResetSession,
|
|
6546
|
-
onResetSession: requestResetSession,
|
|
6547
|
-
showAttachmentButton,
|
|
6548
|
-
showUploadImageButton,
|
|
6549
|
-
showAttachFileButton,
|
|
6550
|
-
onUploadImageClick,
|
|
6551
|
-
onAttachFileClick,
|
|
6552
|
-
editingMessageId,
|
|
6553
|
-
onClearEditing: handleClearEditing,
|
|
6554
|
-
analysisMode: enableDeepModeToggle ? analysisMode : void 0,
|
|
6555
|
-
onAnalysisModeChange: enableDeepModeToggle ? setAnalysisMode : void 0,
|
|
6556
|
-
slashCommands
|
|
7882
|
+
className: "payman-v2-pdf-sheet-top-anchor",
|
|
7883
|
+
"aria-hidden": !pdfSheet,
|
|
7884
|
+
children: /* @__PURE__ */ jsx(
|
|
7885
|
+
PdfSheetV2,
|
|
7886
|
+
{
|
|
7887
|
+
src: pdfSheet?.href ?? null,
|
|
7888
|
+
title: pdfSheet?.title ?? "",
|
|
7889
|
+
onClose: closePdfSheet,
|
|
7890
|
+
mode: "sheet"
|
|
7891
|
+
}
|
|
7892
|
+
)
|
|
6557
7893
|
}
|
|
6558
7894
|
)
|
|
6559
7895
|
]
|
|
6560
|
-
}
|
|
6561
|
-
|
|
6562
|
-
) }),
|
|
7896
|
+
}
|
|
7897
|
+
),
|
|
6563
7898
|
/* @__PURE__ */ jsx(
|
|
6564
7899
|
ImageLightboxV2,
|
|
6565
7900
|
{
|
|
@@ -6594,10 +7929,19 @@ var PaymanChat = forwardRef(
|
|
|
6594
7929
|
function PaymanChat2(props, ref) {
|
|
6595
7930
|
const mergedCallbacks = useSentryChatCallbacks(props.callbacks, props.config);
|
|
6596
7931
|
const chat = useChatV2(props.config, mergedCallbacks);
|
|
6597
|
-
|
|
7932
|
+
const attachmentUpload = useAttachmentUpload(props.config);
|
|
7933
|
+
return /* @__PURE__ */ jsx(
|
|
7934
|
+
PaymanChatInner,
|
|
7935
|
+
{
|
|
7936
|
+
...props,
|
|
7937
|
+
chat,
|
|
7938
|
+
attachmentUpload,
|
|
7939
|
+
ref
|
|
7940
|
+
}
|
|
7941
|
+
);
|
|
6598
7942
|
}
|
|
6599
7943
|
);
|
|
6600
7944
|
|
|
6601
|
-
export { PaymanChat, PaymanChatContext, UserActionStaleError, cancelUserAction, captureSentryError, cn,
|
|
7945
|
+
export { PaymanChat, PaymanChatContext, PdfSheetV2, UserActionStaleError, buildSignedUrlEndpoint, cancelUserAction, captureSentryError, cn, formatAttachmentBytes, formatDate, getPdfTitleFromUrl, isPdfUrl, mapExecutionHistoryPageToChatMessages, mapExecutionHistoryToChatMessages, resendUserAction, stripAttachmentsSuffixFromIntent, submitUserAction, uploadAttachment, uploadAttachments, useAttachmentUpload, useChatV2, usePaymanChat, useVoice };
|
|
6602
7946
|
//# sourceMappingURL=index.mjs.map
|
|
6603
7947
|
//# sourceMappingURL=index.mjs.map
|