@kite-copilot/chat-panel 0.2.51 → 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 +446 -138
- package/dist/auto.d.cts +1 -1
- package/dist/auto.d.ts +1 -1
- package/dist/auto.js +1 -1
- package/dist/{chunk-VBCGW333.js → chunk-VXJQZR5G.js} +447 -139
- 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 +446 -138
- 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");
|
|
@@ -1772,9 +1853,7 @@ function ChatPanel({
|
|
|
1772
1853
|
markDisconnectedWithKeepalive();
|
|
1773
1854
|
};
|
|
1774
1855
|
const handleVisibilityChange = () => {
|
|
1775
|
-
if (document.visibilityState === "
|
|
1776
|
-
markDisconnectedWithKeepalive();
|
|
1777
|
-
} else if (document.visibilityState === "visible") {
|
|
1856
|
+
if (document.visibilityState === "visible") {
|
|
1778
1857
|
markActive();
|
|
1779
1858
|
}
|
|
1780
1859
|
};
|
|
@@ -1912,6 +1991,77 @@ function ChatPanel({
|
|
|
1912
1991
|
const [pendingBulkSession, setPendingBulkSession] = React6.useState(null);
|
|
1913
1992
|
const pendingBulkSessionRef = React6.useRef(null);
|
|
1914
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]);
|
|
1915
2065
|
const [searchExpanded, setSearchExpanded] = React6.useState(false);
|
|
1916
2066
|
const [searchInput, setSearchInput] = React6.useState("");
|
|
1917
2067
|
const searchInputRef = React6.useRef(null);
|
|
@@ -1968,6 +2118,11 @@ function ChatPanel({
|
|
|
1968
2118
|
messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
|
|
1969
2119
|
}
|
|
1970
2120
|
}, [messages, phase, activeGuide]);
|
|
2121
|
+
React6.useEffect(() => {
|
|
2122
|
+
if (isEscalated && agentIsTyping && !activeGuide) {
|
|
2123
|
+
messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
|
|
2124
|
+
}
|
|
2125
|
+
}, [isEscalated, agentIsTyping, activeGuide]);
|
|
1971
2126
|
const latestBulkSummaryNavigation = React6.useMemo(() => {
|
|
1972
2127
|
for (let i = messages.length - 1; i >= 0; i--) {
|
|
1973
2128
|
const msg = messages[i];
|
|
@@ -2204,7 +2359,7 @@ function ChatPanel({
|
|
|
2204
2359
|
setPanelView("landing");
|
|
2205
2360
|
setCurrentFolderId(void 0);
|
|
2206
2361
|
}
|
|
2207
|
-
function handleSubmit(e) {
|
|
2362
|
+
async function handleSubmit(e) {
|
|
2208
2363
|
e.preventDefault();
|
|
2209
2364
|
const trimmed = input.trim();
|
|
2210
2365
|
if (pendingFile) {
|
|
@@ -2224,6 +2379,49 @@ function ChatPanel({
|
|
|
2224
2379
|
if (fileInputRef.current) fileInputRef.current.value = "";
|
|
2225
2380
|
return;
|
|
2226
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
|
+
}
|
|
2227
2425
|
if (!trimmed) return;
|
|
2228
2426
|
if (isEscalated) {
|
|
2229
2427
|
const userMessage = {
|
|
@@ -2388,7 +2586,8 @@ function ChatPanel({
|
|
|
2388
2586
|
user_id: userId,
|
|
2389
2587
|
org_id: orgId,
|
|
2390
2588
|
user_name: userName,
|
|
2391
|
-
user_email: userEmail
|
|
2589
|
+
user_email: userEmail,
|
|
2590
|
+
is_eval: isEval
|
|
2392
2591
|
}),
|
|
2393
2592
|
signal: controller.signal
|
|
2394
2593
|
});
|
|
@@ -3281,19 +3480,23 @@ ${userText}`
|
|
|
3281
3480
|
)
|
|
3282
3481
|
] }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
|
|
3283
3482
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
3284
|
-
"
|
|
3483
|
+
"textarea",
|
|
3285
3484
|
{
|
|
3286
3485
|
ref: searchInputRef,
|
|
3287
|
-
type: "text",
|
|
3288
3486
|
value: searchInput,
|
|
3289
|
-
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
|
+
},
|
|
3290
3492
|
onKeyDown: (e) => {
|
|
3291
|
-
if (e.key === "Enter" && searchInput.trim()) {
|
|
3493
|
+
if (e.key === "Enter" && !e.shiftKey && searchInput.trim()) {
|
|
3292
3494
|
e.preventDefault();
|
|
3293
3495
|
onOpen?.();
|
|
3294
3496
|
startChatFlow(searchInput.trim());
|
|
3295
3497
|
setSearchInput("");
|
|
3296
3498
|
setSearchExpanded(false);
|
|
3499
|
+
e.currentTarget.style.height = "auto";
|
|
3297
3500
|
} else if (e.key === "Escape") {
|
|
3298
3501
|
setSearchExpanded(false);
|
|
3299
3502
|
setSearchInput("");
|
|
@@ -3305,7 +3508,8 @@ ${userText}`
|
|
|
3305
3508
|
}
|
|
3306
3509
|
},
|
|
3307
3510
|
placeholder: "Ask a question...",
|
|
3308
|
-
|
|
3511
|
+
rows: 1,
|
|
3512
|
+
className: "flex-1 text-sm text-gray-700 outline-none bg-transparent resize-none min-h-[20px] max-h-[120px]"
|
|
3309
3513
|
}
|
|
3310
3514
|
),
|
|
3311
3515
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
@@ -3565,12 +3769,55 @@ ${userText}`
|
|
|
3565
3769
|
return null;
|
|
3566
3770
|
}
|
|
3567
3771
|
if (isUser) {
|
|
3568
|
-
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);
|
|
3569
3791
|
}
|
|
3570
3792
|
if (message.role === "agent") {
|
|
3571
|
-
|
|
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: [
|
|
3572
3803
|
isRoleChange && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "text-[10px] text-gray-500 mb-1 ml-1", children: "Agent" }),
|
|
3573
|
-
/* @__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 })
|
|
3574
3821
|
] }, message.id);
|
|
3575
3822
|
}
|
|
3576
3823
|
if (message.kind === "searchSummary") {
|
|
@@ -4606,131 +4853,183 @@ ${userText}`
|
|
|
4606
4853
|
progressSteps
|
|
4607
4854
|
}
|
|
4608
4855
|
) }),
|
|
4609
|
-
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, {}) }) }),
|
|
4610
4857
|
!activeGuide && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { ref: messagesEndRef })
|
|
4611
4858
|
] }) }) }) })
|
|
4612
4859
|
}
|
|
4613
4860
|
),
|
|
4614
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
4615
|
-
|
|
4616
|
-
|
|
4617
|
-
|
|
4618
|
-
|
|
4619
|
-
|
|
4620
|
-
|
|
4621
|
-
|
|
4622
|
-
|
|
4623
|
-
|
|
4624
|
-
|
|
4625
|
-
|
|
4626
|
-
|
|
4627
|
-
|
|
4628
|
-
|
|
4629
|
-
|
|
4630
|
-
|
|
4631
|
-
|
|
4632
|
-
|
|
4633
|
-
|
|
4634
|
-
|
|
4635
|
-
ref: fileInputRef,
|
|
4636
|
-
type: "file",
|
|
4637
|
-
accept: ".csv",
|
|
4638
|
-
className: "hidden",
|
|
4639
|
-
onChange: (e) => {
|
|
4640
|
-
const file = e.target.files?.[0];
|
|
4641
|
-
if (file) {
|
|
4642
|
-
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" })
|
|
4643
4882
|
}
|
|
4644
|
-
|
|
4645
|
-
}
|
|
4646
|
-
|
|
4647
|
-
|
|
4648
|
-
|
|
4649
|
-
|
|
4650
|
-
|
|
4651
|
-
|
|
4652
|
-
|
|
4653
|
-
|
|
4654
|
-
onClick: () => fileInputRef.current?.click(),
|
|
4655
|
-
className: "h-5 w-5 rounded-full text-gray-400 hover:text-gray-600 hover:bg-gray-100",
|
|
4656
|
-
title: "Upload CSV for bulk operations",
|
|
4657
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react4.Paperclip, { className: "h-2.5 w-2.5" })
|
|
4658
|
-
}
|
|
4659
|
-
),
|
|
4660
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
4661
|
-
"textarea",
|
|
4662
|
-
{
|
|
4663
|
-
placeholder: pendingFile ? "Describe what to do with this CSV..." : "Ask anything...",
|
|
4664
|
-
value: input,
|
|
4665
|
-
onChange: (e) => {
|
|
4666
|
-
setInput(e.target.value);
|
|
4667
|
-
if (e.target.value.length > 0) {
|
|
4668
|
-
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"
|
|
4669
4893
|
}
|
|
4670
|
-
},
|
|
4671
|
-
|
|
4672
|
-
|
|
4673
|
-
|
|
4674
|
-
|
|
4675
|
-
|
|
4676
|
-
|
|
4677
|
-
|
|
4678
|
-
|
|
4679
|
-
|
|
4680
|
-
|
|
4681
|
-
e.preventDefault();
|
|
4682
|
-
if (input.trim() || pendingFile) {
|
|
4683
|
-
const form = e.currentTarget.closest("form");
|
|
4684
|
-
if (form) {
|
|
4685
|
-
form.requestSubmit();
|
|
4686
|
-
}
|
|
4687
|
-
}
|
|
4688
|
-
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" })
|
|
4689
4905
|
}
|
|
4690
|
-
|
|
4691
|
-
|
|
4692
|
-
|
|
4693
|
-
|
|
4694
|
-
|
|
4695
|
-
|
|
4696
|
-
|
|
4697
|
-
|
|
4698
|
-
|
|
4699
|
-
|
|
4700
|
-
|
|
4701
|
-
|
|
4702
|
-
|
|
4703
|
-
|
|
4704
|
-
if (
|
|
4705
|
-
|
|
4706
|
-
e.stopPropagation();
|
|
4707
|
-
handleConfirmNavigation(pendingNavigation);
|
|
4708
|
-
return;
|
|
4709
|
-
}
|
|
4710
|
-
const currentGuide = activeGuideRef.current;
|
|
4711
|
-
if (currentGuide) {
|
|
4712
|
-
e.preventDefault();
|
|
4713
|
-
e.stopPropagation();
|
|
4714
|
-
advanceGuide();
|
|
4715
|
-
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);
|
|
4716
4922
|
}
|
|
4717
4923
|
}
|
|
4718
4924
|
}
|
|
4719
|
-
|
|
4720
|
-
|
|
4721
|
-
|
|
4722
|
-
|
|
4723
|
-
|
|
4724
|
-
|
|
4725
|
-
|
|
4726
|
-
|
|
4727
|
-
|
|
4728
|
-
|
|
4729
|
-
|
|
4730
|
-
|
|
4731
|
-
|
|
4732
|
-
|
|
4733
|
-
|
|
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
|
+
),
|
|
4734
5033
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
4735
5034
|
GuideCursor,
|
|
4736
5035
|
{
|
|
@@ -4739,6 +5038,13 @@ ${userText}`
|
|
|
4739
5038
|
visible: cursorState.visible,
|
|
4740
5039
|
onClick: cursorState.onClick
|
|
4741
5040
|
}
|
|
5041
|
+
),
|
|
5042
|
+
lightboxImageUrl && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
5043
|
+
ImageLightbox,
|
|
5044
|
+
{
|
|
5045
|
+
imageUrl: lightboxImageUrl,
|
|
5046
|
+
onClose: () => setLightboxImageUrl(null)
|
|
5047
|
+
}
|
|
4742
5048
|
)
|
|
4743
5049
|
]
|
|
4744
5050
|
}
|
|
@@ -4763,7 +5069,8 @@ function ChatPanelWithToggle({
|
|
|
4763
5069
|
initialCorner,
|
|
4764
5070
|
onCornerChange,
|
|
4765
5071
|
productBackendUrl,
|
|
4766
|
-
getAuthHeaders
|
|
5072
|
+
getAuthHeaders,
|
|
5073
|
+
isEval
|
|
4767
5074
|
}) {
|
|
4768
5075
|
const [internalIsOpen, setInternalIsOpen] = React6.useState(defaultOpen);
|
|
4769
5076
|
const isOpen = controlledIsOpen !== void 0 ? controlledIsOpen : internalIsOpen;
|
|
@@ -4794,7 +5101,8 @@ function ChatPanelWithToggle({
|
|
|
4794
5101
|
initialCorner,
|
|
4795
5102
|
onCornerChange,
|
|
4796
5103
|
productBackendUrl,
|
|
4797
|
-
getAuthHeaders
|
|
5104
|
+
getAuthHeaders,
|
|
5105
|
+
isEval
|
|
4798
5106
|
}
|
|
4799
5107
|
);
|
|
4800
5108
|
}
|