@kite-copilot/chat-panel 0.2.47 → 0.2.49

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/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 import_react = __toESM(require("react"), 1);
69
+ var import_react2 = __toESM(require("react"), 1);
70
70
  var import_client = require("react-dom/client");
71
71
 
72
72
  // src/ChatPanel.tsx
@@ -478,6 +478,78 @@ 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, tool_name, arguments: args, endpoint, method, path_params } = toolRequest;
503
+ console.log("[FrontendToolExecutor] Executing tool:", tool_name, "with args:", args);
504
+ try {
505
+ let url = endpoint;
506
+ for (const param of path_params) {
507
+ if (args[param]) {
508
+ url = url.replace(`{${param}}`, encodeURIComponent(args[param]));
509
+ }
510
+ }
511
+ const queryParams = new URLSearchParams();
512
+ for (const [key, value] of Object.entries(args)) {
513
+ if (!path_params.includes(key) && value !== void 0 && value !== null) {
514
+ queryParams.append(key, String(value));
515
+ }
516
+ }
517
+ const queryString = queryParams.toString();
518
+ const fullUrl = `${productBackendUrl}${url}${queryString ? "?" + queryString : ""}`;
519
+ console.log("[FrontendToolExecutor] Fetching:", fullUrl);
520
+ const response = await fetch(fullUrl, {
521
+ method,
522
+ credentials: "include",
523
+ headers: {
524
+ "Accept": "application/json",
525
+ "Content-Type": "application/json"
526
+ }
527
+ });
528
+ let result;
529
+ if (response.ok) {
530
+ result = await response.json();
531
+ console.log("[FrontendToolExecutor] Tool result:", result);
532
+ } else {
533
+ const errorText = await response.text();
534
+ throw new Error(`HTTP ${response.status}: ${errorText}`);
535
+ }
536
+ await sendToolResult({
537
+ session_id: sessionId,
538
+ call_id,
539
+ result
540
+ });
541
+ } catch (error) {
542
+ console.error("[FrontendToolExecutor] Tool execution failed:", error);
543
+ await sendToolResult({
544
+ session_id: sessionId,
545
+ call_id,
546
+ error: error instanceof Error ? error.message : "Unknown error"
547
+ });
548
+ }
549
+ }, [productBackendUrl, sessionId, sendToolResult]);
550
+ return { executeToolRequest };
551
+ }
552
+
481
553
  // src/components/ui/card.tsx
482
554
  var import_jsx_runtime7 = require("react/jsx-runtime");
483
555
  function Card({ className, ...props }) {
@@ -1078,7 +1150,7 @@ function TypingIndicator({ className = "" }) {
1078
1150
 
1079
1151
  // src/ChatPanel.tsx
1080
1152
  var import_jsx_runtime10 = require("react/jsx-runtime");
1081
- var CHAT_PANEL_VERSION = true ? "0.2.47" : "dev";
1153
+ var CHAT_PANEL_VERSION = true ? "0.2.49" : "dev";
1082
1154
  var DEFAULT_AGENT_URL = "http://localhost:5002";
1083
1155
  var PANEL_WIDTH = 400;
1084
1156
  var PANEL_HEIGHT = 600;
@@ -1561,6 +1633,7 @@ function ChatPanel({
1561
1633
  }
1562
1634
  }, [corner, onCornerChange, dragControls]);
1563
1635
  const [sessionId, setSessionId] = React6.useState(() => crypto.randomUUID());
1636
+ const [sessionUser, setSessionUser] = React6.useState(null);
1564
1637
  const orgConfigState = useOrgConfig({ agentUrl, orgId: orgId || "" });
1565
1638
  const effectiveProductBackendUrl = orgConfigState.config?.productBackendUrl || productBackendUrl;
1566
1639
  const { authState, retry: retryAuth } = useUserAuth({
@@ -1569,6 +1642,11 @@ function ChatPanel({
1569
1642
  enabled: !!effectiveProductBackendUrl && orgConfigState.status === "success"
1570
1643
  // Only enable after config is fetched
1571
1644
  });
1645
+ const { executeToolRequest } = useFrontendToolExecutor({
1646
+ productBackendUrl: effectiveProductBackendUrl || "",
1647
+ agentUrl,
1648
+ sessionId
1649
+ });
1572
1650
  React6.useEffect(() => {
1573
1651
  if (!effectiveProductBackendUrl || orgConfigState.status !== "success") {
1574
1652
  return;
@@ -1601,6 +1679,9 @@ function ChatPanel({
1601
1679
  testProductBackendEndpoint();
1602
1680
  }, [effectiveProductBackendUrl, orgConfigState.status]);
1603
1681
  const effectiveUser = React6.useMemo(() => {
1682
+ if (sessionUser) {
1683
+ return sessionUser;
1684
+ }
1604
1685
  if (authState.status === "authenticated") {
1605
1686
  return {
1606
1687
  userId: authState.user.id,
@@ -1617,7 +1698,23 @@ function ChatPanel({
1617
1698
  userRole: void 0,
1618
1699
  isInternal: false
1619
1700
  };
1620
- }, [authState, userId, userName, userEmail]);
1701
+ }, [sessionUser, authState, userId, userName, userEmail]);
1702
+ React6.useEffect(() => {
1703
+ if (authState.status === "authenticated" && sessionUser === null) {
1704
+ setSessionUser({
1705
+ userId: authState.user.id,
1706
+ userName: authState.user.name,
1707
+ userEmail: authState.user.email,
1708
+ userRole: authState.user.role,
1709
+ isInternal: authState.user.isInternal
1710
+ });
1711
+ console.log("[ChatPanel] Session user captured:", authState.user.id);
1712
+ }
1713
+ }, [authState, sessionUser]);
1714
+ const isWaitingForAuth = React6.useMemo(() => {
1715
+ if (!effectiveProductBackendUrl) return false;
1716
+ return authState.status === "loading" || authState.status === "idle";
1717
+ }, [effectiveProductBackendUrl, authState.status]);
1621
1718
  const [isEscalated, setIsEscalated] = React6.useState(false);
1622
1719
  const escalationWsRef = React6.useRef(null);
1623
1720
  const [agentIsTyping, setAgentIsTyping] = React6.useState(false);
@@ -1645,6 +1742,7 @@ function ChatPanel({
1645
1742
  } else {
1646
1743
  console.log("[KiteChat] Skipping disconnect update - conditions not met");
1647
1744
  }
1745
+ setSessionUser(null);
1648
1746
  setSessionId(crypto.randomUUID());
1649
1747
  setIsEscalated(false);
1650
1748
  if (escalationWsRef.current) {
@@ -2563,6 +2661,12 @@ function ChatPanel({
2563
2661
  content: data.message || "You've been connected to our support queue. An agent will be with you shortly."
2564
2662
  };
2565
2663
  setMessages((prev) => [...prev, escalationMessage]);
2664
+ } else if (eventType === "tool_request") {
2665
+ const toolRequest = data;
2666
+ console.log("[KiteChat] Received tool_request:", toolRequest);
2667
+ executeToolRequest(toolRequest).catch((err) => {
2668
+ console.error("[KiteChat] Tool execution failed:", err);
2669
+ });
2566
2670
  } else if (eventType === "token") {
2567
2671
  }
2568
2672
  } catch (parseError) {
@@ -4714,7 +4818,7 @@ ${userText}`
4714
4818
  {
4715
4819
  type: "submit",
4716
4820
  size: "icon",
4717
- disabled: !input.trim() && !pendingFile,
4821
+ disabled: !input.trim() && !pendingFile || isWaitingForAuth,
4718
4822
  className: "h-6 w-6 rounded-full bg-gray-900 hover:bg-gray-800 disabled:bg-gray-300",
4719
4823
  children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_lucide_react4.ArrowUp, { className: "h-2.5 w-2.5" })
4720
4824
  }
@@ -4827,14 +4931,14 @@ function KiteChatWrapper({
4827
4931
  onConfigUpdate,
4828
4932
  onStateUpdate
4829
4933
  }) {
4830
- const [config, setConfig] = import_react.default.useState(initialConfig);
4831
- const [currentPage, setCurrentPage] = import_react.default.useState(initialConfig.currentPage || "dashboard");
4832
- const [isOpen, setIsOpen] = import_react.default.useState(false);
4833
- const isOpenRef = import_react.default.useRef(false);
4834
- import_react.default.useEffect(() => {
4934
+ const [config, setConfig] = import_react2.default.useState(initialConfig);
4935
+ const [currentPage, setCurrentPage] = import_react2.default.useState(initialConfig.currentPage || "dashboard");
4936
+ const [isOpen, setIsOpen] = import_react2.default.useState(false);
4937
+ const isOpenRef = import_react2.default.useRef(false);
4938
+ import_react2.default.useEffect(() => {
4835
4939
  isOpenRef.current = isOpen;
4836
4940
  }, [isOpen]);
4837
- import_react.default.useEffect(() => {
4941
+ import_react2.default.useEffect(() => {
4838
4942
  onConfigUpdate((newConfig) => {
4839
4943
  if (newConfig.currentPage !== void 0) {
4840
4944
  setCurrentPage(newConfig.currentPage);
@@ -4846,7 +4950,7 @@ function KiteChatWrapper({
4846
4950
  getIsOpen: () => isOpenRef.current
4847
4951
  });
4848
4952
  }, [onConfigUpdate, onStateUpdate]);
4849
- import_react.default.useEffect(() => {
4953
+ import_react2.default.useEffect(() => {
4850
4954
  const container = document.getElementById("kite-chat-root");
4851
4955
  if (!container) return;
4852
4956
  if (config.theme === "dark") {
package/dist/index.js CHANGED
@@ -31,7 +31,7 @@ import {
31
31
  cn,
32
32
  createKiteChat,
33
33
  useGuideCursor
34
- } from "./chunk-XMIO4GMW.js";
34
+ } from "./chunk-YZXB3LLU.js";
35
35
  export {
36
36
  ApiKeyList,
37
37
  AssistantActivity,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kite-copilot/chat-panel",
3
- "version": "0.2.47",
3
+ "version": "0.2.49",
4
4
  "description": "AI-powered chat panel SDK with programmatic lifecycle control",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",