@cmnd-ai/chatbot-react 1.10.0 → 1.14.0

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/Readme.md CHANGED
@@ -117,6 +117,110 @@ const App = () => {
117
117
  };
118
118
  ```
119
119
 
120
+ ## Headless Usage with `useCMNDChat` Hook
121
+
122
+ If you want complete control over your UI while maintaining the powerful chatbot logic, you can use the `useCMNDChat` hook. It handles all state management, real-time streaming, conversation history, and tool orchestration.
123
+
124
+ ```tsx
125
+ import { useCMNDChat, MessageRole } from "@cmnd-ai/chatbot-react";
126
+
127
+ const MyCustomChat = () => {
128
+ const {
129
+ messages,
130
+ input,
131
+ setInput,
132
+ isChatLoading,
133
+ canSendMessage,
134
+ sendMessage,
135
+ submitToolResult,
136
+ conversations,
137
+ handleNewChat,
138
+ handleConversationSelect,
139
+ error,
140
+ } = useCMNDChat({
141
+ chatbotId: 123,
142
+ organizationId: 456,
143
+ baseUrl: "https://api.cmnd.ai",
144
+ apiKey: "your-api-key",
145
+ cleanResponse: true, // Optional: Returns assistant messages as plaintext
146
+ onData: (data) => console.log("Stream update:", data),
147
+ onToolCall: async (tool) => {
148
+ console.log("AI called tool:", tool.name);
149
+
150
+ // For UI tools, you must execute and call submitToolResult
151
+ if (tool.name === "my_custom_tool") {
152
+ const result = await runMyTool(tool.args);
153
+ submitToolResult(JSON.stringify(result));
154
+ }
155
+ },
156
+ });
157
+
158
+ return (
159
+ <div className="custom-chat">
160
+ <div className="message-list">
161
+ {messages.map((m) => (
162
+ <div key={m.id} className={`message ${m.role}`}>
163
+ {m.role === MessageRole.ASSISTANT ? "🤖" : "👤"}: {m.message}
164
+ {/* Handle tool calls */}
165
+ {m.role === MessageRole.FUNCTION && (
166
+ <div className="tool-ui">
167
+ Rendering Tool: {m.tool.name}
168
+ {/* Once done, call submitToolResult("result") */}
169
+ </div>
170
+ )}
171
+ </div>
172
+ ))}
173
+ </div>
174
+
175
+ <div className="controls">
176
+ <input
177
+ value={input}
178
+ onChange={(e) => setInput(e.target.value)}
179
+ placeholder="Type here..."
180
+ />
181
+ <button onClick={() => sendMessage()}>Send</button>
182
+ <button onClick={handleNewChat}>Clear Chat</button>
183
+ </div>
184
+ </div>
185
+ );
186
+ };
187
+ ```
188
+
189
+ ### Hook API Reference
190
+
191
+ #### `UseCMNDChatOptions`
192
+
193
+ | Option | Type | Description |
194
+ | ---------------- | --------------------- | -------------------------------------------------------------------------- |
195
+ | `chatbotId` | `number` | **Required**. Your unique chatbot ID. |
196
+ | `organizationId` | `number` | **Required**. Your unique organization ID. |
197
+ | `baseUrl` | `string` | **Required**. The CMND API base URL. |
198
+ | `apiKey` | `string` | Optional API key for authentication. |
199
+ | `initialMemory` | `object` | Context to send when starting a new conversation. |
200
+ | `UITools` | `CMNDChatbotUITool[]` | Array of custom UI tools. |
201
+ | `onData` | `function` | Triggered for every response chunk or message update. |
202
+ | `onToolCall` | `function` | Triggered when the AI requests a tool execution. |
203
+ | `cleanResponse` | `boolean` | If `true`, assistant messages are returned as plaintext. Default: `false`. |
204
+
205
+ #### `UseCMNDChatResult`
206
+
207
+ | Property | Type | Description |
208
+ | -------------------------- | ----------------------- | --------------------------------------------------------- |
209
+ | `messages` | `Message[]` | Array of all messages in the current conversation thread. |
210
+ | `input` | `string` | The current text in the chat input. |
211
+ | `setInput` | `function` | Update the chat input text. |
212
+ | `isChatLoading` | `boolean` | True if a message is being generated or tool is running. |
213
+ | `canSendMessage` | `boolean` | True if the system is ready to receive the next message. |
214
+ | `sendMessage` | `(text?) => Promise` | Send a message. Uses `input` if `text` is omitted. |
215
+ | `submitToolResult` | `(output) => Promise` | Submit results from a UI tool back to the AI. |
216
+ | `conversations` | `ChatbotConversation[]` | List of historical conversations. |
217
+ | `selectedConversation` | `ChatbotConversation` | The currently active conversation metadata. |
218
+ | `handleNewChat` | `function` | Starts a fresh conversation thread. |
219
+ | `handleConversationSelect` | `function` | Loads a specific conversation from history. |
220
+ | `handleDeleteConversation` | `function` | Deletes a conversation from history. |
221
+ | `tools` | `any[]` | All available tools (API + UI). |
222
+ | `error` | `string` | Contains description of any API or processing errors. |
223
+
120
224
  ## Props
121
225
 
122
226
  ### Required Props
@@ -130,15 +234,15 @@ const App = () => {
130
234
 
131
235
  ### Optional Props
132
236
 
133
- | Prop | Type | Default | Description |
134
- | ----------------------- | --------------------- | ----------- | ----------------------------------------------------- |
135
- | `theme` | `"light" \| "dark"` | `"light"` | Theme for the chatbot |
136
- | `UITools` | `CMNDChatbotUITool[]` | `[]` | Array of UI tools |
137
- | `enabledTools` | `any[]` | `[]` | Array of enabled tools |
138
- | `initialMemory` | `CMNDChatMemory` | `undefined` | Initial conversation memory |
139
- | `customStyles` | `CustomStyles` | `undefined` | Custom CSS styles |
140
- | `Components` | `Components` | `undefined` | Custom component overrides |
141
- | `chatHistoryStorageKey` | `string` | `undefined` | The chat history key defined by the client |
237
+ | Prop | Type | Default | Description |
238
+ | ----------------------- | --------------------- | ----------- | ------------------------------------------ |
239
+ | `theme` | `"light" \| "dark"` | `"light"` | Theme for the chatbot |
240
+ | `UITools` | `CMNDChatbotUITool[]` | `[]` | Array of UI tools |
241
+ | `enabledTools` | `any[]` | `[]` | Array of enabled tools |
242
+ | `initialMemory` | `CMNDChatMemory` | `undefined` | Initial conversation memory |
243
+ | `customStyles` | `CustomStyles` | `undefined` | Custom CSS styles |
244
+ | `Components` | `Components` | `undefined` | Custom component overrides |
245
+ | `chatHistoryStorageKey` | `string` | `undefined` | The chat history key defined by the client |
142
246
 
143
247
  ## Custom Components
144
248
 
@@ -5,7 +5,7 @@ export declare const ChatProviderContext: React.Context<CmndChatContext | undefi
5
5
  export interface ChatProviderProps extends Omit<CmndChatBotProps, "postSessionMessage"> {
6
6
  children?: React.ReactNode | ((props: CmndChatBotProps) => React.ReactNode);
7
7
  }
8
- export declare const setCurrentConversationMemory: (memory: CMNDChatMemory) => Promise<import("axios").AxiosResponse<any, any> | undefined>;
9
- export declare const deleteCurrentConversationMemory: (memoryKeyToDelete: string) => Promise<import("axios").AxiosResponse<any, any> | undefined>;
8
+ export declare const setCurrentConversationMemory: (memory: CMNDChatMemory) => Promise<import("axios").AxiosResponse<any, any, {}> | undefined>;
9
+ export declare const deleteCurrentConversationMemory: (memoryKeyToDelete: string) => Promise<import("axios").AxiosResponse<any, any, {}> | undefined>;
10
10
  declare function ChatProvider(props: ChatProviderProps): JSX.Element | null;
11
11
  export default ChatProvider;
@@ -7,6 +7,8 @@ import deleteChatbotConversationMemory from "../services/deleteChatbotConversati
7
7
  import parseUITools from "../utils/parseUITools.js";
8
8
  import getTools from "../utils/getTools/index.js";
9
9
  import { ConversationsPanel, } from "../components/ConversationsPanel/index.js";
10
+ import socketService from "../services/socketService.js";
11
+ import { SOCKET_EVENTS } from "../constants/socketEvents.js";
10
12
  let globalChatbotConversationRef;
11
13
  let globalChatbotProps;
12
14
  export const ChatProviderContext = React.createContext(undefined);
@@ -64,7 +66,26 @@ function ChatProvider(props) {
64
66
  const conversationsPanelRef = useRef(null);
65
67
  useEffect(() => {
66
68
  globalChatbotConversationRef = chatbotConversationRef;
69
+ if (chatbotConversationRef && socketService.isConnected()) {
70
+ socketService.getSocket()?.emit(SOCKET_EVENTS.JOIN_CHATBOT_CONVERSATION, {
71
+ chatbotConversationRef,
72
+ });
73
+ }
67
74
  }, [chatbotConversationRef]);
75
+ const [isConnected, setIsConnected] = useState(false);
76
+ useEffect(() => {
77
+ const socket = socketService.connect(baseUrl);
78
+ const handleConnect = () => setIsConnected(true);
79
+ const handleDisconnect = () => setIsConnected(false);
80
+ socket.on(SOCKET_EVENTS.CONNECT, handleConnect);
81
+ socket.on(SOCKET_EVENTS.DISCONNECT, handleDisconnect);
82
+ setIsConnected(socket.connected);
83
+ return () => {
84
+ socket.off(SOCKET_EVENTS.CONNECT, handleConnect);
85
+ socket.off(SOCKET_EVENTS.DISCONNECT, handleDisconnect);
86
+ socketService.disconnect();
87
+ };
88
+ }, [baseUrl]);
68
89
  useEffect(() => {
69
90
  setLoading(true);
70
91
  getEmbedChatBotById(baseUrl, organizationId, chatbotId)
@@ -171,6 +192,8 @@ function ChatProvider(props) {
171
192
  closeSidePanel,
172
193
  setMessageText,
173
194
  sendMessage,
195
+ socket: socketService.getSocket(),
196
+ isConnected,
174
197
  }, children: error ? (_jsx("div", { children: "An error occured" })) : (_jsxs(_Fragment, { children: [props.children, _jsx(ConversationsPanel, { ref: conversationsPanelRef, organizationId: organizationId, chatbotId: chatbotId, baseUrl: baseUrl, chatHistoryStorageKey: props.chatHistoryStorageKey, theme: props.theme, enabledTools: getTools({
175
198
  apiTools: enabledTools,
176
199
  uiTools: parseUITools(UITools),
@@ -3,6 +3,7 @@ const processStream = async (reader, onData) => {
3
3
  if (!onData)
4
4
  return;
5
5
  let fullAssistantMessage = "";
6
+ let functionName = "";
6
7
  let buffer = ""; // buffer to store incomplete JSON string fragments
7
8
  try {
8
9
  while (true) {
@@ -44,17 +45,31 @@ const processStream = async (reader, onData) => {
44
45
  });
45
46
  }
46
47
  else if (dataObject.function_call) {
47
- // console.log("no processing necessary");
48
+ const { name } = dataObject.function_call;
49
+ if (name)
50
+ functionName = name;
51
+ onData({
52
+ completionFinished: false,
53
+ finalResponseWithUsageData: false,
54
+ streamingFunctionCall: true,
55
+ functionName,
56
+ });
57
+ }
58
+ else if (dataObject.function_result) {
59
+ onData({
60
+ completionFinished: false,
61
+ finalResponseWithUsageData: false,
62
+ streamingFunctionCall: false,
63
+ functionResult: dataObject.function_result,
64
+ });
48
65
  }
49
66
  else {
50
- //at this point, the dataObject does not have a content propery
51
- //and it is completed
52
- //get the last message from the dataObject to check if it is a function call
53
- const { messages, completionFinished, finalResponseWithUsageData, chatbotConversationRef, totalTokens, totalCost, } = dataObject;
67
+ const { messages, completionFinished, finalResponseWithUsageData, conversationRef, chatbotConversationRef, totalTokens, totalCost, } = dataObject;
54
68
  onData({
55
69
  messages,
56
70
  completionFinished,
57
71
  finalResponseWithUsageData,
72
+ conversationRef,
58
73
  chatbotConversationRef,
59
74
  totalTokens,
60
75
  totalCost,
@@ -68,13 +83,23 @@ const processStream = async (reader, onData) => {
68
83
  continue;
69
84
  }
70
85
  console.error("StreamError caught", error);
71
- onData({
72
- completionFinished: true,
73
- message: error instanceof StreamError
74
- ? error.message
75
- : "Oops! I ran into a problem.",
76
- finalResponseWithUsageData: true,
77
- });
86
+ if (error instanceof StreamError) {
87
+ onData({
88
+ completionFinished: true,
89
+ message: error.message,
90
+ finalResponseWithUsageData: true,
91
+ hasError: true,
92
+ errorPath: error.path,
93
+ });
94
+ }
95
+ else {
96
+ onData({
97
+ completionFinished: true,
98
+ message: "Oops! I ran into a problem.",
99
+ finalResponseWithUsageData: true,
100
+ hasError: true,
101
+ });
102
+ }
78
103
  }
79
104
  }
80
105
  }
@@ -84,11 +109,12 @@ const processStream = async (reader, onData) => {
84
109
  }
85
110
  }
86
111
  catch (error) {
87
- console.error("Error processing stream", error);
112
+ console.error("Fatal error in processStream", error);
88
113
  onData({
89
114
  completionFinished: true,
90
115
  message: "Oops! I ran into a problem.",
91
116
  finalResponseWithUsageData: true,
117
+ hasError: true,
92
118
  });
93
119
  }
94
120
  };
@@ -20,6 +20,7 @@ export interface CmndChatBotProps {
20
20
  LoadingIndicator?: () => JSX.Element;
21
21
  error?: any;
22
22
  };
23
+ cleanResponse?: boolean;
23
24
  }
24
- declare function CmndChatBot({ chatbotId, organizationId, apiKey, baseUrl, theme, UITools, customStyles, chatHistoryStorageKey, enabledTools, Components, initialMemory, }: CmndChatBotProps): JSX.Element;
25
+ declare function CmndChatBot({ chatbotId, organizationId, apiKey, baseUrl, theme, UITools, customStyles, chatHistoryStorageKey, enabledTools, Components, initialMemory, cleanResponse, }: CmndChatBotProps): JSX.Element;
25
26
  export default CmndChatBot;
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import ChatProvider from "../ChatProvider/index.js";
3
- function CmndChatBot({ chatbotId, organizationId, apiKey, baseUrl, theme, UITools, customStyles, chatHistoryStorageKey, enabledTools = [], Components, initialMemory, }) {
4
- return (_jsx(ChatProvider, { chatbotId: chatbotId, organizationId: organizationId, chatHistoryStorageKey: chatHistoryStorageKey, apiKey: apiKey, baseUrl: baseUrl, theme: theme, UITools: UITools, customStyles: customStyles, enabledTools: enabledTools, Components: Components, initialMemory: initialMemory }));
3
+ function CmndChatBot({ chatbotId, organizationId, apiKey, baseUrl, theme, UITools, customStyles, chatHistoryStorageKey, enabledTools = [], Components, initialMemory, cleanResponse, }) {
4
+ return (_jsx(ChatProvider, { chatbotId: chatbotId, organizationId: organizationId, chatHistoryStorageKey: chatHistoryStorageKey, apiKey: apiKey, baseUrl: baseUrl, theme: theme, UITools: UITools, customStyles: customStyles, enabledTools: enabledTools, Components: Components, initialMemory: initialMemory, cleanResponse: cleanResponse }));
5
5
  }
6
6
  export default CmndChatBot;
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import React, { useState, useEffect, forwardRef, useImperativeHandle, } from "react";
2
+ import React, { useState, useEffect, forwardRef, useImperativeHandle, useCallback, } from "react";
3
3
  import useFetchData from "../../hooks/use-fetch-data.js";
4
4
  import getChatBotConversationsList from "../../services/getChatBotConversationsList/index.js";
5
5
  import Conversation from "../Conversation.js";
@@ -11,6 +11,8 @@ import saveConversationIdToLocalStorage from "../../utils/saveConversationIdToLo
11
11
  import getUTCDateTime from "../../utils/getUTCDateTime/index.js";
12
12
  import useMessagesScroll from "../../hooks/use-messages-scroll.js";
13
13
  import { v4 as uuidv4 } from "uuid";
14
+ import { useSocket } from "../../hooks/use-socket.js";
15
+ import { SOCKET_MESSAGE_TYPES } from "../../constants/socketEvents.js";
14
16
  export const ConversationsPanel = forwardRef(({ organizationId, chatbotId, baseUrl, chatHistoryStorageKey, theme = "light", enabledTools = [], setChatbotConversationRef, chatbotConversationRef, postSessionMessage, Components, UITools, customStyles, isSidebarCollapsed, setIsSidebarCollapsed, selectedConversation, setSelectedConversation, messages, setMessages, input, setInput, inputRef, }, ref) => {
15
17
  const [isChatLoading, setIsChatLoading] = useState(false);
16
18
  const [canSendMessage, setCanSendMessage] = useState(true);
@@ -98,6 +100,41 @@ export const ConversationsPanel = forwardRef(({ organizationId, chatbotId, baseU
98
100
  return { chatbotConversations: [] };
99
101
  }
100
102
  }, [organizationId, chatbotId, conversationIds, baseUrl]);
103
+ // Socket message handler
104
+ const handleSocketMessage = useCallback((notification) => {
105
+ console.log("chatbot notification", notification);
106
+ if (notification.type === SOCKET_MESSAGE_TYPES.NEW_HUMAN_INBOX_MESSAGE &&
107
+ notification.chatbotConversationRef === chatbotConversationRef) {
108
+ setMessages((prev) => {
109
+ if (prev.some((m) => m.id === notification.message.id))
110
+ return prev;
111
+ return [...prev, notification.message];
112
+ });
113
+ resetMessagesScroll();
114
+ }
115
+ else if (notification.type === SOCKET_MESSAGE_TYPES.HUMAN_AGENT_JOINED &&
116
+ notification.chatbotConversationRef === chatbotConversationRef) {
117
+ // Add a system message to indicate human agent joined
118
+ const agentName = notification.agentName || "A human agent";
119
+ const systemMessage = {
120
+ id: `system-${notification.timestamp}`,
121
+ role: "assistant",
122
+ message: `${agentName} has joined the conversation`,
123
+ unuseful: false,
124
+ hiddenFromUser: false,
125
+ };
126
+ setMessages((prev) => [...prev, systemMessage]);
127
+ resetMessagesScroll();
128
+ }
129
+ }, [chatbotConversationRef, resetMessagesScroll]);
130
+ // Socket connection
131
+ useSocket({
132
+ baseUrl,
133
+ accessToken: null,
134
+ chatbotConversationRef,
135
+ onMessage: handleSocketMessage,
136
+ enabled: Boolean(chatbotConversationRef),
137
+ });
101
138
  const handleSendClick = () => {
102
139
  if (!input.trim() || !canSendMessage)
103
140
  return;
@@ -0,0 +1,14 @@
1
+ export declare const SOCKET_EVENTS: {
2
+ readonly MESSAGE: "message";
3
+ readonly CONNECT: "connect";
4
+ readonly DISCONNECT: "disconnect";
5
+ readonly ERROR: "error";
6
+ readonly JOIN_CHATBOT_CONVERSATION: "join_chatbot_conversation";
7
+ };
8
+ export declare const SOCKET_MESSAGE_TYPES: {
9
+ readonly NEW_HUMAN_INBOX_MESSAGE: "NEW_HUMAN_INBOX_MESSAGE";
10
+ readonly HUMAN_AGENT_JOINED: "HUMAN_AGENT_JOINED";
11
+ readonly HANDOVER_REQUEST: "HANDOVER_REQUEST";
12
+ };
13
+ export type SocketEvent = (typeof SOCKET_EVENTS)[keyof typeof SOCKET_EVENTS];
14
+ export type SocketMessageType = (typeof SOCKET_MESSAGE_TYPES)[keyof typeof SOCKET_MESSAGE_TYPES];
@@ -0,0 +1,12 @@
1
+ export const SOCKET_EVENTS = {
2
+ MESSAGE: "message",
3
+ CONNECT: "connect",
4
+ DISCONNECT: "disconnect",
5
+ ERROR: "error",
6
+ JOIN_CHATBOT_CONVERSATION: "join_chatbot_conversation",
7
+ };
8
+ export const SOCKET_MESSAGE_TYPES = {
9
+ NEW_HUMAN_INBOX_MESSAGE: "NEW_HUMAN_INBOX_MESSAGE",
10
+ HUMAN_AGENT_JOINED: "HUMAN_AGENT_JOINED",
11
+ HANDOVER_REQUEST: "HANDOVER_REQUEST",
12
+ };
@@ -0,0 +1,130 @@
1
+ /// <reference types="react" />
2
+ import { ChatbotConversation, Message, CMNDChatMemory, CMNDChatbotUITool, ConversationDataObject, ToolDetails } from "../type.js";
3
+ /**
4
+ * Options for configuring the useCMNDChat hook.
5
+ */
6
+ export interface UseCMNDChatOptions {
7
+ /** The unique identifier for the chatbot. */
8
+ chatbotId: number;
9
+ /** The unique identifier for the organization. */
10
+ organizationId: number;
11
+ /** The base URL for the CMND API. */
12
+ baseUrl: string;
13
+ /** Optional API key for authentication. If provided, it will be sent in the 'x-api-key' header. */
14
+ apiKey?: string;
15
+ /** Optional key used for local message persistence. Defaults to a combined string of orgId and chatbotId. */
16
+ chatHistoryStorageKey?: string;
17
+ /** Initial memory/context to send when starting a new conversation. */
18
+ initialMemory?: CMNDChatMemory;
19
+ /** Array of custom UI tools that the AI can call. */
20
+ UITools?: CMNDChatbotUITool[];
21
+ /** Callback triggered whenever new data (chunks or finalized messages) is received from the stream. */
22
+ onData?: (data: ConversationDataObject) => void;
23
+ /**
24
+ * Callback triggered whenever the AI initiates a tool call.
25
+ *
26
+ * For **backend tools**: The hook automatically confirms them, which triggers your backend server
27
+ * to execute the tool and return the output. Use this callback for logging or UI updates.
28
+ *
29
+ * For **UI tools**: You must execute the tool in your frontend, then call submitToolResult with the output.
30
+ *
31
+ * @example
32
+ * ```tsx
33
+ * onToolCall: async (toolDetails) => {
34
+ * if (toolDetails.name === 'show_ui_component') {
35
+ * // UI tool - execute in frontend
36
+ * displayComponent(toolDetails.args);
37
+ * submitToolResult('Component displayed');
38
+ * }
39
+ * // Backend tools are handled automatically by the server
40
+ * }
41
+ * ```
42
+ */
43
+ onToolCall?: (toolCall: ToolDetails) => void;
44
+ /**
45
+ * Whether to clean the AI response by removing markdown characters.
46
+ * If true, assistant messages will be returned as plaintext.
47
+ * @default false
48
+ */
49
+ cleanResponse?: boolean;
50
+ }
51
+ /**
52
+ * The object returned by the useCMNDChat hook.
53
+ */
54
+ export interface UseCMNDChatResult {
55
+ /** The list of messages in the current active conversation thread. */
56
+ messages: Message[];
57
+ /** A setter function for the messages list. */
58
+ setMessages: React.Dispatch<React.SetStateAction<Message[]>>;
59
+ /** The current text value of the chat input field. */
60
+ input: string;
61
+ /** A setter function for the chat input field. */
62
+ setInput: React.Dispatch<React.SetStateAction<string>>;
63
+ /** Indicates if a message is currently being processed or streamed. */
64
+ isChatLoading: boolean;
65
+ /** Indicates if the user is allowed to send a message (e.g., not loading, not empty). */
66
+ canSendMessage: boolean;
67
+ /**
68
+ * Sends a message to the chatbot.
69
+ * @param text Optional text to send. If not provided, it uses the current 'input' state.
70
+ * @param onData Optional callback for this specific message stream.
71
+ */
72
+ sendMessage: (text?: string, onData?: (data: ConversationDataObject) => void) => Promise<void>;
73
+ /**
74
+ * Submits the result of a tool call back to the AI.
75
+ * @param toolOutput The string result of the tool execution.
76
+ * @param onData Optional callback for the resulting message stream.
77
+ */
78
+ submitToolResult: (toolOutput: string, onData?: (data: ConversationDataObject) => void) => Promise<void>;
79
+ /** The reference ID for the current active conversation. */
80
+ chatbotConversationRef: string | undefined;
81
+ /** A list of all historical conversations for the current chatbot/org. */
82
+ conversations: ChatbotConversation[];
83
+ /** The currently selected conversation object from history. */
84
+ selectedConversation: ChatbotConversation | null;
85
+ /** Resets the chat state and prepares for a new conversation thread. */
86
+ handleNewChat: () => void;
87
+ /**
88
+ * Switches to an existing conversation from history.
89
+ * @param conversation The conversation object to load.
90
+ */
91
+ handleConversationSelect: (conversation: ChatbotConversation) => void;
92
+ /**
93
+ * Deletes a conversation from history and local storage.
94
+ * @param conversationId The ID of the conversation to delete.
95
+ */
96
+ handleDeleteConversation: (conversationId: string) => Promise<void>;
97
+ /** Re-fetches the list of historical conversations. */
98
+ refreshConversations: () => Promise<void>;
99
+ /** Combined list of backend tools (from API) and UI tools (provided in options). */
100
+ tools: any[];
101
+ /** Holds any error message encountered during API calls. */
102
+ error: string | null;
103
+ }
104
+ /**
105
+ * A comprehensive hook to manage CMND.AI chatbot logic without being forced to use the default UI.
106
+ * This hook handles conversation state, message sending (including streaming), history management, and tool call orchestration.
107
+ *
108
+ * @example
109
+ * ```tsx
110
+ * const { messages, sendMessage, input, setInput, submitToolResult } = useCMNDChat({
111
+ * chatbotId: 1,
112
+ * organizationId: 1,
113
+ * baseUrl: 'https://api.cmnd.ai',
114
+ * cleanResponse: true, // Optional: Returns assistant messages as plaintext
115
+ * onToolCall: async (toolDetails) => {
116
+ * // Backend tools are auto-confirmed by the hook
117
+ * if (toolDetails.name === 'get_playlists') {
118
+ * console.log('Fetching playlists from backend...');
119
+ * }
120
+ *
121
+ * // UI tools need manual execution and confirmation
122
+ * if (toolDetails.name === 'show_notification') {
123
+ * showNotification(toolDetails.args.message);
124
+ * submitToolResult('Notification displayed');
125
+ * }
126
+ * }
127
+ * });
128
+ * ```
129
+ */
130
+ export declare const useCMNDChat: (options: UseCMNDChatOptions) => UseCMNDChatResult;