@chatbotkit/react 1.6.0 → 1.8.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.
Files changed (41) hide show
  1. package/README.md +198 -9
  2. package/dist/cjs/actions/complete.cjs +178 -0
  3. package/dist/cjs/actions/complete.d.ts +38 -0
  4. package/dist/cjs/components/ConversationManager.cjs +26 -0
  5. package/dist/cjs/components/ConversationManager.d.ts +5 -0
  6. package/dist/cjs/hooks/useConversationManager.cjs +99 -114
  7. package/dist/cjs/hooks/useConversationManager.d.ts +13 -52
  8. package/dist/cjs/hooks/useConversationManagerRemote.cjs +83 -0
  9. package/dist/cjs/hooks/useConversationManagerRemote.d.ts +20 -0
  10. package/dist/cjs/hooks/useConversationManagerState.cjs +32 -0
  11. package/dist/cjs/hooks/useConversationManagerState.d.ts +10 -0
  12. package/dist/cjs/hooks/useConversationManagerStateReducer.cjs +112 -0
  13. package/dist/cjs/hooks/useConversationManagerStateReducer.d.ts +42 -0
  14. package/dist/cjs/index.cjs +4 -1
  15. package/dist/cjs/index.d.ts +1 -0
  16. package/dist/cjs/utils/it.cjs +9 -0
  17. package/dist/cjs/utils/it.d.ts +1 -0
  18. package/dist/cjs/utils/stream.cjs +2 -2
  19. package/dist/cjs/utils/stream.d.ts +6 -7
  20. package/dist/esm/actions/complete.d.ts +38 -0
  21. package/dist/esm/actions/complete.js +173 -0
  22. package/dist/esm/components/AutoScroller.js +1 -1
  23. package/dist/esm/components/ConversationManager.d.ts +5 -0
  24. package/dist/esm/components/ConversationManager.js +21 -0
  25. package/dist/esm/hooks/useConversationManager.d.ts +13 -52
  26. package/dist/esm/hooks/useConversationManager.js +99 -114
  27. package/dist/esm/hooks/useConversationManagerRemote.d.ts +20 -0
  28. package/dist/esm/hooks/useConversationManagerRemote.js +78 -0
  29. package/dist/esm/hooks/useConversationManagerState.d.ts +10 -0
  30. package/dist/esm/hooks/useConversationManagerState.js +27 -0
  31. package/dist/esm/hooks/useConversationManagerStateReducer.d.ts +42 -0
  32. package/dist/esm/hooks/useConversationManagerStateReducer.js +105 -0
  33. package/dist/esm/index.d.ts +1 -0
  34. package/dist/esm/index.js +1 -0
  35. package/dist/esm/utils/it.d.ts +1 -0
  36. package/dist/esm/utils/it.js +5 -0
  37. package/dist/esm/utils/stream.d.ts +6 -7
  38. package/dist/esm/utils/stream.js +2 -2
  39. package/dist/tsconfig.cjs.tsbuildinfo +1 -1
  40. package/dist/tsconfig.esm.tsbuildinfo +1 -1
  41. package/package.json +122 -2
package/README.md CHANGED
@@ -10,9 +10,12 @@ Welcome to the ChatBotKit React SDK! This SDK is your go-to React solution for c
10
10
 
11
11
  The ChatBotKit React SDK offers a comprehensive set of features and capabilities, including:
12
12
 
13
+ - **[streamComplete](https://chatbotkit.github.io/node-sdk/modules/_chatbotkit_react.actions_streamComplete.html#streamcomplete)**: A server-side reaction which allow for function calling and React component streaming.
13
14
  - **[userConversationManager](https://chatbotkit.github.io/node-sdk/modules/_chatbotkit_react.hooks_useConversationManager.html)**: A React Hook for managing conversation flow. Handles all the heavy lifting of sending and receiving messages, as well as thinking and typing indicators.
15
+ - **[ConvesationManager](https://chatbotkit.github.io/node-sdk/modules/_chatbotkit_react.components_ConversationManager.html)**: A React component that provides a conversation manager interface. Useful for chat interfaces to manage conversation flow.
14
16
  - **[AutoTextarea](https://chatbotkit.github.io/node-sdk/modules/_chatbotkit_react.components_AutoTextarea.html)**: A React component that automatically resizes the textarea to fit the content. Useful for chat interfaces to allow users to type messages.
15
17
  - **[ChatInput](https://chatbotkit.github.io/node-sdk/modules/_chatbotkit_react.components_ChatInput.html)**: A React component that provides a chat input interface. Useful for chat interfaces to allow users to type messages. It automatically handles modifiers such as ctrl, cmd and shift.
18
+ - **[ChatMessage](https://chatbotkit.github.io/node-sdk/modules/_chatbotkit_react.components_ChatMessage.html)**: A React component that provides a chat message interface. Useful for chat interfaces to display messages with rich formatting.
16
19
  - **[ChatMessages](https://chatbotkit.github.io/node-sdk/modules/_chatbotkit_react.components_ChatMessages.html)**: A React component that provides a chat messages interface. Useful for chat interfaces to display messages.
17
20
 
18
21
  ## Getting Started
@@ -25,27 +28,192 @@ Embark on your ChatBotKit journey with these easy steps:
25
28
  ```
26
29
  2. **Implementation**: Utilize the SDK to build or manage your chatbot.
27
30
 
31
+ ### A NextGen Example for Next.js
32
+
33
+ This example showcases how to build advanced conversational AI with streaming, function calls, server-side rendering and much more in a Next.js project:
34
+
35
+ ```javascript
36
+ // file: ./app/page.jsx
37
+ import ChatArea from '../components/ChatArea.jsx'
38
+
39
+ export default function Page() {
40
+ return <ChatArea />
41
+ }
42
+
43
+ // file: ./components/ChatArea.jsx
44
+ 'use client'
45
+
46
+ import { useContext } from 'react'
47
+
48
+ import { complete } from '../actions/conversation.js'
49
+
50
+ import { ChatInput, ConversationContext } from '@chatbotkit/react'
51
+ import ConversationManager from '@chatbotkit/react/components/ConversationManager'
52
+
53
+ export function ChatMessages() {
54
+ const {
55
+ thinking,
56
+
57
+ text,
58
+ setText,
59
+
60
+ messages,
61
+
62
+ submit,
63
+ } = useContext(ConversationContext)
64
+
65
+ return (
66
+ <div>
67
+ <div>
68
+ {messages.map(({ id, type, text, children }) => {
69
+ switch (type) {
70
+ case 'user':
71
+ return (
72
+ <div key={id}>
73
+ <div>
74
+ <strong>user:</strong> {text}
75
+ </div>
76
+ </div>
77
+ )
78
+
79
+ case 'bot':
80
+ return (
81
+ <div key={id}>
82
+ <div>
83
+ <strong>bot:</strong> {text}
84
+ </div>
85
+ {children ? <div>{children}</div> : null}
86
+ </div>
87
+ )
88
+ }
89
+ })}
90
+ {thinking ? (
91
+ <div key="thinking">
92
+ <strong>bot:</strong> thinking...
93
+ </div>
94
+ ) : null}
95
+ </div>
96
+ <ChatInput
97
+ value={text}
98
+ onChange={(e) => setText(e.target.value)}
99
+ onSubmit={submit}
100
+ placeholder="Type something..."
101
+ style={{
102
+ border: 0,
103
+ outline: 'none',
104
+ resize: 'none',
105
+ width: '100%',
106
+ marginTop: '10px',
107
+ }}
108
+ />
109
+ </div>
110
+ )
111
+ }
112
+
113
+ export default function ChatArea() {
114
+ return (
115
+ <ConversationManager endpoint={complete}>
116
+ <ChatMessages />
117
+ </ConversationManager>
118
+ )
119
+ }
120
+
121
+ // file: ./actions/conversation.js
122
+ 'use server'
123
+
124
+ import CalendarEvents from '../components/CalendarEvents.jsx'
125
+
126
+ import { streamComplete } from '@chatbotkit/react/actions/complete'
127
+ import { ChatBotKit } from '@chatbotkit/sdk'
128
+
129
+ const cbk = new ChatBotKit({
130
+ secret: process.env.CHATBOTKIT_API_SECRET,
131
+ })
132
+
133
+ export async function complete(_, { messages }) {
134
+ return streamComplete({
135
+ client: cbk.conversation,
136
+
137
+ messages,
138
+
139
+ functions: [
140
+ {
141
+ name: 'getUserName',
142
+ description: 'Get the authenticated user name',
143
+ parameters: {},
144
+ handler: async () => {
145
+ return 'John Doe'
146
+ },
147
+ },
148
+
149
+ {
150
+ name: 'getCalendarEvents',
151
+ description: 'Get a list of calendar events',
152
+ parameters: {},
153
+ handler: async () => {
154
+ const events = [
155
+ { id: 1, title: 'Meeting with Jane Doe' },
156
+ { id: 2, title: 'Meeting with Jill Doe' },
157
+ ]
158
+
159
+ return {
160
+ children: <CalendarEvents events={events} />,
161
+
162
+ result: {
163
+ events,
164
+ },
165
+ }
166
+ },
167
+ },
168
+
169
+ {
170
+ name: 'declineCalendarEvent',
171
+ description: 'Decline a calendar event',
172
+ parameters: {
173
+ type: 'object',
174
+ properties: {
175
+ id: {
176
+ type: 'number',
177
+ description: 'The ID of the event to decline',
178
+ },
179
+ },
180
+ required: ['id'],
181
+ },
182
+ handler: async ({ id }) => {
183
+ return `You have declined the event with ID ${id}`
184
+ },
185
+ },
186
+ ],
187
+ })
188
+ }
189
+ ```
190
+
28
191
  ### A Basic Example for Next.js
29
192
 
30
193
  Here's a straightforward example using the `useConversationManager` React Hook to manage conversation flow within a Next.js application:
31
194
 
32
195
  ```javascript
196
+ // file: ./pages/index.jsx
197
+ import { useState } from 'react'
198
+
33
199
  import { AutoTextarea, useConversationManager } from '@chatbotkit/react'
34
200
 
35
201
  export default function Index() {
202
+ const [conversationId, setConversationId] = useState(null)
203
+ const [token, setToken] = useState(null)
204
+
36
205
  const {
37
- conversationId,
38
- setConversationId,
39
- token,
40
- setToken,
41
206
  text,
42
207
  setText,
208
+
209
+ message,
43
210
  messages,
211
+
44
212
  thinking,
213
+
45
214
  submit,
46
- } = useConversationManager({ stream: true })
215
+ } = useConversationManager({ conversationId, token })
47
216
 
48
- // Function to create a new chat session
49
217
  async function createSession() {
50
218
  const response = await fetch(`/api/session/create`)
51
219
 
@@ -59,7 +227,6 @@ export default function Index() {
59
227
  setToken(token)
60
228
  }
61
229
 
62
- // Handle text submission
63
230
  function handleOnKeyDown(event) {
64
231
  if (event.keyCode === 13) {
65
232
  event.preventDefault()
@@ -68,7 +235,6 @@ export default function Index() {
68
235
  }
69
236
  }
70
237
 
71
- // Render chat interface
72
238
  return (
73
239
  <div style={{ fontFamily: 'monospace', padding: '10px' }}>
74
240
  {conversationId && token ? (
@@ -78,6 +244,11 @@ export default function Index() {
78
244
  <strong>{type}:</strong> {text}
79
245
  </div>
80
246
  ))}
247
+ {message ? (
248
+ <div key={message.id}>
249
+ <strong>bot:</strong> {message.text}
250
+ </div>
251
+ ) : null}
81
252
  {thinking && (
82
253
  <div key="thinking">
83
254
  <strong>bot:</strong> thinking...
@@ -103,9 +274,27 @@ export default function Index() {
103
274
  </div>
104
275
  )
105
276
  }
277
+
278
+ // file: ./pages/api/conversation/complete.js
279
+ import { ChatBotKit } from '@chatbotkit/sdk'
280
+ import { stream } from '@chatbotkit/next/edge'
281
+
282
+ const cbk = new ChatBotKit({
283
+ secret: process.env.CHATBOTKIT_API_SECRET,
284
+ })
285
+
286
+ export default async function handler(req) {
287
+ const { messages } = await req.json()
288
+
289
+ return stream(cbk.conversation.complete(null, { messages }))
290
+ }
291
+
292
+ export const config = {
293
+ runtime: 'edge',
294
+ }
106
295
  ```
107
296
 
108
- Discover a complete example with advanced features [here](https://github.com/chatbotkit/node-sdk/tree/main/examples/nextjs/basic-chat).
297
+ Discover more examples [here](https://github.com/chatbotkit/node-sdk/tree/main/examples/nextjs).
109
298
 
110
299
  ## Documentation
111
300
 
@@ -0,0 +1,178 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.streamComplete = void 0;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ const react_1 = require("react");
6
+ const it_js_1 = require("../utils/it.cjs");
7
+ const stream_js_1 = require("../utils/stream.cjs");
8
+ const string_js_1 = require("../utils/string.cjs");
9
+ async function* complete({ client, messages, functions, maxRecusion = 3, ...options }) {
10
+ var _a, _b, _c, _d, _e, _f;
11
+ if (maxRecusion <= 0) {
12
+ return;
13
+ }
14
+ messages = messages.slice(0);
15
+ const functionDefinitions = functions === null || functions === void 0 ? void 0 : functions.map((fn) => {
16
+ if (typeof fn === 'function') {
17
+ return fn();
18
+ }
19
+ else {
20
+ return fn;
21
+ }
22
+ });
23
+ let it;
24
+ if (!it) {
25
+ const lastMessage = messages[messages.length - 1];
26
+ if (lastMessage) {
27
+ if (lastMessage.type === 'activity') {
28
+ if (((_b = (_a = lastMessage.meta) === null || _a === void 0 ? void 0 : _a.activity) === null || _b === void 0 ? void 0 : _b.type) === 'request') {
29
+ messages.pop();
30
+ it = [{ type: 'message', data: lastMessage }];
31
+ }
32
+ }
33
+ }
34
+ }
35
+ if (!it) {
36
+ it = client
37
+ .complete(null, {
38
+ ...options,
39
+ messages: messages.map(({ type, text, meta }) => {
40
+ return {
41
+ type,
42
+ text,
43
+ meta,
44
+ };
45
+ }),
46
+ functions: functionDefinitions === null || functionDefinitions === void 0 ? void 0 : functionDefinitions.map(({ name, description, parameters }) => {
47
+ return {
48
+ name,
49
+ description,
50
+ parameters: parameters.schema ? parameters.schema : parameters,
51
+ };
52
+ }),
53
+ })
54
+ .stream();
55
+ }
56
+ if (!it) {
57
+ throw new Error('No stream iterator');
58
+ }
59
+ for await (const item of it) {
60
+ yield item;
61
+ const { type, data } = item;
62
+ if (type === 'message') {
63
+ const message = data;
64
+ messages.push(message);
65
+ if (((_d = (_c = message.meta) === null || _c === void 0 ? void 0 : _c.activity) === null || _d === void 0 ? void 0 : _d.type) === 'request') {
66
+ const name = (_e = message.meta.activity.function) === null || _e === void 0 ? void 0 : _e.name;
67
+ const args = (_f = message.meta.activity.function) === null || _f === void 0 ? void 0 : _f.arguments;
68
+ const fn = functionDefinitions === null || functionDefinitions === void 0 ? void 0 : functionDefinitions.find((fn) => fn.name === name);
69
+ if (fn && typeof fn.handler === 'function') {
70
+ if (fn.parameters.validate) {
71
+ const { valid, error } = await fn.parameters.validate(args);
72
+ if (!valid) {
73
+ throw error || new Error('Invalid arguments');
74
+ }
75
+ }
76
+ const output = await fn.handler(args);
77
+ let text;
78
+ let children;
79
+ let result;
80
+ let render;
81
+ if (typeof output === 'string') {
82
+ text = undefined;
83
+ children = undefined;
84
+ render = undefined;
85
+ result = output;
86
+ }
87
+ else if ((0, react_1.isValidElement)(output)) {
88
+ text = '';
89
+ children = output;
90
+ render = undefined;
91
+ result = undefined;
92
+ }
93
+ else {
94
+ if (typeof (output === null || output === void 0 ? void 0 : output.text) === 'string') {
95
+ text = output.text;
96
+ }
97
+ if ((0, react_1.isValidElement)(output === null || output === void 0 ? void 0 : output.children)) {
98
+ children = output.children;
99
+ }
100
+ if (typeof (output === null || output === void 0 ? void 0 : output.render) === 'function') {
101
+ render = output.render;
102
+ }
103
+ if (output === null || output === void 0 ? void 0 : output.result) {
104
+ result = output.result;
105
+ }
106
+ }
107
+ if (text || children) {
108
+ yield {
109
+ type: 'message',
110
+ data: {
111
+ type: 'bot',
112
+ text: text ? text : '',
113
+ children: children ? (0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: children }) : undefined,
114
+ },
115
+ };
116
+ }
117
+ else if (text || render) {
118
+ const result = await (render === null || render === void 0 ? void 0 : render());
119
+ if ((0, it_js_1.isAsyncGenerator)(result)) {
120
+ const id = (0, string_js_1.getRandomId)('tmp-');
121
+ for await (const item of (result)) {
122
+ yield {
123
+ type: 'message',
124
+ data: {
125
+ id: id,
126
+ type: 'bot',
127
+ text: text ? text : '',
128
+ children: item,
129
+ },
130
+ };
131
+ }
132
+ }
133
+ else {
134
+ yield {
135
+ type: 'message',
136
+ data: {
137
+ type: 'bot',
138
+ text: text ? text : '',
139
+ children: (0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: result }),
140
+ },
141
+ };
142
+ }
143
+ }
144
+ if (result) {
145
+ const activityMessage = {
146
+ type: 'activity',
147
+ text: '',
148
+ meta: {
149
+ activity: {
150
+ type: 'response',
151
+ function: {
152
+ name,
153
+ arguments: args,
154
+ result: JSON.stringify(result),
155
+ },
156
+ },
157
+ },
158
+ };
159
+ yield { type: 'message', data: activityMessage };
160
+ messages.push(activityMessage);
161
+ yield* complete({
162
+ ...options,
163
+ client,
164
+ messages,
165
+ functions,
166
+ maxRecusion: maxRecusion - 1,
167
+ });
168
+ }
169
+ }
170
+ }
171
+ }
172
+ }
173
+ }
174
+ function streamComplete(options) {
175
+ return (0, stream_js_1.stream)(complete(options));
176
+ }
177
+ exports.streamComplete = streamComplete;
178
+ exports.default = complete;
@@ -0,0 +1,38 @@
1
+ export function streamComplete(options: Options): import('../utils/stream.cjs').StreamResult;
2
+ export default complete;
3
+ export type ReactElement = import('react').ReactElement;
4
+ export type ReactNode = import('react').ReactNode;
5
+ export type BasicParametersSchema = Record<string, any>;
6
+ export type ValidatingParametersSchema = {
7
+ schema: BasicParametersSchema;
8
+ validate(value: any): Promise<{
9
+ valid: boolean;
10
+ error?: Error;
11
+ }>;
12
+ };
13
+ export type InputMessage = {
14
+ type: 'bot' | 'user' | 'context' | 'instruction' | 'backstory' | 'activity';
15
+ text: string;
16
+ meta?: Record<string, any>;
17
+ };
18
+ export type RenderFunction = () => AsyncGenerator<ReactNode> | ReactNode | Promise<ReactNode>;
19
+ export type HandlerArgs = any;
20
+ export type HandlerResult = string | ReactElement | {
21
+ text?: string;
22
+ children?: ReactNode;
23
+ render: RenderFunction;
24
+ result?: any;
25
+ };
26
+ export type InputFunction = {
27
+ name: string;
28
+ description: string;
29
+ parameters: BasicParametersSchema | ValidatingParametersSchema;
30
+ handler?: (args: HandlerArgs) => Promise<HandlerResult>;
31
+ };
32
+ export type Options = Omit<any, 'messages' | 'functions'> & {
33
+ client: import('@chatbotkit/sdk').ConversationClient;
34
+ messages: InputMessage[];
35
+ functions?: (InputFunction | (() => InputFunction))[];
36
+ maxRecusion?: number;
37
+ };
38
+ declare function complete({ client, messages, functions, maxRecusion, ...options }: Options): any;
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ConversationManager = exports.ConversationContext = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const jsx_runtime_1 = require("react/jsx-runtime");
6
+ const react_1 = require("react");
7
+ const useConversationManager_js_1 = tslib_1.__importDefault(require("../hooks/useConversationManager.cjs"));
8
+ exports.ConversationContext = (0, react_1.createContext)(({
9
+ message: null,
10
+ messages: [],
11
+ thinking: false,
12
+ typing: false,
13
+ text: '',
14
+ setText: () => { },
15
+ error: null,
16
+ setError: () => { },
17
+ submit: () => { },
18
+ trigger: () => { },
19
+ request: () => { },
20
+ }));
21
+ function ConversationManager({ children, ...options }) {
22
+ const manager = (0, useConversationManager_js_1.default)(options);
23
+ return ((0, jsx_runtime_1.jsx)(exports.ConversationContext.Provider, { value: manager, children: children }));
24
+ }
25
+ exports.ConversationManager = ConversationManager;
26
+ exports.default = ConversationManager;
@@ -0,0 +1,5 @@
1
+ export function ConversationManager({ children, ...options }: import('../hooks/useConversationManager.cjs').UseConversationManagerOptions & {
2
+ children: import('react').ReactNode;
3
+ }): import('react').ReactElement;
4
+ export const ConversationContext: import("react").Context<import("../hooks/useConversationManager.js").UseConversationManagerResult>;
5
+ export default ConversationManager;