@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/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");
|
|
@@ -1826,9 +1907,7 @@ function ChatPanel({
|
|
|
1826
1907
|
markDisconnectedWithKeepalive();
|
|
1827
1908
|
};
|
|
1828
1909
|
const handleVisibilityChange = () => {
|
|
1829
|
-
if (document.visibilityState === "
|
|
1830
|
-
markDisconnectedWithKeepalive();
|
|
1831
|
-
} else if (document.visibilityState === "visible") {
|
|
1910
|
+
if (document.visibilityState === "visible") {
|
|
1832
1911
|
markActive();
|
|
1833
1912
|
}
|
|
1834
1913
|
};
|
|
@@ -1966,6 +2045,77 @@ function ChatPanel({
|
|
|
1966
2045
|
const [pendingBulkSession, setPendingBulkSession] = React6.useState(null);
|
|
1967
2046
|
const pendingBulkSessionRef = React6.useRef(null);
|
|
1968
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]);
|
|
1969
2119
|
const [searchExpanded, setSearchExpanded] = React6.useState(false);
|
|
1970
2120
|
const [searchInput, setSearchInput] = React6.useState("");
|
|
1971
2121
|
const searchInputRef = React6.useRef(null);
|
|
@@ -2022,6 +2172,11 @@ function ChatPanel({
|
|
|
2022
2172
|
messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
|
|
2023
2173
|
}
|
|
2024
2174
|
}, [messages, phase, activeGuide]);
|
|
2175
|
+
React6.useEffect(() => {
|
|
2176
|
+
if (isEscalated && agentIsTyping && !activeGuide) {
|
|
2177
|
+
messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
|
|
2178
|
+
}
|
|
2179
|
+
}, [isEscalated, agentIsTyping, activeGuide]);
|
|
2025
2180
|
const latestBulkSummaryNavigation = React6.useMemo(() => {
|
|
2026
2181
|
for (let i = messages.length - 1; i >= 0; i--) {
|
|
2027
2182
|
const msg = messages[i];
|
|
@@ -2258,7 +2413,7 @@ function ChatPanel({
|
|
|
2258
2413
|
setPanelView("landing");
|
|
2259
2414
|
setCurrentFolderId(void 0);
|
|
2260
2415
|
}
|
|
2261
|
-
function handleSubmit(e) {
|
|
2416
|
+
async function handleSubmit(e) {
|
|
2262
2417
|
e.preventDefault();
|
|
2263
2418
|
const trimmed = input.trim();
|
|
2264
2419
|
if (pendingFile) {
|
|
@@ -2278,6 +2433,49 @@ function ChatPanel({
|
|
|
2278
2433
|
if (fileInputRef.current) fileInputRef.current.value = "";
|
|
2279
2434
|
return;
|
|
2280
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
|
+
}
|
|
2281
2479
|
if (!trimmed) return;
|
|
2282
2480
|
if (isEscalated) {
|
|
2283
2481
|
const userMessage = {
|
|
@@ -2442,7 +2640,8 @@ function ChatPanel({
|
|
|
2442
2640
|
user_id: userId,
|
|
2443
2641
|
org_id: orgId,
|
|
2444
2642
|
user_name: userName,
|
|
2445
|
-
user_email: userEmail
|
|
2643
|
+
user_email: userEmail,
|
|
2644
|
+
is_eval: isEval
|
|
2446
2645
|
}),
|
|
2447
2646
|
signal: controller.signal
|
|
2448
2647
|
});
|
|
@@ -3335,19 +3534,23 @@ ${userText}`
|
|
|
3335
3534
|
)
|
|
3336
3535
|
] }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
|
|
3337
3536
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
3338
|
-
"
|
|
3537
|
+
"textarea",
|
|
3339
3538
|
{
|
|
3340
3539
|
ref: searchInputRef,
|
|
3341
|
-
type: "text",
|
|
3342
3540
|
value: searchInput,
|
|
3343
|
-
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
|
+
},
|
|
3344
3546
|
onKeyDown: (e) => {
|
|
3345
|
-
if (e.key === "Enter" && searchInput.trim()) {
|
|
3547
|
+
if (e.key === "Enter" && !e.shiftKey && searchInput.trim()) {
|
|
3346
3548
|
e.preventDefault();
|
|
3347
3549
|
onOpen?.();
|
|
3348
3550
|
startChatFlow(searchInput.trim());
|
|
3349
3551
|
setSearchInput("");
|
|
3350
3552
|
setSearchExpanded(false);
|
|
3553
|
+
e.currentTarget.style.height = "auto";
|
|
3351
3554
|
} else if (e.key === "Escape") {
|
|
3352
3555
|
setSearchExpanded(false);
|
|
3353
3556
|
setSearchInput("");
|
|
@@ -3359,7 +3562,8 @@ ${userText}`
|
|
|
3359
3562
|
}
|
|
3360
3563
|
},
|
|
3361
3564
|
placeholder: "Ask a question...",
|
|
3362
|
-
|
|
3565
|
+
rows: 1,
|
|
3566
|
+
className: "flex-1 text-sm text-gray-700 outline-none bg-transparent resize-none min-h-[20px] max-h-[120px]"
|
|
3363
3567
|
}
|
|
3364
3568
|
),
|
|
3365
3569
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex items-center gap-2", children: [
|
|
@@ -3619,12 +3823,55 @@ ${userText}`
|
|
|
3619
3823
|
return null;
|
|
3620
3824
|
}
|
|
3621
3825
|
if (isUser) {
|
|
3622
|
-
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);
|
|
3623
3845
|
}
|
|
3624
3846
|
if (message.role === "agent") {
|
|
3625
|
-
|
|
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: [
|
|
3626
3857
|
isRoleChange && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "text-[10px] text-gray-500 mb-1 ml-1", children: "Agent" }),
|
|
3627
|
-
/* @__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 })
|
|
3628
3875
|
] }, message.id);
|
|
3629
3876
|
}
|
|
3630
3877
|
if (message.kind === "searchSummary") {
|
|
@@ -4660,131 +4907,183 @@ ${userText}`
|
|
|
4660
4907
|
progressSteps
|
|
4661
4908
|
}
|
|
4662
4909
|
) }),
|
|
4663
|
-
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, {}) }) }),
|
|
4664
4911
|
!activeGuide && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { ref: messagesEndRef })
|
|
4665
4912
|
] }) }) }) })
|
|
4666
4913
|
}
|
|
4667
4914
|
),
|
|
4668
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
4669
|
-
|
|
4670
|
-
|
|
4671
|
-
|
|
4672
|
-
|
|
4673
|
-
|
|
4674
|
-
|
|
4675
|
-
|
|
4676
|
-
|
|
4677
|
-
|
|
4678
|
-
|
|
4679
|
-
|
|
4680
|
-
|
|
4681
|
-
|
|
4682
|
-
|
|
4683
|
-
|
|
4684
|
-
|
|
4685
|
-
|
|
4686
|
-
|
|
4687
|
-
|
|
4688
|
-
|
|
4689
|
-
ref: fileInputRef,
|
|
4690
|
-
type: "file",
|
|
4691
|
-
accept: ".csv",
|
|
4692
|
-
className: "hidden",
|
|
4693
|
-
onChange: (e) => {
|
|
4694
|
-
const file = e.target.files?.[0];
|
|
4695
|
-
if (file) {
|
|
4696
|
-
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" })
|
|
4697
4936
|
}
|
|
4698
|
-
|
|
4699
|
-
}
|
|
4700
|
-
|
|
4701
|
-
|
|
4702
|
-
|
|
4703
|
-
|
|
4704
|
-
|
|
4705
|
-
|
|
4706
|
-
|
|
4707
|
-
|
|
4708
|
-
onClick: () => fileInputRef.current?.click(),
|
|
4709
|
-
className: "h-5 w-5 rounded-full text-gray-400 hover:text-gray-600 hover:bg-gray-100",
|
|
4710
|
-
title: "Upload CSV for bulk operations",
|
|
4711
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react4.Paperclip, { className: "h-2.5 w-2.5" })
|
|
4712
|
-
}
|
|
4713
|
-
),
|
|
4714
|
-
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
4715
|
-
"textarea",
|
|
4716
|
-
{
|
|
4717
|
-
placeholder: pendingFile ? "Describe what to do with this CSV..." : "Ask anything...",
|
|
4718
|
-
value: input,
|
|
4719
|
-
onChange: (e) => {
|
|
4720
|
-
setInput(e.target.value);
|
|
4721
|
-
if (e.target.value.length > 0) {
|
|
4722
|
-
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"
|
|
4723
4947
|
}
|
|
4724
|
-
},
|
|
4725
|
-
|
|
4726
|
-
|
|
4727
|
-
|
|
4728
|
-
|
|
4729
|
-
|
|
4730
|
-
|
|
4731
|
-
|
|
4732
|
-
|
|
4733
|
-
|
|
4734
|
-
|
|
4735
|
-
e.preventDefault();
|
|
4736
|
-
if (input.trim() || pendingFile) {
|
|
4737
|
-
const form = e.currentTarget.closest("form");
|
|
4738
|
-
if (form) {
|
|
4739
|
-
form.requestSubmit();
|
|
4740
|
-
}
|
|
4741
|
-
}
|
|
4742
|
-
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" })
|
|
4743
4959
|
}
|
|
4744
|
-
|
|
4745
|
-
|
|
4746
|
-
|
|
4747
|
-
|
|
4748
|
-
|
|
4749
|
-
|
|
4750
|
-
|
|
4751
|
-
|
|
4752
|
-
|
|
4753
|
-
|
|
4754
|
-
|
|
4755
|
-
|
|
4756
|
-
|
|
4757
|
-
|
|
4758
|
-
if (
|
|
4759
|
-
|
|
4760
|
-
e.stopPropagation();
|
|
4761
|
-
handleConfirmNavigation(pendingNavigation);
|
|
4762
|
-
return;
|
|
4763
|
-
}
|
|
4764
|
-
const currentGuide = activeGuideRef.current;
|
|
4765
|
-
if (currentGuide) {
|
|
4766
|
-
e.preventDefault();
|
|
4767
|
-
e.stopPropagation();
|
|
4768
|
-
advanceGuide();
|
|
4769
|
-
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);
|
|
4770
4976
|
}
|
|
4771
4977
|
}
|
|
4772
4978
|
}
|
|
4773
|
-
|
|
4774
|
-
|
|
4775
|
-
|
|
4776
|
-
|
|
4777
|
-
|
|
4778
|
-
|
|
4779
|
-
|
|
4780
|
-
|
|
4781
|
-
|
|
4782
|
-
|
|
4783
|
-
|
|
4784
|
-
|
|
4785
|
-
|
|
4786
|
-
|
|
4787
|
-
|
|
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
|
+
),
|
|
4788
5087
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
4789
5088
|
GuideCursor,
|
|
4790
5089
|
{
|
|
@@ -4793,6 +5092,13 @@ ${userText}`
|
|
|
4793
5092
|
visible: cursorState.visible,
|
|
4794
5093
|
onClick: cursorState.onClick
|
|
4795
5094
|
}
|
|
5095
|
+
),
|
|
5096
|
+
lightboxImageUrl && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
5097
|
+
ImageLightbox,
|
|
5098
|
+
{
|
|
5099
|
+
imageUrl: lightboxImageUrl,
|
|
5100
|
+
onClose: () => setLightboxImageUrl(null)
|
|
5101
|
+
}
|
|
4796
5102
|
)
|
|
4797
5103
|
]
|
|
4798
5104
|
}
|
|
@@ -4837,7 +5143,8 @@ function ChatPanelWithToggle({
|
|
|
4837
5143
|
initialCorner,
|
|
4838
5144
|
onCornerChange,
|
|
4839
5145
|
productBackendUrl,
|
|
4840
|
-
getAuthHeaders
|
|
5146
|
+
getAuthHeaders,
|
|
5147
|
+
isEval
|
|
4841
5148
|
}) {
|
|
4842
5149
|
const [internalIsOpen, setInternalIsOpen] = React6.useState(defaultOpen);
|
|
4843
5150
|
const isOpen = controlledIsOpen !== void 0 ? controlledIsOpen : internalIsOpen;
|
|
@@ -4868,7 +5175,8 @@ function ChatPanelWithToggle({
|
|
|
4868
5175
|
initialCorner,
|
|
4869
5176
|
onCornerChange,
|
|
4870
5177
|
productBackendUrl,
|
|
4871
|
-
getAuthHeaders
|
|
5178
|
+
getAuthHeaders,
|
|
5179
|
+
isEval
|
|
4872
5180
|
}
|
|
4873
5181
|
);
|
|
4874
5182
|
}
|