@kite-copilot/chat-panel 0.2.24 → 0.2.26

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,68 @@ 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
+ React4.useEffect(() => {
1595
+ if (isEscalated && supabaseClient && sessionId) {
1596
+ subscribeToAgentMessages(sessionId);
1597
+ }
1598
+ }, [isEscalated, supabaseClient, sessionId, subscribeToAgentMessages]);
1599
+ const sendEscalatedMessage = React4.useCallback(async (content) => {
1600
+ if (!supabaseClient || !isEscalated) return false;
1601
+ try {
1602
+ await supabaseClient.from("chat_history").insert({
1603
+ session_id: sessionId,
1604
+ role: "user",
1605
+ content
1606
+ });
1607
+ return true;
1608
+ } catch (err) {
1609
+ console.error("[KiteChat] Failed to send escalated message:", err);
1610
+ return false;
1611
+ }
1612
+ }, [supabaseClient, isEscalated, sessionId]);
1545
1613
  function streamAssistantMessage(messageId, fullText, followups) {
1546
1614
  let textToStream = fullText;
1547
1615
  let extractedFollowups = followups;
@@ -1652,6 +1720,17 @@ function ChatPanel({
1652
1720
  return;
1653
1721
  }
1654
1722
  if (!trimmed) return;
1723
+ if (isEscalated && supabaseClient) {
1724
+ const userMessage = {
1725
+ id: Date.now(),
1726
+ role: "user",
1727
+ content: trimmed
1728
+ };
1729
+ setMessages((prev) => [...prev, userMessage]);
1730
+ sendEscalatedMessage(trimmed);
1731
+ setInput("");
1732
+ return;
1733
+ }
1655
1734
  startChatFlow(trimmed);
1656
1735
  setInput("");
1657
1736
  }
@@ -1980,6 +2059,18 @@ function ChatPanel({
1980
2059
  setProgressSteps([]);
1981
2060
  setPhase("idle");
1982
2061
  streamCompleted = true;
2062
+ } else if (eventType === "escalation") {
2063
+ setIsEscalated(true);
2064
+ setPhase("idle");
2065
+ const escalationMessageId = Date.now() + 2;
2066
+ const escalationMessage = {
2067
+ id: escalationMessageId,
2068
+ role: "assistant",
2069
+ kind: "text",
2070
+ content: data.message || "You've been connected to our support queue. An agent will be with you shortly."
2071
+ };
2072
+ setMessages((prev) => [...prev, escalationMessage]);
2073
+ subscribeToAgentMessages(sessionId);
1983
2074
  }
1984
2075
  } catch (parseError) {
1985
2076
  console.error("Failed to parse SSE event:", parseError);
@@ -2847,6 +2938,12 @@ ${userText}`
2847
2938
  if (isUser) {
2848
2939
  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
2940
  }
2941
+ if (message.role === "agent") {
2942
+ 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: [
2943
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "text-xs text-blue-600 font-medium mb-1", children: "Support Agent" }),
2944
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "whitespace-pre-wrap leading-relaxed", children: renderMarkdown(message.content || "") })
2945
+ ] }) }, message.id);
2946
+ }
2850
2947
  if (message.kind === "searchSummary") {
2851
2948
  return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
2852
2949
  "div",
@@ -4038,7 +4135,9 @@ function ChatPanelWithToggle({
4038
4135
  startingQuestionsEndpoint,
4039
4136
  defaultOpen = false,
4040
4137
  isOpen: controlledIsOpen,
4041
- onOpenChange
4138
+ onOpenChange,
4139
+ supabaseUrl,
4140
+ supabaseAnonKey
4042
4141
  }) {
4043
4142
  const [internalIsOpen, setInternalIsOpen] = React4.useState(defaultOpen);
4044
4143
  const isOpen = controlledIsOpen !== void 0 ? controlledIsOpen : internalIsOpen;
@@ -4069,7 +4168,9 @@ function ChatPanelWithToggle({
4069
4168
  currentPage,
4070
4169
  agentUrl,
4071
4170
  startingQuestions,
4072
- startingQuestionsEndpoint
4171
+ startingQuestionsEndpoint,
4172
+ supabaseUrl,
4173
+ supabaseAnonKey
4073
4174
  }
4074
4175
  );
4075
4176
  }
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-KPTM44LS.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,68 @@ 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
+ React4.useEffect(() => {
1594
+ if (isEscalated && supabaseClient && sessionId) {
1595
+ subscribeToAgentMessages(sessionId);
1596
+ }
1597
+ }, [isEscalated, supabaseClient, sessionId, subscribeToAgentMessages]);
1598
+ const sendEscalatedMessage = React4.useCallback(async (content) => {
1599
+ if (!supabaseClient || !isEscalated) return false;
1600
+ try {
1601
+ await supabaseClient.from("chat_history").insert({
1602
+ session_id: sessionId,
1603
+ role: "user",
1604
+ content
1605
+ });
1606
+ return true;
1607
+ } catch (err) {
1608
+ console.error("[KiteChat] Failed to send escalated message:", err);
1609
+ return false;
1610
+ }
1611
+ }, [supabaseClient, isEscalated, sessionId]);
1544
1612
  function streamAssistantMessage(messageId, fullText, followups) {
1545
1613
  let textToStream = fullText;
1546
1614
  let extractedFollowups = followups;
@@ -1651,6 +1719,17 @@ function ChatPanel({
1651
1719
  return;
1652
1720
  }
1653
1721
  if (!trimmed) return;
1722
+ if (isEscalated && supabaseClient) {
1723
+ const userMessage = {
1724
+ id: Date.now(),
1725
+ role: "user",
1726
+ content: trimmed
1727
+ };
1728
+ setMessages((prev) => [...prev, userMessage]);
1729
+ sendEscalatedMessage(trimmed);
1730
+ setInput("");
1731
+ return;
1732
+ }
1654
1733
  startChatFlow(trimmed);
1655
1734
  setInput("");
1656
1735
  }
@@ -1979,6 +2058,18 @@ function ChatPanel({
1979
2058
  setProgressSteps([]);
1980
2059
  setPhase("idle");
1981
2060
  streamCompleted = true;
2061
+ } else if (eventType === "escalation") {
2062
+ setIsEscalated(true);
2063
+ setPhase("idle");
2064
+ const escalationMessageId = Date.now() + 2;
2065
+ const escalationMessage = {
2066
+ id: escalationMessageId,
2067
+ role: "assistant",
2068
+ kind: "text",
2069
+ content: data.message || "You've been connected to our support queue. An agent will be with you shortly."
2070
+ };
2071
+ setMessages((prev) => [...prev, escalationMessage]);
2072
+ subscribeToAgentMessages(sessionId);
1982
2073
  }
1983
2074
  } catch (parseError) {
1984
2075
  console.error("Failed to parse SSE event:", parseError);
@@ -2846,6 +2937,12 @@ ${userText}`
2846
2937
  if (isUser) {
2847
2938
  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
2939
  }
2940
+ if (message.role === "agent") {
2941
+ 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: [
2942
+ /* @__PURE__ */ jsx9("div", { className: "text-xs text-blue-600 font-medium mb-1", children: "Support Agent" }),
2943
+ /* @__PURE__ */ jsx9("div", { className: "whitespace-pre-wrap leading-relaxed", children: renderMarkdown(message.content || "") })
2944
+ ] }) }, message.id);
2945
+ }
2849
2946
  if (message.kind === "searchSummary") {
2850
2947
  return /* @__PURE__ */ jsx9(
2851
2948
  "div",
@@ -4057,7 +4154,9 @@ function ChatPanelWithToggle({
4057
4154
  startingQuestionsEndpoint,
4058
4155
  defaultOpen = false,
4059
4156
  isOpen: controlledIsOpen,
4060
- onOpenChange
4157
+ onOpenChange,
4158
+ supabaseUrl,
4159
+ supabaseAnonKey
4061
4160
  }) {
4062
4161
  const [internalIsOpen, setInternalIsOpen] = React4.useState(defaultOpen);
4063
4162
  const isOpen = controlledIsOpen !== void 0 ? controlledIsOpen : internalIsOpen;
@@ -4088,7 +4187,9 @@ function ChatPanelWithToggle({
4088
4187
  currentPage,
4089
4188
  agentUrl,
4090
4189
  startingQuestions,
4091
- startingQuestionsEndpoint
4190
+ startingQuestionsEndpoint,
4191
+ supabaseUrl,
4192
+ supabaseAnonKey
4092
4193
  }
4093
4194
  );
4094
4195
  }
@@ -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
  */