@cmnd-ai/chatbot-react 1.1.2 → 1.2.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.
@@ -1,9 +1,9 @@
1
1
  import React from "react";
2
- import { CmndChatBotProps } from "../CmndChatBot";
3
- import { CmndChatContext } from "../type";
2
+ import { CmndChatBotProps } from "../CmndChatBot/index.js";
3
+ import { CmndChatContext } from "../type.js";
4
4
  export declare const ChatProviderContext: React.Context<CmndChatContext | undefined>;
5
- export interface ChatProviderProps extends Omit<CmndChatBotProps, "components"> {
6
- children: React.ReactNode | ((props: Omit<CmndChatBotProps, "components">) => React.ReactNode);
5
+ export interface ChatProviderProps extends CmndChatBotProps {
6
+ children: React.ReactNode | ((props: CmndChatBotProps) => React.ReactNode);
7
7
  }
8
- declare function ChatProvider(props: ChatProviderProps): import("react/jsx-runtime").JSX.Element;
8
+ declare function ChatProvider(props: ChatProviderProps): JSX.Element | null;
9
9
  export default ChatProvider;
@@ -1,121 +1,119 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || function (mod) {
19
- if (mod && mod.__esModule) return mod;
20
- var result = {};
21
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
- __setModuleDefault(result, mod);
23
- return result;
24
- };
25
- Object.defineProperty(exports, "__esModule", { value: true });
26
- exports.ChatProviderContext = void 0;
27
- const jsx_runtime_1 = require("react/jsx-runtime");
28
- const react_1 = __importStar(require("react"));
29
- const constants_1 = require("../constants");
30
- exports.ChatProviderContext = react_1.default.createContext(undefined);
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import React, { useEffect, useRef, useState } from "react";
3
+ import { MessageRole, } from "../type.js";
4
+ import postUserConversation from "../services/postUserConversation.js";
5
+ import Conversation from "../components/Conversation.js";
6
+ import getChatBotById from "../services/getchatBotById.js";
7
+ export const ChatProviderContext = React.createContext(undefined);
31
8
  function ChatProvider(props) {
32
- const { chatbotId, organizationId } = props;
33
- const [chats, setchats] = (0, react_1.useState)({
34
- data: undefined,
35
- error: null,
36
- isLoading: false,
37
- });
38
- const [message, setmessage] = (0, react_1.useState)({
39
- error: null,
40
- isSending: false,
41
- textValue: "",
42
- });
43
- const sendMessage = async () => {
44
- const temp = { ...message };
9
+ const { chatbotId, organizationId, baseUrl, Components, UITools } = props;
10
+ const [loading, setLoading] = useState(true);
11
+ const [messages, setMessages] = useState([]);
12
+ const [error, setError] = useState(null);
13
+ const [input, setInput] = useState("");
14
+ const [canContinue] = useState(false);
15
+ const [isChatLoading, setIsChatLoading] = useState(false);
16
+ const [canSendMessage, setCanSendMessage] = useState(true);
17
+ const messagesRef = useRef(null);
18
+ const [chatbotConversationId, setChatbotConversationId] = useState(undefined);
19
+ const [enabledTools, setEnabledTools] = useState([]);
20
+ useEffect(() => {
21
+ setLoading(true);
22
+ getChatBotById(baseUrl, organizationId, chatbotId)
23
+ .then((response) => {
24
+ const { chatbot } = response.data;
25
+ setEnabledTools(chatbot.enabledTools);
26
+ })
27
+ .catch(() => {
28
+ setError("Error fetching chatbot data");
29
+ })
30
+ .finally(() => {
31
+ setLoading(false);
32
+ });
33
+ }, [organizationId, chatbotId]);
34
+ useEffect(() => {
35
+ scrollToBottom();
36
+ }, [messages, canSendMessage]);
37
+ const scrollToBottom = () => {
38
+ if (messagesRef.current) {
39
+ messagesRef.current.scrollTop = messagesRef.current.scrollHeight;
40
+ }
41
+ };
42
+ const postSessionMessage = async (newMessages, onData) => {
43
+ if (!organizationId || !chatbotId)
44
+ return;
45
+ return postUserConversation({
46
+ orgId: organizationId,
47
+ payload: newMessages,
48
+ apikey: props.apiKey,
49
+ chatbotId,
50
+ baseUrl,
51
+ onData,
52
+ });
53
+ };
54
+ const handleSendClick = async () => {
55
+ if (input.trim() === "" || !canSendMessage)
56
+ return;
57
+ const newUserMessage = {
58
+ unuseful: false,
59
+ hiddenFromUser: false,
60
+ role: "user",
61
+ message: canContinue ? "continue" : input,
62
+ };
63
+ const newMessages = [...messages, newUserMessage];
64
+ setMessages(newMessages);
65
+ setInput("");
66
+ setIsChatLoading(true);
45
67
  try {
46
- temp.error = null;
47
- const requestBody = {
48
- messages: [
49
- {
50
- hiddenFromUser: false,
51
- message: message.textValue,
52
- role: "user",
68
+ const onData = (data) => {
69
+ if (data.finalResponseWithUsageData) {
70
+ setIsChatLoading(false);
71
+ setCanSendMessage(true);
72
+ const { chatbotConversationId, messages } = data;
73
+ if (chatbotConversationId) {
74
+ setChatbotConversationId(chatbotConversationId);
75
+ }
76
+ messages && setMessages(messages);
77
+ }
78
+ if (data.message) {
79
+ setIsChatLoading(false);
80
+ const newAssistantMessage = {
53
81
  unuseful: false,
54
- },
55
- ],
82
+ hiddenFromUser: false,
83
+ role: MessageRole.ASSISTANT,
84
+ message: data.message,
85
+ };
86
+ setMessages([...newMessages, newAssistantMessage]);
87
+ scrollToBottom();
88
+ }
56
89
  };
57
- const results = await postUserConversation({
58
- orgId: organizationId,
59
- payload: requestBody,
60
- apikey: props.apiKey,
61
- chatbotId,
62
- });
63
- if (!results.ok) {
64
- throw new Error(`Failed to post conversation: ${results.statusText}`);
65
- }
66
- temp.textValue = "";
67
- const data = await results.json();
68
- setchats((prev) => ({
69
- ...prev,
70
- data: {
71
- ...prev.data,
72
- messages: [...(prev.data?.messages || [])].concat(...data.messages),
73
- },
74
- }));
90
+ setCanSendMessage(false);
91
+ await postSessionMessage(newMessages, onData);
75
92
  }
76
93
  catch (error) {
77
- console.error("error while sending message: ", error);
78
- temp.error = error;
94
+ console.error(error);
95
+ setError("Error sending message");
79
96
  }
80
- temp.isSending = false;
81
- setmessage(temp);
82
97
  };
83
- (0, react_1.useEffect)(() => {
84
- if (message.isSending) {
85
- sendMessage();
86
- }
87
- // eslint-disable-next-line react-hooks/exhaustive-deps
88
- }, [message.isSending]);
89
- const currentPendingMessage = message.isSending
90
- ? message.textValue
91
- : undefined;
92
- return ((0, jsx_runtime_1.jsx)(exports.ChatProviderContext.Provider, { value: {
98
+ if (loading)
99
+ return null;
100
+ return (_jsx(ChatProviderContext.Provider, { value: {
93
101
  props: {
94
- chats,
95
- userInputData: {
96
- ...message,
97
- setTextValue(value) {
98
- setmessage((prev) => ({ ...prev, textValue: value }));
99
- },
100
- submitMessage() {
101
- setmessage((prev) => ({ ...prev, isSending: true }));
102
- },
103
- },
102
+ ...props,
103
+ messages,
104
+ setMessages,
105
+ error,
106
+ input,
107
+ setInput,
108
+ canSendMessage,
109
+ isChatLoading,
110
+ postSessionMessage,
111
+ setChatbotConversationId,
112
+ setIsChatLoading,
113
+ setCanSendMessage,
114
+ scrollToBottom,
115
+ enabledTools,
104
116
  },
105
- }, children: typeof props.children === "function" ? ((0, jsx_runtime_1.jsx)(props.children, { ...props }) // If it's a function, call it with props
106
- ) : (props.children) // Otherwise, render it as React node
107
- }));
117
+ }, children: error ? (_jsx("div", { children: "An error occured" })) : (_jsx(Conversation, { messages: messages, setMessages: setMessages, postSessionMessage: postSessionMessage, isChatLoading: isChatLoading, messagesRef: messagesRef, input: input, setInput: setInput, handleSendClick: handleSendClick, setChatbotConversationId: setChatbotConversationId, setIsChatLoading: setIsChatLoading, setCanSendMessage: setCanSendMessage, canSendMessage: canSendMessage, scrollToBottom: scrollToBottom, error: error, enabledTools: enabledTools, Components: Components, UITools: UITools })) }));
108
118
  }
109
- exports.default = ChatProvider;
110
- const postUserConversation = ({ orgId, payload, apikey, chatbotId, }) => {
111
- return fetch(`${constants_1.baseUrl}/organizations/${orgId}/chatbots/${chatbotId}/conversations`, {
112
- headers: {
113
- accept: "application/json, text/plain, */*",
114
- "accept-language": "en-US,en;q=0.9",
115
- "content-type": "application/json;charset=UTF-8",
116
- "x-api-key": apikey,
117
- },
118
- body: JSON.stringify(payload),
119
- method: "POST",
120
- });
121
- };
119
+ export default ChatProvider;
@@ -0,0 +1,3 @@
1
+ import { ConversationDataObject } from "../../type.js";
2
+ declare const processStream: (reader: ReadableStreamDefaultReader<any>, onData?: ((data: ConversationDataObject) => void) | undefined) => Promise<void>;
3
+ export default processStream;
@@ -0,0 +1,74 @@
1
+ const processStream = async (reader, onData) => {
2
+ if (!onData)
3
+ return;
4
+ let fullAssistantMessage = "";
5
+ let fullMessageContext = "";
6
+ try {
7
+ while (true) {
8
+ const { value, done } = await reader.read();
9
+ if (done) {
10
+ break;
11
+ }
12
+ // Process the incoming chunk of data
13
+ const chunk = value; // Assuming `value` is a string
14
+ // Split the chunk by lines
15
+ const lines = chunk.split("\n");
16
+ for (const line of lines) {
17
+ let dataString = line;
18
+ if (line.startsWith("data: ")) {
19
+ dataString = line.slice(6);
20
+ }
21
+ if (dataString === "[DONE]") {
22
+ onData({
23
+ completionFinished: true,
24
+ finalResponseWithUsageData: false,
25
+ });
26
+ }
27
+ else {
28
+ try {
29
+ const dataObject = JSON.parse(fullMessageContext + dataString);
30
+ if (dataObject.error) {
31
+ throw new Error(dataObject.error);
32
+ }
33
+ if (dataObject.content) {
34
+ fullAssistantMessage += dataObject.content;
35
+ onData({
36
+ completionFinished: false,
37
+ finalResponseWithUsageData: false,
38
+ message: fullAssistantMessage,
39
+ });
40
+ }
41
+ else {
42
+ //at this point, the dataObject does not have a content propery
43
+ //and it is completed
44
+ //get the last message from the dataObject to check if it is a function call
45
+ const { messages, completionFinished, finalResponseWithUsageData, chatbotConversationId, conversationId, totalTokens, totalCost, } = dataObject;
46
+ onData({
47
+ messages,
48
+ completionFinished,
49
+ finalResponseWithUsageData,
50
+ conversationId,
51
+ chatbotConversationId,
52
+ totalTokens,
53
+ totalCost,
54
+ });
55
+ }
56
+ }
57
+ catch (error) {
58
+ fullMessageContext += dataString;
59
+ }
60
+ }
61
+ }
62
+ }
63
+ }
64
+ catch (error) {
65
+ onData({
66
+ completionFinished: true,
67
+ message: fullAssistantMessage,
68
+ finalResponseWithUsageData: true,
69
+ });
70
+ console.error(error);
71
+ throw new Error(error);
72
+ }
73
+ };
74
+ export default processStream;
@@ -1,2 +1,2 @@
1
- declare const useChatContext: () => import("../type").CmndChatContext;
1
+ declare const useChatContext: () => import("../type.js").CmndChatContext;
2
2
  export default useChatContext;
@@ -1,11 +1,9 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const react_1 = require("react");
4
- const _1 = require(".");
1
+ import { useContext } from "react";
2
+ import { ChatProviderContext } from "./index.js";
5
3
  const useChatContext = () => {
6
- const context = (0, react_1.useContext)(_1.ChatProviderContext);
4
+ const context = useContext(ChatProviderContext);
7
5
  if (!context)
8
6
  throw new Error("Cmnd chat context must be wrapped in a provider");
9
7
  return context;
10
8
  };
11
- exports.default = useChatContext;
9
+ export default useChatContext;
@@ -1,14 +1,12 @@
1
1
  import React from "react";
2
- import { CmndChatContext } from "../type";
3
- export interface CmndChatBotProps {
2
+ import { UIFunctionArguments } from "../type.js";
3
+ import { ConversationProps } from "../components/Conversation.js";
4
+ export interface CmndChatBotProps extends Pick<ConversationProps, 'Components'> {
4
5
  chatbotId: number;
5
6
  organizationId: number;
6
7
  apiKey: string;
7
- components: {
8
- messages: (params: CmndChatContext) => React.ReactNode;
9
- userInputBox: (params: CmndChatContext) => React.ReactNode;
10
- error?: (params: CmndChatContext) => React.ReactNode;
11
- };
8
+ baseUrl: string;
9
+ UITools?: Record<string, React.FC<UIFunctionArguments<any>>>;
12
10
  }
13
- declare function CmndChatBot(props: CmndChatBotProps): import("react/jsx-runtime").JSX.Element;
11
+ declare function CmndChatBot(props: CmndChatBotProps): void;
14
12
  export default CmndChatBot;
@@ -1,16 +1,6 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- const jsx_runtime_1 = require("react/jsx-runtime");
7
- const useChatContext_1 = __importDefault(require("../ChatProvider/useChatContext"));
1
+ import useChatContext from "../ChatProvider/useChatContext.js";
8
2
  function CmndChatBot(props) {
9
- const chatContext = (0, useChatContext_1.default)();
10
- const { props: { chats }, } = chatContext;
11
- if (chats.error && props.components.error) {
12
- return (0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: (0, jsx_runtime_1.jsx)(props.components.error, { props: chatContext.props }) });
13
- }
14
- return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(props.components.messages, { props: chatContext.props }), (0, jsx_runtime_1.jsx)(props.components.userInputBox, { props: chatContext.props })] }));
3
+ const chatContext = useChatContext();
4
+ return;
15
5
  }
16
- exports.default = CmndChatBot;
6
+ export default CmndChatBot;
@@ -0,0 +1,21 @@
1
+ import React, { Dispatch, ReactNode, SetStateAction } from "react";
2
+ import { MessageRole, ToolDetails, ToolData, UIFunctionArguments } from "../type.js";
3
+ interface ChatBubbleProps {
4
+ message: string | ReactNode | null;
5
+ role: MessageRole;
6
+ toolCallDetails?: ToolDetails;
7
+ tools?: ToolData[] | undefined;
8
+ postSessionMessage: any;
9
+ messages: any;
10
+ setMessages: Dispatch<SetStateAction<any>> | any;
11
+ hide?: boolean;
12
+ id: string;
13
+ isLoadingBubble?: boolean;
14
+ setChatbotConversationId: Dispatch<SetStateAction<number | undefined>>;
15
+ setCanSendMessage: Dispatch<SetStateAction<boolean>>;
16
+ setIsChatLoading: Dispatch<SetStateAction<boolean>>;
17
+ scrollToBottom: () => void;
18
+ UITools?: Record<string, React.FC<UIFunctionArguments<any>>>;
19
+ }
20
+ declare const Chatbubble: ({ message, role, toolCallDetails, tools, postSessionMessage, setMessages, messages, hide, setChatbotConversationId, setCanSendMessage, setIsChatLoading, scrollToBottom, isLoadingBubble, UITools, }: ChatBubbleProps) => JSX.Element | null;
21
+ export default Chatbubble;
@@ -0,0 +1,161 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { useCallback, useEffect, } from "react";
3
+ import { MessageRole, FunctionType, } from "../type.js";
4
+ import { BsTools, BsRobot } from "react-icons/bs";
5
+ import { FaUserCircle } from "react-icons/fa";
6
+ import { ErrorBoundary } from "react-error-boundary";
7
+ import UIToolComponent from "../ui-tools/index.js";
8
+ import remarkGfm from "remark-gfm";
9
+ import ReactMarkdown from "react-markdown";
10
+ import SyntaxHighlighter from "react-syntax-highlighter";
11
+ import { oneDark } from "react-syntax-highlighter/dist/esm/styles/prism";
12
+ const getChatAvatar = (role) => {
13
+ switch (role) {
14
+ case MessageRole.USER:
15
+ return _jsx(FaUserCircle, {});
16
+ case MessageRole.FUNCTION:
17
+ return _jsx(BsTools, {});
18
+ case MessageRole.ASSISTANT:
19
+ return _jsx(BsRobot, {});
20
+ default:
21
+ return _jsx(BsRobot, {});
22
+ }
23
+ };
24
+ const Chatbubble = ({ message, role, toolCallDetails, tools, postSessionMessage, setMessages, messages, hide, setChatbotConversationId, setCanSendMessage, setIsChatLoading, scrollToBottom, isLoadingBubble, UITools, }) => {
25
+ const patchLastMessageToolInfo = useCallback((messages, toolInfo) => {
26
+ const lastMessage = messages[messages.length - 1];
27
+ if (lastMessage.role !== MessageRole.FUNCTION) {
28
+ return messages;
29
+ }
30
+ const shallowCopyOfMessagesWithoutLast = messages.slice(0, -1);
31
+ const copyOfLastMessage = { ...lastMessage };
32
+ copyOfLastMessage.tool = {
33
+ ...copyOfLastMessage.tool,
34
+ ...toolInfo,
35
+ };
36
+ const newMessages = [
37
+ ...shallowCopyOfMessagesWithoutLast,
38
+ copyOfLastMessage,
39
+ ];
40
+ return newMessages;
41
+ }, []);
42
+ const confirmToolRun = useCallback(async ({ messages, setMessages, postSessionMessage, }) => {
43
+ const newMessages = patchLastMessageToolInfo(messages, {
44
+ confirmed: true,
45
+ });
46
+ setIsChatLoading(true);
47
+ setCanSendMessage(false);
48
+ setMessages(newMessages);
49
+ await postSessionMessage(newMessages, (data) => {
50
+ if (data.finalResponseWithUsageData) {
51
+ setCanSendMessage(true);
52
+ setIsChatLoading(false);
53
+ const { messages, chatbotConversationId } = data;
54
+ if (chatbotConversationId) {
55
+ setChatbotConversationId(chatbotConversationId);
56
+ // saveConversationIdToLocalStorage(
57
+ // chatbotConversationId.toString(),
58
+ // config.chatbot_id!,
59
+ // config.organization_id!
60
+ // );
61
+ }
62
+ messages && setMessages(messages);
63
+ }
64
+ if (data.message) {
65
+ setIsChatLoading(false);
66
+ const newAssistantMessage = {
67
+ unuseful: false,
68
+ hiddenFromUser: false,
69
+ role: MessageRole.ASSISTANT,
70
+ message: "",
71
+ };
72
+ newAssistantMessage.message = data.message;
73
+ setMessages([...newMessages, newAssistantMessage]);
74
+ scrollToBottom();
75
+ }
76
+ });
77
+ }, [patchLastMessageToolInfo]);
78
+ const toolData = tools?.find((t) => t.title === toolCallDetails?.name);
79
+ useEffect(() => {
80
+ if (role === MessageRole.FUNCTION &&
81
+ tools &&
82
+ toolData?.metadata.functionType === FunctionType.BACKEND &&
83
+ Boolean(toolCallDetails?.runAt) === false) {
84
+ confirmToolRun({
85
+ messages,
86
+ setMessages,
87
+ postSessionMessage,
88
+ });
89
+ }
90
+ }, []);
91
+ if (hide)
92
+ return null;
93
+ const defaultStyle = {
94
+ display: toolData?.metadata.functionType === FunctionType.BACKEND
95
+ ? "none"
96
+ : "flex",
97
+ flexDirection: role === MessageRole.USER ? "row-reverse" : "row",
98
+ gap: "10px",
99
+ textAlign: role === MessageRole.USER ? "right" : "left",
100
+ justifySelf: role === MessageRole.USER ? "flex-start" : "flex-end",
101
+ alignItems: "start",
102
+ width: "100%",
103
+ background: "none",
104
+ };
105
+ return (_jsxs("div", { style: defaultStyle, className: `cmnd-chatbot-chat-bubble ${role}`, children: [_jsx("span", { style: {
106
+ fontSize: "30px",
107
+ color: "black",
108
+ }, children: getChatAvatar(role) }), _jsxs("p", { style: {
109
+ backgroundColor: role === MessageRole.USER ? "#7A8194" : "#373E4E",
110
+ color: "white",
111
+ padding: "10px",
112
+ borderRadius: "10px",
113
+ }, children: [role === MessageRole.USER || isLoadingBubble ? (_jsx("span", { children: message })) : (_jsx(ReactMarkdown, { className: "markdown", remarkPlugins: [remarkGfm], children: message?.toString() ?? "", remarkRehypeOptions: { passThrough: ["link"] }, components: {
114
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
115
+ // @ts-ignore
116
+ code({ inline, className, children, ...props }) {
117
+ const match = /language-(\w+)/.exec(className || "");
118
+ const code = String(children).replace(/\n$/, "");
119
+ const language = match ? match[1] : undefined;
120
+ return !inline && match ? (_jsx(SyntaxHighlighter, { children: code, language: language, wrapLongLines: true, style: oneDark, ...props })) : (_jsx("code", { className: className, ...props, children: children }));
121
+ },
122
+ } })), role === MessageRole.FUNCTION && (_jsx("div", { children: toolData?.metadata?.functionType === FunctionType.UI ? (_jsx(ErrorBoundary, { fallback: _jsxs("div", { children: ["Failed to render ", toolCallDetails?.name, ". Please report this error."] }), onError: (error) => {
123
+ // todo: report this error to some central place
124
+ // with toolCallDetails name, args, and conversation id
125
+ console.log("captured error", error);
126
+ }, children: _jsx(UIToolComponent, { functionName: toolCallDetails?.name ?? "", functionArgs: toolCallDetails?.args, previousRunResults: toolCallDetails?.output, UITools: UITools, captureResults: async (msg) => {
127
+ setIsChatLoading(true);
128
+ setCanSendMessage(false);
129
+ const newMessages = patchLastMessageToolInfo(messages, {
130
+ output: msg,
131
+ runAt: new Date().toISOString(),
132
+ confirmed: true,
133
+ });
134
+ setMessages(newMessages);
135
+ const onData = (data) => {
136
+ if (data.finalResponseWithUsageData) {
137
+ setIsChatLoading(false);
138
+ setCanSendMessage(true);
139
+ const { messages, chatbotConversationId } = data;
140
+ if (chatbotConversationId) {
141
+ setChatbotConversationId(chatbotConversationId);
142
+ }
143
+ messages && setMessages(messages);
144
+ }
145
+ if (data.message) {
146
+ setIsChatLoading(false);
147
+ const newAssistantMessage = {
148
+ unuseful: false,
149
+ hiddenFromUser: false,
150
+ role: MessageRole.ASSISTANT,
151
+ message: "",
152
+ };
153
+ newAssistantMessage.message = data.message;
154
+ setMessages([...newMessages, newAssistantMessage]);
155
+ scrollToBottom();
156
+ }
157
+ };
158
+ await postSessionMessage(newMessages, onData);
159
+ } }) })) : (_jsx(_Fragment, {})) }, "2"))] })] }));
160
+ };
161
+ export default Chatbubble;
@@ -0,0 +1,27 @@
1
+ import React, { Dispatch, SetStateAction } from "react";
2
+ import { InputFieldProps, SendButtonProps, UIFunctionArguments } from "../type.js";
3
+ export interface ConversationProps {
4
+ messages: any[];
5
+ setMessages: Dispatch<SetStateAction<any[]>>;
6
+ handleSendClick: () => void;
7
+ input: string;
8
+ setInput: Dispatch<SetStateAction<string>>;
9
+ isChatLoading: boolean;
10
+ error: string | null;
11
+ messagesRef: React.RefObject<HTMLDivElement>;
12
+ setChatbotConversationId: Dispatch<React.SetStateAction<number | undefined>>;
13
+ setIsChatLoading: Dispatch<SetStateAction<boolean>>;
14
+ setCanSendMessage: Dispatch<SetStateAction<boolean>>;
15
+ canSendMessage: boolean;
16
+ scrollToBottom: () => void;
17
+ enabledTools: any[];
18
+ postSessionMessage: (message: string, onData: any) => void;
19
+ Components?: {
20
+ InputField?: (params: InputFieldProps) => JSX.Element;
21
+ SendButton?: (params: SendButtonProps) => JSX.Element;
22
+ error?: any;
23
+ };
24
+ UITools?: Record<string, React.FC<UIFunctionArguments<any>>>;
25
+ }
26
+ declare const Conversation: ({ messages, handleSendClick, isChatLoading, error, messagesRef, enabledTools, postSessionMessage, setMessages, setChatbotConversationId, setIsChatLoading, setCanSendMessage, scrollToBottom, canSendMessage, setInput, input, Components, UITools, }: ConversationProps) => JSX.Element;
27
+ export default Conversation;
@@ -0,0 +1,19 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import Chatbubble from "./Chatbubble.js";
3
+ import LoadingBubble from "./LoadingBubble.js";
4
+ import { RiSendPlane2Line } from "react-icons/ri";
5
+ const Conversation = ({ messages, handleSendClick, isChatLoading, error, messagesRef, enabledTools, postSessionMessage, setMessages, setChatbotConversationId, setIsChatLoading, setCanSendMessage, scrollToBottom, canSendMessage, setInput, input, Components, UITools, }) => {
6
+ return (_jsxs("div", { className: "cmnd-conversations", children: [_jsxs("div", { ref: messagesRef, id: "messages", className: "cmnd-conversations-messages", children: [error, messages.map((m, i) => (_jsx(Chatbubble, { hide: m.hiddenFromUser, message: m.message, role: m.role, toolCallDetails: m.tool, tools: enabledTools, postSessionMessage: postSessionMessage, messages: messages, setMessages: setMessages, id: m.id, setChatbotConversationId: setChatbotConversationId, setIsChatLoading: setIsChatLoading, setCanSendMessage: setCanSendMessage, scrollToBottom: scrollToBottom, UITools: UITools }, i))), isChatLoading ? _jsx(LoadingBubble, {}) : null] }), _jsxs("div", { id: "cmnd-input-div", className: "cmnd-input-div", children: [Components?.InputField ? (_jsx(Components.InputField, { ...{ input, setInput, canSendMessage, handleSendClick } })) : (_jsx("input", { id: "cmnd-input", className: "cmnd-input", onKeyDown: (e) => {
7
+ if (e.key === "Enter") {
8
+ handleSendClick();
9
+ }
10
+ }, autoComplete: "off", value: input, onChange: (e) => setInput(e.target.value), type: "text", placeholder: "type something..." })), Components?.SendButton ? (_jsx(Components.SendButton, { ...{
11
+ canSendMessage,
12
+ handleSendClick,
13
+ } })) : (_jsx("span", { id: "cmnd-send-button", className: "cmnd-send-button", style: {
14
+ opacity: canSendMessage ? "1" : "0.5",
15
+ cursor: canSendMessage ? "pointer" : "not-allowed",
16
+ fontSize: "1.5rem",
17
+ }, onClick: handleSendClick, children: _jsx(RiSendPlane2Line, {}) }))] })] }));
18
+ };
19
+ export default Conversation;
@@ -0,0 +1,3 @@
1
+ /// <reference types="react" />
2
+ declare const LoadingBubble: () => JSX.Element;
3
+ export default LoadingBubble;
@@ -0,0 +1,12 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { MessageRole } from "../type.js";
3
+ import Chatbubble from "./Chatbubble.js";
4
+ const LoadingBubble = () => {
5
+ const color = "white";
6
+ return (_jsx(Chatbubble, { isLoadingBubble: true, message: _jsx("div", { className: "loading-container", children: _jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", xmlnsXlink: "http://www.w3.org/1999/xlink", style: {
7
+ margin: "auto",
8
+ display: "block",
9
+ shapeRendering: "auto",
10
+ }, width: "60px", height: "30px", viewBox: "0 0 100 100", preserveAspectRatio: "xMidYMid", children: [_jsxs("circle", { cx: "84", cy: "50", r: "10", fill: color, children: [_jsx("animate", { attributeName: "r", repeatCount: "indefinite", dur: "0.25s", calcMode: "spline", keyTimes: "0;1", values: "10;0", keySplines: "0 0.5 0.5 1", begin: "0s" }), _jsx("animate", { attributeName: "fill", repeatCount: "indefinite", dur: "1s", calcMode: "discrete", keyTimes: "0;0.25;0.5;0.75;1", values: color, begin: "0s" })] }), _jsxs("circle", { cx: "16", cy: "50", r: "10", fill: color, children: [_jsx("animate", { attributeName: "r", repeatCount: "indefinite", dur: "1s", calcMode: "spline", keyTimes: "0;0.25;0.5;0.75;1", values: "0;0;10;10;10", keySplines: "0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1", begin: "0s" }), _jsx("animate", { attributeName: "cx", repeatCount: "indefinite", dur: "1s", calcMode: "spline", keyTimes: "0;0.25;0.5;0.75;1", values: "16;16;16;50;84", keySplines: "0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1", begin: "0s" })] }), _jsxs("circle", { cx: "50", cy: "50", r: "10", fill: color, children: [_jsx("animate", { attributeName: "r", repeatCount: "indefinite", dur: "1s", calcMode: "spline", keyTimes: "0;0.25;0.5;0.75;1", values: "0;0;10;10;10", keySplines: "0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1", begin: "-0.25s" }), _jsx("animate", { attributeName: "cx", repeatCount: "indefinite", dur: "1s", calcMode: "spline", keyTimes: "0;0.25;0.5;0.75;1", values: "16;16;16;50;84", keySplines: "0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1", begin: "-0.25s" })] }), _jsxs("circle", { cx: "84", cy: "50", r: "10", fill: color, children: [_jsx("animate", { attributeName: "r", repeatCount: "indefinite", dur: "1s", calcMode: "spline", keyTimes: "0;0.25;0.5;0.75;1", values: "0;0;10;10;10", keySplines: "0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1", begin: "-0.5s" }), _jsx("animate", { attributeName: "cx", repeatCount: "indefinite", dur: "1s", calcMode: "spline", keyTimes: "0;0.25;0.5;0.75;1", values: "16;16;16;50;84", keySplines: "0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1", begin: "-0.5s" })] }), _jsxs("circle", { cx: "16", cy: "50", r: "10", fill: color, children: [_jsx("animate", { attributeName: "r", repeatCount: "indefinite", dur: "1s", calcMode: "spline", keyTimes: "0;0.25;0.5;0.75;1", values: "0;0;10;10;10", keySplines: "0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1", begin: "-0.75s" }), _jsx("animate", { attributeName: "cx", repeatCount: "indefinite", dur: "1s", calcMode: "spline", keyTimes: "0;0.25;0.5;0.75;1", values: "16;16;16;50;84", keySplines: "0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1;0 0.5 0.5 1", begin: "-0.75s" })] })] }) }), role: MessageRole.ASSISTANT, messages: [], postSessionMessage: () => { }, id: "__loading__", setMessages: () => { }, setChatbotConversationId: () => { }, setCanSendMessage: () => { }, setIsChatLoading: () => { }, scrollToBottom: () => { } }));
11
+ };
12
+ export default LoadingBubble;
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { default as ChatProvider } from "./ChatProvider";
2
- export { default as useChatContext } from "./ChatProvider/useChatContext";
3
- export { default as CmndChatBot } from "./CmndChatBot";
4
- export * from "./constants";
1
+ export { default as ChatProvider } from "./ChatProvider/index.js";
2
+ export { default as useChatContext } from "./ChatProvider/useChatContext.js";
3
+ export { CmndChatContext } from "./type.js";
4
+ export { default as CmndChatBot } from "./CmndChatBot/index.js";
package/dist/index.js CHANGED
@@ -1,27 +1,3 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
- for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
- };
16
- var __importDefault = (this && this.__importDefault) || function (mod) {
17
- return (mod && mod.__esModule) ? mod : { "default": mod };
18
- };
19
- Object.defineProperty(exports, "__esModule", { value: true });
20
- exports.CmndChatBot = exports.useChatContext = exports.ChatProvider = void 0;
21
- var ChatProvider_1 = require("./ChatProvider");
22
- Object.defineProperty(exports, "ChatProvider", { enumerable: true, get: function () { return __importDefault(ChatProvider_1).default; } });
23
- var useChatContext_1 = require("./ChatProvider/useChatContext");
24
- Object.defineProperty(exports, "useChatContext", { enumerable: true, get: function () { return __importDefault(useChatContext_1).default; } });
25
- var CmndChatBot_1 = require("./CmndChatBot");
26
- Object.defineProperty(exports, "CmndChatBot", { enumerable: true, get: function () { return __importDefault(CmndChatBot_1).default; } });
27
- __exportStar(require("./constants"), exports);
1
+ export { default as ChatProvider } from "./ChatProvider/index.js";
2
+ export { default as useChatContext } from "./ChatProvider/useChatContext.js";
3
+ export { default as CmndChatBot } from "./CmndChatBot/index.js";
@@ -0,0 +1,2 @@
1
+ declare const getChatBotById: (baseUrl: string, organizationId: number, chatbotId: number) => Promise<import("axios").AxiosResponse<any, any>>;
2
+ export default getChatBotById;
@@ -0,0 +1,6 @@
1
+ import axios from "axios";
2
+ const getChatBotById = (baseUrl, organizationId, chatbotId) => {
3
+ const endpoint = `${baseUrl}/organizations/${organizationId}/chatbots/${chatbotId}`;
4
+ return axios.get(endpoint);
5
+ };
6
+ export default getChatBotById;
@@ -0,0 +1,10 @@
1
+ import { ConversationDataObject } from "../type.js";
2
+ declare const postUserConversation: ({ orgId, payload, apikey, chatbotId, baseUrl, onData, }: {
3
+ orgId: number;
4
+ payload: object;
5
+ chatbotId: number;
6
+ apikey: string;
7
+ baseUrl: string;
8
+ onData?: ((data: ConversationDataObject) => void) | undefined;
9
+ }) => Promise<void>;
10
+ export default postUserConversation;
@@ -0,0 +1,22 @@
1
+ import axios from "axios";
2
+ import processStream from "../ChatProvider/processStream/index.js";
3
+ const postUserConversation = async ({ orgId, payload, apikey, chatbotId, baseUrl, onData, }) => {
4
+ const endpoint = `${baseUrl}/organizations/${orgId}/chatbots/${chatbotId}/conversations`;
5
+ const response = await axios.post(endpoint, {
6
+ messages: payload,
7
+ }, {
8
+ headers: {
9
+ Accept: "text/event-stream",
10
+ "accept-language": "en-US,en;q=0.9",
11
+ "content-type": "application/json;charset=UTF-8",
12
+ "x-api-key": apikey,
13
+ },
14
+ responseType: "stream",
15
+ adapter: "fetch",
16
+ });
17
+ const reader = response.data
18
+ .pipeThrough(new TextDecoderStream())
19
+ .getReader();
20
+ await processStream(reader, onData);
21
+ };
22
+ export default postUserConversation;
package/dist/type.d.ts CHANGED
@@ -1,34 +1,20 @@
1
+ import { ConversationProps } from "./components/Conversation.js";
1
2
  export interface CmndChatContext {
2
- props: {
3
- chats: {
4
- isLoading: boolean;
5
- data: Conversation | undefined;
6
- error: null | unknown;
7
- };
8
- userInputData: {
9
- isSending: boolean;
10
- textValue: string;
11
- /** whether there is an error while sending the message */
12
- error: null | unknown;
13
- /** to change the value of the input text */
14
- setTextValue: (value: string) => any;
15
- /** function to call for submitting a message */
16
- submitMessage: () => void;
17
- /**Message currently being sent */
18
- currentPendingMessage?: string;
19
- };
20
- };
3
+ props: Partial<ConversationProps>;
4
+ }
5
+ export interface InputFieldProps {
6
+ input: string;
7
+ setInput: (input: string) => void;
8
+ canSendMessage: boolean;
9
+ handleSendClick: () => void;
10
+ }
11
+ export interface SendButtonProps {
12
+ handleSendClick: () => void;
13
+ canSendMessage: boolean;
21
14
  }
22
15
  export type ErrorOrData<T> = {
23
16
  error: unknown;
24
17
  } | T;
25
- export interface Message {
26
- id?: string;
27
- role: "user" | "assistant";
28
- message: string;
29
- unuseful: boolean;
30
- hiddenFromUser: boolean;
31
- }
32
18
  export interface Conversation {
33
19
  conversationId: number;
34
20
  conversationTitle: string;
@@ -43,3 +29,75 @@ export interface Conversation {
43
29
  /** Date string format */
44
30
  updatedAt: string;
45
31
  }
32
+ export interface ConversationDataObject {
33
+ completionFinished: boolean;
34
+ finalResponseWithUsageData: boolean;
35
+ message?: string;
36
+ conversationId?: string;
37
+ chatbotConversationId?: number;
38
+ totalTokens?: number;
39
+ totalCost?: number;
40
+ messages?: Message[];
41
+ }
42
+ interface ToolArgument {
43
+ type: string;
44
+ description: string;
45
+ default?: any;
46
+ }
47
+ interface ToolArguments {
48
+ type: string;
49
+ default?: any;
50
+ properties: Record<string, ToolArgument>;
51
+ required?: string[];
52
+ }
53
+ export declare enum FunctionType {
54
+ UI = "ui",
55
+ BACKEND = "backend"
56
+ }
57
+ export type ToolData = {
58
+ [x: string]: any;
59
+ name: string;
60
+ description: string;
61
+ category: string;
62
+ subcategory: string;
63
+ subsubcategory?: string;
64
+ functionType: FunctionType;
65
+ dangerous: boolean;
66
+ arguments: ToolArguments;
67
+ };
68
+ export type UIFunctionArguments<AIProvidedParams> = {
69
+ functionArgs: AIProvidedParams;
70
+ previousRunResults?: string;
71
+ captureResults: (result: string) => void;
72
+ };
73
+ export declare enum MessageRole {
74
+ FUNCTION = "function",
75
+ USER = "user",
76
+ ASSISTANT = "assistant",
77
+ SYSTEM = "system"
78
+ }
79
+ type MessageRoleExceptFunctions = Exclude<MessageRole, MessageRole.FUNCTION>;
80
+ interface GenericMessage {
81
+ id: string;
82
+ unuseful: boolean;
83
+ hiddenFromUser: boolean;
84
+ message?: string;
85
+ role: MessageRoleExceptFunctions;
86
+ }
87
+ export interface ToolDetails {
88
+ args: any;
89
+ name: string;
90
+ confirmed?: boolean;
91
+ runAt?: string;
92
+ output?: string;
93
+ }
94
+ interface ToolMessage {
95
+ id: string;
96
+ unuseful: boolean;
97
+ hiddenFromUser: boolean;
98
+ message?: string;
99
+ role: MessageRole.FUNCTION;
100
+ tool: ToolDetails;
101
+ }
102
+ export type Message = GenericMessage | ToolMessage;
103
+ export {};
package/dist/type.js CHANGED
@@ -1,2 +1,12 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
1
+ export var FunctionType;
2
+ (function (FunctionType) {
3
+ FunctionType["UI"] = "ui";
4
+ FunctionType["BACKEND"] = "backend";
5
+ })(FunctionType = FunctionType || (FunctionType = {}));
6
+ export var MessageRole;
7
+ (function (MessageRole) {
8
+ MessageRole["FUNCTION"] = "function";
9
+ MessageRole["USER"] = "user";
10
+ MessageRole["ASSISTANT"] = "assistant";
11
+ MessageRole["SYSTEM"] = "system";
12
+ })(MessageRole = MessageRole || (MessageRole = {}));
@@ -0,0 +1,10 @@
1
+ import React from "react";
2
+ import { UIFunctionArguments } from "../type.js";
3
+ declare const UIToolComponent: ({ functionName, functionArgs, previousRunResults, captureResults, UITools, }: {
4
+ functionName: string;
5
+ functionArgs: any;
6
+ previousRunResults?: string | undefined;
7
+ captureResults: (result: string) => void;
8
+ UITools?: Record<string, React.FC<UIFunctionArguments<any>>> | undefined;
9
+ }) => JSX.Element;
10
+ export default UIToolComponent;
@@ -0,0 +1,9 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ const UIToolComponent = ({ functionName, functionArgs, previousRunResults, captureResults, UITools = {}, }) => {
3
+ const Component = UITools[functionName];
4
+ if (!Component) {
5
+ throw new Error(`Tried to render non-existing UI-Tool component for ${functionName}.`);
6
+ }
7
+ return (_jsx(Component, { functionArgs: functionArgs, previousRunResults: previousRunResults, captureResults: captureResults }));
8
+ };
9
+ export default UIToolComponent;
@@ -0,0 +1,2 @@
1
+ import { CSSProperties } from "react";
2
+ export declare const overrideStyle: (style: CSSProperties, overrides?: Partial<CSSProperties>) => CSSProperties;
package/dist/utils.js ADDED
@@ -0,0 +1,3 @@
1
+ export const overrideStyle = (style, overrides) => {
2
+ return { ...style, ...overrides };
3
+ };
package/package.json CHANGED
@@ -1,8 +1,9 @@
1
1
  {
2
2
  "name": "@cmnd-ai/chatbot-react",
3
- "version": "1.1.2",
3
+ "version": "1.2.0",
4
4
  "main": "dist/index.js",
5
5
  "description": "",
6
+ "type": "module",
6
7
  "files": [
7
8
  "dist/",
8
9
  "package.json",
@@ -17,11 +18,20 @@
17
18
  "author": "",
18
19
  "license": "ISC",
19
20
  "devDependencies": {
20
- "@types/react": "^18.2.55",
21
+ "@types/react": "18.0.28",
22
+ "@types/react-syntax-highlighter": "^15.5.13",
21
23
  "semantic-release": "^22.0.12",
22
- "typescript": "^5.3.3"
24
+ "typescript": "4.9.5"
23
25
  },
24
26
  "publishConfig": {
25
27
  "access": "public"
28
+ },
29
+ "dependencies": {
30
+ "axios": "^1.7.5",
31
+ "react-error-boundary": "^4.0.13",
32
+ "react-icons": "^5.3.0",
33
+ "react-markdown": "^8.0.6",
34
+ "react-syntax-highlighter": "^15.5.0",
35
+ "remark-gfm": "^3.0.1"
26
36
  }
27
37
  }
@@ -1 +0,0 @@
1
- export declare const baseUrl: "https://api.cmnd.ai";
package/dist/constants.js DELETED
@@ -1,4 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.baseUrl = void 0;
4
- exports.baseUrl = "https://api.cmnd.ai";