@kite-copilot/chat-panel 0.2.24 → 0.2.25

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
@@ -885,6 +885,7 @@ function DataRenderer({ type, data }) {
885
885
  }
886
886
 
887
887
  // src/ChatPanel.tsx
888
+ var import_supabase_js = require("@supabase/supabase-js");
888
889
  var import_jsx_runtime9 = require("react/jsx-runtime");
889
890
  var DEFAULT_AGENT_URL = "http://localhost:5002";
890
891
  var PANEL_WIDTH = 340;
@@ -1313,11 +1314,16 @@ function ChatPanel({
1313
1314
  currentPage,
1314
1315
  agentUrl = DEFAULT_AGENT_URL,
1315
1316
  startingQuestions: startingQuestionsProp,
1316
- startingQuestionsEndpoint
1317
+ startingQuestionsEndpoint,
1318
+ supabaseUrl,
1319
+ supabaseAnonKey
1317
1320
  } = {}) {
1318
1321
  const [messages, setMessages] = React4.useState(initialMessages);
1319
1322
  const [input, setInput] = React4.useState("");
1320
1323
  const [sessionId, setSessionId] = React4.useState(() => crypto.randomUUID());
1324
+ const [isEscalated, setIsEscalated] = React4.useState(false);
1325
+ const [supabaseClient, setSupabaseClient] = React4.useState(null);
1326
+ const realtimeChannelRef = React4.useRef(null);
1321
1327
  const resetSession = React4.useCallback(() => {
1322
1328
  setSessionId(crypto.randomUUID());
1323
1329
  }, []);
@@ -1542,6 +1548,63 @@ function ChatPanel({
1542
1548
  guideComplete,
1543
1549
  onNavigate
1544
1550
  ]);
1551
+ React4.useEffect(() => {
1552
+ if (supabaseUrl && supabaseAnonKey && !supabaseClient) {
1553
+ const client = (0, import_supabase_js.createClient)(supabaseUrl, supabaseAnonKey);
1554
+ setSupabaseClient(client);
1555
+ }
1556
+ }, [supabaseUrl, supabaseAnonKey, supabaseClient]);
1557
+ const subscribeToAgentMessages = React4.useCallback((currentSessionId) => {
1558
+ if (!supabaseClient) return;
1559
+ if (realtimeChannelRef.current) {
1560
+ supabaseClient.removeChannel(realtimeChannelRef.current);
1561
+ }
1562
+ const channel = supabaseClient.channel(`user-chat-${currentSessionId}`).on(
1563
+ "postgres_changes",
1564
+ {
1565
+ event: "INSERT",
1566
+ schema: "public",
1567
+ table: "chat_history",
1568
+ filter: `session_id=eq.${currentSessionId}`
1569
+ },
1570
+ (payload) => {
1571
+ const newMsg = payload.new;
1572
+ if (newMsg.role === "agent") {
1573
+ setMessages((prev) => [
1574
+ ...prev,
1575
+ {
1576
+ id: Date.now(),
1577
+ role: "agent",
1578
+ kind: "text",
1579
+ content: newMsg.content
1580
+ }
1581
+ ]);
1582
+ }
1583
+ }
1584
+ ).subscribe();
1585
+ realtimeChannelRef.current = channel;
1586
+ }, [supabaseClient]);
1587
+ React4.useEffect(() => {
1588
+ return () => {
1589
+ if (realtimeChannelRef.current && supabaseClient) {
1590
+ supabaseClient.removeChannel(realtimeChannelRef.current);
1591
+ }
1592
+ };
1593
+ }, [supabaseClient]);
1594
+ const sendEscalatedMessage = React4.useCallback(async (content) => {
1595
+ if (!supabaseClient || !isEscalated) return false;
1596
+ try {
1597
+ await supabaseClient.from("chat_history").insert({
1598
+ session_id: sessionId,
1599
+ role: "user",
1600
+ content
1601
+ });
1602
+ return true;
1603
+ } catch (err) {
1604
+ console.error("[KiteChat] Failed to send escalated message:", err);
1605
+ return false;
1606
+ }
1607
+ }, [supabaseClient, isEscalated, sessionId]);
1545
1608
  function streamAssistantMessage(messageId, fullText, followups) {
1546
1609
  let textToStream = fullText;
1547
1610
  let extractedFollowups = followups;
@@ -1652,6 +1715,17 @@ function ChatPanel({
1652
1715
  return;
1653
1716
  }
1654
1717
  if (!trimmed) return;
1718
+ if (isEscalated && supabaseClient) {
1719
+ const userMessage = {
1720
+ id: Date.now(),
1721
+ role: "user",
1722
+ content: trimmed
1723
+ };
1724
+ setMessages((prev) => [...prev, userMessage]);
1725
+ sendEscalatedMessage(trimmed);
1726
+ setInput("");
1727
+ return;
1728
+ }
1655
1729
  startChatFlow(trimmed);
1656
1730
  setInput("");
1657
1731
  }
@@ -1980,6 +2054,18 @@ function ChatPanel({
1980
2054
  setProgressSteps([]);
1981
2055
  setPhase("idle");
1982
2056
  streamCompleted = true;
2057
+ } else if (eventType === "escalation") {
2058
+ setIsEscalated(true);
2059
+ setPhase("idle");
2060
+ const escalationMessageId = Date.now() + 2;
2061
+ const escalationMessage = {
2062
+ id: escalationMessageId,
2063
+ role: "assistant",
2064
+ kind: "text",
2065
+ content: data.message || "You've been connected to our support queue. An agent will be with you shortly."
2066
+ };
2067
+ setMessages((prev) => [...prev, escalationMessage]);
2068
+ subscribeToAgentMessages(sessionId);
1983
2069
  }
1984
2070
  } catch (parseError) {
1985
2071
  console.error("Failed to parse SSE event:", parseError);
@@ -2847,6 +2933,12 @@ ${userText}`
2847
2933
  if (isUser) {
2848
2934
  return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: `flex justify-end ${isRoleChange ? "mt-3" : ""}`, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "max-w-[260px] rounded-2xl rounded-br-md bg-gray-900 px-3.5 py-2.5 text-sm text-white shadow-sm", children: message.content }) }, message.id);
2849
2935
  }
2936
+ if (message.role === "agent") {
2937
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: `flex justify-start ${isRoleChange ? "mt-3" : ""}`, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "max-w-[260px] rounded-2xl rounded-bl-md bg-blue-50 border border-blue-200 px-3.5 py-2.5 text-sm text-gray-900 shadow-sm", children: [
2938
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "text-xs text-blue-600 font-medium mb-1", children: "Support Agent" }),
2939
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "whitespace-pre-wrap leading-relaxed", children: renderMarkdown(message.content || "") })
2940
+ ] }) }, message.id);
2941
+ }
2850
2942
  if (message.kind === "searchSummary") {
2851
2943
  return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2852
2944
  "div",
@@ -4038,7 +4130,9 @@ function ChatPanelWithToggle({
4038
4130
  startingQuestionsEndpoint,
4039
4131
  defaultOpen = false,
4040
4132
  isOpen: controlledIsOpen,
4041
- onOpenChange
4133
+ onOpenChange,
4134
+ supabaseUrl,
4135
+ supabaseAnonKey
4042
4136
  }) {
4043
4137
  const [internalIsOpen, setInternalIsOpen] = React4.useState(defaultOpen);
4044
4138
  const isOpen = controlledIsOpen !== void 0 ? controlledIsOpen : internalIsOpen;
@@ -4069,7 +4163,9 @@ function ChatPanelWithToggle({
4069
4163
  currentPage,
4070
4164
  agentUrl,
4071
4165
  startingQuestions,
4072
- startingQuestionsEndpoint
4166
+ startingQuestionsEndpoint,
4167
+ supabaseUrl,
4168
+ supabaseAnonKey
4073
4169
  }
4074
4170
  );
4075
4171
  }
package/dist/auto.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { K as KiteChatConfig, a as KiteChatInstance } from './createKiteChat-CyoN-YV4.cjs';
1
+ import { K as KiteChatConfig, a as KiteChatInstance } from './createKiteChat-CGiuk776.cjs';
2
2
  import 'react/jsx-runtime';
3
3
 
4
4
  /**
package/dist/auto.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { K as KiteChatConfig, a as KiteChatInstance } from './createKiteChat-CyoN-YV4.js';
1
+ import { K as KiteChatConfig, a as KiteChatInstance } from './createKiteChat-CGiuk776.js';
2
2
  import 'react/jsx-runtime';
3
3
 
4
4
  /**
package/dist/auto.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  createKiteChat
3
- } from "./chunk-TBMYN3GD.js";
3
+ } from "./chunk-WCRTS3TD.js";
4
4
 
5
5
  // src/auto.ts
6
6
  function mountKiteChat(config) {
@@ -884,6 +884,7 @@ function DataRenderer({ type, data }) {
884
884
  // src/ChatPanel.tsx
885
885
  import * as React4 from "react";
886
886
  import { ArrowLeft, ArrowUp, Command, CornerDownLeft, CheckCircle2 as CheckCircle23, SquarePen, Paperclip, X, FileSpreadsheet, Loader2 as Loader22, ChevronLeft, ChevronRight, Sparkles } from "lucide-react";
887
+ import { createClient } from "@supabase/supabase-js";
887
888
  import { Fragment as Fragment2, jsx as jsx9, jsxs as jsxs5 } from "react/jsx-runtime";
888
889
  var DEFAULT_AGENT_URL = "http://localhost:5002";
889
890
  var PANEL_WIDTH = 340;
@@ -1312,11 +1313,16 @@ function ChatPanel({
1312
1313
  currentPage,
1313
1314
  agentUrl = DEFAULT_AGENT_URL,
1314
1315
  startingQuestions: startingQuestionsProp,
1315
- startingQuestionsEndpoint
1316
+ startingQuestionsEndpoint,
1317
+ supabaseUrl,
1318
+ supabaseAnonKey
1316
1319
  } = {}) {
1317
1320
  const [messages, setMessages] = React4.useState(initialMessages);
1318
1321
  const [input, setInput] = React4.useState("");
1319
1322
  const [sessionId, setSessionId] = React4.useState(() => crypto.randomUUID());
1323
+ const [isEscalated, setIsEscalated] = React4.useState(false);
1324
+ const [supabaseClient, setSupabaseClient] = React4.useState(null);
1325
+ const realtimeChannelRef = React4.useRef(null);
1320
1326
  const resetSession = React4.useCallback(() => {
1321
1327
  setSessionId(crypto.randomUUID());
1322
1328
  }, []);
@@ -1541,6 +1547,63 @@ function ChatPanel({
1541
1547
  guideComplete,
1542
1548
  onNavigate
1543
1549
  ]);
1550
+ React4.useEffect(() => {
1551
+ if (supabaseUrl && supabaseAnonKey && !supabaseClient) {
1552
+ const client = createClient(supabaseUrl, supabaseAnonKey);
1553
+ setSupabaseClient(client);
1554
+ }
1555
+ }, [supabaseUrl, supabaseAnonKey, supabaseClient]);
1556
+ const subscribeToAgentMessages = React4.useCallback((currentSessionId) => {
1557
+ if (!supabaseClient) return;
1558
+ if (realtimeChannelRef.current) {
1559
+ supabaseClient.removeChannel(realtimeChannelRef.current);
1560
+ }
1561
+ const channel = supabaseClient.channel(`user-chat-${currentSessionId}`).on(
1562
+ "postgres_changes",
1563
+ {
1564
+ event: "INSERT",
1565
+ schema: "public",
1566
+ table: "chat_history",
1567
+ filter: `session_id=eq.${currentSessionId}`
1568
+ },
1569
+ (payload) => {
1570
+ const newMsg = payload.new;
1571
+ if (newMsg.role === "agent") {
1572
+ setMessages((prev) => [
1573
+ ...prev,
1574
+ {
1575
+ id: Date.now(),
1576
+ role: "agent",
1577
+ kind: "text",
1578
+ content: newMsg.content
1579
+ }
1580
+ ]);
1581
+ }
1582
+ }
1583
+ ).subscribe();
1584
+ realtimeChannelRef.current = channel;
1585
+ }, [supabaseClient]);
1586
+ React4.useEffect(() => {
1587
+ return () => {
1588
+ if (realtimeChannelRef.current && supabaseClient) {
1589
+ supabaseClient.removeChannel(realtimeChannelRef.current);
1590
+ }
1591
+ };
1592
+ }, [supabaseClient]);
1593
+ const sendEscalatedMessage = React4.useCallback(async (content) => {
1594
+ if (!supabaseClient || !isEscalated) return false;
1595
+ try {
1596
+ await supabaseClient.from("chat_history").insert({
1597
+ session_id: sessionId,
1598
+ role: "user",
1599
+ content
1600
+ });
1601
+ return true;
1602
+ } catch (err) {
1603
+ console.error("[KiteChat] Failed to send escalated message:", err);
1604
+ return false;
1605
+ }
1606
+ }, [supabaseClient, isEscalated, sessionId]);
1544
1607
  function streamAssistantMessage(messageId, fullText, followups) {
1545
1608
  let textToStream = fullText;
1546
1609
  let extractedFollowups = followups;
@@ -1651,6 +1714,17 @@ function ChatPanel({
1651
1714
  return;
1652
1715
  }
1653
1716
  if (!trimmed) return;
1717
+ if (isEscalated && supabaseClient) {
1718
+ const userMessage = {
1719
+ id: Date.now(),
1720
+ role: "user",
1721
+ content: trimmed
1722
+ };
1723
+ setMessages((prev) => [...prev, userMessage]);
1724
+ sendEscalatedMessage(trimmed);
1725
+ setInput("");
1726
+ return;
1727
+ }
1654
1728
  startChatFlow(trimmed);
1655
1729
  setInput("");
1656
1730
  }
@@ -1979,6 +2053,18 @@ function ChatPanel({
1979
2053
  setProgressSteps([]);
1980
2054
  setPhase("idle");
1981
2055
  streamCompleted = true;
2056
+ } else if (eventType === "escalation") {
2057
+ setIsEscalated(true);
2058
+ setPhase("idle");
2059
+ const escalationMessageId = Date.now() + 2;
2060
+ const escalationMessage = {
2061
+ id: escalationMessageId,
2062
+ role: "assistant",
2063
+ kind: "text",
2064
+ content: data.message || "You've been connected to our support queue. An agent will be with you shortly."
2065
+ };
2066
+ setMessages((prev) => [...prev, escalationMessage]);
2067
+ subscribeToAgentMessages(sessionId);
1982
2068
  }
1983
2069
  } catch (parseError) {
1984
2070
  console.error("Failed to parse SSE event:", parseError);
@@ -2846,6 +2932,12 @@ ${userText}`
2846
2932
  if (isUser) {
2847
2933
  return /* @__PURE__ */ jsx9("div", { className: `flex justify-end ${isRoleChange ? "mt-3" : ""}`, children: /* @__PURE__ */ jsx9("div", { className: "max-w-[260px] rounded-2xl rounded-br-md bg-gray-900 px-3.5 py-2.5 text-sm text-white shadow-sm", children: message.content }) }, message.id);
2848
2934
  }
2935
+ if (message.role === "agent") {
2936
+ return /* @__PURE__ */ jsx9("div", { className: `flex justify-start ${isRoleChange ? "mt-3" : ""}`, children: /* @__PURE__ */ jsxs5("div", { className: "max-w-[260px] rounded-2xl rounded-bl-md bg-blue-50 border border-blue-200 px-3.5 py-2.5 text-sm text-gray-900 shadow-sm", children: [
2937
+ /* @__PURE__ */ jsx9("div", { className: "text-xs text-blue-600 font-medium mb-1", children: "Support Agent" }),
2938
+ /* @__PURE__ */ jsx9("div", { className: "whitespace-pre-wrap leading-relaxed", children: renderMarkdown(message.content || "") })
2939
+ ] }) }, message.id);
2940
+ }
2849
2941
  if (message.kind === "searchSummary") {
2850
2942
  return /* @__PURE__ */ jsx9(
2851
2943
  "div",
@@ -4057,7 +4149,9 @@ function ChatPanelWithToggle({
4057
4149
  startingQuestionsEndpoint,
4058
4150
  defaultOpen = false,
4059
4151
  isOpen: controlledIsOpen,
4060
- onOpenChange
4152
+ onOpenChange,
4153
+ supabaseUrl,
4154
+ supabaseAnonKey
4061
4155
  }) {
4062
4156
  const [internalIsOpen, setInternalIsOpen] = React4.useState(defaultOpen);
4063
4157
  const isOpen = controlledIsOpen !== void 0 ? controlledIsOpen : internalIsOpen;
@@ -4088,7 +4182,9 @@ function ChatPanelWithToggle({
4088
4182
  currentPage,
4089
4183
  agentUrl,
4090
4184
  startingQuestions,
4091
- startingQuestionsEndpoint
4185
+ startingQuestionsEndpoint,
4186
+ supabaseUrl,
4187
+ supabaseAnonKey
4092
4188
  }
4093
4189
  );
4094
4190
  }
@@ -98,8 +98,12 @@ interface ChatPanelProps {
98
98
  startingQuestions?: StartingQuestion[];
99
99
  /** API endpoint to fetch starting questions */
100
100
  startingQuestionsEndpoint?: string;
101
+ /** Supabase URL for Realtime escalation support */
102
+ supabaseUrl?: string;
103
+ /** Supabase anon key for Realtime escalation support */
104
+ supabaseAnonKey?: string;
101
105
  }
102
- declare function ChatPanel({ isOpen, onClose, onOpen, onBack, onNavigate, onActionComplete, currentPage, agentUrl, startingQuestions: startingQuestionsProp, startingQuestionsEndpoint, }?: ChatPanelProps): react_jsx_runtime.JSX.Element;
106
+ declare function ChatPanel({ isOpen, onClose, onOpen, onBack, onNavigate, onActionComplete, currentPage, agentUrl, startingQuestions: startingQuestionsProp, startingQuestionsEndpoint, supabaseUrl, supabaseAnonKey, }?: ChatPanelProps): react_jsx_runtime.JSX.Element;
103
107
  /**
104
108
  * PanelToggle - An arrow button on the right edge that toggles the side panel
105
109
  * Shows left arrow when closed (click to open), right arrow when open (click to close)
@@ -144,8 +148,12 @@ interface ChatPanelWithToggleProps {
144
148
  isOpen?: boolean;
145
149
  /** Callback when panel open state changes */
146
150
  onOpenChange?: (isOpen: boolean) => void;
151
+ /** Supabase URL for Realtime escalation support */
152
+ supabaseUrl?: string;
153
+ /** Supabase anon key for Realtime escalation support */
154
+ supabaseAnonKey?: string;
147
155
  }
148
- declare function ChatPanelWithToggle({ onNavigate, onActionComplete, currentPage, agentUrl, startingQuestions, startingQuestionsEndpoint, defaultOpen, isOpen: controlledIsOpen, onOpenChange, }: ChatPanelWithToggleProps): react_jsx_runtime.JSX.Element;
156
+ declare function ChatPanelWithToggle({ onNavigate, onActionComplete, currentPage, agentUrl, startingQuestions, startingQuestionsEndpoint, defaultOpen, isOpen: controlledIsOpen, onOpenChange, supabaseUrl, supabaseAnonKey, }: ChatPanelWithToggleProps): react_jsx_runtime.JSX.Element;
149
157
  /**
150
158
  * @deprecated Use ChatPanelWithToggle instead for the new side panel UX
151
159
  */
@@ -98,8 +98,12 @@ interface ChatPanelProps {
98
98
  startingQuestions?: StartingQuestion[];
99
99
  /** API endpoint to fetch starting questions */
100
100
  startingQuestionsEndpoint?: string;
101
+ /** Supabase URL for Realtime escalation support */
102
+ supabaseUrl?: string;
103
+ /** Supabase anon key for Realtime escalation support */
104
+ supabaseAnonKey?: string;
101
105
  }
102
- declare function ChatPanel({ isOpen, onClose, onOpen, onBack, onNavigate, onActionComplete, currentPage, agentUrl, startingQuestions: startingQuestionsProp, startingQuestionsEndpoint, }?: ChatPanelProps): react_jsx_runtime.JSX.Element;
106
+ declare function ChatPanel({ isOpen, onClose, onOpen, onBack, onNavigate, onActionComplete, currentPage, agentUrl, startingQuestions: startingQuestionsProp, startingQuestionsEndpoint, supabaseUrl, supabaseAnonKey, }?: ChatPanelProps): react_jsx_runtime.JSX.Element;
103
107
  /**
104
108
  * PanelToggle - An arrow button on the right edge that toggles the side panel
105
109
  * Shows left arrow when closed (click to open), right arrow when open (click to close)
@@ -144,8 +148,12 @@ interface ChatPanelWithToggleProps {
144
148
  isOpen?: boolean;
145
149
  /** Callback when panel open state changes */
146
150
  onOpenChange?: (isOpen: boolean) => void;
151
+ /** Supabase URL for Realtime escalation support */
152
+ supabaseUrl?: string;
153
+ /** Supabase anon key for Realtime escalation support */
154
+ supabaseAnonKey?: string;
147
155
  }
148
- declare function ChatPanelWithToggle({ onNavigate, onActionComplete, currentPage, agentUrl, startingQuestions, startingQuestionsEndpoint, defaultOpen, isOpen: controlledIsOpen, onOpenChange, }: ChatPanelWithToggleProps): react_jsx_runtime.JSX.Element;
156
+ declare function ChatPanelWithToggle({ onNavigate, onActionComplete, currentPage, agentUrl, startingQuestions, startingQuestionsEndpoint, defaultOpen, isOpen: controlledIsOpen, onOpenChange, supabaseUrl, supabaseAnonKey, }: ChatPanelWithToggleProps): react_jsx_runtime.JSX.Element;
149
157
  /**
150
158
  * @deprecated Use ChatPanelWithToggle instead for the new side panel UX
151
159
  */