@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.
@@ -896,28 +896,22 @@ function useUserAuth({
896
896
  }) {
897
897
  const [authState, setAuthState] = React4.useState({ status: "idle" });
898
898
  const lastSessionIdRef = React4.useRef(null);
899
+ const lastEnabledRef = React4.useRef(enabled);
899
900
  const fetchUser = React4.useCallback(async () => {
900
901
  if (!productBackendUrl || !enabled) {
901
- console.log("[useUserAuth] Skipping auth - productBackendUrl:", productBackendUrl, "enabled:", enabled);
902
902
  setAuthState({ status: "idle" });
903
903
  return;
904
904
  }
905
- console.log("[useUserAuth] Starting auth request to product backend...");
906
- console.log("[useUserAuth] Product backend URL:", productBackendUrl);
907
- console.log("[useUserAuth] Full request URL:", `${productBackendUrl}/users/me`);
908
905
  setAuthState({ status: "loading" });
909
906
  try {
910
907
  const response = await fetch(`${productBackendUrl}/users/me`, {
911
908
  method: "GET",
912
909
  credentials: "include",
913
- // Include cookies for authentication
914
910
  headers: {
915
911
  "Accept": "application/json"
916
912
  }
917
913
  });
918
- console.log("[useUserAuth] Response received - status:", response.status, "ok:", response.ok);
919
914
  if (!response.ok) {
920
- console.log("[useUserAuth] Auth request failed with status:", response.status);
921
915
  if (response.status === 401) {
922
916
  throw new Error("Please log in to use the chat assistant.");
923
917
  }
@@ -927,27 +921,36 @@ function useUserAuth({
927
921
  throw new Error(`Authentication failed (${response.status})`);
928
922
  }
929
923
  const user = await response.json();
930
- console.log("[useUserAuth] Auth SUCCESS - parsed user data:");
931
- console.log("[useUserAuth] id:", user.id);
932
- console.log("[useUserAuth] email:", user.email);
933
- console.log("[useUserAuth] name:", user.name);
934
- console.log("[useUserAuth] role:", user.role);
935
- console.log("[useUserAuth] isInternal:", user.isInternal);
936
- console.log("[useUserAuth] agreementsSigned:", user.agreementsSigned);
937
- console.log("[useUserAuth] lastLoginTime:", user.lastLoginTime);
938
924
  setAuthState({ status: "authenticated", user });
939
925
  } catch (error) {
940
- console.log("[useUserAuth] Auth ERROR:", error);
926
+ if (error instanceof Error) {
927
+ const errorMessage = error.message.toLowerCase();
928
+ const isCorsError = errorMessage.includes("cors") || errorMessage.includes("network");
929
+ const is404Error = errorMessage.includes("404");
930
+ if (isCorsError || is404Error) {
931
+ console.warn("[useUserAuth] Auth endpoint unavailable, falling back to unauthenticated mode:", error.message);
932
+ setAuthState({ status: "idle" });
933
+ return;
934
+ }
935
+ }
941
936
  const message = error instanceof Error ? error.message : "Unable to verify your identity. Please try again.";
942
937
  setAuthState({ status: "error", error: message });
943
938
  }
944
939
  }, [productBackendUrl, enabled]);
945
940
  React4.useEffect(() => {
946
- if (sessionId !== lastSessionIdRef.current) {
941
+ const sessionChanged = sessionId !== lastSessionIdRef.current;
942
+ const enabledChanged = enabled !== lastEnabledRef.current;
943
+ const becameEnabled = enabled && !lastEnabledRef.current;
944
+ if (sessionChanged) {
947
945
  lastSessionIdRef.current = sessionId;
946
+ }
947
+ if (enabledChanged) {
948
+ lastEnabledRef.current = enabled;
949
+ }
950
+ if (sessionChanged || becameEnabled) {
948
951
  fetchUser();
949
952
  }
950
- }, [sessionId, fetchUser]);
953
+ }, [sessionId, enabled, fetchUser]);
951
954
  const retry = React4.useCallback(() => {
952
955
  fetchUser();
953
956
  }, [fetchUser]);
@@ -964,13 +967,11 @@ function useOrgConfig({ agentUrl, orgId }) {
964
967
  });
965
968
  React5.useEffect(() => {
966
969
  if (!agentUrl || !orgId) {
967
- console.log("[useOrgConfig] Skipping - missing agentUrl or orgId", { agentUrl, orgId });
968
970
  return;
969
971
  }
970
972
  const fetchConfig = async () => {
971
973
  setState({ status: "loading", config: null, error: null });
972
974
  const url = `${agentUrl}/org/${orgId}/config`;
973
- console.log("[useOrgConfig] Fetching org config from:", url);
974
975
  try {
975
976
  const response = await fetch(url, {
976
977
  method: "GET",
@@ -982,7 +983,6 @@ function useOrgConfig({ agentUrl, orgId }) {
982
983
  throw new Error(`Failed to fetch org config (${response.status})`);
983
984
  }
984
985
  const config = await response.json();
985
- console.log("[useOrgConfig] Received config:", config);
986
986
  setState({ status: "success", config, error: null });
987
987
  } catch (error) {
988
988
  const message = error instanceof Error ? error.message : "Failed to fetch org config";
@@ -995,6 +995,75 @@ function useOrgConfig({ agentUrl, orgId }) {
995
995
  return state;
996
996
  }
997
997
 
998
+ // src/hooks/useFrontendToolExecutor.ts
999
+ import { useCallback as useCallback3 } from "react";
1000
+ function useFrontendToolExecutor({
1001
+ productBackendUrl,
1002
+ agentUrl,
1003
+ sessionId
1004
+ }) {
1005
+ const sendToolResult = useCallback3(async (payload) => {
1006
+ try {
1007
+ await fetch(`${agentUrl}/chat/tool-result`, {
1008
+ method: "POST",
1009
+ headers: {
1010
+ "Content-Type": "application/json"
1011
+ },
1012
+ body: JSON.stringify(payload)
1013
+ });
1014
+ } catch (error) {
1015
+ console.error("[FrontendToolExecutor] Failed to send tool result:", error);
1016
+ }
1017
+ }, [agentUrl]);
1018
+ const executeToolRequest = useCallback3(async (toolRequest) => {
1019
+ const { call_id, arguments: args, endpoint, method, path_params } = toolRequest;
1020
+ try {
1021
+ let url = endpoint;
1022
+ for (const param of path_params) {
1023
+ if (args[param]) {
1024
+ url = url.replace(`{${param}}`, encodeURIComponent(args[param]));
1025
+ }
1026
+ }
1027
+ const queryParams = new URLSearchParams();
1028
+ for (const [key, value] of Object.entries(args)) {
1029
+ if (!path_params.includes(key) && value !== void 0 && value !== null) {
1030
+ queryParams.append(key, String(value));
1031
+ }
1032
+ }
1033
+ const queryString = queryParams.toString();
1034
+ const fullUrl = `${productBackendUrl}${url}${queryString ? "?" + queryString : ""}`;
1035
+ const response = await fetch(fullUrl, {
1036
+ method,
1037
+ credentials: "include",
1038
+ headers: {
1039
+ "Accept": "application/json",
1040
+ "Content-Type": "application/json"
1041
+ }
1042
+ });
1043
+ let result;
1044
+ if (response.ok) {
1045
+ result = await response.json();
1046
+ } else {
1047
+ const errorText = await response.text();
1048
+ throw new Error(`HTTP ${response.status}: ${errorText}`);
1049
+ }
1050
+ await sendToolResult({
1051
+ session_id: sessionId,
1052
+ call_id,
1053
+ result
1054
+ });
1055
+ } catch (error) {
1056
+ console.error("[FrontendToolExecutor] Tool execution failed:", error);
1057
+ await sendToolResult({
1058
+ session_id: sessionId,
1059
+ call_id,
1060
+ error: error instanceof Error ? error.message : "Unknown error"
1061
+ });
1062
+ }
1063
+ }, [productBackendUrl, sessionId, sendToolResult]);
1064
+ return { executeToolRequest };
1065
+ }
1066
+
998
1067
  // src/components/TypingIndicator.tsx
999
1068
  import { jsx as jsx9, jsxs as jsxs5 } from "react/jsx-runtime";
1000
1069
  function TypingIndicator({ className = "" }) {
@@ -1025,7 +1094,6 @@ function TypingIndicator({ className = "" }) {
1025
1094
 
1026
1095
  // src/ChatPanel.tsx
1027
1096
  import { Fragment as Fragment2, jsx as jsx10, jsxs as jsxs6 } from "react/jsx-runtime";
1028
- var CHAT_PANEL_VERSION = true ? "0.2.48" : "dev";
1029
1097
  var DEFAULT_AGENT_URL = "http://localhost:5002";
1030
1098
  var PANEL_WIDTH = 400;
1031
1099
  var PANEL_HEIGHT = 600;
@@ -1489,7 +1557,8 @@ function ChatPanel({
1489
1557
  supabaseAnonKey,
1490
1558
  initialCorner = "bottom-left",
1491
1559
  onCornerChange,
1492
- productBackendUrl
1560
+ productBackendUrl,
1561
+ getAuthHeaders
1493
1562
  } = {}) {
1494
1563
  const [messages, setMessages] = React6.useState(initialMessages);
1495
1564
  const [input, setInput] = React6.useState("");
@@ -1517,37 +1586,11 @@ function ChatPanel({
1517
1586
  enabled: !!effectiveProductBackendUrl && orgConfigState.status === "success"
1518
1587
  // Only enable after config is fetched
1519
1588
  });
1520
- React6.useEffect(() => {
1521
- if (!effectiveProductBackendUrl || orgConfigState.status !== "success") {
1522
- return;
1523
- }
1524
- const testProductBackendEndpoint = async () => {
1525
- const url = `${effectiveProductBackendUrl}/getDocument/snowkite/categories/`;
1526
- console.log("[KiteChat TEST] Testing product backend connectivity...");
1527
- console.log("[KiteChat TEST] URL:", url);
1528
- try {
1529
- const response = await fetch(url, {
1530
- method: "GET",
1531
- // Note: not using credentials: 'include' to avoid CORS issues with wildcard
1532
- headers: {
1533
- "Accept": "application/json"
1534
- }
1535
- });
1536
- console.log("[KiteChat TEST] Response status:", response.status);
1537
- console.log("[KiteChat TEST] Response ok:", response.ok);
1538
- if (response.ok) {
1539
- const data = await response.json();
1540
- console.log("[KiteChat TEST] SUCCESS - product backend reachable, data:", data);
1541
- } else {
1542
- const errorText = await response.text();
1543
- console.log("[KiteChat TEST] FAILED - status:", response.status, "body:", errorText);
1544
- }
1545
- } catch (error) {
1546
- console.error("[KiteChat TEST] ERROR:", error);
1547
- }
1548
- };
1549
- testProductBackendEndpoint();
1550
- }, [effectiveProductBackendUrl, orgConfigState.status]);
1589
+ const { executeToolRequest } = useFrontendToolExecutor({
1590
+ productBackendUrl: effectiveProductBackendUrl || "",
1591
+ agentUrl,
1592
+ sessionId
1593
+ });
1551
1594
  const effectiveUser = React6.useMemo(() => {
1552
1595
  if (sessionUser) {
1553
1596
  return sessionUser;
@@ -1578,7 +1621,6 @@ function ChatPanel({
1578
1621
  userRole: authState.user.role,
1579
1622
  isInternal: authState.user.isInternal
1580
1623
  });
1581
- console.log("[ChatPanel] Session user captured:", authState.user.id);
1582
1624
  }
1583
1625
  }, [authState, sessionUser]);
1584
1626
  const isWaitingForAuth = React6.useMemo(() => {
@@ -1591,26 +1633,18 @@ function ChatPanel({
1591
1633
  const supabaseRef = React6.useRef(null);
1592
1634
  const typingChannelRef = React6.useRef(null);
1593
1635
  const typingTimeoutRef = React6.useRef(null);
1594
- React6.useEffect(() => {
1595
- console.log(`[KiteChat] Chat Panel v${CHAT_PANEL_VERSION} loaded`);
1596
- }, []);
1597
1636
  const resetSession = React6.useCallback(() => {
1598
- console.log("[KiteChat] resetSession called", { isEscalated, hasSupabase: !!supabaseRef.current, sessionId });
1599
1637
  if (isEscalated && supabaseRef.current && sessionId) {
1600
- console.log("[KiteChat] Updating customer_status to disconnected for session:", sessionId);
1601
1638
  supabaseRef.current.from("escalations").update({
1602
1639
  customer_status: "disconnected",
1603
1640
  customer_last_seen: (/* @__PURE__ */ new Date()).toISOString()
1604
1641
  }).eq("session_id", sessionId).then(
1605
- (result) => {
1606
- console.log("[KiteChat] Disconnect update result:", result);
1642
+ () => {
1607
1643
  },
1608
1644
  (err) => {
1609
1645
  console.error("[KiteChat] Disconnect update failed:", err);
1610
1646
  }
1611
1647
  );
1612
- } else {
1613
- console.log("[KiteChat] Skipping disconnect update - conditions not met");
1614
1648
  }
1615
1649
  setSessionUser(null);
1616
1650
  setSessionId(crypto.randomUUID());
@@ -1636,12 +1670,9 @@ function ChatPanel({
1636
1670
  }
1637
1671
  const channelName = `typing:${sessionId}`;
1638
1672
  const channel = supabaseRef.current.channel(channelName);
1639
- console.log(`[KiteChat] Subscribing to typing channel: ${channelName}`);
1640
1673
  channel.on("broadcast", { event: "typing" }, (payload) => {
1641
- console.log("[KiteChat] Received typing broadcast:", payload);
1642
1674
  const { sender, isTyping } = payload.payload;
1643
1675
  if (sender === "agent") {
1644
- console.log(`[KiteChat] Agent typing: ${isTyping}`);
1645
1676
  setAgentIsTyping(isTyping);
1646
1677
  if (isTyping) {
1647
1678
  if (typingTimeoutRef.current) {
@@ -1653,10 +1684,11 @@ function ChatPanel({
1653
1684
  }
1654
1685
  }
1655
1686
  }).subscribe((status) => {
1656
- console.log(`[KiteChat] Typing channel status: ${status}`);
1657
1687
  if (status === "SUBSCRIBED") {
1658
1688
  typingChannelRef.current = channel;
1659
- console.log("[KiteChat] Typing channel ready");
1689
+ console.log("[KiteChat] Typing channel subscribed successfully");
1690
+ } else if (status === "CHANNEL_ERROR") {
1691
+ console.error("[KiteChat] Typing channel subscription failed");
1660
1692
  }
1661
1693
  });
1662
1694
  return () => {
@@ -1667,6 +1699,20 @@ function ChatPanel({
1667
1699
  }
1668
1700
  };
1669
1701
  }, [isEscalated, sessionId]);
1702
+ React6.useEffect(() => {
1703
+ if (!isOpen && isEscalated && supabaseRef.current && sessionId) {
1704
+ console.log("[KiteChat] Panel closed during live chat, marking disconnected");
1705
+ supabaseRef.current.from("escalations").update({
1706
+ customer_status: "disconnected",
1707
+ customer_last_seen: (/* @__PURE__ */ new Date()).toISOString()
1708
+ }).eq("session_id", sessionId).then(
1709
+ () => console.log("[KiteChat] Successfully marked disconnected on panel close"),
1710
+ (err) => {
1711
+ console.error("[KiteChat] Failed to mark disconnected on panel close:", err);
1712
+ }
1713
+ );
1714
+ }
1715
+ }, [isOpen, isEscalated, sessionId]);
1670
1716
  const heartbeatIntervalRef = React6.useRef(null);
1671
1717
  const updateCustomerStatus = React6.useCallback(async (status) => {
1672
1718
  if (!supabaseRef.current || !sessionId) return;
@@ -1685,9 +1731,20 @@ function ChatPanel({
1685
1731
  }
1686
1732
  const currentSessionId = sessionId;
1687
1733
  const supabase = supabaseRef.current;
1688
- updateCustomerStatus("active");
1734
+ const markActive = () => {
1735
+ supabase.from("escalations").update({
1736
+ customer_status: "active",
1737
+ customer_last_seen: (/* @__PURE__ */ new Date()).toISOString()
1738
+ }).eq("session_id", currentSessionId).then(
1739
+ () => {
1740
+ },
1741
+ (err) => console.error("[KiteChat] Failed to update customer status:", err)
1742
+ );
1743
+ };
1744
+ console.log("[KiteChat] Starting presence heartbeat for live chat");
1745
+ markActive();
1689
1746
  heartbeatIntervalRef.current = window.setInterval(() => {
1690
- updateCustomerStatus("active");
1747
+ markActive();
1691
1748
  }, 6e4);
1692
1749
  const handleBeforeUnload = () => {
1693
1750
  supabase.from("escalations").update({
@@ -1702,7 +1759,7 @@ function ChatPanel({
1702
1759
  customer_last_seen: (/* @__PURE__ */ new Date()).toISOString()
1703
1760
  }).eq("session_id", currentSessionId);
1704
1761
  } else if (document.visibilityState === "visible") {
1705
- updateCustomerStatus("active");
1762
+ markActive();
1706
1763
  }
1707
1764
  };
1708
1765
  window.addEventListener("beforeunload", handleBeforeUnload);
@@ -1710,13 +1767,12 @@ function ChatPanel({
1710
1767
  return () => {
1711
1768
  window.removeEventListener("beforeunload", handleBeforeUnload);
1712
1769
  document.removeEventListener("visibilitychange", handleVisibilityChange);
1770
+ console.log("[KiteChat] Escalation ended, marking disconnected");
1713
1771
  supabase.from("escalations").update({
1714
1772
  customer_status: "disconnected",
1715
1773
  customer_last_seen: (/* @__PURE__ */ new Date()).toISOString()
1716
1774
  }).eq("session_id", currentSessionId).then(
1717
- () => {
1718
- console.log("[KiteChat] Marked customer as disconnected");
1719
- },
1775
+ () => console.log("[KiteChat] Successfully marked disconnected on escalation end"),
1720
1776
  (err) => {
1721
1777
  console.error("[KiteChat] Failed to mark disconnected:", err);
1722
1778
  }
@@ -1726,17 +1782,14 @@ function ChatPanel({
1726
1782
  heartbeatIntervalRef.current = null;
1727
1783
  }
1728
1784
  };
1729
- }, [isEscalated, sessionId, updateCustomerStatus]);
1785
+ }, [isEscalated, sessionId]);
1730
1786
  const sendTypingIndicator = React6.useCallback((isTyping) => {
1731
- if (!typingChannelRef.current) {
1732
- console.log("[KiteChat] Cannot send typing - channel not ready");
1733
- return;
1734
- }
1735
- if (!isEscalated) {
1736
- console.log("[KiteChat] Cannot send typing - not escalated");
1787
+ if (!typingChannelRef.current || !isEscalated) {
1788
+ if (isTyping) {
1789
+ console.warn("[KiteChat] Typing channel not ready, cannot send typing indicator");
1790
+ }
1737
1791
  return;
1738
1792
  }
1739
- console.log(`[KiteChat] Sending typing indicator: ${isTyping}`);
1740
1793
  typingChannelRef.current.send({
1741
1794
  type: "broadcast",
1742
1795
  event: "typing",
@@ -1745,16 +1798,23 @@ function ChatPanel({
1745
1798
  }, [isEscalated]);
1746
1799
  const userTypingTimeoutRef = React6.useRef(null);
1747
1800
  const handleTypingStart = React6.useCallback(() => {
1748
- if (!isEscalated || !supabaseRef.current) return;
1801
+ if (!isEscalated || !supabaseRef.current || !sessionId) return;
1749
1802
  sendTypingIndicator(true);
1750
- updateCustomerStatus("active");
1803
+ supabaseRef.current.from("escalations").update({
1804
+ customer_status: "active",
1805
+ customer_last_seen: (/* @__PURE__ */ new Date()).toISOString()
1806
+ }).eq("session_id", sessionId).then(
1807
+ () => {
1808
+ },
1809
+ (err) => console.error("[KiteChat] Failed to update presence:", err)
1810
+ );
1751
1811
  if (userTypingTimeoutRef.current) {
1752
1812
  window.clearTimeout(userTypingTimeoutRef.current);
1753
1813
  }
1754
1814
  userTypingTimeoutRef.current = window.setTimeout(() => {
1755
1815
  sendTypingIndicator(false);
1756
1816
  }, 1500);
1757
- }, [isEscalated, sendTypingIndicator, updateCustomerStatus]);
1817
+ }, [isEscalated, sendTypingIndicator, sessionId]);
1758
1818
  const streamIntervals = React6.useRef({});
1759
1819
  const isEmpty = messages.length === 0;
1760
1820
  const [phase, setPhase] = React6.useState("idle");
@@ -1789,12 +1849,6 @@ function ChatPanel({
1789
1849
  const latestBulkSummaryNavigationRef = React6.useRef(null);
1790
1850
  const [guideComplete, setGuideComplete] = React6.useState(false);
1791
1851
  React6.useEffect(() => {
1792
- window.resetIntegrationNotification = () => {
1793
- localStorage.removeItem("gmailNotificationSeen");
1794
- console.log(
1795
- "Integration notification reset! Click the Integrations tab to see it again."
1796
- );
1797
- };
1798
1852
  const handleIntegrationTabClick = () => {
1799
1853
  const hasSeenNotification = localStorage.getItem("gmailNotificationSeen");
1800
1854
  if (!hasSeenNotification) {
@@ -1936,17 +1990,7 @@ function ChatPanel({
1936
1990
  return;
1937
1991
  }
1938
1992
  const currentBulkNav = latestBulkSummaryNavigationRef.current;
1939
- console.log(
1940
- "[DEBUG] Keyboard handler - latestBulkSummaryNavigation:",
1941
- currentBulkNav,
1942
- "onNavigate:",
1943
- !!onNavigate
1944
- );
1945
1993
  if (currentBulkNav && onNavigate) {
1946
- console.log(
1947
- "[DEBUG] Navigating via keyboard to:",
1948
- currentBulkNav.page
1949
- );
1950
1994
  e.preventDefault();
1951
1995
  e.stopPropagation();
1952
1996
  onNavigate(currentBulkNav.page, currentBulkNav.subtab);
@@ -1992,7 +2036,6 @@ function ChatPanel({
1992
2036
  const messageId = data.message_id;
1993
2037
  const isDuplicate = messageId ? prev.some((m) => m.serverMessageId === messageId) : prev.slice(-5).some((m) => m.content === content);
1994
2038
  if (isDuplicate) {
1995
- console.debug("[KiteChat] Skipping duplicate agent message:", messageId || content.slice(0, 30));
1996
2039
  return prev;
1997
2040
  }
1998
2041
  return [...prev, {
@@ -2015,7 +2058,6 @@ function ChatPanel({
2015
2058
  console.error("[KiteChat] Escalation WebSocket error:", err);
2016
2059
  };
2017
2060
  ws.onclose = () => {
2018
- console.log("[KiteChat] Escalation WebSocket closed");
2019
2061
  };
2020
2062
  escalationWsRef.current = ws;
2021
2063
  }, [agentUrl]);
@@ -2029,13 +2071,22 @@ function ChatPanel({
2029
2071
  type: "user_message",
2030
2072
  content
2031
2073
  }));
2032
- updateCustomerStatus("active");
2074
+ if (supabaseRef.current && sessionId) {
2075
+ supabaseRef.current.from("escalations").update({
2076
+ customer_status: "active",
2077
+ customer_last_seen: (/* @__PURE__ */ new Date()).toISOString()
2078
+ }).eq("session_id", sessionId).then(
2079
+ () => {
2080
+ },
2081
+ (err) => console.error("[KiteChat] Failed to update presence:", err)
2082
+ );
2083
+ }
2033
2084
  return true;
2034
2085
  } catch (err) {
2035
2086
  console.error("[KiteChat] Failed to send escalated message:", err);
2036
2087
  return false;
2037
2088
  }
2038
- }, [updateCustomerStatus]);
2089
+ }, [sessionId]);
2039
2090
  React6.useEffect(() => {
2040
2091
  return () => {
2041
2092
  if (escalationWsRef.current) {
@@ -2309,14 +2360,6 @@ function ChatPanel({
2309
2360
  try {
2310
2361
  const controller = new AbortController();
2311
2362
  const timeoutId = setTimeout(() => controller.abort(), 6e4);
2312
- console.log("[ChatPanel] Sending chat request to agent backend...");
2313
- console.log("[ChatPanel] Agent URL:", agentUrl);
2314
- console.log("[ChatPanel] User data being sent:");
2315
- console.log("[ChatPanel] user_id:", effectiveUser.userId);
2316
- console.log("[ChatPanel] user_name:", effectiveUser.userName);
2317
- console.log("[ChatPanel] user_email:", effectiveUser.userEmail);
2318
- console.log("[ChatPanel] org_id:", orgId);
2319
- console.log("[ChatPanel] authState.status:", authState.status);
2320
2363
  const response = await fetch(`${agentUrl}/chat/stream`, {
2321
2364
  method: "POST",
2322
2365
  headers: {
@@ -2531,6 +2574,11 @@ function ChatPanel({
2531
2574
  content: data.message || "You've been connected to our support queue. An agent will be with you shortly."
2532
2575
  };
2533
2576
  setMessages((prev) => [...prev, escalationMessage]);
2577
+ } else if (eventType === "tool_request") {
2578
+ const toolRequest = data;
2579
+ executeToolRequest(toolRequest).catch((err) => {
2580
+ console.error("[KiteChat] Tool execution failed:", err);
2581
+ });
2534
2582
  } else if (eventType === "token") {
2535
2583
  }
2536
2584
  } catch (parseError) {
@@ -2845,11 +2893,6 @@ ${userText}`
2845
2893
  }
2846
2894
  });
2847
2895
  } else if (eventType === "summary") {
2848
- console.log("[DEBUG] Received summary event - data:", data);
2849
- console.log(
2850
- "[DEBUG] navigationPage from backend:",
2851
- data.navigationPage
2852
- );
2853
2896
  setPhase("idle");
2854
2897
  setProgressSteps([]);
2855
2898
  setPendingBulkSession(null);
@@ -2869,7 +2912,6 @@ ${userText}`
2869
2912
  navigationPage: data.navigationPage
2870
2913
  }
2871
2914
  };
2872
- console.log("[DEBUG] Creating bulkSummary message:", newMsg);
2873
2915
  return [...filtered, newMsg];
2874
2916
  });
2875
2917
  setTimeout(() => {
@@ -4440,28 +4482,11 @@ ${userText}`
4440
4482
  onClick: (e) => {
4441
4483
  e.preventDefault();
4442
4484
  e.stopPropagation();
4443
- console.log(
4444
- "[DEBUG] Button clicked - navigationPage:",
4445
- navigationPage,
4446
- "onNavigate:",
4447
- !!onNavigate
4448
- );
4449
4485
  if (onNavigate && navigationPage.page) {
4450
- console.log(
4451
- "[DEBUG] Calling onNavigate with page:",
4452
- navigationPage.page
4453
- );
4454
4486
  onNavigate(
4455
4487
  navigationPage.page,
4456
4488
  navigationPage.subtab
4457
4489
  );
4458
- } else {
4459
- console.log(
4460
- "[DEBUG] Condition failed - onNavigate:",
4461
- !!onNavigate,
4462
- "navigationPage.page:",
4463
- navigationPage.page
4464
- );
4465
4490
  }
4466
4491
  },
4467
4492
  className: "flex items-center gap-2 text-xs text-gray-500 hover:text-gray-700 transition-colors group cursor-pointer",
@@ -4741,7 +4766,8 @@ function ChatPanelWithToggle({
4741
4766
  supabaseAnonKey,
4742
4767
  initialCorner,
4743
4768
  onCornerChange,
4744
- productBackendUrl
4769
+ productBackendUrl,
4770
+ getAuthHeaders
4745
4771
  }) {
4746
4772
  const [internalIsOpen, setInternalIsOpen] = React6.useState(defaultOpen);
4747
4773
  const isOpen = controlledIsOpen !== void 0 ? controlledIsOpen : internalIsOpen;
@@ -4771,7 +4797,8 @@ function ChatPanelWithToggle({
4771
4797
  supabaseAnonKey,
4772
4798
  initialCorner,
4773
4799
  onCornerChange,
4774
- productBackendUrl
4800
+ productBackendUrl,
4801
+ getAuthHeaders
4775
4802
  }
4776
4803
  );
4777
4804
  }
@@ -4845,7 +4872,8 @@ function KiteChatWrapper({
4845
4872
  userEmail: config.userEmail,
4846
4873
  supabaseUrl: config.supabaseUrl,
4847
4874
  supabaseAnonKey: config.supabaseAnonKey,
4848
- productBackendUrl: config.productBackendUrl
4875
+ productBackendUrl: config.productBackendUrl,
4876
+ getAuthHeaders: config.getAuthHeaders
4849
4877
  }
4850
4878
  );
4851
4879
  }
@@ -4888,7 +4916,6 @@ function createKiteChat(config) {
4888
4916
  }
4889
4917
  )
4890
4918
  );
4891
- console.log("[KiteChat] Mounted");
4892
4919
  },
4893
4920
  unmount() {
4894
4921
  if (!root) {
@@ -4900,7 +4927,6 @@ function createKiteChat(config) {
4900
4927
  containerElement = null;
4901
4928
  configUpdater = null;
4902
4929
  stateUpdaters = null;
4903
- console.log("[KiteChat] Unmounted");
4904
4930
  },
4905
4931
  open() {
4906
4932
  stateUpdaters?.setIsOpen(true);
@@ -118,8 +118,10 @@ interface ChatPanelProps {
118
118
  onCornerChange?: (corner: PanelCorner) => void;
119
119
  /** Product backend URL for user authentication (e.g., https://dev.api.rocketalumnisolutions.com) */
120
120
  productBackendUrl?: string;
121
+ /** Optional async function to provide authentication headers for API requests */
122
+ getAuthHeaders?: () => Promise<Record<string, string>>;
121
123
  }
122
- declare function ChatPanel({ isOpen, onClose, onOpen, onBack, onNavigate, onActionComplete, currentPage, agentUrl, startingQuestions: startingQuestionsProp, startingQuestionsEndpoint, userId, orgId, userName, userEmail, supabaseUrl, supabaseAnonKey, initialCorner, onCornerChange, productBackendUrl, }?: ChatPanelProps): react_jsx_runtime.JSX.Element;
124
+ declare function ChatPanel({ isOpen, onClose, onOpen, onBack, onNavigate, onActionComplete, currentPage, agentUrl, startingQuestions: startingQuestionsProp, startingQuestionsEndpoint, userId, orgId, userName, userEmail, supabaseUrl, supabaseAnonKey, initialCorner, onCornerChange, productBackendUrl, getAuthHeaders, }?: ChatPanelProps): react_jsx_runtime.JSX.Element;
123
125
  /**
124
126
  * PanelToggle - An arrow button on the right edge that toggles the side panel
125
127
  * Shows left arrow when closed (click to open), right arrow when open (click to close)
@@ -182,8 +184,10 @@ interface ChatPanelWithToggleProps {
182
184
  onCornerChange?: (corner: PanelCorner) => void;
183
185
  /** Product backend URL for user authentication (e.g., https://dev.api.rocketalumnisolutions.com) */
184
186
  productBackendUrl?: string;
187
+ /** Optional async function to provide authentication headers for API requests */
188
+ getAuthHeaders?: () => Promise<Record<string, string>>;
185
189
  }
186
- declare function ChatPanelWithToggle({ onNavigate, onActionComplete, currentPage, agentUrl, startingQuestions, startingQuestionsEndpoint, defaultOpen, isOpen: controlledIsOpen, onOpenChange, userId, orgId, userName, userEmail, supabaseUrl, supabaseAnonKey, initialCorner, onCornerChange, productBackendUrl, }: ChatPanelWithToggleProps): react_jsx_runtime.JSX.Element;
190
+ declare function ChatPanelWithToggle({ onNavigate, onActionComplete, currentPage, agentUrl, startingQuestions, startingQuestionsEndpoint, defaultOpen, isOpen: controlledIsOpen, onOpenChange, userId, orgId, userName, userEmail, supabaseUrl, supabaseAnonKey, initialCorner, onCornerChange, productBackendUrl, getAuthHeaders, }: ChatPanelWithToggleProps): react_jsx_runtime.JSX.Element;
187
191
  /**
188
192
  * @deprecated Use ChatPanelWithToggle instead for the new side panel UX
189
193
  */
@@ -253,6 +257,8 @@ interface KiteChatConfig {
253
257
  supabaseAnonKey?: string;
254
258
  /** Product backend URL for user authentication (e.g., https://dev.api.rocketalumnisolutions.com) */
255
259
  productBackendUrl?: string;
260
+ /** Optional async function to provide authentication headers for API requests */
261
+ getAuthHeaders?: () => Promise<Record<string, string>>;
256
262
  }
257
263
  /**
258
264
  * Instance returned by createKiteChat with lifecycle control methods.
@@ -118,8 +118,10 @@ interface ChatPanelProps {
118
118
  onCornerChange?: (corner: PanelCorner) => void;
119
119
  /** Product backend URL for user authentication (e.g., https://dev.api.rocketalumnisolutions.com) */
120
120
  productBackendUrl?: string;
121
+ /** Optional async function to provide authentication headers for API requests */
122
+ getAuthHeaders?: () => Promise<Record<string, string>>;
121
123
  }
122
- declare function ChatPanel({ isOpen, onClose, onOpen, onBack, onNavigate, onActionComplete, currentPage, agentUrl, startingQuestions: startingQuestionsProp, startingQuestionsEndpoint, userId, orgId, userName, userEmail, supabaseUrl, supabaseAnonKey, initialCorner, onCornerChange, productBackendUrl, }?: ChatPanelProps): react_jsx_runtime.JSX.Element;
124
+ declare function ChatPanel({ isOpen, onClose, onOpen, onBack, onNavigate, onActionComplete, currentPage, agentUrl, startingQuestions: startingQuestionsProp, startingQuestionsEndpoint, userId, orgId, userName, userEmail, supabaseUrl, supabaseAnonKey, initialCorner, onCornerChange, productBackendUrl, getAuthHeaders, }?: ChatPanelProps): react_jsx_runtime.JSX.Element;
123
125
  /**
124
126
  * PanelToggle - An arrow button on the right edge that toggles the side panel
125
127
  * Shows left arrow when closed (click to open), right arrow when open (click to close)
@@ -182,8 +184,10 @@ interface ChatPanelWithToggleProps {
182
184
  onCornerChange?: (corner: PanelCorner) => void;
183
185
  /** Product backend URL for user authentication (e.g., https://dev.api.rocketalumnisolutions.com) */
184
186
  productBackendUrl?: string;
187
+ /** Optional async function to provide authentication headers for API requests */
188
+ getAuthHeaders?: () => Promise<Record<string, string>>;
185
189
  }
186
- declare function ChatPanelWithToggle({ onNavigate, onActionComplete, currentPage, agentUrl, startingQuestions, startingQuestionsEndpoint, defaultOpen, isOpen: controlledIsOpen, onOpenChange, userId, orgId, userName, userEmail, supabaseUrl, supabaseAnonKey, initialCorner, onCornerChange, productBackendUrl, }: ChatPanelWithToggleProps): react_jsx_runtime.JSX.Element;
190
+ declare function ChatPanelWithToggle({ onNavigate, onActionComplete, currentPage, agentUrl, startingQuestions, startingQuestionsEndpoint, defaultOpen, isOpen: controlledIsOpen, onOpenChange, userId, orgId, userName, userEmail, supabaseUrl, supabaseAnonKey, initialCorner, onCornerChange, productBackendUrl, getAuthHeaders, }: ChatPanelWithToggleProps): react_jsx_runtime.JSX.Element;
187
191
  /**
188
192
  * @deprecated Use ChatPanelWithToggle instead for the new side panel UX
189
193
  */
@@ -253,6 +257,8 @@ interface KiteChatConfig {
253
257
  supabaseAnonKey?: string;
254
258
  /** Product backend URL for user authentication (e.g., https://dev.api.rocketalumnisolutions.com) */
255
259
  productBackendUrl?: string;
260
+ /** Optional async function to provide authentication headers for API requests */
261
+ getAuthHeaders?: () => Promise<Record<string, string>>;
256
262
  }
257
263
  /**
258
264
  * Instance returned by createKiteChat with lifecycle control methods.