@kite-copilot/chat-panel 0.2.52 → 0.2.53
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/auto.cjs +445 -135
- package/dist/auto.d.cts +1 -1
- package/dist/auto.d.ts +1 -1
- package/dist/auto.js +1 -1
- package/dist/{chunk-KIOKMXFF.js → chunk-VXJQZR5G.js} +446 -136
- package/dist/{createKiteChat-DeQKgFyx.d.cts → createKiteChat-Cl1sNjam.d.cts} +6 -2
- package/dist/{createKiteChat-DeQKgFyx.d.ts → createKiteChat-Cl1sNjam.d.ts} +6 -2
- package/dist/embed.global.js +26 -22
- package/dist/index.cjs +445 -135
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/styles.css +1 -1
- package/package.json +1 -1
package/dist/auto.cjs
CHANGED
|
@@ -1066,29 +1066,29 @@ function DataRenderer({ type, data }) {
|
|
|
1066
1066
|
// src/components/TypingIndicator.tsx
|
|
1067
1067
|
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
1068
1068
|
function TypingIndicator({ className = "" }) {
|
|
1069
|
-
return /* @__PURE__ */ (0, import_jsx_runtime9.
|
|
1069
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: `flex items-center gap-1.5 ${className}`, children: [
|
|
1070
1070
|
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1071
1071
|
"span",
|
|
1072
1072
|
{
|
|
1073
|
-
className: "w-2 h-2 bg-gray-
|
|
1073
|
+
className: "w-2 h-2 bg-gray-500 rounded-full animate-bounce",
|
|
1074
1074
|
style: { animationDelay: "0ms", animationDuration: "600ms" }
|
|
1075
1075
|
}
|
|
1076
1076
|
),
|
|
1077
1077
|
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1078
1078
|
"span",
|
|
1079
1079
|
{
|
|
1080
|
-
className: "w-2 h-2 bg-gray-
|
|
1080
|
+
className: "w-2 h-2 bg-gray-500 rounded-full animate-bounce",
|
|
1081
1081
|
style: { animationDelay: "150ms", animationDuration: "600ms" }
|
|
1082
1082
|
}
|
|
1083
1083
|
),
|
|
1084
1084
|
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1085
1085
|
"span",
|
|
1086
1086
|
{
|
|
1087
|
-
className: "w-2 h-2 bg-gray-
|
|
1087
|
+
className: "w-2 h-2 bg-gray-500 rounded-full animate-bounce",
|
|
1088
1088
|
style: { animationDelay: "300ms", animationDuration: "600ms" }
|
|
1089
1089
|
}
|
|
1090
1090
|
)
|
|
1091
|
-
] })
|
|
1091
|
+
] });
|
|
1092
1092
|
}
|
|
1093
1093
|
|
|
1094
1094
|
// src/ChatPanel.tsx
|
|
@@ -1537,6 +1537,78 @@ function AuthErrorState({
|
|
|
1537
1537
|
)
|
|
1538
1538
|
] });
|
|
1539
1539
|
}
|
|
1540
|
+
function ImageLightbox({
|
|
1541
|
+
imageUrl,
|
|
1542
|
+
onClose
|
|
1543
|
+
}) {
|
|
1544
|
+
const handleDownload = async () => {
|
|
1545
|
+
try {
|
|
1546
|
+
const response = await fetch(imageUrl);
|
|
1547
|
+
const blob = await response.blob();
|
|
1548
|
+
const url = window.URL.createObjectURL(blob);
|
|
1549
|
+
const a = document.createElement("a");
|
|
1550
|
+
a.href = url;
|
|
1551
|
+
const urlParts = imageUrl.split("/");
|
|
1552
|
+
const filename = urlParts[urlParts.length - 1] || "image.jpg";
|
|
1553
|
+
a.download = filename;
|
|
1554
|
+
document.body.appendChild(a);
|
|
1555
|
+
a.click();
|
|
1556
|
+
document.body.removeChild(a);
|
|
1557
|
+
window.URL.revokeObjectURL(url);
|
|
1558
|
+
} catch (error) {
|
|
1559
|
+
console.error("Failed to download image:", error);
|
|
1560
|
+
window.open(imageUrl, "_blank");
|
|
1561
|
+
}
|
|
1562
|
+
};
|
|
1563
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
1564
|
+
"div",
|
|
1565
|
+
{
|
|
1566
|
+
className: "fixed inset-0 z-[100] flex items-center justify-center bg-black/80",
|
|
1567
|
+
onClick: onClose,
|
|
1568
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
1569
|
+
"div",
|
|
1570
|
+
{
|
|
1571
|
+
className: "relative max-w-[90vw] max-h-[90vh] flex flex-col items-center",
|
|
1572
|
+
onClick: (e) => e.stopPropagation(),
|
|
1573
|
+
children: [
|
|
1574
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
1575
|
+
"img",
|
|
1576
|
+
{
|
|
1577
|
+
src: imageUrl,
|
|
1578
|
+
alt: "Full size preview",
|
|
1579
|
+
className: "max-w-full max-h-[80vh] object-contain rounded-lg"
|
|
1580
|
+
}
|
|
1581
|
+
),
|
|
1582
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex gap-3 mt-4", children: [
|
|
1583
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
1584
|
+
"button",
|
|
1585
|
+
{
|
|
1586
|
+
onClick: handleDownload,
|
|
1587
|
+
className: "flex items-center gap-2 px-4 py-2 bg-white text-gray-800 rounded-lg hover:bg-gray-100 transition-colors text-sm font-medium",
|
|
1588
|
+
children: [
|
|
1589
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react4.Download, { className: "h-4 w-4" }),
|
|
1590
|
+
"Download"
|
|
1591
|
+
]
|
|
1592
|
+
}
|
|
1593
|
+
),
|
|
1594
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
1595
|
+
"button",
|
|
1596
|
+
{
|
|
1597
|
+
onClick: onClose,
|
|
1598
|
+
className: "flex items-center gap-2 px-4 py-2 bg-gray-700 text-white rounded-lg hover:bg-gray-600 transition-colors text-sm font-medium",
|
|
1599
|
+
children: [
|
|
1600
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react4.X, { className: "h-4 w-4" }),
|
|
1601
|
+
"Close"
|
|
1602
|
+
]
|
|
1603
|
+
}
|
|
1604
|
+
)
|
|
1605
|
+
] })
|
|
1606
|
+
]
|
|
1607
|
+
}
|
|
1608
|
+
)
|
|
1609
|
+
}
|
|
1610
|
+
);
|
|
1611
|
+
}
|
|
1540
1612
|
function ChatPanel({
|
|
1541
1613
|
isOpen = true,
|
|
1542
1614
|
onClose,
|
|
@@ -1557,7 +1629,8 @@ function ChatPanel({
|
|
|
1557
1629
|
initialCorner = "bottom-left",
|
|
1558
1630
|
onCornerChange,
|
|
1559
1631
|
productBackendUrl,
|
|
1560
|
-
getAuthHeaders
|
|
1632
|
+
getAuthHeaders,
|
|
1633
|
+
isEval = false
|
|
1561
1634
|
} = {}) {
|
|
1562
1635
|
const [messages, setMessages] = React6.useState(initialMessages);
|
|
1563
1636
|
const [input, setInput] = React6.useState("");
|
|
@@ -1667,13 +1740,20 @@ function ChatPanel({
|
|
|
1667
1740
|
}, [effectiveSupabaseUrl, effectiveSupabaseAnonKey]);
|
|
1668
1741
|
React6.useEffect(() => {
|
|
1669
1742
|
if (!isEscalated || !sessionId || !supabaseRef.current) {
|
|
1743
|
+
console.log("[KiteChat] Typing channel skip - isEscalated:", isEscalated, "sessionId:", sessionId, "supabase:", !!supabaseRef.current);
|
|
1670
1744
|
return;
|
|
1671
1745
|
}
|
|
1672
1746
|
const channelName = `typing:${sessionId}`;
|
|
1673
|
-
|
|
1747
|
+
console.log("[KiteChat] Subscribing to typing channel:", channelName, "sessionId:", sessionId);
|
|
1748
|
+
const channel = supabaseRef.current.channel(channelName, {
|
|
1749
|
+
config: { broadcast: { self: true } }
|
|
1750
|
+
});
|
|
1674
1751
|
channel.on("broadcast", { event: "typing" }, (payload) => {
|
|
1752
|
+
console.log("[KiteChat] Received typing event:", payload);
|
|
1675
1753
|
const { sender, isTyping } = payload.payload;
|
|
1754
|
+
console.log("[KiteChat] Typing event - sender:", sender, "isTyping:", isTyping);
|
|
1676
1755
|
if (sender === "agent") {
|
|
1756
|
+
console.log("[KiteChat] Setting agentIsTyping to:", isTyping);
|
|
1677
1757
|
setAgentIsTyping(isTyping);
|
|
1678
1758
|
if (isTyping) {
|
|
1679
1759
|
if (typingTimeoutRef.current) {
|
|
@@ -1685,6 +1765,7 @@ function ChatPanel({
|
|
|
1685
1765
|
}
|
|
1686
1766
|
}
|
|
1687
1767
|
}).subscribe((status) => {
|
|
1768
|
+
console.log("[KiteChat] Typing channel subscription status:", status);
|
|
1688
1769
|
if (status === "SUBSCRIBED") {
|
|
1689
1770
|
typingChannelRef.current = channel;
|
|
1690
1771
|
console.log("[KiteChat] Typing channel subscribed successfully");
|
|
@@ -1699,7 +1780,7 @@ function ChatPanel({
|
|
|
1699
1780
|
window.clearTimeout(typingTimeoutRef.current);
|
|
1700
1781
|
}
|
|
1701
1782
|
};
|
|
1702
|
-
}, [isEscalated, sessionId]);
|
|
1783
|
+
}, [isEscalated, sessionId, effectiveSupabaseUrl, effectiveSupabaseAnonKey]);
|
|
1703
1784
|
React6.useEffect(() => {
|
|
1704
1785
|
if (!isOpen && isEscalated && supabaseRef.current && sessionId) {
|
|
1705
1786
|
console.log("[KiteChat] Panel closed during live chat, marking disconnected");
|
|
@@ -1910,6 +1991,77 @@ function ChatPanel({
|
|
|
1910
1991
|
const [pendingBulkSession, setPendingBulkSession] = React6.useState(null);
|
|
1911
1992
|
const pendingBulkSessionRef = React6.useRef(null);
|
|
1912
1993
|
const fileInputRef = React6.useRef(null);
|
|
1994
|
+
const [pendingImages, setPendingImages] = React6.useState([]);
|
|
1995
|
+
const [isUploadingImage, setIsUploadingImage] = React6.useState(false);
|
|
1996
|
+
const [isDragOver, setIsDragOver] = React6.useState(false);
|
|
1997
|
+
const imageInputRef = React6.useRef(null);
|
|
1998
|
+
const [lightboxImageUrl, setLightboxImageUrl] = React6.useState(null);
|
|
1999
|
+
const uploadImageToStorage = React6.useCallback(async (file) => {
|
|
2000
|
+
if (!supabaseRef.current) {
|
|
2001
|
+
console.error("[KiteChat] Supabase client not available for file upload");
|
|
2002
|
+
return null;
|
|
2003
|
+
}
|
|
2004
|
+
const fileExt = file.name.split(".").pop();
|
|
2005
|
+
const fileName = `${sessionId}/${Date.now()}-${Math.random().toString(36).substring(7)}.${fileExt}`;
|
|
2006
|
+
const bucketName = "chat-attachments";
|
|
2007
|
+
try {
|
|
2008
|
+
const { data, error } = await supabaseRef.current.storage.from(bucketName).upload(fileName, file, {
|
|
2009
|
+
cacheControl: "3600",
|
|
2010
|
+
upsert: false
|
|
2011
|
+
});
|
|
2012
|
+
if (error) {
|
|
2013
|
+
console.error("[KiteChat] Upload error:", error);
|
|
2014
|
+
return null;
|
|
2015
|
+
}
|
|
2016
|
+
const { data: urlData } = supabaseRef.current.storage.from(bucketName).getPublicUrl(fileName);
|
|
2017
|
+
return urlData?.publicUrl || null;
|
|
2018
|
+
} catch (err) {
|
|
2019
|
+
console.error("[KiteChat] Upload failed:", err);
|
|
2020
|
+
return null;
|
|
2021
|
+
}
|
|
2022
|
+
}, [sessionId]);
|
|
2023
|
+
const handleImageSelect = React6.useCallback((files) => {
|
|
2024
|
+
if (!files) return;
|
|
2025
|
+
const imageFiles = Array.from(files).filter(
|
|
2026
|
+
(file) => file.type.startsWith("image/") || file.type === "application/pdf"
|
|
2027
|
+
);
|
|
2028
|
+
const newImages = imageFiles.map((file) => ({
|
|
2029
|
+
file,
|
|
2030
|
+
preview: file.type.startsWith("image/") ? URL.createObjectURL(file) : ""
|
|
2031
|
+
}));
|
|
2032
|
+
setPendingImages((prev) => [...prev, ...newImages]);
|
|
2033
|
+
}, []);
|
|
2034
|
+
const handleDragOver = React6.useCallback((e) => {
|
|
2035
|
+
e.preventDefault();
|
|
2036
|
+
e.stopPropagation();
|
|
2037
|
+
setIsDragOver(true);
|
|
2038
|
+
}, []);
|
|
2039
|
+
const handleDragLeave = React6.useCallback((e) => {
|
|
2040
|
+
e.preventDefault();
|
|
2041
|
+
e.stopPropagation();
|
|
2042
|
+
setIsDragOver(false);
|
|
2043
|
+
}, []);
|
|
2044
|
+
const handleDrop = React6.useCallback((e) => {
|
|
2045
|
+
e.preventDefault();
|
|
2046
|
+
e.stopPropagation();
|
|
2047
|
+
setIsDragOver(false);
|
|
2048
|
+
const files = e.dataTransfer.files;
|
|
2049
|
+
if (files.length > 0) {
|
|
2050
|
+
const csvFile = Array.from(files).find((f) => f.name.endsWith(".csv"));
|
|
2051
|
+
if (csvFile && !isEscalated) {
|
|
2052
|
+
setPendingFile(csvFile);
|
|
2053
|
+
} else {
|
|
2054
|
+
handleImageSelect(files);
|
|
2055
|
+
}
|
|
2056
|
+
}
|
|
2057
|
+
}, [isEscalated, handleImageSelect]);
|
|
2058
|
+
React6.useEffect(() => {
|
|
2059
|
+
return () => {
|
|
2060
|
+
pendingImages.forEach((img) => {
|
|
2061
|
+
if (img.preview) URL.revokeObjectURL(img.preview);
|
|
2062
|
+
});
|
|
2063
|
+
};
|
|
2064
|
+
}, [pendingImages]);
|
|
1913
2065
|
const [searchExpanded, setSearchExpanded] = React6.useState(false);
|
|
1914
2066
|
const [searchInput, setSearchInput] = React6.useState("");
|
|
1915
2067
|
const searchInputRef = React6.useRef(null);
|
|
@@ -1966,6 +2118,11 @@ function ChatPanel({
|
|
|
1966
2118
|
messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
|
|
1967
2119
|
}
|
|
1968
2120
|
}, [messages, phase, activeGuide]);
|
|
2121
|
+
React6.useEffect(() => {
|
|
2122
|
+
if (isEscalated && agentIsTyping && !activeGuide) {
|
|
2123
|
+
messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
|
|
2124
|
+
}
|
|
2125
|
+
}, [isEscalated, agentIsTyping, activeGuide]);
|
|
1969
2126
|
const latestBulkSummaryNavigation = React6.useMemo(() => {
|
|
1970
2127
|
for (let i = messages.length - 1; i >= 0; i--) {
|
|
1971
2128
|
const msg = messages[i];
|
|
@@ -2202,7 +2359,7 @@ function ChatPanel({
|
|
|
2202
2359
|
setPanelView("landing");
|
|
2203
2360
|
setCurrentFolderId(void 0);
|
|
2204
2361
|
}
|
|
2205
|
-
function handleSubmit(e) {
|
|
2362
|
+
async function handleSubmit(e) {
|
|
2206
2363
|
e.preventDefault();
|
|
2207
2364
|
const trimmed = input.trim();
|
|
2208
2365
|
if (pendingFile) {
|
|
@@ -2222,6 +2379,49 @@ function ChatPanel({
|
|
|
2222
2379
|
if (fileInputRef.current) fileInputRef.current.value = "";
|
|
2223
2380
|
return;
|
|
2224
2381
|
}
|
|
2382
|
+
if (pendingImages.length > 0) {
|
|
2383
|
+
setIsUploadingImage(true);
|
|
2384
|
+
try {
|
|
2385
|
+
const uploadedUrls = [];
|
|
2386
|
+
for (const img of pendingImages) {
|
|
2387
|
+
const url = await uploadImageToStorage(img.file);
|
|
2388
|
+
if (url) {
|
|
2389
|
+
uploadedUrls.push(url);
|
|
2390
|
+
}
|
|
2391
|
+
if (img.preview) URL.revokeObjectURL(img.preview);
|
|
2392
|
+
}
|
|
2393
|
+
if (uploadedUrls.length > 0) {
|
|
2394
|
+
const imageMarkdown = uploadedUrls.map((url) => ``).join("\n");
|
|
2395
|
+
const messageContent = trimmed ? `${trimmed}
|
|
2396
|
+
|
|
2397
|
+
${imageMarkdown}` : imageMarkdown;
|
|
2398
|
+
const userMessage = {
|
|
2399
|
+
id: Date.now(),
|
|
2400
|
+
role: "user",
|
|
2401
|
+
content: messageContent,
|
|
2402
|
+
imageUrls: uploadedUrls
|
|
2403
|
+
};
|
|
2404
|
+
setMessages((prev) => [...prev, userMessage]);
|
|
2405
|
+
if (isEscalated) {
|
|
2406
|
+
sendEscalatedMessage(messageContent);
|
|
2407
|
+
sendTypingIndicator(false);
|
|
2408
|
+
if (userTypingTimeoutRef.current) {
|
|
2409
|
+
window.clearTimeout(userTypingTimeoutRef.current);
|
|
2410
|
+
userTypingTimeoutRef.current = null;
|
|
2411
|
+
}
|
|
2412
|
+
} else {
|
|
2413
|
+
startChatFlow(messageContent);
|
|
2414
|
+
}
|
|
2415
|
+
}
|
|
2416
|
+
} catch (err) {
|
|
2417
|
+
console.error("[KiteChat] Failed to upload images:", err);
|
|
2418
|
+
} finally {
|
|
2419
|
+
setIsUploadingImage(false);
|
|
2420
|
+
setPendingImages([]);
|
|
2421
|
+
setInput("");
|
|
2422
|
+
}
|
|
2423
|
+
return;
|
|
2424
|
+
}
|
|
2225
2425
|
if (!trimmed) return;
|
|
2226
2426
|
if (isEscalated) {
|
|
2227
2427
|
const userMessage = {
|
|
@@ -2386,7 +2586,8 @@ function ChatPanel({
|
|
|
2386
2586
|
user_id: userId,
|
|
2387
2587
|
org_id: orgId,
|
|
2388
2588
|
user_name: userName,
|
|
2389
|
-
user_email: userEmail
|
|
2589
|
+
user_email: userEmail,
|
|
2590
|
+
is_eval: isEval
|
|
2390
2591
|
}),
|
|
2391
2592
|
signal: controller.signal
|
|
2392
2593
|
});
|
|
@@ -3279,19 +3480,23 @@ ${userText}`
|
|
|
3279
3480
|
)
|
|
3280
3481
|
] }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
|
|
3281
3482
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
3282
|
-
"
|
|
3483
|
+
"textarea",
|
|
3283
3484
|
{
|
|
3284
3485
|
ref: searchInputRef,
|
|
3285
|
-
type: "text",
|
|
3286
3486
|
value: searchInput,
|
|
3287
|
-
onChange: (e) =>
|
|
3487
|
+
onChange: (e) => {
|
|
3488
|
+
setSearchInput(e.target.value);
|
|
3489
|
+
e.target.style.height = "auto";
|
|
3490
|
+
e.target.style.height = Math.min(e.target.scrollHeight, 120) + "px";
|
|
3491
|
+
},
|
|
3288
3492
|
onKeyDown: (e) => {
|
|
3289
|
-
if (e.key === "Enter" && searchInput.trim()) {
|
|
3493
|
+
if (e.key === "Enter" && !e.shiftKey && searchInput.trim()) {
|
|
3290
3494
|
e.preventDefault();
|
|
3291
3495
|
onOpen?.();
|
|
3292
3496
|
startChatFlow(searchInput.trim());
|
|
3293
3497
|
setSearchInput("");
|
|
3294
3498
|
setSearchExpanded(false);
|
|
3499
|
+
e.currentTarget.style.height = "auto";
|
|
3295
3500
|
} else if (e.key === "Escape") {
|
|
3296
3501
|
setSearchExpanded(false);
|
|
3297
3502
|
setSearchInput("");
|
|
@@ -3303,7 +3508,8 @@ ${userText}`
|
|
|
3303
3508
|
}
|
|
3304
3509
|
},
|
|
3305
3510
|
placeholder: "Ask a question...",
|
|
3306
|
-
|
|
3511
|
+
rows: 1,
|
|
3512
|
+
className: "flex-1 text-sm text-gray-700 outline-none bg-transparent resize-none min-h-[20px] max-h-[120px]"
|
|
3307
3513
|
}
|
|
3308
3514
|
),
|
|
3309
3515
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
@@ -3563,12 +3769,55 @@ ${userText}`
|
|
|
3563
3769
|
return null;
|
|
3564
3770
|
}
|
|
3565
3771
|
if (isUser) {
|
|
3566
|
-
return /* @__PURE__ */ (0, import_jsx_runtime10.
|
|
3772
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: `flex flex-col items-end gap-2 ${isRoleChange ? "mt-3" : ""}`, children: [
|
|
3773
|
+
message.imageUrls && message.imageUrls.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "flex flex-wrap gap-1 justify-end max-w-[260px]", children: message.imageUrls.map((url, imgIndex) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
3774
|
+
"button",
|
|
3775
|
+
{
|
|
3776
|
+
onClick: () => setLightboxImageUrl(url),
|
|
3777
|
+
className: "block cursor-pointer",
|
|
3778
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
3779
|
+
"img",
|
|
3780
|
+
{
|
|
3781
|
+
src: url,
|
|
3782
|
+
alt: `Attachment ${imgIndex + 1}`,
|
|
3783
|
+
className: "max-h-32 max-w-[200px] rounded-lg object-cover border border-gray-700 hover:opacity-90 transition-opacity"
|
|
3784
|
+
}
|
|
3785
|
+
)
|
|
3786
|
+
},
|
|
3787
|
+
imgIndex
|
|
3788
|
+
)) }),
|
|
3789
|
+
message.content && !message.content.match(/^!\[image\]\([^)]+\)(\n!\[image\]\([^)]+\))*$/) && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "max-w-[260px] rounded-2xl rounded-br-md bg-gray-900 px-3 py-2 text-sm text-white shadow-sm", children: message.content.replace(/!\[image\]\([^)]+\)\n*/g, "").trim() })
|
|
3790
|
+
] }, message.id);
|
|
3567
3791
|
}
|
|
3568
3792
|
if (message.role === "agent") {
|
|
3569
|
-
|
|
3793
|
+
const imageRegex = /!\[image\]\(([^)]+)\)/g;
|
|
3794
|
+
const extractedImageUrls = [];
|
|
3795
|
+
let match;
|
|
3796
|
+
const contentStr = message.content || "";
|
|
3797
|
+
while ((match = imageRegex.exec(contentStr)) !== null) {
|
|
3798
|
+
extractedImageUrls.push(match[1]);
|
|
3799
|
+
}
|
|
3800
|
+
const agentImageUrls = message.imageUrls || extractedImageUrls;
|
|
3801
|
+
const agentTextContent = contentStr.replace(/!\[image\]\([^)]+\)\n*/g, "").trim();
|
|
3802
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: `flex flex-col items-start gap-2 ${isRoleChange ? "mt-3" : ""}`, children: [
|
|
3570
3803
|
isRoleChange && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "text-[10px] text-gray-500 mb-1 ml-1", children: "Agent" }),
|
|
3571
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "
|
|
3804
|
+
agentImageUrls.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "flex flex-wrap gap-1 justify-start max-w-[300px]", children: agentImageUrls.map((url, imgIndex) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
3805
|
+
"button",
|
|
3806
|
+
{
|
|
3807
|
+
onClick: () => setLightboxImageUrl(url),
|
|
3808
|
+
className: "block cursor-pointer",
|
|
3809
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
3810
|
+
"img",
|
|
3811
|
+
{
|
|
3812
|
+
src: url,
|
|
3813
|
+
alt: `Attachment ${imgIndex + 1}`,
|
|
3814
|
+
className: "max-h-32 max-w-[200px] rounded-lg object-cover border border-gray-300 hover:opacity-90 transition-opacity"
|
|
3815
|
+
}
|
|
3816
|
+
)
|
|
3817
|
+
},
|
|
3818
|
+
imgIndex
|
|
3819
|
+
)) }),
|
|
3820
|
+
agentTextContent && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "max-w-[300px] rounded-2xl rounded-bl-md bg-gray-100 px-4 py-3 text-sm text-gray-700", children: agentTextContent })
|
|
3572
3821
|
] }, message.id);
|
|
3573
3822
|
}
|
|
3574
3823
|
if (message.kind === "searchSummary") {
|
|
@@ -4604,131 +4853,183 @@ ${userText}`
|
|
|
4604
4853
|
progressSteps
|
|
4605
4854
|
}
|
|
4606
4855
|
) }),
|
|
4607
|
-
isEscalated && agentIsTyping && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "mt-2", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(TypingIndicator, {}) }),
|
|
4856
|
+
isEscalated && agentIsTyping && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "flex items-start mt-2", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "bg-gray-200 rounded-2xl rounded-bl-md px-4 py-3", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(TypingIndicator, {}) }) }),
|
|
4608
4857
|
!activeGuide && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { ref: messagesEndRef })
|
|
4609
4858
|
] }) }) }) })
|
|
4610
4859
|
}
|
|
4611
4860
|
),
|
|
4612
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
4613
|
-
|
|
4614
|
-
|
|
4615
|
-
|
|
4616
|
-
|
|
4617
|
-
|
|
4618
|
-
|
|
4619
|
-
|
|
4620
|
-
|
|
4621
|
-
|
|
4622
|
-
|
|
4623
|
-
|
|
4624
|
-
|
|
4625
|
-
|
|
4626
|
-
|
|
4627
|
-
|
|
4628
|
-
|
|
4629
|
-
|
|
4630
|
-
|
|
4631
|
-
|
|
4632
|
-
|
|
4633
|
-
ref: fileInputRef,
|
|
4634
|
-
type: "file",
|
|
4635
|
-
accept: ".csv",
|
|
4636
|
-
className: "hidden",
|
|
4637
|
-
onChange: (e) => {
|
|
4638
|
-
const file = e.target.files?.[0];
|
|
4639
|
-
if (file) {
|
|
4640
|
-
setPendingFile(file);
|
|
4861
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
4862
|
+
"div",
|
|
4863
|
+
{
|
|
4864
|
+
className: `px-4 py-3 bg-white shrink-0 ${isDragOver ? "ring-2 ring-blue-400 ring-inset bg-blue-50" : ""}`,
|
|
4865
|
+
onDragOver: handleDragOver,
|
|
4866
|
+
onDragLeave: handleDragLeave,
|
|
4867
|
+
onDrop: handleDrop,
|
|
4868
|
+
children: [
|
|
4869
|
+
pendingFile && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "mb-2 flex items-center gap-2 rounded-xl bg-blue-50 border border-blue-200 px-3 py-2", children: [
|
|
4870
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react4.FileSpreadsheet, { className: "h-4 w-4 text-blue-600" }),
|
|
4871
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "text-xs text-blue-700 flex-1 truncate", children: pendingFile.name }),
|
|
4872
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
4873
|
+
"button",
|
|
4874
|
+
{
|
|
4875
|
+
type: "button",
|
|
4876
|
+
onClick: () => {
|
|
4877
|
+
setPendingFile(null);
|
|
4878
|
+
if (fileInputRef.current) fileInputRef.current.value = "";
|
|
4879
|
+
},
|
|
4880
|
+
className: "text-blue-600 hover:text-blue-800",
|
|
4881
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react4.X, { className: "h-4 w-4" })
|
|
4641
4882
|
}
|
|
4642
|
-
|
|
4643
|
-
}
|
|
4644
|
-
|
|
4645
|
-
|
|
4646
|
-
|
|
4647
|
-
|
|
4648
|
-
|
|
4649
|
-
|
|
4650
|
-
|
|
4651
|
-
|
|
4652
|
-
onClick: () => fileInputRef.current?.click(),
|
|
4653
|
-
className: "h-5 w-5 rounded-full text-gray-400 hover:text-gray-600 hover:bg-gray-100",
|
|
4654
|
-
title: "Upload CSV for bulk operations",
|
|
4655
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react4.Paperclip, { className: "h-2.5 w-2.5" })
|
|
4656
|
-
}
|
|
4657
|
-
),
|
|
4658
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
4659
|
-
"textarea",
|
|
4660
|
-
{
|
|
4661
|
-
placeholder: pendingFile ? "Describe what to do with this CSV..." : "Ask anything...",
|
|
4662
|
-
value: input,
|
|
4663
|
-
onChange: (e) => {
|
|
4664
|
-
setInput(e.target.value);
|
|
4665
|
-
if (e.target.value.length > 0) {
|
|
4666
|
-
handleTypingStart();
|
|
4883
|
+
)
|
|
4884
|
+
] }),
|
|
4885
|
+
pendingImages.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "mb-2 flex flex-wrap gap-2", children: [
|
|
4886
|
+
pendingImages.map((img, index) => /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "relative group", children: [
|
|
4887
|
+
img.preview ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
4888
|
+
"img",
|
|
4889
|
+
{
|
|
4890
|
+
src: img.preview,
|
|
4891
|
+
alt: `Preview ${index + 1}`,
|
|
4892
|
+
className: "h-16 w-16 object-cover rounded-lg border border-gray-200"
|
|
4667
4893
|
}
|
|
4668
|
-
},
|
|
4669
|
-
|
|
4670
|
-
|
|
4671
|
-
|
|
4672
|
-
|
|
4673
|
-
|
|
4674
|
-
|
|
4675
|
-
|
|
4676
|
-
|
|
4677
|
-
|
|
4678
|
-
|
|
4679
|
-
e.preventDefault();
|
|
4680
|
-
if (input.trim() || pendingFile) {
|
|
4681
|
-
const form = e.currentTarget.closest("form");
|
|
4682
|
-
if (form) {
|
|
4683
|
-
form.requestSubmit();
|
|
4684
|
-
}
|
|
4685
|
-
}
|
|
4686
|
-
return;
|
|
4894
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "h-16 w-16 rounded-lg border border-gray-200 bg-gray-100 flex items-center justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react4.FileSpreadsheet, { className: "h-6 w-6 text-gray-400" }) }),
|
|
4895
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
4896
|
+
"button",
|
|
4897
|
+
{
|
|
4898
|
+
type: "button",
|
|
4899
|
+
onClick: () => {
|
|
4900
|
+
if (img.preview) URL.revokeObjectURL(img.preview);
|
|
4901
|
+
setPendingImages((prev) => prev.filter((_, i) => i !== index));
|
|
4902
|
+
},
|
|
4903
|
+
className: "absolute -top-1 -right-1 h-4 w-4 rounded-full bg-gray-800 text-white flex items-center justify-center opacity-0 group-hover:opacity-100 transition-opacity",
|
|
4904
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react4.X, { className: "h-2.5 w-2.5" })
|
|
4687
4905
|
}
|
|
4688
|
-
|
|
4689
|
-
|
|
4690
|
-
|
|
4691
|
-
|
|
4692
|
-
|
|
4693
|
-
|
|
4694
|
-
|
|
4695
|
-
|
|
4696
|
-
|
|
4697
|
-
|
|
4698
|
-
|
|
4699
|
-
|
|
4700
|
-
|
|
4701
|
-
|
|
4702
|
-
if (
|
|
4703
|
-
|
|
4704
|
-
e.stopPropagation();
|
|
4705
|
-
handleConfirmNavigation(pendingNavigation);
|
|
4706
|
-
return;
|
|
4707
|
-
}
|
|
4708
|
-
const currentGuide = activeGuideRef.current;
|
|
4709
|
-
if (currentGuide) {
|
|
4710
|
-
e.preventDefault();
|
|
4711
|
-
e.stopPropagation();
|
|
4712
|
-
advanceGuide();
|
|
4713
|
-
return;
|
|
4906
|
+
)
|
|
4907
|
+
] }, index)),
|
|
4908
|
+
isUploadingImage && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "h-16 w-16 rounded-lg border border-gray-200 bg-gray-50 flex items-center justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react4.Loader2, { className: "h-5 w-5 animate-spin text-gray-400" }) })
|
|
4909
|
+
] }),
|
|
4910
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("form", { onSubmit: handleSubmit, className: "w-full", children: [
|
|
4911
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
4912
|
+
"input",
|
|
4913
|
+
{
|
|
4914
|
+
ref: fileInputRef,
|
|
4915
|
+
type: "file",
|
|
4916
|
+
accept: ".csv",
|
|
4917
|
+
className: "hidden",
|
|
4918
|
+
onChange: (e) => {
|
|
4919
|
+
const file = e.target.files?.[0];
|
|
4920
|
+
if (file) {
|
|
4921
|
+
setPendingFile(file);
|
|
4714
4922
|
}
|
|
4715
4923
|
}
|
|
4716
4924
|
}
|
|
4717
|
-
|
|
4718
|
-
|
|
4719
|
-
|
|
4720
|
-
|
|
4721
|
-
|
|
4722
|
-
|
|
4723
|
-
|
|
4724
|
-
|
|
4725
|
-
|
|
4726
|
-
|
|
4727
|
-
|
|
4728
|
-
|
|
4729
|
-
|
|
4730
|
-
|
|
4731
|
-
|
|
4925
|
+
),
|
|
4926
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
4927
|
+
"input",
|
|
4928
|
+
{
|
|
4929
|
+
ref: imageInputRef,
|
|
4930
|
+
type: "file",
|
|
4931
|
+
accept: "image/*,.pdf",
|
|
4932
|
+
multiple: true,
|
|
4933
|
+
className: "hidden",
|
|
4934
|
+
onChange: (e) => handleImageSelect(e.target.files)
|
|
4935
|
+
}
|
|
4936
|
+
),
|
|
4937
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: `flex w-full items-start gap-2 rounded-xl border bg-white px-3 py-2 shadow-sm ${isDragOver ? "border-blue-400" : "border-gray-200"}`, children: [
|
|
4938
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
4939
|
+
Button,
|
|
4940
|
+
{
|
|
4941
|
+
type: "button",
|
|
4942
|
+
size: "icon",
|
|
4943
|
+
variant: "ghost",
|
|
4944
|
+
onClick: () => {
|
|
4945
|
+
if (isEscalated) {
|
|
4946
|
+
imageInputRef.current?.click();
|
|
4947
|
+
} else {
|
|
4948
|
+
fileInputRef.current?.click();
|
|
4949
|
+
}
|
|
4950
|
+
},
|
|
4951
|
+
className: "h-5 w-5 rounded-full text-gray-400 hover:text-gray-600 hover:bg-gray-100",
|
|
4952
|
+
title: isEscalated ? "Attach image or file" : "Upload CSV for bulk operations",
|
|
4953
|
+
disabled: isUploadingImage,
|
|
4954
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react4.Paperclip, { className: "h-2.5 w-2.5" })
|
|
4955
|
+
}
|
|
4956
|
+
),
|
|
4957
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
4958
|
+
"textarea",
|
|
4959
|
+
{
|
|
4960
|
+
placeholder: pendingFile ? "Describe what to do with this CSV..." : pendingImages.length > 0 ? "Add a message (optional)..." : isDragOver ? "Drop files here..." : "Ask anything...",
|
|
4961
|
+
value: input,
|
|
4962
|
+
onChange: (e) => {
|
|
4963
|
+
setInput(e.target.value);
|
|
4964
|
+
if (e.target.value.length > 0) {
|
|
4965
|
+
handleTypingStart();
|
|
4966
|
+
}
|
|
4967
|
+
},
|
|
4968
|
+
rows: 1,
|
|
4969
|
+
className: "flex-1 border-0 bg-transparent focus-visible:ring-0 focus-visible:ring-offset-0 text-sm placeholder:text-gray-400 resize-none overflow-hidden outline-none",
|
|
4970
|
+
style: { minHeight: "20px", maxHeight: "120px" },
|
|
4971
|
+
onInput: (e) => {
|
|
4972
|
+
const target = e.target;
|
|
4973
|
+
target.style.height = "auto";
|
|
4974
|
+
target.style.height = Math.min(target.scrollHeight, 120) + "px";
|
|
4975
|
+
},
|
|
4976
|
+
onKeyDown: (e) => {
|
|
4977
|
+
if (e.key === "Enter" && !e.shiftKey && !e.metaKey && !e.ctrlKey) {
|
|
4978
|
+
e.preventDefault();
|
|
4979
|
+
if (input.trim() || pendingFile || pendingImages.length > 0) {
|
|
4980
|
+
const form = e.currentTarget.closest("form");
|
|
4981
|
+
if (form) {
|
|
4982
|
+
form.requestSubmit();
|
|
4983
|
+
}
|
|
4984
|
+
}
|
|
4985
|
+
return;
|
|
4986
|
+
}
|
|
4987
|
+
if ((e.metaKey || e.ctrlKey) && e.key === "Enter") {
|
|
4988
|
+
const currentBulkSession = pendingBulkSessionRef.current;
|
|
4989
|
+
if (currentBulkSession) {
|
|
4990
|
+
e.preventDefault();
|
|
4991
|
+
e.stopPropagation();
|
|
4992
|
+
confirmBulkOperation(currentBulkSession);
|
|
4993
|
+
return;
|
|
4994
|
+
}
|
|
4995
|
+
if (pendingAction) {
|
|
4996
|
+
e.preventDefault();
|
|
4997
|
+
e.stopPropagation();
|
|
4998
|
+
handleActionSubmit();
|
|
4999
|
+
return;
|
|
5000
|
+
}
|
|
5001
|
+
if (pendingNavigation) {
|
|
5002
|
+
e.preventDefault();
|
|
5003
|
+
e.stopPropagation();
|
|
5004
|
+
handleConfirmNavigation(pendingNavigation);
|
|
5005
|
+
return;
|
|
5006
|
+
}
|
|
5007
|
+
const currentGuide = activeGuideRef.current;
|
|
5008
|
+
if (currentGuide) {
|
|
5009
|
+
e.preventDefault();
|
|
5010
|
+
e.stopPropagation();
|
|
5011
|
+
advanceGuide();
|
|
5012
|
+
return;
|
|
5013
|
+
}
|
|
5014
|
+
}
|
|
5015
|
+
}
|
|
5016
|
+
}
|
|
5017
|
+
),
|
|
5018
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
5019
|
+
Button,
|
|
5020
|
+
{
|
|
5021
|
+
type: "submit",
|
|
5022
|
+
size: "icon",
|
|
5023
|
+
disabled: !input.trim() && !pendingFile || isWaitingForAuth,
|
|
5024
|
+
className: "h-6 w-6 rounded-full bg-gray-700 hover:bg-gray-600 disabled:bg-gray-300",
|
|
5025
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react4.ArrowUp, { className: "h-2.5 w-2.5 text-white" })
|
|
5026
|
+
}
|
|
5027
|
+
)
|
|
5028
|
+
] })
|
|
5029
|
+
] })
|
|
5030
|
+
]
|
|
5031
|
+
}
|
|
5032
|
+
),
|
|
4732
5033
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
4733
5034
|
GuideCursor,
|
|
4734
5035
|
{
|
|
@@ -4737,6 +5038,13 @@ ${userText}`
|
|
|
4737
5038
|
visible: cursorState.visible,
|
|
4738
5039
|
onClick: cursorState.onClick
|
|
4739
5040
|
}
|
|
5041
|
+
),
|
|
5042
|
+
lightboxImageUrl && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
5043
|
+
ImageLightbox,
|
|
5044
|
+
{
|
|
5045
|
+
imageUrl: lightboxImageUrl,
|
|
5046
|
+
onClose: () => setLightboxImageUrl(null)
|
|
5047
|
+
}
|
|
4740
5048
|
)
|
|
4741
5049
|
]
|
|
4742
5050
|
}
|
|
@@ -4761,7 +5069,8 @@ function ChatPanelWithToggle({
|
|
|
4761
5069
|
initialCorner,
|
|
4762
5070
|
onCornerChange,
|
|
4763
5071
|
productBackendUrl,
|
|
4764
|
-
getAuthHeaders
|
|
5072
|
+
getAuthHeaders,
|
|
5073
|
+
isEval
|
|
4765
5074
|
}) {
|
|
4766
5075
|
const [internalIsOpen, setInternalIsOpen] = React6.useState(defaultOpen);
|
|
4767
5076
|
const isOpen = controlledIsOpen !== void 0 ? controlledIsOpen : internalIsOpen;
|
|
@@ -4792,7 +5101,8 @@ function ChatPanelWithToggle({
|
|
|
4792
5101
|
initialCorner,
|
|
4793
5102
|
onCornerChange,
|
|
4794
5103
|
productBackendUrl,
|
|
4795
|
-
getAuthHeaders
|
|
5104
|
+
getAuthHeaders,
|
|
5105
|
+
isEval
|
|
4796
5106
|
}
|
|
4797
5107
|
);
|
|
4798
5108
|
}
|