@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/index.cjs
CHANGED
|
@@ -1120,29 +1120,29 @@ function DataRenderer({ type, data }) {
|
|
|
1120
1120
|
// src/components/TypingIndicator.tsx
|
|
1121
1121
|
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
1122
1122
|
function TypingIndicator({ className = "" }) {
|
|
1123
|
-
return /* @__PURE__ */ (0, import_jsx_runtime9.
|
|
1123
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: `flex items-center gap-1.5 ${className}`, children: [
|
|
1124
1124
|
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1125
1125
|
"span",
|
|
1126
1126
|
{
|
|
1127
|
-
className: "w-2 h-2 bg-gray-
|
|
1127
|
+
className: "w-2 h-2 bg-gray-500 rounded-full animate-bounce",
|
|
1128
1128
|
style: { animationDelay: "0ms", animationDuration: "600ms" }
|
|
1129
1129
|
}
|
|
1130
1130
|
),
|
|
1131
1131
|
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1132
1132
|
"span",
|
|
1133
1133
|
{
|
|
1134
|
-
className: "w-2 h-2 bg-gray-
|
|
1134
|
+
className: "w-2 h-2 bg-gray-500 rounded-full animate-bounce",
|
|
1135
1135
|
style: { animationDelay: "150ms", animationDuration: "600ms" }
|
|
1136
1136
|
}
|
|
1137
1137
|
),
|
|
1138
1138
|
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1139
1139
|
"span",
|
|
1140
1140
|
{
|
|
1141
|
-
className: "w-2 h-2 bg-gray-
|
|
1141
|
+
className: "w-2 h-2 bg-gray-500 rounded-full animate-bounce",
|
|
1142
1142
|
style: { animationDelay: "300ms", animationDuration: "600ms" }
|
|
1143
1143
|
}
|
|
1144
1144
|
)
|
|
1145
|
-
] })
|
|
1145
|
+
] });
|
|
1146
1146
|
}
|
|
1147
1147
|
|
|
1148
1148
|
// src/ChatPanel.tsx
|
|
@@ -1591,6 +1591,78 @@ function AuthErrorState({
|
|
|
1591
1591
|
)
|
|
1592
1592
|
] });
|
|
1593
1593
|
}
|
|
1594
|
+
function ImageLightbox({
|
|
1595
|
+
imageUrl,
|
|
1596
|
+
onClose
|
|
1597
|
+
}) {
|
|
1598
|
+
const handleDownload = async () => {
|
|
1599
|
+
try {
|
|
1600
|
+
const response = await fetch(imageUrl);
|
|
1601
|
+
const blob = await response.blob();
|
|
1602
|
+
const url = window.URL.createObjectURL(blob);
|
|
1603
|
+
const a = document.createElement("a");
|
|
1604
|
+
a.href = url;
|
|
1605
|
+
const urlParts = imageUrl.split("/");
|
|
1606
|
+
const filename = urlParts[urlParts.length - 1] || "image.jpg";
|
|
1607
|
+
a.download = filename;
|
|
1608
|
+
document.body.appendChild(a);
|
|
1609
|
+
a.click();
|
|
1610
|
+
document.body.removeChild(a);
|
|
1611
|
+
window.URL.revokeObjectURL(url);
|
|
1612
|
+
} catch (error) {
|
|
1613
|
+
console.error("Failed to download image:", error);
|
|
1614
|
+
window.open(imageUrl, "_blank");
|
|
1615
|
+
}
|
|
1616
|
+
};
|
|
1617
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
1618
|
+
"div",
|
|
1619
|
+
{
|
|
1620
|
+
className: "fixed inset-0 z-[100] flex items-center justify-center bg-black/80",
|
|
1621
|
+
onClick: onClose,
|
|
1622
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
1623
|
+
"div",
|
|
1624
|
+
{
|
|
1625
|
+
className: "relative max-w-[90vw] max-h-[90vh] flex flex-col items-center",
|
|
1626
|
+
onClick: (e) => e.stopPropagation(),
|
|
1627
|
+
children: [
|
|
1628
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
1629
|
+
"img",
|
|
1630
|
+
{
|
|
1631
|
+
src: imageUrl,
|
|
1632
|
+
alt: "Full size preview",
|
|
1633
|
+
className: "max-w-full max-h-[80vh] object-contain rounded-lg"
|
|
1634
|
+
}
|
|
1635
|
+
),
|
|
1636
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex gap-3 mt-4", children: [
|
|
1637
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
1638
|
+
"button",
|
|
1639
|
+
{
|
|
1640
|
+
onClick: handleDownload,
|
|
1641
|
+
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",
|
|
1642
|
+
children: [
|
|
1643
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react4.Download, { className: "h-4 w-4" }),
|
|
1644
|
+
"Download"
|
|
1645
|
+
]
|
|
1646
|
+
}
|
|
1647
|
+
),
|
|
1648
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
1649
|
+
"button",
|
|
1650
|
+
{
|
|
1651
|
+
onClick: onClose,
|
|
1652
|
+
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",
|
|
1653
|
+
children: [
|
|
1654
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react4.X, { className: "h-4 w-4" }),
|
|
1655
|
+
"Close"
|
|
1656
|
+
]
|
|
1657
|
+
}
|
|
1658
|
+
)
|
|
1659
|
+
] })
|
|
1660
|
+
]
|
|
1661
|
+
}
|
|
1662
|
+
)
|
|
1663
|
+
}
|
|
1664
|
+
);
|
|
1665
|
+
}
|
|
1594
1666
|
function ChatPanel({
|
|
1595
1667
|
isOpen = true,
|
|
1596
1668
|
onClose,
|
|
@@ -1611,7 +1683,8 @@ function ChatPanel({
|
|
|
1611
1683
|
initialCorner = "bottom-left",
|
|
1612
1684
|
onCornerChange,
|
|
1613
1685
|
productBackendUrl,
|
|
1614
|
-
getAuthHeaders
|
|
1686
|
+
getAuthHeaders,
|
|
1687
|
+
isEval = false
|
|
1615
1688
|
} = {}) {
|
|
1616
1689
|
const [messages, setMessages] = React6.useState(initialMessages);
|
|
1617
1690
|
const [input, setInput] = React6.useState("");
|
|
@@ -1721,13 +1794,20 @@ function ChatPanel({
|
|
|
1721
1794
|
}, [effectiveSupabaseUrl, effectiveSupabaseAnonKey]);
|
|
1722
1795
|
React6.useEffect(() => {
|
|
1723
1796
|
if (!isEscalated || !sessionId || !supabaseRef.current) {
|
|
1797
|
+
console.log("[KiteChat] Typing channel skip - isEscalated:", isEscalated, "sessionId:", sessionId, "supabase:", !!supabaseRef.current);
|
|
1724
1798
|
return;
|
|
1725
1799
|
}
|
|
1726
1800
|
const channelName = `typing:${sessionId}`;
|
|
1727
|
-
|
|
1801
|
+
console.log("[KiteChat] Subscribing to typing channel:", channelName, "sessionId:", sessionId);
|
|
1802
|
+
const channel = supabaseRef.current.channel(channelName, {
|
|
1803
|
+
config: { broadcast: { self: true } }
|
|
1804
|
+
});
|
|
1728
1805
|
channel.on("broadcast", { event: "typing" }, (payload) => {
|
|
1806
|
+
console.log("[KiteChat] Received typing event:", payload);
|
|
1729
1807
|
const { sender, isTyping } = payload.payload;
|
|
1808
|
+
console.log("[KiteChat] Typing event - sender:", sender, "isTyping:", isTyping);
|
|
1730
1809
|
if (sender === "agent") {
|
|
1810
|
+
console.log("[KiteChat] Setting agentIsTyping to:", isTyping);
|
|
1731
1811
|
setAgentIsTyping(isTyping);
|
|
1732
1812
|
if (isTyping) {
|
|
1733
1813
|
if (typingTimeoutRef.current) {
|
|
@@ -1739,6 +1819,7 @@ function ChatPanel({
|
|
|
1739
1819
|
}
|
|
1740
1820
|
}
|
|
1741
1821
|
}).subscribe((status) => {
|
|
1822
|
+
console.log("[KiteChat] Typing channel subscription status:", status);
|
|
1742
1823
|
if (status === "SUBSCRIBED") {
|
|
1743
1824
|
typingChannelRef.current = channel;
|
|
1744
1825
|
console.log("[KiteChat] Typing channel subscribed successfully");
|
|
@@ -1753,7 +1834,7 @@ function ChatPanel({
|
|
|
1753
1834
|
window.clearTimeout(typingTimeoutRef.current);
|
|
1754
1835
|
}
|
|
1755
1836
|
};
|
|
1756
|
-
}, [isEscalated, sessionId]);
|
|
1837
|
+
}, [isEscalated, sessionId, effectiveSupabaseUrl, effectiveSupabaseAnonKey]);
|
|
1757
1838
|
React6.useEffect(() => {
|
|
1758
1839
|
if (!isOpen && isEscalated && supabaseRef.current && sessionId) {
|
|
1759
1840
|
console.log("[KiteChat] Panel closed during live chat, marking disconnected");
|
|
@@ -1964,6 +2045,77 @@ function ChatPanel({
|
|
|
1964
2045
|
const [pendingBulkSession, setPendingBulkSession] = React6.useState(null);
|
|
1965
2046
|
const pendingBulkSessionRef = React6.useRef(null);
|
|
1966
2047
|
const fileInputRef = React6.useRef(null);
|
|
2048
|
+
const [pendingImages, setPendingImages] = React6.useState([]);
|
|
2049
|
+
const [isUploadingImage, setIsUploadingImage] = React6.useState(false);
|
|
2050
|
+
const [isDragOver, setIsDragOver] = React6.useState(false);
|
|
2051
|
+
const imageInputRef = React6.useRef(null);
|
|
2052
|
+
const [lightboxImageUrl, setLightboxImageUrl] = React6.useState(null);
|
|
2053
|
+
const uploadImageToStorage = React6.useCallback(async (file) => {
|
|
2054
|
+
if (!supabaseRef.current) {
|
|
2055
|
+
console.error("[KiteChat] Supabase client not available for file upload");
|
|
2056
|
+
return null;
|
|
2057
|
+
}
|
|
2058
|
+
const fileExt = file.name.split(".").pop();
|
|
2059
|
+
const fileName = `${sessionId}/${Date.now()}-${Math.random().toString(36).substring(7)}.${fileExt}`;
|
|
2060
|
+
const bucketName = "chat-attachments";
|
|
2061
|
+
try {
|
|
2062
|
+
const { data, error } = await supabaseRef.current.storage.from(bucketName).upload(fileName, file, {
|
|
2063
|
+
cacheControl: "3600",
|
|
2064
|
+
upsert: false
|
|
2065
|
+
});
|
|
2066
|
+
if (error) {
|
|
2067
|
+
console.error("[KiteChat] Upload error:", error);
|
|
2068
|
+
return null;
|
|
2069
|
+
}
|
|
2070
|
+
const { data: urlData } = supabaseRef.current.storage.from(bucketName).getPublicUrl(fileName);
|
|
2071
|
+
return urlData?.publicUrl || null;
|
|
2072
|
+
} catch (err) {
|
|
2073
|
+
console.error("[KiteChat] Upload failed:", err);
|
|
2074
|
+
return null;
|
|
2075
|
+
}
|
|
2076
|
+
}, [sessionId]);
|
|
2077
|
+
const handleImageSelect = React6.useCallback((files) => {
|
|
2078
|
+
if (!files) return;
|
|
2079
|
+
const imageFiles = Array.from(files).filter(
|
|
2080
|
+
(file) => file.type.startsWith("image/") || file.type === "application/pdf"
|
|
2081
|
+
);
|
|
2082
|
+
const newImages = imageFiles.map((file) => ({
|
|
2083
|
+
file,
|
|
2084
|
+
preview: file.type.startsWith("image/") ? URL.createObjectURL(file) : ""
|
|
2085
|
+
}));
|
|
2086
|
+
setPendingImages((prev) => [...prev, ...newImages]);
|
|
2087
|
+
}, []);
|
|
2088
|
+
const handleDragOver = React6.useCallback((e) => {
|
|
2089
|
+
e.preventDefault();
|
|
2090
|
+
e.stopPropagation();
|
|
2091
|
+
setIsDragOver(true);
|
|
2092
|
+
}, []);
|
|
2093
|
+
const handleDragLeave = React6.useCallback((e) => {
|
|
2094
|
+
e.preventDefault();
|
|
2095
|
+
e.stopPropagation();
|
|
2096
|
+
setIsDragOver(false);
|
|
2097
|
+
}, []);
|
|
2098
|
+
const handleDrop = React6.useCallback((e) => {
|
|
2099
|
+
e.preventDefault();
|
|
2100
|
+
e.stopPropagation();
|
|
2101
|
+
setIsDragOver(false);
|
|
2102
|
+
const files = e.dataTransfer.files;
|
|
2103
|
+
if (files.length > 0) {
|
|
2104
|
+
const csvFile = Array.from(files).find((f) => f.name.endsWith(".csv"));
|
|
2105
|
+
if (csvFile && !isEscalated) {
|
|
2106
|
+
setPendingFile(csvFile);
|
|
2107
|
+
} else {
|
|
2108
|
+
handleImageSelect(files);
|
|
2109
|
+
}
|
|
2110
|
+
}
|
|
2111
|
+
}, [isEscalated, handleImageSelect]);
|
|
2112
|
+
React6.useEffect(() => {
|
|
2113
|
+
return () => {
|
|
2114
|
+
pendingImages.forEach((img) => {
|
|
2115
|
+
if (img.preview) URL.revokeObjectURL(img.preview);
|
|
2116
|
+
});
|
|
2117
|
+
};
|
|
2118
|
+
}, [pendingImages]);
|
|
1967
2119
|
const [searchExpanded, setSearchExpanded] = React6.useState(false);
|
|
1968
2120
|
const [searchInput, setSearchInput] = React6.useState("");
|
|
1969
2121
|
const searchInputRef = React6.useRef(null);
|
|
@@ -2020,6 +2172,11 @@ function ChatPanel({
|
|
|
2020
2172
|
messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
|
|
2021
2173
|
}
|
|
2022
2174
|
}, [messages, phase, activeGuide]);
|
|
2175
|
+
React6.useEffect(() => {
|
|
2176
|
+
if (isEscalated && agentIsTyping && !activeGuide) {
|
|
2177
|
+
messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
|
|
2178
|
+
}
|
|
2179
|
+
}, [isEscalated, agentIsTyping, activeGuide]);
|
|
2023
2180
|
const latestBulkSummaryNavigation = React6.useMemo(() => {
|
|
2024
2181
|
for (let i = messages.length - 1; i >= 0; i--) {
|
|
2025
2182
|
const msg = messages[i];
|
|
@@ -2256,7 +2413,7 @@ function ChatPanel({
|
|
|
2256
2413
|
setPanelView("landing");
|
|
2257
2414
|
setCurrentFolderId(void 0);
|
|
2258
2415
|
}
|
|
2259
|
-
function handleSubmit(e) {
|
|
2416
|
+
async function handleSubmit(e) {
|
|
2260
2417
|
e.preventDefault();
|
|
2261
2418
|
const trimmed = input.trim();
|
|
2262
2419
|
if (pendingFile) {
|
|
@@ -2276,6 +2433,49 @@ function ChatPanel({
|
|
|
2276
2433
|
if (fileInputRef.current) fileInputRef.current.value = "";
|
|
2277
2434
|
return;
|
|
2278
2435
|
}
|
|
2436
|
+
if (pendingImages.length > 0) {
|
|
2437
|
+
setIsUploadingImage(true);
|
|
2438
|
+
try {
|
|
2439
|
+
const uploadedUrls = [];
|
|
2440
|
+
for (const img of pendingImages) {
|
|
2441
|
+
const url = await uploadImageToStorage(img.file);
|
|
2442
|
+
if (url) {
|
|
2443
|
+
uploadedUrls.push(url);
|
|
2444
|
+
}
|
|
2445
|
+
if (img.preview) URL.revokeObjectURL(img.preview);
|
|
2446
|
+
}
|
|
2447
|
+
if (uploadedUrls.length > 0) {
|
|
2448
|
+
const imageMarkdown = uploadedUrls.map((url) => ``).join("\n");
|
|
2449
|
+
const messageContent = trimmed ? `${trimmed}
|
|
2450
|
+
|
|
2451
|
+
${imageMarkdown}` : imageMarkdown;
|
|
2452
|
+
const userMessage = {
|
|
2453
|
+
id: Date.now(),
|
|
2454
|
+
role: "user",
|
|
2455
|
+
content: messageContent,
|
|
2456
|
+
imageUrls: uploadedUrls
|
|
2457
|
+
};
|
|
2458
|
+
setMessages((prev) => [...prev, userMessage]);
|
|
2459
|
+
if (isEscalated) {
|
|
2460
|
+
sendEscalatedMessage(messageContent);
|
|
2461
|
+
sendTypingIndicator(false);
|
|
2462
|
+
if (userTypingTimeoutRef.current) {
|
|
2463
|
+
window.clearTimeout(userTypingTimeoutRef.current);
|
|
2464
|
+
userTypingTimeoutRef.current = null;
|
|
2465
|
+
}
|
|
2466
|
+
} else {
|
|
2467
|
+
startChatFlow(messageContent);
|
|
2468
|
+
}
|
|
2469
|
+
}
|
|
2470
|
+
} catch (err) {
|
|
2471
|
+
console.error("[KiteChat] Failed to upload images:", err);
|
|
2472
|
+
} finally {
|
|
2473
|
+
setIsUploadingImage(false);
|
|
2474
|
+
setPendingImages([]);
|
|
2475
|
+
setInput("");
|
|
2476
|
+
}
|
|
2477
|
+
return;
|
|
2478
|
+
}
|
|
2279
2479
|
if (!trimmed) return;
|
|
2280
2480
|
if (isEscalated) {
|
|
2281
2481
|
const userMessage = {
|
|
@@ -2440,7 +2640,8 @@ function ChatPanel({
|
|
|
2440
2640
|
user_id: userId,
|
|
2441
2641
|
org_id: orgId,
|
|
2442
2642
|
user_name: userName,
|
|
2443
|
-
user_email: userEmail
|
|
2643
|
+
user_email: userEmail,
|
|
2644
|
+
is_eval: isEval
|
|
2444
2645
|
}),
|
|
2445
2646
|
signal: controller.signal
|
|
2446
2647
|
});
|
|
@@ -3333,19 +3534,23 @@ ${userText}`
|
|
|
3333
3534
|
)
|
|
3334
3535
|
] }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
|
|
3335
3536
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
3336
|
-
"
|
|
3537
|
+
"textarea",
|
|
3337
3538
|
{
|
|
3338
3539
|
ref: searchInputRef,
|
|
3339
|
-
type: "text",
|
|
3340
3540
|
value: searchInput,
|
|
3341
|
-
onChange: (e) =>
|
|
3541
|
+
onChange: (e) => {
|
|
3542
|
+
setSearchInput(e.target.value);
|
|
3543
|
+
e.target.style.height = "auto";
|
|
3544
|
+
e.target.style.height = Math.min(e.target.scrollHeight, 120) + "px";
|
|
3545
|
+
},
|
|
3342
3546
|
onKeyDown: (e) => {
|
|
3343
|
-
if (e.key === "Enter" && searchInput.trim()) {
|
|
3547
|
+
if (e.key === "Enter" && !e.shiftKey && searchInput.trim()) {
|
|
3344
3548
|
e.preventDefault();
|
|
3345
3549
|
onOpen?.();
|
|
3346
3550
|
startChatFlow(searchInput.trim());
|
|
3347
3551
|
setSearchInput("");
|
|
3348
3552
|
setSearchExpanded(false);
|
|
3553
|
+
e.currentTarget.style.height = "auto";
|
|
3349
3554
|
} else if (e.key === "Escape") {
|
|
3350
3555
|
setSearchExpanded(false);
|
|
3351
3556
|
setSearchInput("");
|
|
@@ -3357,7 +3562,8 @@ ${userText}`
|
|
|
3357
3562
|
}
|
|
3358
3563
|
},
|
|
3359
3564
|
placeholder: "Ask a question...",
|
|
3360
|
-
|
|
3565
|
+
rows: 1,
|
|
3566
|
+
className: "flex-1 text-sm text-gray-700 outline-none bg-transparent resize-none min-h-[20px] max-h-[120px]"
|
|
3361
3567
|
}
|
|
3362
3568
|
),
|
|
3363
3569
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
@@ -3617,12 +3823,55 @@ ${userText}`
|
|
|
3617
3823
|
return null;
|
|
3618
3824
|
}
|
|
3619
3825
|
if (isUser) {
|
|
3620
|
-
return /* @__PURE__ */ (0, import_jsx_runtime10.
|
|
3826
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: `flex flex-col items-end gap-2 ${isRoleChange ? "mt-3" : ""}`, children: [
|
|
3827
|
+
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)(
|
|
3828
|
+
"button",
|
|
3829
|
+
{
|
|
3830
|
+
onClick: () => setLightboxImageUrl(url),
|
|
3831
|
+
className: "block cursor-pointer",
|
|
3832
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
3833
|
+
"img",
|
|
3834
|
+
{
|
|
3835
|
+
src: url,
|
|
3836
|
+
alt: `Attachment ${imgIndex + 1}`,
|
|
3837
|
+
className: "max-h-32 max-w-[200px] rounded-lg object-cover border border-gray-700 hover:opacity-90 transition-opacity"
|
|
3838
|
+
}
|
|
3839
|
+
)
|
|
3840
|
+
},
|
|
3841
|
+
imgIndex
|
|
3842
|
+
)) }),
|
|
3843
|
+
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() })
|
|
3844
|
+
] }, message.id);
|
|
3621
3845
|
}
|
|
3622
3846
|
if (message.role === "agent") {
|
|
3623
|
-
|
|
3847
|
+
const imageRegex = /!\[image\]\(([^)]+)\)/g;
|
|
3848
|
+
const extractedImageUrls = [];
|
|
3849
|
+
let match;
|
|
3850
|
+
const contentStr = message.content || "";
|
|
3851
|
+
while ((match = imageRegex.exec(contentStr)) !== null) {
|
|
3852
|
+
extractedImageUrls.push(match[1]);
|
|
3853
|
+
}
|
|
3854
|
+
const agentImageUrls = message.imageUrls || extractedImageUrls;
|
|
3855
|
+
const agentTextContent = contentStr.replace(/!\[image\]\([^)]+\)\n*/g, "").trim();
|
|
3856
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: `flex flex-col items-start gap-2 ${isRoleChange ? "mt-3" : ""}`, children: [
|
|
3624
3857
|
isRoleChange && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "text-[10px] text-gray-500 mb-1 ml-1", children: "Agent" }),
|
|
3625
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "
|
|
3858
|
+
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)(
|
|
3859
|
+
"button",
|
|
3860
|
+
{
|
|
3861
|
+
onClick: () => setLightboxImageUrl(url),
|
|
3862
|
+
className: "block cursor-pointer",
|
|
3863
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
3864
|
+
"img",
|
|
3865
|
+
{
|
|
3866
|
+
src: url,
|
|
3867
|
+
alt: `Attachment ${imgIndex + 1}`,
|
|
3868
|
+
className: "max-h-32 max-w-[200px] rounded-lg object-cover border border-gray-300 hover:opacity-90 transition-opacity"
|
|
3869
|
+
}
|
|
3870
|
+
)
|
|
3871
|
+
},
|
|
3872
|
+
imgIndex
|
|
3873
|
+
)) }),
|
|
3874
|
+
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 })
|
|
3626
3875
|
] }, message.id);
|
|
3627
3876
|
}
|
|
3628
3877
|
if (message.kind === "searchSummary") {
|
|
@@ -4658,131 +4907,183 @@ ${userText}`
|
|
|
4658
4907
|
progressSteps
|
|
4659
4908
|
}
|
|
4660
4909
|
) }),
|
|
4661
|
-
isEscalated && agentIsTyping && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "mt-2", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(TypingIndicator, {}) }),
|
|
4910
|
+
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, {}) }) }),
|
|
4662
4911
|
!activeGuide && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { ref: messagesEndRef })
|
|
4663
4912
|
] }) }) }) })
|
|
4664
4913
|
}
|
|
4665
4914
|
),
|
|
4666
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
4667
|
-
|
|
4668
|
-
|
|
4669
|
-
|
|
4670
|
-
|
|
4671
|
-
|
|
4672
|
-
|
|
4673
|
-
|
|
4674
|
-
|
|
4675
|
-
|
|
4676
|
-
|
|
4677
|
-
|
|
4678
|
-
|
|
4679
|
-
|
|
4680
|
-
|
|
4681
|
-
|
|
4682
|
-
|
|
4683
|
-
|
|
4684
|
-
|
|
4685
|
-
|
|
4686
|
-
|
|
4687
|
-
ref: fileInputRef,
|
|
4688
|
-
type: "file",
|
|
4689
|
-
accept: ".csv",
|
|
4690
|
-
className: "hidden",
|
|
4691
|
-
onChange: (e) => {
|
|
4692
|
-
const file = e.target.files?.[0];
|
|
4693
|
-
if (file) {
|
|
4694
|
-
setPendingFile(file);
|
|
4915
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
4916
|
+
"div",
|
|
4917
|
+
{
|
|
4918
|
+
className: `px-4 py-3 bg-white shrink-0 ${isDragOver ? "ring-2 ring-blue-400 ring-inset bg-blue-50" : ""}`,
|
|
4919
|
+
onDragOver: handleDragOver,
|
|
4920
|
+
onDragLeave: handleDragLeave,
|
|
4921
|
+
onDrop: handleDrop,
|
|
4922
|
+
children: [
|
|
4923
|
+
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: [
|
|
4924
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react4.FileSpreadsheet, { className: "h-4 w-4 text-blue-600" }),
|
|
4925
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "text-xs text-blue-700 flex-1 truncate", children: pendingFile.name }),
|
|
4926
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
4927
|
+
"button",
|
|
4928
|
+
{
|
|
4929
|
+
type: "button",
|
|
4930
|
+
onClick: () => {
|
|
4931
|
+
setPendingFile(null);
|
|
4932
|
+
if (fileInputRef.current) fileInputRef.current.value = "";
|
|
4933
|
+
},
|
|
4934
|
+
className: "text-blue-600 hover:text-blue-800",
|
|
4935
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react4.X, { className: "h-4 w-4" })
|
|
4695
4936
|
}
|
|
4696
|
-
|
|
4697
|
-
}
|
|
4698
|
-
|
|
4699
|
-
|
|
4700
|
-
|
|
4701
|
-
|
|
4702
|
-
|
|
4703
|
-
|
|
4704
|
-
|
|
4705
|
-
|
|
4706
|
-
onClick: () => fileInputRef.current?.click(),
|
|
4707
|
-
className: "h-5 w-5 rounded-full text-gray-400 hover:text-gray-600 hover:bg-gray-100",
|
|
4708
|
-
title: "Upload CSV for bulk operations",
|
|
4709
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react4.Paperclip, { className: "h-2.5 w-2.5" })
|
|
4710
|
-
}
|
|
4711
|
-
),
|
|
4712
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
4713
|
-
"textarea",
|
|
4714
|
-
{
|
|
4715
|
-
placeholder: pendingFile ? "Describe what to do with this CSV..." : "Ask anything...",
|
|
4716
|
-
value: input,
|
|
4717
|
-
onChange: (e) => {
|
|
4718
|
-
setInput(e.target.value);
|
|
4719
|
-
if (e.target.value.length > 0) {
|
|
4720
|
-
handleTypingStart();
|
|
4937
|
+
)
|
|
4938
|
+
] }),
|
|
4939
|
+
pendingImages.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "mb-2 flex flex-wrap gap-2", children: [
|
|
4940
|
+
pendingImages.map((img, index) => /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "relative group", children: [
|
|
4941
|
+
img.preview ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
4942
|
+
"img",
|
|
4943
|
+
{
|
|
4944
|
+
src: img.preview,
|
|
4945
|
+
alt: `Preview ${index + 1}`,
|
|
4946
|
+
className: "h-16 w-16 object-cover rounded-lg border border-gray-200"
|
|
4721
4947
|
}
|
|
4722
|
-
},
|
|
4723
|
-
|
|
4724
|
-
|
|
4725
|
-
|
|
4726
|
-
|
|
4727
|
-
|
|
4728
|
-
|
|
4729
|
-
|
|
4730
|
-
|
|
4731
|
-
|
|
4732
|
-
|
|
4733
|
-
e.preventDefault();
|
|
4734
|
-
if (input.trim() || pendingFile) {
|
|
4735
|
-
const form = e.currentTarget.closest("form");
|
|
4736
|
-
if (form) {
|
|
4737
|
-
form.requestSubmit();
|
|
4738
|
-
}
|
|
4739
|
-
}
|
|
4740
|
-
return;
|
|
4948
|
+
) : /* @__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" }) }),
|
|
4949
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
4950
|
+
"button",
|
|
4951
|
+
{
|
|
4952
|
+
type: "button",
|
|
4953
|
+
onClick: () => {
|
|
4954
|
+
if (img.preview) URL.revokeObjectURL(img.preview);
|
|
4955
|
+
setPendingImages((prev) => prev.filter((_, i) => i !== index));
|
|
4956
|
+
},
|
|
4957
|
+
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",
|
|
4958
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react4.X, { className: "h-2.5 w-2.5" })
|
|
4741
4959
|
}
|
|
4742
|
-
|
|
4743
|
-
|
|
4744
|
-
|
|
4745
|
-
|
|
4746
|
-
|
|
4747
|
-
|
|
4748
|
-
|
|
4749
|
-
|
|
4750
|
-
|
|
4751
|
-
|
|
4752
|
-
|
|
4753
|
-
|
|
4754
|
-
|
|
4755
|
-
|
|
4756
|
-
if (
|
|
4757
|
-
|
|
4758
|
-
e.stopPropagation();
|
|
4759
|
-
handleConfirmNavigation(pendingNavigation);
|
|
4760
|
-
return;
|
|
4761
|
-
}
|
|
4762
|
-
const currentGuide = activeGuideRef.current;
|
|
4763
|
-
if (currentGuide) {
|
|
4764
|
-
e.preventDefault();
|
|
4765
|
-
e.stopPropagation();
|
|
4766
|
-
advanceGuide();
|
|
4767
|
-
return;
|
|
4960
|
+
)
|
|
4961
|
+
] }, index)),
|
|
4962
|
+
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" }) })
|
|
4963
|
+
] }),
|
|
4964
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("form", { onSubmit: handleSubmit, className: "w-full", children: [
|
|
4965
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
4966
|
+
"input",
|
|
4967
|
+
{
|
|
4968
|
+
ref: fileInputRef,
|
|
4969
|
+
type: "file",
|
|
4970
|
+
accept: ".csv",
|
|
4971
|
+
className: "hidden",
|
|
4972
|
+
onChange: (e) => {
|
|
4973
|
+
const file = e.target.files?.[0];
|
|
4974
|
+
if (file) {
|
|
4975
|
+
setPendingFile(file);
|
|
4768
4976
|
}
|
|
4769
4977
|
}
|
|
4770
4978
|
}
|
|
4771
|
-
|
|
4772
|
-
|
|
4773
|
-
|
|
4774
|
-
|
|
4775
|
-
|
|
4776
|
-
|
|
4777
|
-
|
|
4778
|
-
|
|
4779
|
-
|
|
4780
|
-
|
|
4781
|
-
|
|
4782
|
-
|
|
4783
|
-
|
|
4784
|
-
|
|
4785
|
-
|
|
4979
|
+
),
|
|
4980
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
4981
|
+
"input",
|
|
4982
|
+
{
|
|
4983
|
+
ref: imageInputRef,
|
|
4984
|
+
type: "file",
|
|
4985
|
+
accept: "image/*,.pdf",
|
|
4986
|
+
multiple: true,
|
|
4987
|
+
className: "hidden",
|
|
4988
|
+
onChange: (e) => handleImageSelect(e.target.files)
|
|
4989
|
+
}
|
|
4990
|
+
),
|
|
4991
|
+
/* @__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: [
|
|
4992
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
4993
|
+
Button,
|
|
4994
|
+
{
|
|
4995
|
+
type: "button",
|
|
4996
|
+
size: "icon",
|
|
4997
|
+
variant: "ghost",
|
|
4998
|
+
onClick: () => {
|
|
4999
|
+
if (isEscalated) {
|
|
5000
|
+
imageInputRef.current?.click();
|
|
5001
|
+
} else {
|
|
5002
|
+
fileInputRef.current?.click();
|
|
5003
|
+
}
|
|
5004
|
+
},
|
|
5005
|
+
className: "h-5 w-5 rounded-full text-gray-400 hover:text-gray-600 hover:bg-gray-100",
|
|
5006
|
+
title: isEscalated ? "Attach image or file" : "Upload CSV for bulk operations",
|
|
5007
|
+
disabled: isUploadingImage,
|
|
5008
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react4.Paperclip, { className: "h-2.5 w-2.5" })
|
|
5009
|
+
}
|
|
5010
|
+
),
|
|
5011
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
5012
|
+
"textarea",
|
|
5013
|
+
{
|
|
5014
|
+
placeholder: pendingFile ? "Describe what to do with this CSV..." : pendingImages.length > 0 ? "Add a message (optional)..." : isDragOver ? "Drop files here..." : "Ask anything...",
|
|
5015
|
+
value: input,
|
|
5016
|
+
onChange: (e) => {
|
|
5017
|
+
setInput(e.target.value);
|
|
5018
|
+
if (e.target.value.length > 0) {
|
|
5019
|
+
handleTypingStart();
|
|
5020
|
+
}
|
|
5021
|
+
},
|
|
5022
|
+
rows: 1,
|
|
5023
|
+
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",
|
|
5024
|
+
style: { minHeight: "20px", maxHeight: "120px" },
|
|
5025
|
+
onInput: (e) => {
|
|
5026
|
+
const target = e.target;
|
|
5027
|
+
target.style.height = "auto";
|
|
5028
|
+
target.style.height = Math.min(target.scrollHeight, 120) + "px";
|
|
5029
|
+
},
|
|
5030
|
+
onKeyDown: (e) => {
|
|
5031
|
+
if (e.key === "Enter" && !e.shiftKey && !e.metaKey && !e.ctrlKey) {
|
|
5032
|
+
e.preventDefault();
|
|
5033
|
+
if (input.trim() || pendingFile || pendingImages.length > 0) {
|
|
5034
|
+
const form = e.currentTarget.closest("form");
|
|
5035
|
+
if (form) {
|
|
5036
|
+
form.requestSubmit();
|
|
5037
|
+
}
|
|
5038
|
+
}
|
|
5039
|
+
return;
|
|
5040
|
+
}
|
|
5041
|
+
if ((e.metaKey || e.ctrlKey) && e.key === "Enter") {
|
|
5042
|
+
const currentBulkSession = pendingBulkSessionRef.current;
|
|
5043
|
+
if (currentBulkSession) {
|
|
5044
|
+
e.preventDefault();
|
|
5045
|
+
e.stopPropagation();
|
|
5046
|
+
confirmBulkOperation(currentBulkSession);
|
|
5047
|
+
return;
|
|
5048
|
+
}
|
|
5049
|
+
if (pendingAction) {
|
|
5050
|
+
e.preventDefault();
|
|
5051
|
+
e.stopPropagation();
|
|
5052
|
+
handleActionSubmit();
|
|
5053
|
+
return;
|
|
5054
|
+
}
|
|
5055
|
+
if (pendingNavigation) {
|
|
5056
|
+
e.preventDefault();
|
|
5057
|
+
e.stopPropagation();
|
|
5058
|
+
handleConfirmNavigation(pendingNavigation);
|
|
5059
|
+
return;
|
|
5060
|
+
}
|
|
5061
|
+
const currentGuide = activeGuideRef.current;
|
|
5062
|
+
if (currentGuide) {
|
|
5063
|
+
e.preventDefault();
|
|
5064
|
+
e.stopPropagation();
|
|
5065
|
+
advanceGuide();
|
|
5066
|
+
return;
|
|
5067
|
+
}
|
|
5068
|
+
}
|
|
5069
|
+
}
|
|
5070
|
+
}
|
|
5071
|
+
),
|
|
5072
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
5073
|
+
Button,
|
|
5074
|
+
{
|
|
5075
|
+
type: "submit",
|
|
5076
|
+
size: "icon",
|
|
5077
|
+
disabled: !input.trim() && !pendingFile || isWaitingForAuth,
|
|
5078
|
+
className: "h-6 w-6 rounded-full bg-gray-700 hover:bg-gray-600 disabled:bg-gray-300",
|
|
5079
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react4.ArrowUp, { className: "h-2.5 w-2.5 text-white" })
|
|
5080
|
+
}
|
|
5081
|
+
)
|
|
5082
|
+
] })
|
|
5083
|
+
] })
|
|
5084
|
+
]
|
|
5085
|
+
}
|
|
5086
|
+
),
|
|
4786
5087
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
4787
5088
|
GuideCursor,
|
|
4788
5089
|
{
|
|
@@ -4791,6 +5092,13 @@ ${userText}`
|
|
|
4791
5092
|
visible: cursorState.visible,
|
|
4792
5093
|
onClick: cursorState.onClick
|
|
4793
5094
|
}
|
|
5095
|
+
),
|
|
5096
|
+
lightboxImageUrl && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
5097
|
+
ImageLightbox,
|
|
5098
|
+
{
|
|
5099
|
+
imageUrl: lightboxImageUrl,
|
|
5100
|
+
onClose: () => setLightboxImageUrl(null)
|
|
5101
|
+
}
|
|
4794
5102
|
)
|
|
4795
5103
|
]
|
|
4796
5104
|
}
|
|
@@ -4835,7 +5143,8 @@ function ChatPanelWithToggle({
|
|
|
4835
5143
|
initialCorner,
|
|
4836
5144
|
onCornerChange,
|
|
4837
5145
|
productBackendUrl,
|
|
4838
|
-
getAuthHeaders
|
|
5146
|
+
getAuthHeaders,
|
|
5147
|
+
isEval
|
|
4839
5148
|
}) {
|
|
4840
5149
|
const [internalIsOpen, setInternalIsOpen] = React6.useState(defaultOpen);
|
|
4841
5150
|
const isOpen = controlledIsOpen !== void 0 ? controlledIsOpen : internalIsOpen;
|
|
@@ -4866,7 +5175,8 @@ function ChatPanelWithToggle({
|
|
|
4866
5175
|
initialCorner,
|
|
4867
5176
|
onCornerChange,
|
|
4868
5177
|
productBackendUrl,
|
|
4869
|
-
getAuthHeaders
|
|
5178
|
+
getAuthHeaders,
|
|
5179
|
+
isEval
|
|
4870
5180
|
}
|
|
4871
5181
|
);
|
|
4872
5182
|
}
|