@kite-copilot/chat-panel 0.2.43 → 0.2.44

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 CHANGED
@@ -39,7 +39,7 @@ var import_react = __toESM(require("react"), 1);
39
39
  var import_client = require("react-dom/client");
40
40
 
41
41
  // src/ChatPanel.tsx
42
- var React5 = __toESM(require("react"), 1);
42
+ var React6 = __toESM(require("react"), 1);
43
43
  var import_supabase_js = require("@supabase/supabase-js");
44
44
 
45
45
  // src/lib/utils.ts
@@ -405,6 +405,47 @@ function useUserAuth({
405
405
  return { authState, retry };
406
406
  }
407
407
 
408
+ // src/hooks/useOrgConfig.ts
409
+ var React5 = __toESM(require("react"), 1);
410
+ function useOrgConfig({ agentUrl, orgId }) {
411
+ const [state, setState] = React5.useState({
412
+ status: "idle",
413
+ config: null,
414
+ error: null
415
+ });
416
+ React5.useEffect(() => {
417
+ if (!agentUrl || !orgId) {
418
+ console.log("[useOrgConfig] Skipping - missing agentUrl or orgId", { agentUrl, orgId });
419
+ return;
420
+ }
421
+ const fetchConfig = async () => {
422
+ setState({ status: "loading", config: null, error: null });
423
+ const url = `${agentUrl}/org/${orgId}/config`;
424
+ console.log("[useOrgConfig] Fetching org config from:", url);
425
+ try {
426
+ const response = await fetch(url, {
427
+ method: "GET",
428
+ headers: {
429
+ "Accept": "application/json"
430
+ }
431
+ });
432
+ if (!response.ok) {
433
+ throw new Error(`Failed to fetch org config (${response.status})`);
434
+ }
435
+ const config = await response.json();
436
+ console.log("[useOrgConfig] Received config:", config);
437
+ setState({ status: "success", config, error: null });
438
+ } catch (error) {
439
+ const message = error instanceof Error ? error.message : "Failed to fetch org config";
440
+ console.error("[useOrgConfig] Error:", message);
441
+ setState({ status: "error", config: null, error: message });
442
+ }
443
+ };
444
+ fetchConfig();
445
+ }, [agentUrl, orgId]);
446
+ return state;
447
+ }
448
+
408
449
  // src/components/ui/card.tsx
409
450
  var import_jsx_runtime7 = require("react/jsx-runtime");
410
451
  function Card({ className, ...props }) {
@@ -982,7 +1023,7 @@ function TypingIndicator({ className = "" }) {
982
1023
 
983
1024
  // src/ChatPanel.tsx
984
1025
  var import_jsx_runtime10 = require("react/jsx-runtime");
985
- var CHAT_PANEL_VERSION = true ? "0.2.43" : "dev";
1026
+ var CHAT_PANEL_VERSION = true ? "0.2.44" : "dev";
986
1027
  var DEFAULT_AGENT_URL = "http://localhost:5002";
987
1028
  var PANEL_WIDTH = 340;
988
1029
  function unescapeJsonString(str) {
@@ -1446,16 +1487,18 @@ function ChatPanel({
1446
1487
  supabaseAnonKey,
1447
1488
  productBackendUrl
1448
1489
  } = {}) {
1449
- const [messages, setMessages] = React5.useState(initialMessages);
1450
- const [input, setInput] = React5.useState("");
1451
- const [sessionId, setSessionId] = React5.useState(() => crypto.randomUUID());
1490
+ const [messages, setMessages] = React6.useState(initialMessages);
1491
+ const [input, setInput] = React6.useState("");
1492
+ const [sessionId, setSessionId] = React6.useState(() => crypto.randomUUID());
1493
+ const orgConfigState = useOrgConfig({ agentUrl, orgId: orgId || "" });
1494
+ const effectiveProductBackendUrl = orgConfigState.config?.productBackendUrl || productBackendUrl;
1452
1495
  const { authState, retry: retryAuth } = useUserAuth({
1453
- productBackendUrl,
1496
+ productBackendUrl: effectiveProductBackendUrl,
1454
1497
  sessionId,
1455
- enabled: !!productBackendUrl
1456
- // Only enable if URL is provided
1498
+ enabled: !!effectiveProductBackendUrl && orgConfigState.status === "success"
1499
+ // Only enable after config is fetched
1457
1500
  });
1458
- const effectiveUser = React5.useMemo(() => {
1501
+ const effectiveUser = React6.useMemo(() => {
1459
1502
  if (authState.status === "authenticated") {
1460
1503
  return {
1461
1504
  userId: authState.user.id,
@@ -1473,16 +1516,16 @@ function ChatPanel({
1473
1516
  isInternal: false
1474
1517
  };
1475
1518
  }, [authState, userId, userName, userEmail]);
1476
- const [isEscalated, setIsEscalated] = React5.useState(false);
1477
- const escalationWsRef = React5.useRef(null);
1478
- const [agentIsTyping, setAgentIsTyping] = React5.useState(false);
1479
- const supabaseRef = React5.useRef(null);
1480
- const typingChannelRef = React5.useRef(null);
1481
- const typingTimeoutRef = React5.useRef(null);
1482
- React5.useEffect(() => {
1519
+ const [isEscalated, setIsEscalated] = React6.useState(false);
1520
+ const escalationWsRef = React6.useRef(null);
1521
+ const [agentIsTyping, setAgentIsTyping] = React6.useState(false);
1522
+ const supabaseRef = React6.useRef(null);
1523
+ const typingChannelRef = React6.useRef(null);
1524
+ const typingTimeoutRef = React6.useRef(null);
1525
+ React6.useEffect(() => {
1483
1526
  console.log(`[KiteChat] Chat Panel v${CHAT_PANEL_VERSION} loaded`);
1484
1527
  }, []);
1485
- const resetSession = React5.useCallback(() => {
1528
+ const resetSession = React6.useCallback(() => {
1486
1529
  console.log("[KiteChat] resetSession called", { isEscalated, hasSupabase: !!supabaseRef.current, sessionId });
1487
1530
  if (isEscalated && supabaseRef.current && sessionId) {
1488
1531
  console.log("[KiteChat] Updating customer_status to disconnected for session:", sessionId);
@@ -1512,12 +1555,12 @@ function ChatPanel({
1512
1555
  typingChannelRef.current = null;
1513
1556
  }
1514
1557
  }, [isEscalated, sessionId]);
1515
- React5.useEffect(() => {
1558
+ React6.useEffect(() => {
1516
1559
  if (supabaseUrl && supabaseAnonKey && !supabaseRef.current) {
1517
1560
  supabaseRef.current = (0, import_supabase_js.createClient)(supabaseUrl, supabaseAnonKey);
1518
1561
  }
1519
1562
  }, [supabaseUrl, supabaseAnonKey]);
1520
- React5.useEffect(() => {
1563
+ React6.useEffect(() => {
1521
1564
  if (!isEscalated || !sessionId || !supabaseRef.current) {
1522
1565
  return;
1523
1566
  }
@@ -1554,8 +1597,8 @@ function ChatPanel({
1554
1597
  }
1555
1598
  };
1556
1599
  }, [isEscalated, sessionId]);
1557
- const heartbeatIntervalRef = React5.useRef(null);
1558
- const updateCustomerStatus = React5.useCallback(async (status) => {
1600
+ const heartbeatIntervalRef = React6.useRef(null);
1601
+ const updateCustomerStatus = React6.useCallback(async (status) => {
1559
1602
  if (!supabaseRef.current || !sessionId) return;
1560
1603
  try {
1561
1604
  await supabaseRef.current.from("escalations").update({
@@ -1566,7 +1609,7 @@ function ChatPanel({
1566
1609
  console.error("[KiteChat] Failed to update customer status:", err);
1567
1610
  }
1568
1611
  }, [sessionId]);
1569
- React5.useEffect(() => {
1612
+ React6.useEffect(() => {
1570
1613
  if (!isEscalated || !sessionId || !supabaseRef.current) {
1571
1614
  return;
1572
1615
  }
@@ -1614,7 +1657,7 @@ function ChatPanel({
1614
1657
  }
1615
1658
  };
1616
1659
  }, [isEscalated, sessionId, updateCustomerStatus]);
1617
- const sendTypingIndicator = React5.useCallback((isTyping) => {
1660
+ const sendTypingIndicator = React6.useCallback((isTyping) => {
1618
1661
  if (!typingChannelRef.current) {
1619
1662
  console.log("[KiteChat] Cannot send typing - channel not ready");
1620
1663
  return;
@@ -1630,8 +1673,8 @@ function ChatPanel({
1630
1673
  payload: { sender: "user", isTyping }
1631
1674
  });
1632
1675
  }, [isEscalated]);
1633
- const userTypingTimeoutRef = React5.useRef(null);
1634
- const handleTypingStart = React5.useCallback(() => {
1676
+ const userTypingTimeoutRef = React6.useRef(null);
1677
+ const handleTypingStart = React6.useCallback(() => {
1635
1678
  if (!isEscalated || !supabaseRef.current) return;
1636
1679
  sendTypingIndicator(true);
1637
1680
  updateCustomerStatus("active");
@@ -1642,19 +1685,19 @@ function ChatPanel({
1642
1685
  sendTypingIndicator(false);
1643
1686
  }, 1500);
1644
1687
  }, [isEscalated, sendTypingIndicator, updateCustomerStatus]);
1645
- const streamIntervals = React5.useRef({});
1688
+ const streamIntervals = React6.useRef({});
1646
1689
  const isEmpty = messages.length === 0;
1647
- const [phase, setPhase] = React5.useState("idle");
1648
- const [progressSteps, setProgressSteps] = React5.useState([]);
1649
- const phaseTimers = React5.useRef([]);
1690
+ const [phase, setPhase] = React6.useState("idle");
1691
+ const [progressSteps, setProgressSteps] = React6.useState([]);
1692
+ const phaseTimers = React6.useRef([]);
1650
1693
  const lastRole = messages.length ? messages[messages.length - 1].role : void 0;
1651
- const [panelView, setPanelView] = React5.useState(
1694
+ const [panelView, setPanelView] = React6.useState(
1652
1695
  "landing"
1653
1696
  );
1654
- const [currentFolderId, setCurrentFolderId] = React5.useState(void 0);
1655
- const [startingQuestions, setStartingQuestions] = React5.useState(startingQuestionsProp || defaultStartingQuestions);
1656
- const [loadingQuestions, setLoadingQuestions] = React5.useState(false);
1657
- React5.useEffect(() => {
1697
+ const [currentFolderId, setCurrentFolderId] = React6.useState(void 0);
1698
+ const [startingQuestions, setStartingQuestions] = React6.useState(startingQuestionsProp || defaultStartingQuestions);
1699
+ const [loadingQuestions, setLoadingQuestions] = React6.useState(false);
1700
+ React6.useEffect(() => {
1658
1701
  if (startingQuestionsEndpoint && !startingQuestionsProp) {
1659
1702
  setLoadingQuestions(true);
1660
1703
  fetch(startingQuestionsEndpoint).then((res) => res.json()).then((data) => {
@@ -1666,16 +1709,16 @@ function ChatPanel({
1666
1709
  }).finally(() => setLoadingQuestions(false));
1667
1710
  }
1668
1711
  }, [startingQuestionsEndpoint, startingQuestionsProp]);
1669
- React5.useEffect(() => {
1712
+ React6.useEffect(() => {
1670
1713
  if (startingQuestionsProp) {
1671
1714
  setStartingQuestions(startingQuestionsProp);
1672
1715
  }
1673
1716
  }, [startingQuestionsProp]);
1674
- const [activeGuide, setActiveGuide] = React5.useState(void 0);
1675
- const activeGuideRef = React5.useRef(void 0);
1676
- const latestBulkSummaryNavigationRef = React5.useRef(null);
1677
- const [guideComplete, setGuideComplete] = React5.useState(false);
1678
- React5.useEffect(() => {
1717
+ const [activeGuide, setActiveGuide] = React6.useState(void 0);
1718
+ const activeGuideRef = React6.useRef(void 0);
1719
+ const latestBulkSummaryNavigationRef = React6.useRef(null);
1720
+ const [guideComplete, setGuideComplete] = React6.useState(false);
1721
+ React6.useEffect(() => {
1679
1722
  window.resetIntegrationNotification = () => {
1680
1723
  localStorage.removeItem("gmailNotificationSeen");
1681
1724
  console.log(
@@ -1709,7 +1752,7 @@ function ChatPanel({
1709
1752
  );
1710
1753
  };
1711
1754
  }, []);
1712
- React5.useEffect(() => {
1755
+ React6.useEffect(() => {
1713
1756
  if (activeGuide) {
1714
1757
  if (!activeGuideRef.current || activeGuideRef.current.id !== activeGuide.id || activeGuideRef.current.stepIndex !== activeGuide.stepIndex) {
1715
1758
  activeGuideRef.current = activeGuide;
@@ -1718,21 +1761,21 @@ function ChatPanel({
1718
1761
  activeGuideRef.current = void 0;
1719
1762
  }
1720
1763
  }, [activeGuide]);
1721
- const [pendingNavigation, setPendingNavigation] = React5.useState(null);
1722
- const [pendingAction, setPendingAction] = React5.useState(null);
1723
- const [actionFormData, setActionFormData] = React5.useState({});
1724
- const messagesEndRef = React5.useRef(null);
1725
- const messagesContainerRef = React5.useRef(null);
1726
- const currentStepRef = React5.useRef(null);
1764
+ const [pendingNavigation, setPendingNavigation] = React6.useState(null);
1765
+ const [pendingAction, setPendingAction] = React6.useState(null);
1766
+ const [actionFormData, setActionFormData] = React6.useState({});
1767
+ const messagesEndRef = React6.useRef(null);
1768
+ const messagesContainerRef = React6.useRef(null);
1769
+ const currentStepRef = React6.useRef(null);
1727
1770
  const { cursorState, moveTo, hide } = useGuideCursor();
1728
- const [pendingFile, setPendingFile] = React5.useState(null);
1729
- const [pendingBulkSession, setPendingBulkSession] = React5.useState(null);
1730
- const pendingBulkSessionRef = React5.useRef(null);
1731
- const fileInputRef = React5.useRef(null);
1732
- const [searchExpanded, setSearchExpanded] = React5.useState(false);
1733
- const [searchInput, setSearchInput] = React5.useState("");
1734
- const searchInputRef = React5.useRef(null);
1735
- React5.useEffect(() => {
1771
+ const [pendingFile, setPendingFile] = React6.useState(null);
1772
+ const [pendingBulkSession, setPendingBulkSession] = React6.useState(null);
1773
+ const pendingBulkSessionRef = React6.useRef(null);
1774
+ const fileInputRef = React6.useRef(null);
1775
+ const [searchExpanded, setSearchExpanded] = React6.useState(false);
1776
+ const [searchInput, setSearchInput] = React6.useState("");
1777
+ const searchInputRef = React6.useRef(null);
1778
+ React6.useEffect(() => {
1736
1779
  if (!activeGuide || activeGuide.id !== "add-api-key" || activeGuide.stepIndex !== 2) {
1737
1780
  return;
1738
1781
  }
@@ -1758,7 +1801,7 @@ function ChatPanel({
1758
1801
  const interval = setInterval(checkForDialogOpen, 300);
1759
1802
  return () => clearInterval(interval);
1760
1803
  }, [activeGuide, hide]);
1761
- React5.useEffect(() => {
1804
+ React6.useEffect(() => {
1762
1805
  return () => {
1763
1806
  Object.values(streamIntervals.current).forEach(
1764
1807
  (id) => window.clearInterval(id)
@@ -1768,7 +1811,7 @@ function ChatPanel({
1768
1811
  phaseTimers.current = [];
1769
1812
  };
1770
1813
  }, []);
1771
- React5.useEffect(() => {
1814
+ React6.useEffect(() => {
1772
1815
  if (activeGuide && messages.length > 0) {
1773
1816
  const lastMessage = messages[messages.length - 1];
1774
1817
  if (lastMessage.kind === "guideStep" || lastMessage.kind === "guideComplete") {
@@ -1785,7 +1828,7 @@ function ChatPanel({
1785
1828
  messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
1786
1829
  }
1787
1830
  }, [messages, phase, activeGuide]);
1788
- const latestBulkSummaryNavigation = React5.useMemo(() => {
1831
+ const latestBulkSummaryNavigation = React6.useMemo(() => {
1789
1832
  for (let i = messages.length - 1; i >= 0; i--) {
1790
1833
  const msg = messages[i];
1791
1834
  if (msg.kind === "bulkSummary" && msg.bulkSummary?.navigationPage && msg.bulkSummary.successes > 0) {
@@ -1794,13 +1837,13 @@ function ChatPanel({
1794
1837
  }
1795
1838
  return null;
1796
1839
  }, [messages]);
1797
- React5.useEffect(() => {
1840
+ React6.useEffect(() => {
1798
1841
  latestBulkSummaryNavigationRef.current = latestBulkSummaryNavigation;
1799
1842
  }, [latestBulkSummaryNavigation]);
1800
- React5.useEffect(() => {
1843
+ React6.useEffect(() => {
1801
1844
  pendingBulkSessionRef.current = pendingBulkSession;
1802
1845
  }, [pendingBulkSession]);
1803
- React5.useEffect(() => {
1846
+ React6.useEffect(() => {
1804
1847
  const handleKeyDown = (e) => {
1805
1848
  if ((e.metaKey || e.ctrlKey) && e.key === "Enter") {
1806
1849
  const currentBulkSession = pendingBulkSessionRef.current;
@@ -1863,7 +1906,7 @@ function ChatPanel({
1863
1906
  guideComplete,
1864
1907
  onNavigate
1865
1908
  ]);
1866
- const connectToEscalationWs = React5.useCallback((currentSessionId) => {
1909
+ const connectToEscalationWs = React6.useCallback((currentSessionId) => {
1867
1910
  if (!agentUrl) return;
1868
1911
  if (escalationWsRef.current) {
1869
1912
  escalationWsRef.current.close();
@@ -1906,7 +1949,7 @@ function ChatPanel({
1906
1949
  };
1907
1950
  escalationWsRef.current = ws;
1908
1951
  }, [agentUrl]);
1909
- const sendEscalatedMessage = React5.useCallback(async (content) => {
1952
+ const sendEscalatedMessage = React6.useCallback(async (content) => {
1910
1953
  if (!escalationWsRef.current || escalationWsRef.current.readyState !== WebSocket.OPEN) {
1911
1954
  console.error("[KiteChat] Escalation WebSocket not connected");
1912
1955
  return false;
@@ -1923,14 +1966,14 @@ function ChatPanel({
1923
1966
  return false;
1924
1967
  }
1925
1968
  }, [updateCustomerStatus]);
1926
- React5.useEffect(() => {
1969
+ React6.useEffect(() => {
1927
1970
  return () => {
1928
1971
  if (escalationWsRef.current) {
1929
1972
  escalationWsRef.current.close();
1930
1973
  }
1931
1974
  };
1932
1975
  }, []);
1933
- React5.useEffect(() => {
1976
+ React6.useEffect(() => {
1934
1977
  if (isEscalated && sessionId) {
1935
1978
  connectToEscalationWs(sessionId);
1936
1979
  }
@@ -3159,7 +3202,38 @@ ${userText}`
3159
3202
  ] })
3160
3203
  ] }) }) });
3161
3204
  }
3162
- if (productBackendUrl) {
3205
+ if (orgConfigState.status === "loading") {
3206
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
3207
+ "section",
3208
+ {
3209
+ className: `fixed top-0 right-0 z-40 flex flex-col bg-white border-l border-gray-200 h-full overflow-hidden transition-transform duration-300 ${isOpen ? "translate-x-0" : "translate-x-full"}`,
3210
+ style: { width: `${PANEL_WIDTH}px` },
3211
+ children: [
3212
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex items-center justify-between px-4 py-3 border-b border-gray-100 bg-gradient-to-r from-gray-50 to-white shrink-0", children: [
3213
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex items-center gap-2.5", children: [
3214
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react4.Sparkles, { className: "h-3.5 w-3.5 text-black", fill: "currentColor" }),
3215
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("h3", { className: "text-sm font-semibold text-gray-800", children: "Copilot" })
3216
+ ] }),
3217
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
3218
+ Button,
3219
+ {
3220
+ variant: "ghost",
3221
+ size: "sm",
3222
+ className: "h-7 w-7 p-0 text-gray-400 hover:text-gray-600 hover:bg-gray-100 rounded-full",
3223
+ onClick: () => onClose?.(),
3224
+ children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react4.X, { className: "h-4 w-4" })
3225
+ }
3226
+ )
3227
+ ] }),
3228
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "flex-1 flex items-center justify-center", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "text-center", children: [
3229
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react4.Loader2, { className: "h-8 w-8 animate-spin text-gray-400 mx-auto mb-3" }),
3230
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { className: "text-sm text-gray-500", children: "Loading..." })
3231
+ ] }) })
3232
+ ]
3233
+ }
3234
+ );
3235
+ }
3236
+ if (effectiveProductBackendUrl) {
3163
3237
  if (authState.status === "loading") {
3164
3238
  return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
3165
3239
  "section",
@@ -4334,7 +4408,7 @@ ${userText}`
4334
4408
  message.id
4335
4409
  );
4336
4410
  }
4337
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(React5.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
4411
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(React6.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
4338
4412
  "div",
4339
4413
  {
4340
4414
  ref: isCurrentGuideStep ? currentStepRef : null,
@@ -4571,7 +4645,7 @@ function ChatPanelWithToggle({
4571
4645
  supabaseAnonKey,
4572
4646
  productBackendUrl
4573
4647
  }) {
4574
- const [internalIsOpen, setInternalIsOpen] = React5.useState(defaultOpen);
4648
+ const [internalIsOpen, setInternalIsOpen] = React6.useState(defaultOpen);
4575
4649
  const isOpen = controlledIsOpen !== void 0 ? controlledIsOpen : internalIsOpen;
4576
4650
  const setIsOpen = (open) => {
4577
4651
  if (controlledIsOpen === void 0) {
@@ -4579,7 +4653,7 @@ function ChatPanelWithToggle({
4579
4653
  }
4580
4654
  onOpenChange?.(open);
4581
4655
  };
4582
- React5.useEffect(() => {
4656
+ React6.useEffect(() => {
4583
4657
  const originalPadding = document.body.style.paddingRight;
4584
4658
  const originalTransition = document.body.style.transition;
4585
4659
  document.body.style.transition = "padding-right 0.3s ease";
package/dist/auto.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  createKiteChat
3
- } from "./chunk-XZM4VX5Y.js";
3
+ } from "./chunk-G74XTXWW.js";
4
4
 
5
5
  // src/auto.ts
6
6
  function mountKiteChat(config) {