@kite-copilot/chat-panel 0.2.48 → 0.2.50
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/README.md +38 -0
- package/dist/auto.cjs +176 -150
- package/dist/auto.d.cts +1 -1
- package/dist/auto.d.ts +1 -1
- package/dist/auto.js +1 -1
- package/dist/{chunk-LOTJ3U5L.js → chunk-BLSVIF7H.js} +168 -142
- package/dist/{createKiteChat-e6BnJS6T.d.cts → createKiteChat-DeQKgFyx.d.cts} +8 -2
- package/dist/{createKiteChat-e6BnJS6T.d.ts → createKiteChat-DeQKgFyx.d.ts} +8 -2
- package/dist/embed.global.js +22 -22
- package/dist/index.cjs +176 -150
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -66,7 +66,7 @@ __export(src_exports, {
|
|
|
66
66
|
module.exports = __toCommonJS(src_exports);
|
|
67
67
|
|
|
68
68
|
// src/createKiteChat.tsx
|
|
69
|
-
var
|
|
69
|
+
var import_react2 = __toESM(require("react"), 1);
|
|
70
70
|
var import_client = require("react-dom/client");
|
|
71
71
|
|
|
72
72
|
// src/ChatPanel.tsx
|
|
@@ -379,28 +379,22 @@ function useUserAuth({
|
|
|
379
379
|
}) {
|
|
380
380
|
const [authState, setAuthState] = React4.useState({ status: "idle" });
|
|
381
381
|
const lastSessionIdRef = React4.useRef(null);
|
|
382
|
+
const lastEnabledRef = React4.useRef(enabled);
|
|
382
383
|
const fetchUser = React4.useCallback(async () => {
|
|
383
384
|
if (!productBackendUrl || !enabled) {
|
|
384
|
-
console.log("[useUserAuth] Skipping auth - productBackendUrl:", productBackendUrl, "enabled:", enabled);
|
|
385
385
|
setAuthState({ status: "idle" });
|
|
386
386
|
return;
|
|
387
387
|
}
|
|
388
|
-
console.log("[useUserAuth] Starting auth request to product backend...");
|
|
389
|
-
console.log("[useUserAuth] Product backend URL:", productBackendUrl);
|
|
390
|
-
console.log("[useUserAuth] Full request URL:", `${productBackendUrl}/users/me`);
|
|
391
388
|
setAuthState({ status: "loading" });
|
|
392
389
|
try {
|
|
393
390
|
const response = await fetch(`${productBackendUrl}/users/me`, {
|
|
394
391
|
method: "GET",
|
|
395
392
|
credentials: "include",
|
|
396
|
-
// Include cookies for authentication
|
|
397
393
|
headers: {
|
|
398
394
|
"Accept": "application/json"
|
|
399
395
|
}
|
|
400
396
|
});
|
|
401
|
-
console.log("[useUserAuth] Response received - status:", response.status, "ok:", response.ok);
|
|
402
397
|
if (!response.ok) {
|
|
403
|
-
console.log("[useUserAuth] Auth request failed with status:", response.status);
|
|
404
398
|
if (response.status === 401) {
|
|
405
399
|
throw new Error("Please log in to use the chat assistant.");
|
|
406
400
|
}
|
|
@@ -410,27 +404,36 @@ function useUserAuth({
|
|
|
410
404
|
throw new Error(`Authentication failed (${response.status})`);
|
|
411
405
|
}
|
|
412
406
|
const user = await response.json();
|
|
413
|
-
console.log("[useUserAuth] Auth SUCCESS - parsed user data:");
|
|
414
|
-
console.log("[useUserAuth] id:", user.id);
|
|
415
|
-
console.log("[useUserAuth] email:", user.email);
|
|
416
|
-
console.log("[useUserAuth] name:", user.name);
|
|
417
|
-
console.log("[useUserAuth] role:", user.role);
|
|
418
|
-
console.log("[useUserAuth] isInternal:", user.isInternal);
|
|
419
|
-
console.log("[useUserAuth] agreementsSigned:", user.agreementsSigned);
|
|
420
|
-
console.log("[useUserAuth] lastLoginTime:", user.lastLoginTime);
|
|
421
407
|
setAuthState({ status: "authenticated", user });
|
|
422
408
|
} catch (error) {
|
|
423
|
-
|
|
409
|
+
if (error instanceof Error) {
|
|
410
|
+
const errorMessage = error.message.toLowerCase();
|
|
411
|
+
const isCorsError = errorMessage.includes("cors") || errorMessage.includes("network");
|
|
412
|
+
const is404Error = errorMessage.includes("404");
|
|
413
|
+
if (isCorsError || is404Error) {
|
|
414
|
+
console.warn("[useUserAuth] Auth endpoint unavailable, falling back to unauthenticated mode:", error.message);
|
|
415
|
+
setAuthState({ status: "idle" });
|
|
416
|
+
return;
|
|
417
|
+
}
|
|
418
|
+
}
|
|
424
419
|
const message = error instanceof Error ? error.message : "Unable to verify your identity. Please try again.";
|
|
425
420
|
setAuthState({ status: "error", error: message });
|
|
426
421
|
}
|
|
427
422
|
}, [productBackendUrl, enabled]);
|
|
428
423
|
React4.useEffect(() => {
|
|
429
|
-
|
|
424
|
+
const sessionChanged = sessionId !== lastSessionIdRef.current;
|
|
425
|
+
const enabledChanged = enabled !== lastEnabledRef.current;
|
|
426
|
+
const becameEnabled = enabled && !lastEnabledRef.current;
|
|
427
|
+
if (sessionChanged) {
|
|
430
428
|
lastSessionIdRef.current = sessionId;
|
|
429
|
+
}
|
|
430
|
+
if (enabledChanged) {
|
|
431
|
+
lastEnabledRef.current = enabled;
|
|
432
|
+
}
|
|
433
|
+
if (sessionChanged || becameEnabled) {
|
|
431
434
|
fetchUser();
|
|
432
435
|
}
|
|
433
|
-
}, [sessionId, fetchUser]);
|
|
436
|
+
}, [sessionId, enabled, fetchUser]);
|
|
434
437
|
const retry = React4.useCallback(() => {
|
|
435
438
|
fetchUser();
|
|
436
439
|
}, [fetchUser]);
|
|
@@ -447,13 +450,11 @@ function useOrgConfig({ agentUrl, orgId }) {
|
|
|
447
450
|
});
|
|
448
451
|
React5.useEffect(() => {
|
|
449
452
|
if (!agentUrl || !orgId) {
|
|
450
|
-
console.log("[useOrgConfig] Skipping - missing agentUrl or orgId", { agentUrl, orgId });
|
|
451
453
|
return;
|
|
452
454
|
}
|
|
453
455
|
const fetchConfig = async () => {
|
|
454
456
|
setState({ status: "loading", config: null, error: null });
|
|
455
457
|
const url = `${agentUrl}/org/${orgId}/config`;
|
|
456
|
-
console.log("[useOrgConfig] Fetching org config from:", url);
|
|
457
458
|
try {
|
|
458
459
|
const response = await fetch(url, {
|
|
459
460
|
method: "GET",
|
|
@@ -465,7 +466,6 @@ function useOrgConfig({ agentUrl, orgId }) {
|
|
|
465
466
|
throw new Error(`Failed to fetch org config (${response.status})`);
|
|
466
467
|
}
|
|
467
468
|
const config = await response.json();
|
|
468
|
-
console.log("[useOrgConfig] Received config:", config);
|
|
469
469
|
setState({ status: "success", config, error: null });
|
|
470
470
|
} catch (error) {
|
|
471
471
|
const message = error instanceof Error ? error.message : "Failed to fetch org config";
|
|
@@ -478,6 +478,75 @@ function useOrgConfig({ agentUrl, orgId }) {
|
|
|
478
478
|
return state;
|
|
479
479
|
}
|
|
480
480
|
|
|
481
|
+
// src/hooks/useFrontendToolExecutor.ts
|
|
482
|
+
var import_react = require("react");
|
|
483
|
+
function useFrontendToolExecutor({
|
|
484
|
+
productBackendUrl,
|
|
485
|
+
agentUrl,
|
|
486
|
+
sessionId
|
|
487
|
+
}) {
|
|
488
|
+
const sendToolResult = (0, import_react.useCallback)(async (payload) => {
|
|
489
|
+
try {
|
|
490
|
+
await fetch(`${agentUrl}/chat/tool-result`, {
|
|
491
|
+
method: "POST",
|
|
492
|
+
headers: {
|
|
493
|
+
"Content-Type": "application/json"
|
|
494
|
+
},
|
|
495
|
+
body: JSON.stringify(payload)
|
|
496
|
+
});
|
|
497
|
+
} catch (error) {
|
|
498
|
+
console.error("[FrontendToolExecutor] Failed to send tool result:", error);
|
|
499
|
+
}
|
|
500
|
+
}, [agentUrl]);
|
|
501
|
+
const executeToolRequest = (0, import_react.useCallback)(async (toolRequest) => {
|
|
502
|
+
const { call_id, arguments: args, endpoint, method, path_params } = toolRequest;
|
|
503
|
+
try {
|
|
504
|
+
let url = endpoint;
|
|
505
|
+
for (const param of path_params) {
|
|
506
|
+
if (args[param]) {
|
|
507
|
+
url = url.replace(`{${param}}`, encodeURIComponent(args[param]));
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
const queryParams = new URLSearchParams();
|
|
511
|
+
for (const [key, value] of Object.entries(args)) {
|
|
512
|
+
if (!path_params.includes(key) && value !== void 0 && value !== null) {
|
|
513
|
+
queryParams.append(key, String(value));
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
const queryString = queryParams.toString();
|
|
517
|
+
const fullUrl = `${productBackendUrl}${url}${queryString ? "?" + queryString : ""}`;
|
|
518
|
+
const response = await fetch(fullUrl, {
|
|
519
|
+
method,
|
|
520
|
+
credentials: "include",
|
|
521
|
+
headers: {
|
|
522
|
+
"Accept": "application/json",
|
|
523
|
+
"Content-Type": "application/json"
|
|
524
|
+
}
|
|
525
|
+
});
|
|
526
|
+
let result;
|
|
527
|
+
if (response.ok) {
|
|
528
|
+
result = await response.json();
|
|
529
|
+
} else {
|
|
530
|
+
const errorText = await response.text();
|
|
531
|
+
throw new Error(`HTTP ${response.status}: ${errorText}`);
|
|
532
|
+
}
|
|
533
|
+
await sendToolResult({
|
|
534
|
+
session_id: sessionId,
|
|
535
|
+
call_id,
|
|
536
|
+
result
|
|
537
|
+
});
|
|
538
|
+
} catch (error) {
|
|
539
|
+
console.error("[FrontendToolExecutor] Tool execution failed:", error);
|
|
540
|
+
await sendToolResult({
|
|
541
|
+
session_id: sessionId,
|
|
542
|
+
call_id,
|
|
543
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
544
|
+
});
|
|
545
|
+
}
|
|
546
|
+
}, [productBackendUrl, sessionId, sendToolResult]);
|
|
547
|
+
return { executeToolRequest };
|
|
548
|
+
}
|
|
549
|
+
|
|
481
550
|
// src/components/ui/card.tsx
|
|
482
551
|
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
483
552
|
function Card({ className, ...props }) {
|
|
@@ -1078,7 +1147,6 @@ function TypingIndicator({ className = "" }) {
|
|
|
1078
1147
|
|
|
1079
1148
|
// src/ChatPanel.tsx
|
|
1080
1149
|
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
1081
|
-
var CHAT_PANEL_VERSION = true ? "0.2.48" : "dev";
|
|
1082
1150
|
var DEFAULT_AGENT_URL = "http://localhost:5002";
|
|
1083
1151
|
var PANEL_WIDTH = 400;
|
|
1084
1152
|
var PANEL_HEIGHT = 600;
|
|
@@ -1542,7 +1610,8 @@ function ChatPanel({
|
|
|
1542
1610
|
supabaseAnonKey,
|
|
1543
1611
|
initialCorner = "bottom-left",
|
|
1544
1612
|
onCornerChange,
|
|
1545
|
-
productBackendUrl
|
|
1613
|
+
productBackendUrl,
|
|
1614
|
+
getAuthHeaders
|
|
1546
1615
|
} = {}) {
|
|
1547
1616
|
const [messages, setMessages] = React6.useState(initialMessages);
|
|
1548
1617
|
const [input, setInput] = React6.useState("");
|
|
@@ -1570,37 +1639,11 @@ function ChatPanel({
|
|
|
1570
1639
|
enabled: !!effectiveProductBackendUrl && orgConfigState.status === "success"
|
|
1571
1640
|
// Only enable after config is fetched
|
|
1572
1641
|
});
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
const url = `${effectiveProductBackendUrl}/getDocument/snowkite/categories/`;
|
|
1579
|
-
console.log("[KiteChat TEST] Testing product backend connectivity...");
|
|
1580
|
-
console.log("[KiteChat TEST] URL:", url);
|
|
1581
|
-
try {
|
|
1582
|
-
const response = await fetch(url, {
|
|
1583
|
-
method: "GET",
|
|
1584
|
-
// Note: not using credentials: 'include' to avoid CORS issues with wildcard
|
|
1585
|
-
headers: {
|
|
1586
|
-
"Accept": "application/json"
|
|
1587
|
-
}
|
|
1588
|
-
});
|
|
1589
|
-
console.log("[KiteChat TEST] Response status:", response.status);
|
|
1590
|
-
console.log("[KiteChat TEST] Response ok:", response.ok);
|
|
1591
|
-
if (response.ok) {
|
|
1592
|
-
const data = await response.json();
|
|
1593
|
-
console.log("[KiteChat TEST] SUCCESS - product backend reachable, data:", data);
|
|
1594
|
-
} else {
|
|
1595
|
-
const errorText = await response.text();
|
|
1596
|
-
console.log("[KiteChat TEST] FAILED - status:", response.status, "body:", errorText);
|
|
1597
|
-
}
|
|
1598
|
-
} catch (error) {
|
|
1599
|
-
console.error("[KiteChat TEST] ERROR:", error);
|
|
1600
|
-
}
|
|
1601
|
-
};
|
|
1602
|
-
testProductBackendEndpoint();
|
|
1603
|
-
}, [effectiveProductBackendUrl, orgConfigState.status]);
|
|
1642
|
+
const { executeToolRequest } = useFrontendToolExecutor({
|
|
1643
|
+
productBackendUrl: effectiveProductBackendUrl || "",
|
|
1644
|
+
agentUrl,
|
|
1645
|
+
sessionId
|
|
1646
|
+
});
|
|
1604
1647
|
const effectiveUser = React6.useMemo(() => {
|
|
1605
1648
|
if (sessionUser) {
|
|
1606
1649
|
return sessionUser;
|
|
@@ -1631,7 +1674,6 @@ function ChatPanel({
|
|
|
1631
1674
|
userRole: authState.user.role,
|
|
1632
1675
|
isInternal: authState.user.isInternal
|
|
1633
1676
|
});
|
|
1634
|
-
console.log("[ChatPanel] Session user captured:", authState.user.id);
|
|
1635
1677
|
}
|
|
1636
1678
|
}, [authState, sessionUser]);
|
|
1637
1679
|
const isWaitingForAuth = React6.useMemo(() => {
|
|
@@ -1644,26 +1686,18 @@ function ChatPanel({
|
|
|
1644
1686
|
const supabaseRef = React6.useRef(null);
|
|
1645
1687
|
const typingChannelRef = React6.useRef(null);
|
|
1646
1688
|
const typingTimeoutRef = React6.useRef(null);
|
|
1647
|
-
React6.useEffect(() => {
|
|
1648
|
-
console.log(`[KiteChat] Chat Panel v${CHAT_PANEL_VERSION} loaded`);
|
|
1649
|
-
}, []);
|
|
1650
1689
|
const resetSession = React6.useCallback(() => {
|
|
1651
|
-
console.log("[KiteChat] resetSession called", { isEscalated, hasSupabase: !!supabaseRef.current, sessionId });
|
|
1652
1690
|
if (isEscalated && supabaseRef.current && sessionId) {
|
|
1653
|
-
console.log("[KiteChat] Updating customer_status to disconnected for session:", sessionId);
|
|
1654
1691
|
supabaseRef.current.from("escalations").update({
|
|
1655
1692
|
customer_status: "disconnected",
|
|
1656
1693
|
customer_last_seen: (/* @__PURE__ */ new Date()).toISOString()
|
|
1657
1694
|
}).eq("session_id", sessionId).then(
|
|
1658
|
-
(
|
|
1659
|
-
console.log("[KiteChat] Disconnect update result:", result);
|
|
1695
|
+
() => {
|
|
1660
1696
|
},
|
|
1661
1697
|
(err) => {
|
|
1662
1698
|
console.error("[KiteChat] Disconnect update failed:", err);
|
|
1663
1699
|
}
|
|
1664
1700
|
);
|
|
1665
|
-
} else {
|
|
1666
|
-
console.log("[KiteChat] Skipping disconnect update - conditions not met");
|
|
1667
1701
|
}
|
|
1668
1702
|
setSessionUser(null);
|
|
1669
1703
|
setSessionId(crypto.randomUUID());
|
|
@@ -1689,12 +1723,9 @@ function ChatPanel({
|
|
|
1689
1723
|
}
|
|
1690
1724
|
const channelName = `typing:${sessionId}`;
|
|
1691
1725
|
const channel = supabaseRef.current.channel(channelName);
|
|
1692
|
-
console.log(`[KiteChat] Subscribing to typing channel: ${channelName}`);
|
|
1693
1726
|
channel.on("broadcast", { event: "typing" }, (payload) => {
|
|
1694
|
-
console.log("[KiteChat] Received typing broadcast:", payload);
|
|
1695
1727
|
const { sender, isTyping } = payload.payload;
|
|
1696
1728
|
if (sender === "agent") {
|
|
1697
|
-
console.log(`[KiteChat] Agent typing: ${isTyping}`);
|
|
1698
1729
|
setAgentIsTyping(isTyping);
|
|
1699
1730
|
if (isTyping) {
|
|
1700
1731
|
if (typingTimeoutRef.current) {
|
|
@@ -1706,10 +1737,11 @@ function ChatPanel({
|
|
|
1706
1737
|
}
|
|
1707
1738
|
}
|
|
1708
1739
|
}).subscribe((status) => {
|
|
1709
|
-
console.log(`[KiteChat] Typing channel status: ${status}`);
|
|
1710
1740
|
if (status === "SUBSCRIBED") {
|
|
1711
1741
|
typingChannelRef.current = channel;
|
|
1712
|
-
console.log("[KiteChat] Typing channel
|
|
1742
|
+
console.log("[KiteChat] Typing channel subscribed successfully");
|
|
1743
|
+
} else if (status === "CHANNEL_ERROR") {
|
|
1744
|
+
console.error("[KiteChat] Typing channel subscription failed");
|
|
1713
1745
|
}
|
|
1714
1746
|
});
|
|
1715
1747
|
return () => {
|
|
@@ -1720,6 +1752,20 @@ function ChatPanel({
|
|
|
1720
1752
|
}
|
|
1721
1753
|
};
|
|
1722
1754
|
}, [isEscalated, sessionId]);
|
|
1755
|
+
React6.useEffect(() => {
|
|
1756
|
+
if (!isOpen && isEscalated && supabaseRef.current && sessionId) {
|
|
1757
|
+
console.log("[KiteChat] Panel closed during live chat, marking disconnected");
|
|
1758
|
+
supabaseRef.current.from("escalations").update({
|
|
1759
|
+
customer_status: "disconnected",
|
|
1760
|
+
customer_last_seen: (/* @__PURE__ */ new Date()).toISOString()
|
|
1761
|
+
}).eq("session_id", sessionId).then(
|
|
1762
|
+
() => console.log("[KiteChat] Successfully marked disconnected on panel close"),
|
|
1763
|
+
(err) => {
|
|
1764
|
+
console.error("[KiteChat] Failed to mark disconnected on panel close:", err);
|
|
1765
|
+
}
|
|
1766
|
+
);
|
|
1767
|
+
}
|
|
1768
|
+
}, [isOpen, isEscalated, sessionId]);
|
|
1723
1769
|
const heartbeatIntervalRef = React6.useRef(null);
|
|
1724
1770
|
const updateCustomerStatus = React6.useCallback(async (status) => {
|
|
1725
1771
|
if (!supabaseRef.current || !sessionId) return;
|
|
@@ -1738,9 +1784,20 @@ function ChatPanel({
|
|
|
1738
1784
|
}
|
|
1739
1785
|
const currentSessionId = sessionId;
|
|
1740
1786
|
const supabase = supabaseRef.current;
|
|
1741
|
-
|
|
1787
|
+
const markActive = () => {
|
|
1788
|
+
supabase.from("escalations").update({
|
|
1789
|
+
customer_status: "active",
|
|
1790
|
+
customer_last_seen: (/* @__PURE__ */ new Date()).toISOString()
|
|
1791
|
+
}).eq("session_id", currentSessionId).then(
|
|
1792
|
+
() => {
|
|
1793
|
+
},
|
|
1794
|
+
(err) => console.error("[KiteChat] Failed to update customer status:", err)
|
|
1795
|
+
);
|
|
1796
|
+
};
|
|
1797
|
+
console.log("[KiteChat] Starting presence heartbeat for live chat");
|
|
1798
|
+
markActive();
|
|
1742
1799
|
heartbeatIntervalRef.current = window.setInterval(() => {
|
|
1743
|
-
|
|
1800
|
+
markActive();
|
|
1744
1801
|
}, 6e4);
|
|
1745
1802
|
const handleBeforeUnload = () => {
|
|
1746
1803
|
supabase.from("escalations").update({
|
|
@@ -1755,7 +1812,7 @@ function ChatPanel({
|
|
|
1755
1812
|
customer_last_seen: (/* @__PURE__ */ new Date()).toISOString()
|
|
1756
1813
|
}).eq("session_id", currentSessionId);
|
|
1757
1814
|
} else if (document.visibilityState === "visible") {
|
|
1758
|
-
|
|
1815
|
+
markActive();
|
|
1759
1816
|
}
|
|
1760
1817
|
};
|
|
1761
1818
|
window.addEventListener("beforeunload", handleBeforeUnload);
|
|
@@ -1763,13 +1820,12 @@ function ChatPanel({
|
|
|
1763
1820
|
return () => {
|
|
1764
1821
|
window.removeEventListener("beforeunload", handleBeforeUnload);
|
|
1765
1822
|
document.removeEventListener("visibilitychange", handleVisibilityChange);
|
|
1823
|
+
console.log("[KiteChat] Escalation ended, marking disconnected");
|
|
1766
1824
|
supabase.from("escalations").update({
|
|
1767
1825
|
customer_status: "disconnected",
|
|
1768
1826
|
customer_last_seen: (/* @__PURE__ */ new Date()).toISOString()
|
|
1769
1827
|
}).eq("session_id", currentSessionId).then(
|
|
1770
|
-
() =>
|
|
1771
|
-
console.log("[KiteChat] Marked customer as disconnected");
|
|
1772
|
-
},
|
|
1828
|
+
() => console.log("[KiteChat] Successfully marked disconnected on escalation end"),
|
|
1773
1829
|
(err) => {
|
|
1774
1830
|
console.error("[KiteChat] Failed to mark disconnected:", err);
|
|
1775
1831
|
}
|
|
@@ -1779,17 +1835,14 @@ function ChatPanel({
|
|
|
1779
1835
|
heartbeatIntervalRef.current = null;
|
|
1780
1836
|
}
|
|
1781
1837
|
};
|
|
1782
|
-
}, [isEscalated, sessionId
|
|
1838
|
+
}, [isEscalated, sessionId]);
|
|
1783
1839
|
const sendTypingIndicator = React6.useCallback((isTyping) => {
|
|
1784
|
-
if (!typingChannelRef.current) {
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
if (!isEscalated) {
|
|
1789
|
-
console.log("[KiteChat] Cannot send typing - not escalated");
|
|
1840
|
+
if (!typingChannelRef.current || !isEscalated) {
|
|
1841
|
+
if (isTyping) {
|
|
1842
|
+
console.warn("[KiteChat] Typing channel not ready, cannot send typing indicator");
|
|
1843
|
+
}
|
|
1790
1844
|
return;
|
|
1791
1845
|
}
|
|
1792
|
-
console.log(`[KiteChat] Sending typing indicator: ${isTyping}`);
|
|
1793
1846
|
typingChannelRef.current.send({
|
|
1794
1847
|
type: "broadcast",
|
|
1795
1848
|
event: "typing",
|
|
@@ -1798,16 +1851,23 @@ function ChatPanel({
|
|
|
1798
1851
|
}, [isEscalated]);
|
|
1799
1852
|
const userTypingTimeoutRef = React6.useRef(null);
|
|
1800
1853
|
const handleTypingStart = React6.useCallback(() => {
|
|
1801
|
-
if (!isEscalated || !supabaseRef.current) return;
|
|
1854
|
+
if (!isEscalated || !supabaseRef.current || !sessionId) return;
|
|
1802
1855
|
sendTypingIndicator(true);
|
|
1803
|
-
|
|
1856
|
+
supabaseRef.current.from("escalations").update({
|
|
1857
|
+
customer_status: "active",
|
|
1858
|
+
customer_last_seen: (/* @__PURE__ */ new Date()).toISOString()
|
|
1859
|
+
}).eq("session_id", sessionId).then(
|
|
1860
|
+
() => {
|
|
1861
|
+
},
|
|
1862
|
+
(err) => console.error("[KiteChat] Failed to update presence:", err)
|
|
1863
|
+
);
|
|
1804
1864
|
if (userTypingTimeoutRef.current) {
|
|
1805
1865
|
window.clearTimeout(userTypingTimeoutRef.current);
|
|
1806
1866
|
}
|
|
1807
1867
|
userTypingTimeoutRef.current = window.setTimeout(() => {
|
|
1808
1868
|
sendTypingIndicator(false);
|
|
1809
1869
|
}, 1500);
|
|
1810
|
-
}, [isEscalated, sendTypingIndicator,
|
|
1870
|
+
}, [isEscalated, sendTypingIndicator, sessionId]);
|
|
1811
1871
|
const streamIntervals = React6.useRef({});
|
|
1812
1872
|
const isEmpty = messages.length === 0;
|
|
1813
1873
|
const [phase, setPhase] = React6.useState("idle");
|
|
@@ -1842,12 +1902,6 @@ function ChatPanel({
|
|
|
1842
1902
|
const latestBulkSummaryNavigationRef = React6.useRef(null);
|
|
1843
1903
|
const [guideComplete, setGuideComplete] = React6.useState(false);
|
|
1844
1904
|
React6.useEffect(() => {
|
|
1845
|
-
window.resetIntegrationNotification = () => {
|
|
1846
|
-
localStorage.removeItem("gmailNotificationSeen");
|
|
1847
|
-
console.log(
|
|
1848
|
-
"Integration notification reset! Click the Integrations tab to see it again."
|
|
1849
|
-
);
|
|
1850
|
-
};
|
|
1851
1905
|
const handleIntegrationTabClick = () => {
|
|
1852
1906
|
const hasSeenNotification = localStorage.getItem("gmailNotificationSeen");
|
|
1853
1907
|
if (!hasSeenNotification) {
|
|
@@ -1989,17 +2043,7 @@ function ChatPanel({
|
|
|
1989
2043
|
return;
|
|
1990
2044
|
}
|
|
1991
2045
|
const currentBulkNav = latestBulkSummaryNavigationRef.current;
|
|
1992
|
-
console.log(
|
|
1993
|
-
"[DEBUG] Keyboard handler - latestBulkSummaryNavigation:",
|
|
1994
|
-
currentBulkNav,
|
|
1995
|
-
"onNavigate:",
|
|
1996
|
-
!!onNavigate
|
|
1997
|
-
);
|
|
1998
2046
|
if (currentBulkNav && onNavigate) {
|
|
1999
|
-
console.log(
|
|
2000
|
-
"[DEBUG] Navigating via keyboard to:",
|
|
2001
|
-
currentBulkNav.page
|
|
2002
|
-
);
|
|
2003
2047
|
e.preventDefault();
|
|
2004
2048
|
e.stopPropagation();
|
|
2005
2049
|
onNavigate(currentBulkNav.page, currentBulkNav.subtab);
|
|
@@ -2045,7 +2089,6 @@ function ChatPanel({
|
|
|
2045
2089
|
const messageId = data.message_id;
|
|
2046
2090
|
const isDuplicate = messageId ? prev.some((m) => m.serverMessageId === messageId) : prev.slice(-5).some((m) => m.content === content);
|
|
2047
2091
|
if (isDuplicate) {
|
|
2048
|
-
console.debug("[KiteChat] Skipping duplicate agent message:", messageId || content.slice(0, 30));
|
|
2049
2092
|
return prev;
|
|
2050
2093
|
}
|
|
2051
2094
|
return [...prev, {
|
|
@@ -2068,7 +2111,6 @@ function ChatPanel({
|
|
|
2068
2111
|
console.error("[KiteChat] Escalation WebSocket error:", err);
|
|
2069
2112
|
};
|
|
2070
2113
|
ws.onclose = () => {
|
|
2071
|
-
console.log("[KiteChat] Escalation WebSocket closed");
|
|
2072
2114
|
};
|
|
2073
2115
|
escalationWsRef.current = ws;
|
|
2074
2116
|
}, [agentUrl]);
|
|
@@ -2082,13 +2124,22 @@ function ChatPanel({
|
|
|
2082
2124
|
type: "user_message",
|
|
2083
2125
|
content
|
|
2084
2126
|
}));
|
|
2085
|
-
|
|
2127
|
+
if (supabaseRef.current && sessionId) {
|
|
2128
|
+
supabaseRef.current.from("escalations").update({
|
|
2129
|
+
customer_status: "active",
|
|
2130
|
+
customer_last_seen: (/* @__PURE__ */ new Date()).toISOString()
|
|
2131
|
+
}).eq("session_id", sessionId).then(
|
|
2132
|
+
() => {
|
|
2133
|
+
},
|
|
2134
|
+
(err) => console.error("[KiteChat] Failed to update presence:", err)
|
|
2135
|
+
);
|
|
2136
|
+
}
|
|
2086
2137
|
return true;
|
|
2087
2138
|
} catch (err) {
|
|
2088
2139
|
console.error("[KiteChat] Failed to send escalated message:", err);
|
|
2089
2140
|
return false;
|
|
2090
2141
|
}
|
|
2091
|
-
}, [
|
|
2142
|
+
}, [sessionId]);
|
|
2092
2143
|
React6.useEffect(() => {
|
|
2093
2144
|
return () => {
|
|
2094
2145
|
if (escalationWsRef.current) {
|
|
@@ -2362,14 +2413,6 @@ function ChatPanel({
|
|
|
2362
2413
|
try {
|
|
2363
2414
|
const controller = new AbortController();
|
|
2364
2415
|
const timeoutId = setTimeout(() => controller.abort(), 6e4);
|
|
2365
|
-
console.log("[ChatPanel] Sending chat request to agent backend...");
|
|
2366
|
-
console.log("[ChatPanel] Agent URL:", agentUrl);
|
|
2367
|
-
console.log("[ChatPanel] User data being sent:");
|
|
2368
|
-
console.log("[ChatPanel] user_id:", effectiveUser.userId);
|
|
2369
|
-
console.log("[ChatPanel] user_name:", effectiveUser.userName);
|
|
2370
|
-
console.log("[ChatPanel] user_email:", effectiveUser.userEmail);
|
|
2371
|
-
console.log("[ChatPanel] org_id:", orgId);
|
|
2372
|
-
console.log("[ChatPanel] authState.status:", authState.status);
|
|
2373
2416
|
const response = await fetch(`${agentUrl}/chat/stream`, {
|
|
2374
2417
|
method: "POST",
|
|
2375
2418
|
headers: {
|
|
@@ -2584,6 +2627,11 @@ function ChatPanel({
|
|
|
2584
2627
|
content: data.message || "You've been connected to our support queue. An agent will be with you shortly."
|
|
2585
2628
|
};
|
|
2586
2629
|
setMessages((prev) => [...prev, escalationMessage]);
|
|
2630
|
+
} else if (eventType === "tool_request") {
|
|
2631
|
+
const toolRequest = data;
|
|
2632
|
+
executeToolRequest(toolRequest).catch((err) => {
|
|
2633
|
+
console.error("[KiteChat] Tool execution failed:", err);
|
|
2634
|
+
});
|
|
2587
2635
|
} else if (eventType === "token") {
|
|
2588
2636
|
}
|
|
2589
2637
|
} catch (parseError) {
|
|
@@ -2898,11 +2946,6 @@ ${userText}`
|
|
|
2898
2946
|
}
|
|
2899
2947
|
});
|
|
2900
2948
|
} else if (eventType === "summary") {
|
|
2901
|
-
console.log("[DEBUG] Received summary event - data:", data);
|
|
2902
|
-
console.log(
|
|
2903
|
-
"[DEBUG] navigationPage from backend:",
|
|
2904
|
-
data.navigationPage
|
|
2905
|
-
);
|
|
2906
2949
|
setPhase("idle");
|
|
2907
2950
|
setProgressSteps([]);
|
|
2908
2951
|
setPendingBulkSession(null);
|
|
@@ -2922,7 +2965,6 @@ ${userText}`
|
|
|
2922
2965
|
navigationPage: data.navigationPage
|
|
2923
2966
|
}
|
|
2924
2967
|
};
|
|
2925
|
-
console.log("[DEBUG] Creating bulkSummary message:", newMsg);
|
|
2926
2968
|
return [...filtered, newMsg];
|
|
2927
2969
|
});
|
|
2928
2970
|
setTimeout(() => {
|
|
@@ -4493,28 +4535,11 @@ ${userText}`
|
|
|
4493
4535
|
onClick: (e) => {
|
|
4494
4536
|
e.preventDefault();
|
|
4495
4537
|
e.stopPropagation();
|
|
4496
|
-
console.log(
|
|
4497
|
-
"[DEBUG] Button clicked - navigationPage:",
|
|
4498
|
-
navigationPage,
|
|
4499
|
-
"onNavigate:",
|
|
4500
|
-
!!onNavigate
|
|
4501
|
-
);
|
|
4502
4538
|
if (onNavigate && navigationPage.page) {
|
|
4503
|
-
console.log(
|
|
4504
|
-
"[DEBUG] Calling onNavigate with page:",
|
|
4505
|
-
navigationPage.page
|
|
4506
|
-
);
|
|
4507
4539
|
onNavigate(
|
|
4508
4540
|
navigationPage.page,
|
|
4509
4541
|
navigationPage.subtab
|
|
4510
4542
|
);
|
|
4511
|
-
} else {
|
|
4512
|
-
console.log(
|
|
4513
|
-
"[DEBUG] Condition failed - onNavigate:",
|
|
4514
|
-
!!onNavigate,
|
|
4515
|
-
"navigationPage.page:",
|
|
4516
|
-
navigationPage.page
|
|
4517
|
-
);
|
|
4518
4543
|
}
|
|
4519
4544
|
},
|
|
4520
4545
|
className: "flex items-center gap-2 text-xs text-gray-500 hover:text-gray-700 transition-colors group cursor-pointer",
|
|
@@ -4794,7 +4819,8 @@ function ChatPanelWithToggle({
|
|
|
4794
4819
|
supabaseAnonKey,
|
|
4795
4820
|
initialCorner,
|
|
4796
4821
|
onCornerChange,
|
|
4797
|
-
productBackendUrl
|
|
4822
|
+
productBackendUrl,
|
|
4823
|
+
getAuthHeaders
|
|
4798
4824
|
}) {
|
|
4799
4825
|
const [internalIsOpen, setInternalIsOpen] = React6.useState(defaultOpen);
|
|
4800
4826
|
const isOpen = controlledIsOpen !== void 0 ? controlledIsOpen : internalIsOpen;
|
|
@@ -4824,7 +4850,8 @@ function ChatPanelWithToggle({
|
|
|
4824
4850
|
supabaseAnonKey,
|
|
4825
4851
|
initialCorner,
|
|
4826
4852
|
onCornerChange,
|
|
4827
|
-
productBackendUrl
|
|
4853
|
+
productBackendUrl,
|
|
4854
|
+
getAuthHeaders
|
|
4828
4855
|
}
|
|
4829
4856
|
);
|
|
4830
4857
|
}
|
|
@@ -4848,14 +4875,14 @@ function KiteChatWrapper({
|
|
|
4848
4875
|
onConfigUpdate,
|
|
4849
4876
|
onStateUpdate
|
|
4850
4877
|
}) {
|
|
4851
|
-
const [config, setConfig] =
|
|
4852
|
-
const [currentPage, setCurrentPage] =
|
|
4853
|
-
const [isOpen, setIsOpen] =
|
|
4854
|
-
const isOpenRef =
|
|
4855
|
-
|
|
4878
|
+
const [config, setConfig] = import_react2.default.useState(initialConfig);
|
|
4879
|
+
const [currentPage, setCurrentPage] = import_react2.default.useState(initialConfig.currentPage || "dashboard");
|
|
4880
|
+
const [isOpen, setIsOpen] = import_react2.default.useState(false);
|
|
4881
|
+
const isOpenRef = import_react2.default.useRef(false);
|
|
4882
|
+
import_react2.default.useEffect(() => {
|
|
4856
4883
|
isOpenRef.current = isOpen;
|
|
4857
4884
|
}, [isOpen]);
|
|
4858
|
-
|
|
4885
|
+
import_react2.default.useEffect(() => {
|
|
4859
4886
|
onConfigUpdate((newConfig) => {
|
|
4860
4887
|
if (newConfig.currentPage !== void 0) {
|
|
4861
4888
|
setCurrentPage(newConfig.currentPage);
|
|
@@ -4867,7 +4894,7 @@ function KiteChatWrapper({
|
|
|
4867
4894
|
getIsOpen: () => isOpenRef.current
|
|
4868
4895
|
});
|
|
4869
4896
|
}, [onConfigUpdate, onStateUpdate]);
|
|
4870
|
-
|
|
4897
|
+
import_react2.default.useEffect(() => {
|
|
4871
4898
|
const container = document.getElementById("kite-chat-root");
|
|
4872
4899
|
if (!container) return;
|
|
4873
4900
|
if (config.theme === "dark") {
|
|
@@ -4896,7 +4923,8 @@ function KiteChatWrapper({
|
|
|
4896
4923
|
userEmail: config.userEmail,
|
|
4897
4924
|
supabaseUrl: config.supabaseUrl,
|
|
4898
4925
|
supabaseAnonKey: config.supabaseAnonKey,
|
|
4899
|
-
productBackendUrl: config.productBackendUrl
|
|
4926
|
+
productBackendUrl: config.productBackendUrl,
|
|
4927
|
+
getAuthHeaders: config.getAuthHeaders
|
|
4900
4928
|
}
|
|
4901
4929
|
);
|
|
4902
4930
|
}
|
|
@@ -4939,7 +4967,6 @@ function createKiteChat(config) {
|
|
|
4939
4967
|
}
|
|
4940
4968
|
)
|
|
4941
4969
|
);
|
|
4942
|
-
console.log("[KiteChat] Mounted");
|
|
4943
4970
|
},
|
|
4944
4971
|
unmount() {
|
|
4945
4972
|
if (!root) {
|
|
@@ -4951,7 +4978,6 @@ function createKiteChat(config) {
|
|
|
4951
4978
|
containerElement = null;
|
|
4952
4979
|
configUpdater = null;
|
|
4953
4980
|
stateUpdaters = null;
|
|
4954
|
-
console.log("[KiteChat] Unmounted");
|
|
4955
4981
|
},
|
|
4956
4982
|
open() {
|
|
4957
4983
|
stateUpdaters?.setIsOpen(true);
|
package/dist/index.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { i as ActionData, A as ActionType, C as ChatPanel, d as ChatPanelProps, b as ChatPanelWithToggle, e as ChatPanelWithToggleProps, H as HelpButton, g as HelpButtonProps, K as KiteChatConfig, a as KiteChatInstance, N as NavigationTarget, h as Page, k as PanelCorner, P as PanelToggle, f as PanelToggleProps, S as SettingsTab, j as StartingQuestion, c as createKiteChat } from './createKiteChat-
|
|
1
|
+
export { i as ActionData, A as ActionType, C as ChatPanel, d as ChatPanelProps, b as ChatPanelWithToggle, e as ChatPanelWithToggleProps, H as HelpButton, g as HelpButtonProps, K as KiteChatConfig, a as KiteChatInstance, N as NavigationTarget, h as Page, k as PanelCorner, P as PanelToggle, f as PanelToggleProps, S as SettingsTab, j as StartingQuestion, c as createKiteChat } from './createKiteChat-DeQKgFyx.cjs';
|
|
2
2
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
3
3
|
import * as class_variance_authority_types from 'class-variance-authority/types';
|
|
4
4
|
import * as React from 'react';
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { i as ActionData, A as ActionType, C as ChatPanel, d as ChatPanelProps, b as ChatPanelWithToggle, e as ChatPanelWithToggleProps, H as HelpButton, g as HelpButtonProps, K as KiteChatConfig, a as KiteChatInstance, N as NavigationTarget, h as Page, k as PanelCorner, P as PanelToggle, f as PanelToggleProps, S as SettingsTab, j as StartingQuestion, c as createKiteChat } from './createKiteChat-
|
|
1
|
+
export { i as ActionData, A as ActionType, C as ChatPanel, d as ChatPanelProps, b as ChatPanelWithToggle, e as ChatPanelWithToggleProps, H as HelpButton, g as HelpButtonProps, K as KiteChatConfig, a as KiteChatInstance, N as NavigationTarget, h as Page, k as PanelCorner, P as PanelToggle, f as PanelToggleProps, S as SettingsTab, j as StartingQuestion, c as createKiteChat } from './createKiteChat-DeQKgFyx.js';
|
|
2
2
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
3
3
|
import * as class_variance_authority_types from 'class-variance-authority/types';
|
|
4
4
|
import * as React from 'react';
|
package/dist/index.js
CHANGED