@paymanai/payman-ask-sdk 4.0.18 → 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 -25
- package/dist/index.d.ts +93 -25
- package/dist/index.js +1757 -381
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1749 -384
- package/dist/index.mjs.map +1 -1
- package/dist/styles.css +484 -25
- package/dist/styles.css.map +1 -1
- package/package.json +2 -2
- package/dist/index.native.js +0 -3675
- 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/;
|
|
@@ -846,17 +854,6 @@ function useStreamManagerV2(config, callbacks, setMessages, setIsWaitingForRespo
|
|
|
846
854
|
signal: abortController.signal,
|
|
847
855
|
onEvent: (event) => {
|
|
848
856
|
if (abortController.signal.aborted) return;
|
|
849
|
-
try {
|
|
850
|
-
const et = event?.eventType;
|
|
851
|
-
if (et === "RUN_IN_PROGRESS" || et === "INTENT_PROGRESS" || et === "THINKING_DELTA") {
|
|
852
|
-
const len = (event.partialText ?? event.text ?? "").length;
|
|
853
|
-
console.log(`[stream] ${et} (+${len} chars)`);
|
|
854
|
-
} else {
|
|
855
|
-
console.log(`[stream] ${et ?? "?"}:`, JSON.stringify(event));
|
|
856
|
-
}
|
|
857
|
-
} catch {
|
|
858
|
-
console.log("[stream] (unserializable event)", event?.eventType);
|
|
859
|
-
}
|
|
860
857
|
processStreamEventV2(event, state);
|
|
861
858
|
if (state.lastUserAction) {
|
|
862
859
|
callbacksRef.current.onUserActionRequired?.(state.lastUserAction);
|
|
@@ -1052,10 +1049,85 @@ function createCancelledMessageUpdate(steps, currentMessage) {
|
|
|
1052
1049
|
currentMessage: currentMessage || "Thinking..."
|
|
1053
1050
|
};
|
|
1054
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
|
+
}
|
|
1055
1127
|
var UserActionStaleError = class extends Error {
|
|
1056
1128
|
constructor(userActionId, message = "User action is no longer actionable") {
|
|
1057
1129
|
super(message);
|
|
1058
|
-
|
|
1130
|
+
__publicField2(this, "userActionId");
|
|
1059
1131
|
this.name = "UserActionStaleError";
|
|
1060
1132
|
this.userActionId = userActionId;
|
|
1061
1133
|
}
|
|
@@ -1116,12 +1188,32 @@ function getStoredOrInitialMessages(config) {
|
|
|
1116
1188
|
function getSessionIdFromMessages(messages) {
|
|
1117
1189
|
return messages.find((message) => message.sessionId)?.sessionId;
|
|
1118
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
|
+
}
|
|
1119
1210
|
function useChatV2(config, callbacks = {}) {
|
|
1120
1211
|
const [messages, setMessages] = useState(() => getStoredOrInitialMessages(config));
|
|
1121
1212
|
const [isWaitingForResponse, setIsWaitingForResponse] = useState(() => {
|
|
1122
1213
|
if (!config.userId) return false;
|
|
1123
1214
|
return activeStreamStore.get(config.userId)?.isWaiting ?? false;
|
|
1124
1215
|
});
|
|
1216
|
+
const [isUploadingAttachments, setIsUploadingAttachments] = useState(false);
|
|
1125
1217
|
const sessionIdRef = useRef(
|
|
1126
1218
|
getSessionIdFromMessages(getStoredOrInitialMessages(config)) ?? config.initialSessionId ?? void 0
|
|
1127
1219
|
);
|
|
@@ -1196,21 +1288,45 @@ function useChatV2(config, callbacks = {}) {
|
|
|
1196
1288
|
);
|
|
1197
1289
|
const sendMessage = useCallback(
|
|
1198
1290
|
async (userMessage, options) => {
|
|
1199
|
-
|
|
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
|
+
}
|
|
1200
1309
|
if (!sessionIdRef.current && configRef.current.autoGenerateSessionId !== false) {
|
|
1201
1310
|
sessionIdRef.current = generateId();
|
|
1202
1311
|
callbacksRef.current.onSessionIdChange?.(sessionIdRef.current);
|
|
1203
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;
|
|
1204
1319
|
const userMessageId = `user-${Date.now()}`;
|
|
1205
1320
|
const userMsg = {
|
|
1206
1321
|
id: userMessageId,
|
|
1207
1322
|
sessionId: sessionIdRef.current,
|
|
1208
1323
|
role: "user",
|
|
1209
|
-
content:
|
|
1210
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
1324
|
+
content: trimmedMessage,
|
|
1325
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1326
|
+
attachments: messageAttachments
|
|
1211
1327
|
};
|
|
1212
1328
|
setMessages((prev) => [...prev, userMsg]);
|
|
1213
|
-
callbacksRef.current.onMessageSent?.(
|
|
1329
|
+
callbacksRef.current.onMessageSent?.(trimmedMessage);
|
|
1214
1330
|
setIsWaitingForResponse(true);
|
|
1215
1331
|
callbacksRef.current.onStreamStart?.();
|
|
1216
1332
|
const streamingId = `assistant-${Date.now()}`;
|
|
@@ -1237,11 +1353,14 @@ function useChatV2(config, callbacks = {}) {
|
|
|
1237
1353
|
activeStreamStore.start(userId, abortController, initialMessages);
|
|
1238
1354
|
}
|
|
1239
1355
|
const newSessionId = await startStream(
|
|
1240
|
-
|
|
1356
|
+
trimmedMessage,
|
|
1241
1357
|
streamingId,
|
|
1242
1358
|
sessionIdRef.current,
|
|
1243
1359
|
abortController,
|
|
1244
|
-
|
|
1360
|
+
{
|
|
1361
|
+
analysisMode: options?.analysisMode,
|
|
1362
|
+
attachments: streamAttachments
|
|
1363
|
+
}
|
|
1245
1364
|
);
|
|
1246
1365
|
const finalStreamUserId = streamUserIdRef.current ?? userId;
|
|
1247
1366
|
if (finalStreamUserId) {
|
|
@@ -1419,6 +1538,18 @@ function useChatV2(config, callbacks = {}) {
|
|
|
1419
1538
|
setMessages(config.initialMessages);
|
|
1420
1539
|
sessionIdRef.current = getSessionIdFromMessages(config.initialMessages) ?? config.initialSessionId;
|
|
1421
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]);
|
|
1422
1553
|
useEffect(() => {
|
|
1423
1554
|
const prevUserId = prevUserIdRef.current;
|
|
1424
1555
|
prevUserIdRef.current = config.userId;
|
|
@@ -1453,6 +1584,7 @@ function useChatV2(config, callbacks = {}) {
|
|
|
1453
1584
|
getSessionId,
|
|
1454
1585
|
getMessages,
|
|
1455
1586
|
isWaitingForResponse,
|
|
1587
|
+
isUploadingAttachments,
|
|
1456
1588
|
sessionId: sessionIdRef.current,
|
|
1457
1589
|
userActionState,
|
|
1458
1590
|
submitUserAction: submitUserAction2,
|
|
@@ -1676,6 +1808,102 @@ function useVoice(config = {}, callbacks = {}) {
|
|
|
1676
1808
|
reset
|
|
1677
1809
|
};
|
|
1678
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
|
+
}
|
|
1679
1907
|
function classifyField(field) {
|
|
1680
1908
|
if (!field) return "text";
|
|
1681
1909
|
if (Array.isArray(field.oneOf) && field.oneOf.length > 0) return "select";
|
|
@@ -1792,6 +2020,66 @@ function buildContent(schema, values) {
|
|
|
1792
2020
|
}
|
|
1793
2021
|
return content;
|
|
1794
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
|
+
}
|
|
1795
2083
|
var PaymanChatContext = createContext(void 0);
|
|
1796
2084
|
function usePaymanChat() {
|
|
1797
2085
|
const context = useContext(PaymanChatContext);
|
|
@@ -1902,6 +2190,111 @@ function subscribeToCfRay(urlPattern, listener) {
|
|
|
1902
2190
|
};
|
|
1903
2191
|
}
|
|
1904
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
|
+
|
|
1905
2298
|
// src/utils/slashCommands.ts
|
|
1906
2299
|
var DEFAULT_SLASH_COMMANDS = [
|
|
1907
2300
|
{
|
|
@@ -3053,6 +3446,108 @@ function ActionTooltipV2({ label, children }) {
|
|
|
3053
3446
|
] }) })
|
|
3054
3447
|
] });
|
|
3055
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
|
+
}
|
|
3056
3551
|
function formatMessageTime(timestamp) {
|
|
3057
3552
|
const value = new Date(timestamp);
|
|
3058
3553
|
if (Number.isNaN(value.getTime())) return "";
|
|
@@ -3065,6 +3560,7 @@ function UserMessageV2({
|
|
|
3065
3560
|
message,
|
|
3066
3561
|
onEdit,
|
|
3067
3562
|
onRetry,
|
|
3563
|
+
onImageClick,
|
|
3068
3564
|
retryDisabled = false,
|
|
3069
3565
|
actions
|
|
3070
3566
|
}) {
|
|
@@ -3147,7 +3643,15 @@ function UserMessageV2({
|
|
|
3147
3643
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
3148
3644
|
toastPortal,
|
|
3149
3645
|
/* @__PURE__ */ jsx("div", { className: "payman-v2-user-msg payman-v2-fade-in", children: /* @__PURE__ */ jsxs("div", { className: "payman-v2-user-msg-group", children: [
|
|
3150
|
-
/* @__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: [
|
|
3151
3655
|
/* @__PURE__ */ jsx("span", { className: "payman-v2-user-msg-command-chip", children: parsedCommand.command }),
|
|
3152
3656
|
parsedCommand.body.trim() ? /* @__PURE__ */ jsx("p", { className: "payman-v2-user-msg-text", children: parsedCommand.body }) : null
|
|
3153
3657
|
] }) : /* @__PURE__ */ jsx("p", { className: "payman-v2-user-msg-text", children: message.content }) }),
|
|
@@ -3372,9 +3876,44 @@ function MarkdownImageV2({
|
|
|
3372
3876
|
}
|
|
3373
3877
|
) });
|
|
3374
3878
|
}
|
|
3375
|
-
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) {
|
|
3376
3909
|
return {
|
|
3377
|
-
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
|
+
},
|
|
3378
3917
|
code: ({ children }) => /* @__PURE__ */ jsx("code", { children }),
|
|
3379
3918
|
pre: ({ children }) => /* @__PURE__ */ jsx("div", { className: "payman-v2-markdown-pre", children: /* @__PURE__ */ jsx("pre", { children }) }),
|
|
3380
3919
|
ul: ({ children }) => /* @__PURE__ */ jsx("ul", { children }),
|
|
@@ -3387,7 +3926,15 @@ function buildComponents(onImageClick, isResolvingRef) {
|
|
|
3387
3926
|
em: ({ children }) => /* @__PURE__ */ jsx("em", { children }),
|
|
3388
3927
|
blockquote: ({ children }) => /* @__PURE__ */ jsx("blockquote", { children }),
|
|
3389
3928
|
hr: () => /* @__PURE__ */ jsx("hr", {}),
|
|
3390
|
-
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
|
+
},
|
|
3391
3938
|
img: ({ src, alt }) => /* @__PURE__ */ jsx(
|
|
3392
3939
|
MarkdownImageV2,
|
|
3393
3940
|
{
|
|
@@ -3408,13 +3955,15 @@ function MarkdownRendererV2({
|
|
|
3408
3955
|
content,
|
|
3409
3956
|
isStreaming,
|
|
3410
3957
|
isResolvingImages,
|
|
3411
|
-
onImageClick
|
|
3958
|
+
onImageClick,
|
|
3959
|
+
onPdfClick,
|
|
3960
|
+
autoOpenPdf
|
|
3412
3961
|
}) {
|
|
3413
3962
|
const isResolvingRef = useRef(isResolvingImages);
|
|
3414
3963
|
isResolvingRef.current = isResolvingImages;
|
|
3415
3964
|
const components = useMemo(
|
|
3416
|
-
() => buildComponents(onImageClick, isResolvingRef),
|
|
3417
|
-
[onImageClick]
|
|
3965
|
+
() => buildComponents(onImageClick, isResolvingRef, onPdfClick, autoOpenPdf),
|
|
3966
|
+
[onImageClick, onPdfClick, autoOpenPdf]
|
|
3418
3967
|
);
|
|
3419
3968
|
return /* @__PURE__ */ jsx(
|
|
3420
3969
|
"div",
|
|
@@ -3783,6 +4332,17 @@ function stripIncompleteImageToken(text) {
|
|
|
3783
4332
|
if (/^!\[[^\]]*\]\([^)]*\)/.test(after)) return text;
|
|
3784
4333
|
return text.slice(0, lastBang);
|
|
3785
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
|
+
}
|
|
3786
4346
|
function getFeedbackState(message) {
|
|
3787
4347
|
const feedback = message.feedback;
|
|
3788
4348
|
if (feedback === "up" || feedback === "down") return feedback;
|
|
@@ -3806,6 +4366,12 @@ function AssistantMessageV2({
|
|
|
3806
4366
|
() => getFeedbackState(message)
|
|
3807
4367
|
);
|
|
3808
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
|
+
}, []);
|
|
3809
4375
|
const canSubmitFeedback = !!onSubmitFeedback && !!message.executionId;
|
|
3810
4376
|
const [toast, setToast] = useState(null);
|
|
3811
4377
|
const copyResetTimerRef = useRef(null);
|
|
@@ -3830,7 +4396,7 @@ function AssistantMessageV2({
|
|
|
3830
4396
|
const raw = message.isStreaming ? message.streamingContent || message.content : message.content;
|
|
3831
4397
|
if (!raw) return "";
|
|
3832
4398
|
const normalized = raw.replace(/\\n/g, "\n");
|
|
3833
|
-
return message.isStreaming ?
|
|
4399
|
+
return message.isStreaming ? stripIncompleteMarkdownTokens(normalized) : normalized;
|
|
3834
4400
|
})();
|
|
3835
4401
|
const isThinkingStreaming = !!message.isStreaming && !rawResponseContent && !message.isError;
|
|
3836
4402
|
const responseTypingEnabled = hasEverStreamed.current && Boolean(rawResponseContent) && !message.isError;
|
|
@@ -4000,10 +4566,12 @@ function AssistantMessageV2({
|
|
|
4000
4566
|
/* @__PURE__ */ jsx("div", { className: "payman-v2-assistant-msg-content-area", children: displayContent ? /* @__PURE__ */ jsx(
|
|
4001
4567
|
MarkdownRendererV2,
|
|
4002
4568
|
{
|
|
4003
|
-
content: displayContent,
|
|
4569
|
+
content: message.isStreaming && !isCancelled || isResponseTyping ? stripIncompleteMarkdownTokens(displayContent) : displayContent,
|
|
4004
4570
|
isStreaming: message.isStreaming && !isCancelled || isResponseTyping,
|
|
4005
4571
|
isResolvingImages: message.isResolvingImages,
|
|
4006
|
-
onImageClick
|
|
4572
|
+
onImageClick,
|
|
4573
|
+
onPdfClick: handlePdfClick,
|
|
4574
|
+
autoOpenPdf: hasEverStreamed.current
|
|
4007
4575
|
}
|
|
4008
4576
|
) : !isThinkingStreaming ? /* @__PURE__ */ jsx("span", { className: "payman-v2-assistant-msg-placeholder", children: "..." }) : null }),
|
|
4009
4577
|
isCancelled && message.isStreaming && /* @__PURE__ */ jsxs("div", { className: "payman-v2-assistant-msg-paused", children: [
|
|
@@ -4220,7 +4788,6 @@ function VerificationInline({
|
|
|
4220
4788
|
const [code, setCode] = useState("");
|
|
4221
4789
|
const [errored, setErrored] = useState(false);
|
|
4222
4790
|
const [resendSec, setResendSec] = useState(0);
|
|
4223
|
-
const [hiddenAfterResend, setHiddenAfterResend] = useState(false);
|
|
4224
4791
|
const lastSubmittedRef = useRef(null);
|
|
4225
4792
|
const resendTimerRef = useRef(void 0);
|
|
4226
4793
|
const status = prompt.status;
|
|
@@ -4234,9 +4801,6 @@ function VerificationInline({
|
|
|
4234
4801
|
lastSubmittedRef.current = null;
|
|
4235
4802
|
}
|
|
4236
4803
|
}, [prompt.subAction, prompt.userActionId]);
|
|
4237
|
-
useEffect(() => {
|
|
4238
|
-
setHiddenAfterResend(false);
|
|
4239
|
-
}, [prompt.expirySeconds, prompt.message, prompt.subAction, prompt.userActionId]);
|
|
4240
4804
|
useEffect(() => {
|
|
4241
4805
|
if (code.length < codeLen) lastSubmittedRef.current = null;
|
|
4242
4806
|
}, [code, codeLen]);
|
|
@@ -4287,13 +4851,11 @@ function VerificationInline({
|
|
|
4287
4851
|
if (locked || resendSec > 0) return;
|
|
4288
4852
|
setErrored(false);
|
|
4289
4853
|
setCode("");
|
|
4290
|
-
setHiddenAfterResend(true);
|
|
4291
4854
|
lastSubmittedRef.current = null;
|
|
4292
4855
|
try {
|
|
4293
4856
|
await onResend(prompt.userActionId);
|
|
4294
4857
|
startResendCooldown();
|
|
4295
4858
|
} catch {
|
|
4296
|
-
setHiddenAfterResend(false);
|
|
4297
4859
|
}
|
|
4298
4860
|
}, [locked, onResend, prompt.userActionId, resendSec, startResendCooldown]);
|
|
4299
4861
|
const handleCancel = useCallback(() => {
|
|
@@ -4301,7 +4863,6 @@ function VerificationInline({
|
|
|
4301
4863
|
void onCancel(prompt.userActionId);
|
|
4302
4864
|
}, [busy, onCancel, prompt.userActionId]);
|
|
4303
4865
|
const description = prompt.message?.trim() || (isNumeric ? `Enter the ${codeLen}-digit code to continue` : "Enter the verification code to continue");
|
|
4304
|
-
if (hiddenAfterResend) return null;
|
|
4305
4866
|
return /* @__PURE__ */ jsxs("div", { className: "payman-v2-ua", role: "group", "aria-label": "Verification required", children: [
|
|
4306
4867
|
/* @__PURE__ */ jsxs("div", { className: "payman-v2-ua-head", children: [
|
|
4307
4868
|
/* @__PURE__ */ jsx(ShieldCheck, { className: "payman-v2-ua-icon", size: 15, strokeWidth: 1.75, "aria-hidden": true }),
|
|
@@ -4397,9 +4958,6 @@ function SchemaFormInline({
|
|
|
4397
4958
|
const busy = status === "submitting";
|
|
4398
4959
|
const stale = status === "stale";
|
|
4399
4960
|
const locked = busy || stale || expired;
|
|
4400
|
-
const isUserConfirmation = prompt.subAction === "UserConfirmation";
|
|
4401
|
-
const messageFormat = prompt.metadata?.["payman/messageFormat"];
|
|
4402
|
-
const renderMarkdown = messageFormat === "markdown";
|
|
4403
4961
|
const setValue = (key, value) => {
|
|
4404
4962
|
setValues((prev) => ({ ...prev, [key]: value }));
|
|
4405
4963
|
setErrors((prev) => {
|
|
@@ -4425,8 +4983,8 @@ function SchemaFormInline({
|
|
|
4425
4983
|
/* @__PURE__ */ jsx("span", { className: "payman-v2-ua-title", children: "Action required" }),
|
|
4426
4984
|
typeof secondsLeft === "number" && !stale && /* @__PURE__ */ jsx("span", { className: "payman-v2-ua-timer", children: expired ? "Expired" : `${secondsLeft}s` })
|
|
4427
4985
|
] }),
|
|
4428
|
-
prompt.message?.trim() &&
|
|
4429
|
-
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]) => {
|
|
4430
4988
|
const widget = classifyField(field);
|
|
4431
4989
|
const label = field.title || key;
|
|
4432
4990
|
const required = isRequired(schema, key);
|
|
@@ -4499,7 +5057,7 @@ function SchemaFormInline({
|
|
|
4499
5057
|
className: "payman-v2-ua-btn payman-v2-ua-btn-primary",
|
|
4500
5058
|
disabled: locked,
|
|
4501
5059
|
onClick: handleSubmit,
|
|
4502
|
-
children: busy ? "Submitting\u2026" :
|
|
5060
|
+
children: busy ? "Submitting\u2026" : "Submit"
|
|
4503
5061
|
}
|
|
4504
5062
|
),
|
|
4505
5063
|
/* @__PURE__ */ jsx(
|
|
@@ -4555,25 +5113,10 @@ function useExpiryCountdown(prompt) {
|
|
|
4555
5113
|
const expired = initial !== void 0 && secondsLeft === 0;
|
|
4556
5114
|
return [secondsLeft, expired];
|
|
4557
5115
|
}
|
|
4558
|
-
function UserActionInline({
|
|
4559
|
-
prompt,
|
|
4560
|
-
onSubmit,
|
|
4561
|
-
onCancel,
|
|
4562
|
-
onResend,
|
|
4563
|
-
onExpired
|
|
4564
|
-
}) {
|
|
5116
|
+
function UserActionInline({ prompt, onSubmit, onCancel, onResend }) {
|
|
4565
5117
|
const [secondsLeft, expired] = useExpiryCountdown(prompt);
|
|
4566
|
-
useEffect(() => {
|
|
4567
|
-
if (expired && prompt.kind !== "notification") onExpired?.();
|
|
4568
|
-
}, [expired, onExpired, prompt.kind]);
|
|
4569
5118
|
let body;
|
|
4570
|
-
if (
|
|
4571
|
-
const note = {
|
|
4572
|
-
id: `${prompt.userActionId}-expired`,
|
|
4573
|
-
message: prompt.kind === "verification" ? "Verification Request Expired" : "User Form Expired"
|
|
4574
|
-
};
|
|
4575
|
-
body = /* @__PURE__ */ jsx(NotificationInline, { notification: note });
|
|
4576
|
-
} else if (prompt.kind === "verification") {
|
|
5119
|
+
if (prompt.kind === "verification") {
|
|
4577
5120
|
body = /* @__PURE__ */ jsx(
|
|
4578
5121
|
VerificationInline,
|
|
4579
5122
|
{
|
|
@@ -4613,23 +5156,10 @@ function UserActionInline({
|
|
|
4613
5156
|
}
|
|
4614
5157
|
var SCROLL_THRESHOLD2 = 100;
|
|
4615
5158
|
var USER_SCROLL_UP_EPSILON = 4;
|
|
4616
|
-
var PROMPT_KEY_SEPARATOR = "";
|
|
4617
|
-
function getPromptSlotKey(prompt) {
|
|
4618
|
-
return prompt.toolCallId || prompt.userActionId;
|
|
4619
|
-
}
|
|
4620
|
-
function getPromptViewKey(prompt) {
|
|
4621
|
-
return [
|
|
4622
|
-
getPromptSlotKey(prompt),
|
|
4623
|
-
prompt.userActionId,
|
|
4624
|
-
prompt.subAction ?? "",
|
|
4625
|
-
prompt.expirySeconds ?? "",
|
|
4626
|
-
prompt.message ?? ""
|
|
4627
|
-
].join(PROMPT_KEY_SEPARATOR);
|
|
4628
|
-
}
|
|
4629
5159
|
var MessageListV2 = forwardRef(
|
|
4630
5160
|
function MessageListV22({
|
|
4631
5161
|
messages,
|
|
4632
|
-
isStreaming = false,
|
|
5162
|
+
isStreaming: _isStreaming = false,
|
|
4633
5163
|
onEditUserMessage,
|
|
4634
5164
|
onRetryUserMessage,
|
|
4635
5165
|
onImageClick,
|
|
@@ -4643,7 +5173,8 @@ var MessageListV2 = forwardRef(
|
|
|
4643
5173
|
onResendUserAction,
|
|
4644
5174
|
onDismissNotification,
|
|
4645
5175
|
onSubmitFeedback,
|
|
4646
|
-
typingSpeed = 4
|
|
5176
|
+
typingSpeed = 4,
|
|
5177
|
+
sidePanelOpen = false
|
|
4647
5178
|
}, ref) {
|
|
4648
5179
|
const noop = useCallback(async () => {
|
|
4649
5180
|
}, []);
|
|
@@ -4651,10 +5182,11 @@ var MessageListV2 = forwardRef(
|
|
|
4651
5182
|
const scrollInnerRef = useRef(null);
|
|
4652
5183
|
const isNearBottomRef = useRef(true);
|
|
4653
5184
|
const [showScrollBtn, setShowScrollBtn] = useState(false);
|
|
4654
|
-
const [expiredPromptViewState, setExpiredPromptViewState] = useState({});
|
|
4655
5185
|
const prevCountRef = useRef(messages.length);
|
|
4656
5186
|
const pauseStickUntilUserMessageRef = useRef(false);
|
|
4657
5187
|
const followingBottomRef = useRef(true);
|
|
5188
|
+
const sidePanelOpenRef = useRef(sidePanelOpen);
|
|
5189
|
+
sidePanelOpenRef.current = sidePanelOpen;
|
|
4658
5190
|
const lastPinAtRef = useRef(0);
|
|
4659
5191
|
const prevScrollTopRef = useRef(0);
|
|
4660
5192
|
const getDistanceFromBottom = useCallback(() => {
|
|
@@ -4662,81 +5194,6 @@ var MessageListV2 = forwardRef(
|
|
|
4662
5194
|
if (!el) return 0;
|
|
4663
5195
|
return el.scrollHeight - el.scrollTop - el.clientHeight;
|
|
4664
5196
|
}, []);
|
|
4665
|
-
const messageActivityFingerprint = useMemo(() => {
|
|
4666
|
-
const last = messages[messages.length - 1];
|
|
4667
|
-
const promptFingerprint = (userActionPrompts ?? []).map((prompt) => `${getPromptViewKey(prompt)}:${prompt.status}`).join(PROMPT_KEY_SEPARATOR);
|
|
4668
|
-
const notificationFingerprint = (notifications ?? []).map((notification) => notification.id).join(PROMPT_KEY_SEPARATOR);
|
|
4669
|
-
if (!last) {
|
|
4670
|
-
return [
|
|
4671
|
-
0,
|
|
4672
|
-
isStreaming ? "streaming" : "idle",
|
|
4673
|
-
promptFingerprint,
|
|
4674
|
-
notificationFingerprint
|
|
4675
|
-
].join(PROMPT_KEY_SEPARATOR);
|
|
4676
|
-
}
|
|
4677
|
-
return [
|
|
4678
|
-
messages.length,
|
|
4679
|
-
isStreaming ? "streaming" : "idle",
|
|
4680
|
-
last.id,
|
|
4681
|
-
last.role,
|
|
4682
|
-
last.content ?? "",
|
|
4683
|
-
last.isStreaming ? "streaming" : "done",
|
|
4684
|
-
last.streamProgress ?? "",
|
|
4685
|
-
last.steps?.length ?? 0,
|
|
4686
|
-
last.errorDetails ?? "",
|
|
4687
|
-
promptFingerprint,
|
|
4688
|
-
notificationFingerprint
|
|
4689
|
-
].join(PROMPT_KEY_SEPARATOR);
|
|
4690
|
-
}, [isStreaming, messages, notifications, userActionPrompts]);
|
|
4691
|
-
const handleUserActionExpired = useCallback(
|
|
4692
|
-
(promptKey) => {
|
|
4693
|
-
setExpiredPromptViewState((prev) => {
|
|
4694
|
-
if (prev[promptKey]) return prev;
|
|
4695
|
-
return {
|
|
4696
|
-
...prev,
|
|
4697
|
-
[promptKey]: { baseline: messageActivityFingerprint, hidden: false }
|
|
4698
|
-
};
|
|
4699
|
-
});
|
|
4700
|
-
},
|
|
4701
|
-
[messageActivityFingerprint]
|
|
4702
|
-
);
|
|
4703
|
-
useEffect(() => {
|
|
4704
|
-
setExpiredPromptViewState((prev) => {
|
|
4705
|
-
let changed = false;
|
|
4706
|
-
const next = {};
|
|
4707
|
-
for (const [key, state] of Object.entries(prev)) {
|
|
4708
|
-
if (!state.hidden && state.baseline !== messageActivityFingerprint) {
|
|
4709
|
-
next[key] = { ...state, hidden: true };
|
|
4710
|
-
changed = true;
|
|
4711
|
-
} else {
|
|
4712
|
-
next[key] = state;
|
|
4713
|
-
}
|
|
4714
|
-
}
|
|
4715
|
-
return changed ? next : prev;
|
|
4716
|
-
});
|
|
4717
|
-
}, [messageActivityFingerprint]);
|
|
4718
|
-
useEffect(() => {
|
|
4719
|
-
const livePromptKeys = new Set((userActionPrompts ?? []).map(getPromptViewKey));
|
|
4720
|
-
setExpiredPromptViewState((prev) => {
|
|
4721
|
-
let changed = false;
|
|
4722
|
-
const next = {};
|
|
4723
|
-
for (const [key, state] of Object.entries(prev)) {
|
|
4724
|
-
if (livePromptKeys.has(key)) {
|
|
4725
|
-
next[key] = state;
|
|
4726
|
-
} else {
|
|
4727
|
-
changed = true;
|
|
4728
|
-
}
|
|
4729
|
-
}
|
|
4730
|
-
return changed ? next : prev;
|
|
4731
|
-
});
|
|
4732
|
-
}, [userActionPrompts]);
|
|
4733
|
-
const visibleUserActionPrompts = useMemo(
|
|
4734
|
-
() => userActionPrompts?.filter((prompt) => {
|
|
4735
|
-
const promptKey = getPromptViewKey(prompt);
|
|
4736
|
-
return !expiredPromptViewState[promptKey]?.hidden;
|
|
4737
|
-
}),
|
|
4738
|
-
[expiredPromptViewState, userActionPrompts]
|
|
4739
|
-
);
|
|
4740
5197
|
const pinToBottom = useCallback((behavior = "instant") => {
|
|
4741
5198
|
const el = scrollRef.current;
|
|
4742
5199
|
if (!el) return;
|
|
@@ -4777,17 +5234,25 @@ var MessageListV2 = forwardRef(
|
|
|
4777
5234
|
const nearBottom = distance <= SCROLL_THRESHOLD2;
|
|
4778
5235
|
isNearBottomRef.current = nearBottom;
|
|
4779
5236
|
setShowScrollBtn(!nearBottom);
|
|
4780
|
-
const sincePin = performance.now() - lastPinAtRef.current;
|
|
4781
|
-
if (sincePin < 250) return;
|
|
4782
5237
|
const scrolledUp = currentScrollTop < prevScrollTop - USER_SCROLL_UP_EPSILON;
|
|
4783
5238
|
if (scrolledUp) {
|
|
4784
5239
|
followingBottomRef.current = false;
|
|
4785
5240
|
pauseStickUntilUserMessageRef.current = true;
|
|
4786
|
-
|
|
5241
|
+
return;
|
|
5242
|
+
}
|
|
5243
|
+
const sincePin = performance.now() - lastPinAtRef.current;
|
|
5244
|
+
if (sincePin < 250) return;
|
|
5245
|
+
if (nearBottom) {
|
|
4787
5246
|
followingBottomRef.current = true;
|
|
4788
5247
|
pauseStickUntilUserMessageRef.current = false;
|
|
4789
5248
|
}
|
|
4790
5249
|
}, [getDistanceFromBottom]);
|
|
5250
|
+
const handleWheel = useCallback((e) => {
|
|
5251
|
+
if (e.deltaY < 0) {
|
|
5252
|
+
followingBottomRef.current = false;
|
|
5253
|
+
pauseStickUntilUserMessageRef.current = true;
|
|
5254
|
+
}
|
|
5255
|
+
}, []);
|
|
4791
5256
|
useEffect(() => {
|
|
4792
5257
|
const prevCount = prevCountRef.current;
|
|
4793
5258
|
prevCountRef.current = messages.length;
|
|
@@ -4797,7 +5262,7 @@ var MessageListV2 = forwardRef(
|
|
|
4797
5262
|
pauseStickUntilUserMessageRef.current = false;
|
|
4798
5263
|
followingBottomRef.current = true;
|
|
4799
5264
|
requestAnimationFrame(() => scrollToBottom());
|
|
4800
|
-
} else if (!pauseStickUntilUserMessageRef.current && followingBottomRef.current) {
|
|
5265
|
+
} else if (!sidePanelOpenRef.current && !pauseStickUntilUserMessageRef.current && followingBottomRef.current) {
|
|
4801
5266
|
requestAnimationFrame(() => scrollToBottom("instant"));
|
|
4802
5267
|
}
|
|
4803
5268
|
}
|
|
@@ -4806,27 +5271,16 @@ var MessageListV2 = forwardRef(
|
|
|
4806
5271
|
const inner = scrollInnerRef.current;
|
|
4807
5272
|
if (!inner) return;
|
|
4808
5273
|
const pinIfFollowing = () => {
|
|
5274
|
+
if (sidePanelOpenRef.current) return;
|
|
4809
5275
|
if (pauseStickUntilUserMessageRef.current) return;
|
|
4810
5276
|
if (!followingBottomRef.current) return;
|
|
5277
|
+
if (getDistanceFromBottom() > SCROLL_THRESHOLD2) return;
|
|
4811
5278
|
pinToBottom("instant");
|
|
4812
5279
|
};
|
|
4813
|
-
const ro = new ResizeObserver(
|
|
4814
|
-
pinIfFollowing();
|
|
4815
|
-
});
|
|
5280
|
+
const ro = new ResizeObserver(pinIfFollowing);
|
|
4816
5281
|
ro.observe(inner);
|
|
4817
|
-
|
|
4818
|
-
|
|
4819
|
-
});
|
|
4820
|
-
mo.observe(inner, {
|
|
4821
|
-
childList: true,
|
|
4822
|
-
subtree: true,
|
|
4823
|
-
characterData: true
|
|
4824
|
-
});
|
|
4825
|
-
return () => {
|
|
4826
|
-
ro.disconnect();
|
|
4827
|
-
mo.disconnect();
|
|
4828
|
-
};
|
|
4829
|
-
}, [pinToBottom]);
|
|
5282
|
+
return () => ro.disconnect();
|
|
5283
|
+
}, [pinToBottom, getDistanceFromBottom]);
|
|
4830
5284
|
useEffect(() => {
|
|
4831
5285
|
if (messages.length > 0) {
|
|
4832
5286
|
setTimeout(() => scrollToBottom("instant"), 50);
|
|
@@ -4838,6 +5292,7 @@ var MessageListV2 = forwardRef(
|
|
|
4838
5292
|
{
|
|
4839
5293
|
ref: scrollRef,
|
|
4840
5294
|
onScroll: handleScroll,
|
|
5295
|
+
onWheel: handleWheel,
|
|
4841
5296
|
className: "payman-v2-message-scroll payman-v2-scrollbar",
|
|
4842
5297
|
children: /* @__PURE__ */ jsxs(
|
|
4843
5298
|
"div",
|
|
@@ -4851,6 +5306,7 @@ var MessageListV2 = forwardRef(
|
|
|
4851
5306
|
message,
|
|
4852
5307
|
onEdit: onEditUserMessage,
|
|
4853
5308
|
onRetry: onRetryUserMessage,
|
|
5309
|
+
onImageClick,
|
|
4854
5310
|
retryDisabled,
|
|
4855
5311
|
actions: messageActions?.userMessageActions
|
|
4856
5312
|
}
|
|
@@ -4873,20 +5329,16 @@ var MessageListV2 = forwardRef(
|
|
|
4873
5329
|
},
|
|
4874
5330
|
note.id
|
|
4875
5331
|
)),
|
|
4876
|
-
|
|
4877
|
-
|
|
4878
|
-
|
|
4879
|
-
|
|
4880
|
-
|
|
4881
|
-
|
|
4882
|
-
|
|
4883
|
-
|
|
4884
|
-
|
|
4885
|
-
|
|
4886
|
-
},
|
|
4887
|
-
promptKey
|
|
4888
|
-
);
|
|
4889
|
-
})
|
|
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
|
+
))
|
|
4890
5342
|
]
|
|
4891
5343
|
}
|
|
4892
5344
|
)
|
|
@@ -4916,45 +5368,281 @@ var MessageListV2 = forwardRef(
|
|
|
4916
5368
|
] });
|
|
4917
5369
|
}
|
|
4918
5370
|
);
|
|
4919
|
-
|
|
4920
|
-
|
|
4921
|
-
|
|
4922
|
-
|
|
4923
|
-
|
|
4924
|
-
|
|
4925
|
-
|
|
4926
|
-
|
|
4927
|
-
|
|
4928
|
-
|
|
4929
|
-
|
|
4930
|
-
|
|
4931
|
-
|
|
4932
|
-
|
|
4933
|
-
|
|
4934
|
-
|
|
4935
|
-
|
|
4936
|
-
|
|
4937
|
-
|
|
4938
|
-
|
|
4939
|
-
|
|
4940
|
-
|
|
4941
|
-
|
|
4942
|
-
|
|
4943
|
-
|
|
4944
|
-
|
|
4945
|
-
|
|
4946
|
-
|
|
4947
|
-
|
|
4948
|
-
|
|
4949
|
-
|
|
4950
|
-
|
|
4951
|
-
|
|
4952
|
-
|
|
4953
|
-
|
|
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 = []
|
|
5511
|
+
}, ref) {
|
|
5512
|
+
const [value, setValue] = useState("");
|
|
5513
|
+
const [isFocused, setIsFocused] = useState(false);
|
|
5514
|
+
const [showActions, setShowActions] = useState(false);
|
|
5515
|
+
const [showVoiceTooltip, setShowVoiceTooltip] = useState(false);
|
|
5516
|
+
const [selectedCommandIndex, setSelectedCommandIndex] = useState(0);
|
|
5517
|
+
const [inlineHint, setInlineHint] = useState(null);
|
|
5518
|
+
const [commandMenuDismissed, setCommandMenuDismissed] = useState(false);
|
|
5519
|
+
const [attachedFiles, setAttachedFiles] = useState([]);
|
|
5520
|
+
const [previewFile, setPreviewFile] = useState(null);
|
|
5521
|
+
const [isSending, setIsSending] = useState(false);
|
|
5522
|
+
const textareaRef = useRef(null);
|
|
5523
|
+
const actionsRef = useRef(null);
|
|
5524
|
+
const imageInputRef = useRef(null);
|
|
5525
|
+
const fileInputRef = useRef(null);
|
|
5526
|
+
const preRecordTextRef = useRef("");
|
|
5527
|
+
const voiceTooltipTimerRef = useRef(
|
|
4954
5528
|
null
|
|
4955
5529
|
);
|
|
4956
5530
|
const voiceDraftSyncActiveRef = useRef(false);
|
|
4957
|
-
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;
|
|
4958
5646
|
const hasAttachmentOptions = showUploadImageButton || showAttachFileButton;
|
|
4959
5647
|
const showAttachmentMenuButton = showAttachmentButton && hasAttachmentOptions;
|
|
4960
5648
|
const showVoiceButton = enableVoice && onVoicePress != null;
|
|
@@ -4994,9 +5682,10 @@ var ChatInputV2 = forwardRef(
|
|
|
4994
5682
|
const end = message.length;
|
|
4995
5683
|
textarea.setSelectionRange(end, end);
|
|
4996
5684
|
});
|
|
4997
|
-
}
|
|
5685
|
+
},
|
|
5686
|
+
clearAttachments: clearAttachmentsFromInput
|
|
4998
5687
|
}),
|
|
4999
|
-
[disabled]
|
|
5688
|
+
[disabled, clearAttachmentsFromInput]
|
|
5000
5689
|
);
|
|
5001
5690
|
useEffect(() => {
|
|
5002
5691
|
if (!showActions) return;
|
|
@@ -5030,8 +5719,23 @@ var ChatInputV2 = forwardRef(
|
|
|
5030
5719
|
const separator = base && !base.endsWith(" ") && transcribedText ? " " : "";
|
|
5031
5720
|
setValue(`${base}${separator}${transcribedText}`);
|
|
5032
5721
|
}, [isRecording, transcribedText]);
|
|
5033
|
-
|
|
5034
|
-
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
|
+
}
|
|
5035
5739
|
const commandHint = getSlashCommandValidationHint(value);
|
|
5036
5740
|
if (commandHint) {
|
|
5037
5741
|
setInlineHint(commandHint);
|
|
@@ -5041,15 +5745,38 @@ var ChatInputV2 = forwardRef(
|
|
|
5041
5745
|
preRecordTextRef.current = "";
|
|
5042
5746
|
setInlineHint(null);
|
|
5043
5747
|
onClearEditing?.();
|
|
5044
|
-
|
|
5748
|
+
const textToSend = value.trim();
|
|
5749
|
+
const filesToSend = attachedFiles.map((f) => f.file);
|
|
5750
|
+
const attachmentsToSend = [...uploadedAttachmentPayloads];
|
|
5045
5751
|
setValue("");
|
|
5752
|
+
clearAttachmentsFromInput();
|
|
5046
5753
|
requestAnimationFrame(() => {
|
|
5047
5754
|
if (textareaRef.current) {
|
|
5048
5755
|
textareaRef.current.style.height = "auto";
|
|
5049
5756
|
textareaRef.current.focus();
|
|
5050
5757
|
}
|
|
5051
5758
|
});
|
|
5052
|
-
|
|
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
|
+
]);
|
|
5053
5780
|
const selectCommand = useCallback(
|
|
5054
5781
|
(command) => {
|
|
5055
5782
|
const insertText = command.insertText ?? `${command.name} `;
|
|
@@ -5094,18 +5821,30 @@ var ChatInputV2 = forwardRef(
|
|
|
5094
5821
|
}
|
|
5095
5822
|
if (e.key === "Enter" && !e.shiftKey) {
|
|
5096
5823
|
e.preventDefault();
|
|
5097
|
-
if (isStreaming) return;
|
|
5098
|
-
handleSend();
|
|
5824
|
+
if (isStreaming || isSending || isUploadingAttachments) return;
|
|
5825
|
+
void handleSend();
|
|
5099
5826
|
}
|
|
5100
5827
|
};
|
|
5101
5828
|
const handleUploadImageClick = () => {
|
|
5829
|
+
imageInputRef.current?.click();
|
|
5102
5830
|
onUploadImageClick?.();
|
|
5103
5831
|
setShowActions(false);
|
|
5104
5832
|
};
|
|
5105
5833
|
const handleAttachFileClick = () => {
|
|
5834
|
+
fileInputRef.current?.click();
|
|
5106
5835
|
onAttachFileClick?.();
|
|
5107
5836
|
setShowActions(false);
|
|
5108
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
|
+
};
|
|
5109
5848
|
const hideVoiceTooltip = useCallback(() => {
|
|
5110
5849
|
if (voiceTooltipTimerRef.current) {
|
|
5111
5850
|
clearTimeout(voiceTooltipTimerRef.current);
|
|
@@ -5133,9 +5872,39 @@ var ChatInputV2 = forwardRef(
|
|
|
5133
5872
|
}
|
|
5134
5873
|
onVoicePress();
|
|
5135
5874
|
};
|
|
5136
|
-
const canSend = value.trim().length > 0 && !disabled;
|
|
5137
|
-
const sendDisabled = !canSend || isStreaming;
|
|
5875
|
+
const canSend = (value.trim().length > 0 || attachedFiles.length > 0) && !disabled;
|
|
5876
|
+
const sendDisabled = !canSend || isStreaming || isUploadingAttachments || !attachmentsReady || hasAttachmentUploadErrors || isSending;
|
|
5138
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
|
+
),
|
|
5139
5908
|
/* @__PURE__ */ jsx(AnimatePresence, { children: showCommandSuggestions && /* @__PURE__ */ jsx(
|
|
5140
5909
|
motion.div,
|
|
5141
5910
|
{
|
|
@@ -5174,6 +5943,115 @@ var ChatInputV2 = forwardRef(
|
|
|
5174
5943
|
),
|
|
5175
5944
|
children: [
|
|
5176
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
|
+
) }),
|
|
5177
6055
|
/* @__PURE__ */ jsx(AnimatePresence, { initial: false, children: editingMessageId && /* @__PURE__ */ jsxs(
|
|
5178
6056
|
motion.div,
|
|
5179
6057
|
{
|
|
@@ -5405,13 +6283,13 @@ var ChatInputV2 = forwardRef(
|
|
|
5405
6283
|
"button",
|
|
5406
6284
|
{
|
|
5407
6285
|
type: "button",
|
|
5408
|
-
onClick: handleSend,
|
|
6286
|
+
onClick: () => void handleSend(),
|
|
5409
6287
|
disabled: sendDisabled,
|
|
5410
6288
|
className: cn(
|
|
5411
6289
|
"payman-v2-input-send-btn",
|
|
5412
6290
|
sendDisabled && "payman-v2-input-send-btn-disabled"
|
|
5413
6291
|
),
|
|
5414
|
-
"aria-label": "Send message",
|
|
6292
|
+
"aria-label": isUploadingAttachments || isSending ? "Uploading attachments" : "Send message",
|
|
5415
6293
|
children: /* @__PURE__ */ jsx(
|
|
5416
6294
|
ArrowUp,
|
|
5417
6295
|
{
|
|
@@ -5946,6 +6824,389 @@ function TimelineBars({
|
|
|
5946
6824
|
)
|
|
5947
6825
|
] });
|
|
5948
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
|
+
}
|
|
5949
7210
|
var DEFAULT_USER_ACTION_STATE = {
|
|
5950
7211
|
prompts: [],
|
|
5951
7212
|
notifications: []
|
|
@@ -6040,7 +7301,8 @@ var PaymanChatInner = forwardRef(function PaymanChatInner2({
|
|
|
6040
7301
|
onLoadMoreMessages,
|
|
6041
7302
|
isLoadingMoreMessages = false,
|
|
6042
7303
|
hasMoreMessages = false,
|
|
6043
|
-
chat
|
|
7304
|
+
chat,
|
|
7305
|
+
attachmentUpload
|
|
6044
7306
|
}, ref) {
|
|
6045
7307
|
const [inputValue, setInputValue] = useState("");
|
|
6046
7308
|
const prevInputValueRef = useRef(inputValue);
|
|
@@ -6119,6 +7381,19 @@ var PaymanChatInner = forwardRef(function PaymanChatInner2({
|
|
|
6119
7381
|
}
|
|
6120
7382
|
}
|
|
6121
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
|
+
}, []);
|
|
6122
7397
|
const contextValue = useMemo(
|
|
6123
7398
|
() => ({
|
|
6124
7399
|
resetSession,
|
|
@@ -6127,7 +7402,8 @@ var PaymanChatInner = forwardRef(function PaymanChatInner2({
|
|
|
6127
7402
|
cancelStream,
|
|
6128
7403
|
getSessionId,
|
|
6129
7404
|
getMessages,
|
|
6130
|
-
isWaitingForResponse
|
|
7405
|
+
isWaitingForResponse,
|
|
7406
|
+
openPdfSheet
|
|
6131
7407
|
}),
|
|
6132
7408
|
[
|
|
6133
7409
|
resetSession,
|
|
@@ -6136,7 +7412,8 @@ var PaymanChatInner = forwardRef(function PaymanChatInner2({
|
|
|
6136
7412
|
cancelStream,
|
|
6137
7413
|
getSessionId,
|
|
6138
7414
|
getMessages,
|
|
6139
|
-
isWaitingForResponse
|
|
7415
|
+
isWaitingForResponse,
|
|
7416
|
+
openPdfSheet
|
|
6140
7417
|
]
|
|
6141
7418
|
);
|
|
6142
7419
|
const {
|
|
@@ -6192,7 +7469,10 @@ var PaymanChatInner = forwardRef(function PaymanChatInner2({
|
|
|
6192
7469
|
setInputValue("");
|
|
6193
7470
|
setLightboxSrc(null);
|
|
6194
7471
|
setLightboxAlt("");
|
|
7472
|
+
setPdfSheet(null);
|
|
7473
|
+
autoOpenedPdfHrefsRef.current.clear();
|
|
6195
7474
|
chatInputV2Ref.current?.setDraft("");
|
|
7475
|
+
chatInputV2Ref.current?.clearAttachments();
|
|
6196
7476
|
clearTranscript();
|
|
6197
7477
|
if (isRecording) {
|
|
6198
7478
|
stopRecording();
|
|
@@ -6243,14 +7523,20 @@ var PaymanChatInner = forwardRef(function PaymanChatInner2({
|
|
|
6243
7523
|
emptyStateComponent,
|
|
6244
7524
|
showResetSession = false,
|
|
6245
7525
|
enableDeepModeToggle = true,
|
|
6246
|
-
showAttachmentButton = true,
|
|
6247
|
-
showUploadImageButton = true,
|
|
6248
|
-
showAttachFileButton = true,
|
|
6249
7526
|
messageActions: messageActionsConfig,
|
|
6250
7527
|
enableSlashCommands = true,
|
|
6251
7528
|
slashCommands: slashCommandsConfig,
|
|
6252
7529
|
commandPermissions
|
|
6253
7530
|
} = config;
|
|
7531
|
+
const attachmentSettings = useMemo(
|
|
7532
|
+
() => resolveChatAttachmentConfig(config),
|
|
7533
|
+
[
|
|
7534
|
+
config.attachments,
|
|
7535
|
+
config.showAttachmentButton,
|
|
7536
|
+
config.showUploadImageButton,
|
|
7537
|
+
config.showAttachFileButton
|
|
7538
|
+
]
|
|
7539
|
+
);
|
|
6254
7540
|
const messageActions = useMemo(
|
|
6255
7541
|
() => ({
|
|
6256
7542
|
userMessageActions: {
|
|
@@ -6338,11 +7624,22 @@ var PaymanChatInner = forwardRef(function PaymanChatInner2({
|
|
|
6338
7624
|
};
|
|
6339
7625
|
const userActionPrompts = isUserActionSupported ? userActionState.prompts : void 0;
|
|
6340
7626
|
const notifications = userActionState.notifications;
|
|
6341
|
-
const
|
|
7627
|
+
const handleAttachmentsChange = useCallback(
|
|
7628
|
+
(attachments) => {
|
|
7629
|
+
attachmentUpload.syncAttachments(attachments);
|
|
7630
|
+
},
|
|
7631
|
+
[attachmentUpload]
|
|
7632
|
+
);
|
|
7633
|
+
const handleV2Send = (text, files = [], attachments = []) => {
|
|
6342
7634
|
if (isRecording) stopRecording();
|
|
6343
|
-
if (text.trim() && !disableInput && isSessionParamsConfigured) {
|
|
7635
|
+
if ((text.trim() || files.length > 0) && !disableInput && isSessionParamsConfigured) {
|
|
7636
|
+
if (files.length > 0 && attachments.length === 0) return;
|
|
6344
7637
|
setEditingMessageId(null);
|
|
6345
|
-
void sendMessage(text.trim(), {
|
|
7638
|
+
void sendMessage(text.trim(), {
|
|
7639
|
+
analysisMode: effectiveAnalysisMode,
|
|
7640
|
+
attachments,
|
|
7641
|
+
files
|
|
7642
|
+
});
|
|
6346
7643
|
}
|
|
6347
7644
|
};
|
|
6348
7645
|
const handleVoicePress = useCallback(async () => {
|
|
@@ -6390,155 +7687,214 @@ var PaymanChatInner = forwardRef(function PaymanChatInner2({
|
|
|
6390
7687
|
style,
|
|
6391
7688
|
children: [
|
|
6392
7689
|
children,
|
|
6393
|
-
/* @__PURE__ */
|
|
6394
|
-
|
|
7690
|
+
/* @__PURE__ */ jsxs(
|
|
7691
|
+
"div",
|
|
6395
7692
|
{
|
|
6396
|
-
|
|
6397
|
-
|
|
6398
|
-
|
|
6399
|
-
|
|
6400
|
-
|
|
6401
|
-
|
|
6402
|
-
/* @__PURE__ */ jsx(
|
|
6403
|
-
MessageList,
|
|
6404
|
-
{
|
|
6405
|
-
messages,
|
|
6406
|
-
isLoading: false,
|
|
6407
|
-
emptyStateText,
|
|
6408
|
-
showEmptyStateIcon,
|
|
6409
|
-
emptyStateComponent,
|
|
6410
|
-
layout,
|
|
6411
|
-
showTimestamps,
|
|
6412
|
-
stage: config.stage || "DEVELOPMENT",
|
|
6413
|
-
animated,
|
|
6414
|
-
showAgentName,
|
|
6415
|
-
agentName,
|
|
6416
|
-
showAvatars,
|
|
6417
|
-
showUserAvatar,
|
|
6418
|
-
showAssistantAvatar,
|
|
6419
|
-
showExecutionSteps,
|
|
6420
|
-
showStreamingDot,
|
|
6421
|
-
streamingStepsText,
|
|
6422
|
-
completedStepsText,
|
|
6423
|
-
onExecutionTraceClick,
|
|
6424
|
-
onLoadMoreMessages,
|
|
6425
|
-
isLoadingMoreMessages,
|
|
6426
|
-
hasMoreMessages
|
|
6427
|
-
}
|
|
6428
|
-
),
|
|
6429
|
-
/* @__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(
|
|
6430
7699
|
motion.div,
|
|
6431
7700
|
{
|
|
6432
|
-
initial: { opacity:
|
|
6433
|
-
|
|
6434
|
-
transition: {
|
|
6435
|
-
|
|
6436
|
-
|
|
6437
|
-
|
|
6438
|
-
|
|
6439
|
-
|
|
6440
|
-
|
|
6441
|
-
|
|
6442
|
-
|
|
6443
|
-
|
|
6444
|
-
|
|
6445
|
-
|
|
6446
|
-
|
|
6447
|
-
|
|
6448
|
-
|
|
6449
|
-
|
|
6450
|
-
|
|
6451
|
-
|
|
6452
|
-
|
|
6453
|
-
|
|
6454
|
-
|
|
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
|
-
|
|
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,
|
|
6481
7789
|
{
|
|
6482
|
-
|
|
6483
|
-
|
|
6484
|
-
|
|
6485
|
-
|
|
6486
|
-
|
|
6487
|
-
|
|
6488
|
-
|
|
6489
|
-
|
|
6490
|
-
|
|
6491
|
-
|
|
6492
|
-
|
|
6493
|
-
|
|
6494
|
-
|
|
6495
|
-
|
|
6496
|
-
|
|
6497
|
-
|
|
6498
|
-
|
|
6499
|
-
|
|
6500
|
-
|
|
6501
|
-
|
|
6502
|
-
|
|
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,
|
|
6503
7872
|
{
|
|
6504
|
-
|
|
6505
|
-
|
|
7873
|
+
src: pdfSheet?.href ?? null,
|
|
7874
|
+
title: pdfSheet?.title ?? "",
|
|
7875
|
+
onClose: closePdfSheet,
|
|
7876
|
+
mode: "split"
|
|
6506
7877
|
}
|
|
6507
7878
|
),
|
|
6508
|
-
|
|
6509
|
-
|
|
7879
|
+
pdfPreviewMode === "sheet" && /* @__PURE__ */ jsx(
|
|
7880
|
+
"div",
|
|
6510
7881
|
{
|
|
6511
|
-
|
|
6512
|
-
|
|
6513
|
-
|
|
6514
|
-
|
|
6515
|
-
|
|
6516
|
-
|
|
6517
|
-
|
|
6518
|
-
|
|
6519
|
-
|
|
6520
|
-
|
|
6521
|
-
|
|
6522
|
-
onCancelRecording: handleCancelRecording,
|
|
6523
|
-
onConfirmRecording: handleConfirmRecording,
|
|
6524
|
-
showResetSession,
|
|
6525
|
-
onResetSession: requestResetSession,
|
|
6526
|
-
showAttachmentButton,
|
|
6527
|
-
showUploadImageButton,
|
|
6528
|
-
showAttachFileButton,
|
|
6529
|
-
onUploadImageClick,
|
|
6530
|
-
onAttachFileClick,
|
|
6531
|
-
editingMessageId,
|
|
6532
|
-
onClearEditing: handleClearEditing,
|
|
6533
|
-
analysisMode: enableDeepModeToggle ? analysisMode : void 0,
|
|
6534
|
-
onAnalysisModeChange: enableDeepModeToggle ? setAnalysisMode : void 0,
|
|
6535
|
-
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
|
+
)
|
|
6536
7893
|
}
|
|
6537
7894
|
)
|
|
6538
7895
|
]
|
|
6539
|
-
}
|
|
6540
|
-
|
|
6541
|
-
) }),
|
|
7896
|
+
}
|
|
7897
|
+
),
|
|
6542
7898
|
/* @__PURE__ */ jsx(
|
|
6543
7899
|
ImageLightboxV2,
|
|
6544
7900
|
{
|
|
@@ -6573,10 +7929,19 @@ var PaymanChat = forwardRef(
|
|
|
6573
7929
|
function PaymanChat2(props, ref) {
|
|
6574
7930
|
const mergedCallbacks = useSentryChatCallbacks(props.callbacks, props.config);
|
|
6575
7931
|
const chat = useChatV2(props.config, mergedCallbacks);
|
|
6576
|
-
|
|
7932
|
+
const attachmentUpload = useAttachmentUpload(props.config);
|
|
7933
|
+
return /* @__PURE__ */ jsx(
|
|
7934
|
+
PaymanChatInner,
|
|
7935
|
+
{
|
|
7936
|
+
...props,
|
|
7937
|
+
chat,
|
|
7938
|
+
attachmentUpload,
|
|
7939
|
+
ref
|
|
7940
|
+
}
|
|
7941
|
+
);
|
|
6577
7942
|
}
|
|
6578
7943
|
);
|
|
6579
7944
|
|
|
6580
|
-
export { PaymanChat, PaymanChatContext, UserActionStaleError, cancelUserAction, captureSentryError, cn, formatDate, resendUserAction, submitUserAction, useChatV2, usePaymanChat, useVoice };
|
|
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 };
|
|
6581
7946
|
//# sourceMappingURL=index.mjs.map
|
|
6582
7947
|
//# sourceMappingURL=index.mjs.map
|