├── .eslintrc.json
├── .env.example
├── app
├── globals.css
├── layout.js
└── page.js
├── .vscode
├── extensions.json
└── settings.json
├── postcss.config.js
├── next.config.mjs
├── components
├── functions
│ ├── index.js
│ ├── SlotSelectionForm.jsx
│ └── CaptureDetailsForm.jsx
├── Footer.jsx
└── ChatArea.jsx
├── .devcontainer
└── devcontainer.json
├── .gitignore
├── tailwind.config.js
├── .prettierrc.json
├── tsconfig.json
├── package.json
├── LICENSE
├── README.md
└── actions
└── conversation.jsx
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "next/core-web-vitals"
3 | }
4 |
--------------------------------------------------------------------------------
/.env.example:
--------------------------------------------------------------------------------
1 | # The ChatBotKit Secret Token
2 | CHATBOTKIT_API_SECRET=
3 |
--------------------------------------------------------------------------------
/app/globals.css:
--------------------------------------------------------------------------------
1 | @tailwind base;
2 | @tailwind components;
3 | @tailwind utilities;
4 |
--------------------------------------------------------------------------------
/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | "recommendations": ["esbenp.prettier-vscode", "dbaeumer.vscode-eslint"]
3 | }
4 |
--------------------------------------------------------------------------------
/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | tailwindcss: {},
4 | autoprefixer: {},
5 | },
6 | }
7 |
--------------------------------------------------------------------------------
/app/layout.js:
--------------------------------------------------------------------------------
1 | import './globals.css'
2 |
3 | export default function Layout({ children }) {
4 | return (
5 |
6 |
{children}
7 |
8 | )
9 | }
10 |
--------------------------------------------------------------------------------
/next.config.mjs:
--------------------------------------------------------------------------------
1 | /** @type {import('next').NextConfig} */
2 | const nextConfig = {
3 | experimental: {
4 | serverActions: {
5 | allowedOrigins: ['localhost:3000'],
6 | },
7 | },
8 | }
9 |
10 | export default nextConfig
11 |
--------------------------------------------------------------------------------
/components/functions/index.js:
--------------------------------------------------------------------------------
1 | // @note due to bug in next we need to preload our client side code here
2 | // @see https://github.com/vercel/next.js/issues/58125
3 | //
4 | import '@/components/functions/CaptureDetailsForm'
5 | import '@/components/functions/SlotSelectionForm'
6 |
--------------------------------------------------------------------------------
/.devcontainer/devcontainer.json:
--------------------------------------------------------------------------------
1 | {
2 | "image": "mcr.microsoft.com/devcontainers/javascript-node:1.0.7-18-bullseye",
3 | "features": {
4 | "git-lfs": "latest"
5 | },
6 | "customizations": {
7 | "vscode": {
8 | "extensions": ["dbaeumer.vscode-eslint", "esbenp.prettier-vscode"],
9 | "settings": {
10 | "editor.formatOnSave": true,
11 | "editor.defaultFormatter": "esbenp.prettier-vscode"
12 | }
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 | .yarn/install-state.gz
8 |
9 | # testing
10 | /coverage
11 |
12 | # next.js
13 | /.next/
14 | /out/
15 |
16 | # production
17 | /build
18 |
19 | # misc
20 | .DS_Store
21 | *.pem
22 |
23 | # debug
24 | npm-debug.log*
25 | yarn-debug.log*
26 | yarn-error.log*
27 |
28 | # local env files
29 | .env*.local
30 |
31 | # vercel
32 | .vercel
33 |
34 | # typescript
35 | *.tsbuildinfo
36 | next-env.d.ts
37 |
--------------------------------------------------------------------------------
/tailwind.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('tailwindcss').Config} */
2 | module.exports = {
3 | content: [
4 | './pages/**/*.{js,ts,jsx,tsx,mdx}',
5 | './components/**/*.{js,ts,jsx,tsx,mdx}',
6 | './app/**/*.{js,ts,jsx,tsx,mdx}',
7 | ],
8 | theme: {
9 | extend: {
10 | backgroundImage: {
11 | 'gradient-radial': 'radial-gradient(var(--tw-gradient-stops))',
12 | 'gradient-conic':
13 | 'conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))',
14 | },
15 | },
16 | },
17 | plugins: [require('@tailwindcss/typography')],
18 | }
19 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "typescript.tsdk": "node_modules/typescript/lib",
3 | "typescript.enablePromptUseWorkspaceTsdk": false,
4 | "editor.tabSize": 2,
5 | "editor.rulers": [80],
6 | "editor.defaultFormatter": "esbenp.prettier-vscode",
7 | "editor.formatOnSave": true,
8 | "terminal.integrated.scrollback": 100000,
9 | "editor.codeActionsOnSave": {
10 | "source.fixAll.eslint": "explicit"
11 | },
12 | "githubPullRequests.remotes": ["origin"],
13 | "files.autoSave": "off",
14 | "files.associations": {
15 | "*.xml": "html",
16 | "*.svg": "html"
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/.prettierrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "plugins": ["@trivago/prettier-plugin-sort-imports"],
3 | "semi": false,
4 | "trailingComma": "es5",
5 | "singleQuote": true,
6 | "printWidth": 80,
7 | "tabWidth": 2,
8 | "useTabs": false,
9 | "bracketSpacing": true,
10 | "bracketSameLine": false,
11 | "arrowParens": "always",
12 | "importOrder": [
13 | ".css$",
14 | "^core-js-pure",
15 | "^jest",
16 | "^@/styles",
17 | "^dotenv",
18 | "^react",
19 | "^react-*",
20 | "^next/*",
21 | "^@/",
22 | "^:/",
23 | "^#/",
24 | "^[./]",
25 | "^@",
26 | "^."
27 | ],
28 | "importOrderSeparation": true,
29 | "importOrderSortSpecifiers": true
30 | }
31 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "lib": ["dom", "dom.iterable", "esnext"],
4 | "allowJs": true,
5 | "skipLibCheck": true,
6 | "strict": true,
7 | "noEmit": true,
8 | "esModuleInterop": true,
9 | "module": "esnext",
10 | "moduleResolution": "bundler",
11 | "resolveJsonModule": true,
12 | "isolatedModules": true,
13 | "jsx": "preserve",
14 | "incremental": true,
15 | "plugins": [
16 | {
17 | "name": "next"
18 | }
19 | ],
20 | "paths": {
21 | "@/*": ["./*"]
22 | }
23 | },
24 | "include": [
25 | "next-env.d.ts",
26 | "**/*.ts",
27 | "**/*.tsx",
28 | ".next/types/**/*.ts",
29 | "app/page.js"
30 | ],
31 | "exclude": ["node_modules"]
32 | }
33 |
--------------------------------------------------------------------------------
/app/page.js:
--------------------------------------------------------------------------------
1 | import { complete } from '@/actions/conversation'
2 | import ChatArea from '@/components/ChatArea'
3 | import Footer from '@/components/Footer'
4 | import '@/components/functions'
5 |
6 | import ConversationManager from '@chatbotkit/react/components/ConversationManager'
7 |
8 | export default function Page() {
9 | return (
10 |
11 |
12 |
13 | Please use the area below to book an appointment with me. My
14 | intelligent assistant will help you with selecting the right time and
15 | date for your appointment.
16 |
17 |
18 |
19 |
20 |
21 | )
22 | }
23 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "example-nextjs-calendar-bot",
3 | "version": "0.1.0",
4 | "private": true,
5 | "license": "MIT",
6 | "scripts": {
7 | "dev": "next dev",
8 | "build": "next build",
9 | "start": "next start",
10 | "lint": "next lint",
11 | "format": "prettier --write ."
12 | },
13 | "dependencies": {
14 | "@chatbotkit/react": "^1.8.2",
15 | "@chatbotkit/sdk": "^1.8.0",
16 | "clsx": "^2.1.0",
17 | "next": "14.1.4",
18 | "react": "^18",
19 | "react-dom": "^18"
20 | },
21 | "devDependencies": {
22 | "@tailwindcss/typography": "^0.5.12",
23 | "@trivago/prettier-plugin-sort-imports": "^4.3.0",
24 | "@types/node": "20.11.30",
25 | "autoprefixer": "^10.0.1",
26 | "eslint": "^8",
27 | "eslint-config-next": "14.1.4",
28 | "postcss": "^8",
29 | "prettier": "^3.2.5",
30 | "tailwindcss": "^3.3.0",
31 | "typescript": "^5.4.3"
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/components/functions/SlotSelectionForm.jsx:
--------------------------------------------------------------------------------
1 | 'use client'
2 |
3 | import { useContext } from 'react'
4 |
5 | import { ConversationContext } from '@chatbotkit/react'
6 |
7 | export default function SlotSelectionForm({ slots }) {
8 | const { request } = useContext(ConversationContext)
9 |
10 | function captureSlot(slot) {
11 | request('captureSlot', { slot })
12 | }
13 |
14 | return (
15 |
16 |
17 | Please select an available slot to book an appointment:
18 |
19 |
32 |
33 | )
34 | }
35 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2024 ChatBotKit
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/components/Footer.jsx:
--------------------------------------------------------------------------------
1 | export default function Footer() {
2 | return (
3 |
36 | )
37 | }
38 |
--------------------------------------------------------------------------------
/components/functions/CaptureDetailsForm.jsx:
--------------------------------------------------------------------------------
1 | 'use client'
2 |
3 | import { useContext } from 'react'
4 |
5 | import { ConversationContext } from '@chatbotkit/react'
6 |
7 | export default function CaptureDetailsForm({ events }) {
8 | const { request } = useContext(ConversationContext)
9 |
10 | function captureDetails(event) {
11 | request('captureDetails', {
12 | name: event.target.form.name.value,
13 | email: event.target.form.email.value,
14 | })
15 | }
16 |
17 | return (
18 |
19 |
20 | Please provide your name and email to book an appointment:
21 |
22 |
47 |
48 | )
49 | }
50 |
--------------------------------------------------------------------------------
/components/ChatArea.jsx:
--------------------------------------------------------------------------------
1 | 'use client'
2 |
3 | import { useContext } from 'react'
4 |
5 | import { ChatInput, ChatMessage, ConversationContext } from '@chatbotkit/react'
6 |
7 | import clsx from 'clsx'
8 |
9 | export function UserMessage({ text, children, ...props }) {
10 | return (
11 |
12 | {text ? (
13 |
17 | ) : null}
18 | {children}
19 |
20 | )
21 | }
22 |
23 | export function BotMessage({ text, children, ...props }) {
24 | return (
25 |
26 | {text ? (
27 |
31 | ) : null}
32 | {children}
33 |
34 | )
35 | }
36 |
37 | export default function ChatArea() {
38 | const {
39 | thinking,
40 |
41 | text,
42 | setText,
43 |
44 | message,
45 | messages,
46 |
47 | submit,
48 | } = useContext(ConversationContext)
49 |
50 | return (
51 |
52 | {messages.length ? (
53 |
54 | {messages
55 | .filter(({ type }) => ['user', 'bot'].includes(type))
56 | .map(({ id, type, text, children }, index, messages) => {
57 | const disableInteractivity = index < messages.length - 1
58 |
59 | switch (type) {
60 | case 'user':
61 | return
62 |
63 | case 'bot':
64 | return (
65 |
66 | {children ? (
67 |
76 | {children}
77 |
78 | ) : null}
79 |
80 | )
81 | }
82 | })}
83 | {message ?
: null}
84 | {thinking ?
: null}
85 |
86 | ) : null}
87 |
setText(e.target.value)}
91 | onSubmit={submit}
92 | placeholder="Your message..."
93 | />
94 |
95 | )
96 | }
97 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://chatbotkit-example-calendar-bot.vercel.app)
2 |
3 | # Appointment Scheduling Bot
4 |
5 | This repository contains the code for an appointment scheduling chatbot designed to assist in managing calendar bookings. The chatbot, built with the ChatBotKit SDK, facilitates the booking of appointments following specific rules and guidelines to ensure an efficient and conflict-free scheduling process.
6 |
7 | https://github.com/chatbotkit/example-nextjs-calendar-bot/assets/5363404/3aaf362f-3dc4-4b11-93dd-f14248309059
8 |
9 | ## Features
10 |
11 | - **Appointment Scheduling**: Users can schedule appointments within predefined time slots, ensuring adherence to the specified availability and rules set for Dr. Smith.
12 | - **Dynamic Calendar Handling**: The chatbot integrates a calendar system that lists available slots and manages bookings dynamically.
13 | User Interaction: Through UI components, the chatbot captures user details and appointment preferences, providing a seamless booking experience.
14 |
15 | ## Technology Stack
16 |
17 | - **ChatBotKit SDK**: For building the chatbot logic and handling conversation flow.
18 | - **React**: For UI components that interact with the user, such as forms for capturing appointment details and slot selection.
19 |
20 | ## Setup
21 |
22 | 1. Ensure you have Node.js installed.
23 | 2. Clone this repository.
24 | 3. Install dependencies by running npm install.
25 | 4. Set the `CHATBOTKIT_API_SECRET` environment variable with your ChatBotKit API secret.
26 | 5. Optionally, set the `CHATBOTKIT_MODEL` environment variable to specify the model used for conversation (default is GPT-3.5 Turbo).
27 |
28 | ## Usage
29 |
30 | Run the development server:
31 |
32 | ```bash
33 | npm run dev
34 | ```
35 |
36 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
37 |
38 | The system will automatically handle appointment bookings based on the following rules:
39 |
40 | - Appointments can only be booked between 11 am and 5 pm.
41 | - Dr. Smith must have at least 30 minutes between appointments.
42 | - A maximum of 3 appointments per day, 5 per week, and 10 per month is enforced.
43 | - Each appointment lasts 30 minutes.
44 | - Appointments can be booked up to a month in advance.
45 |
46 | The chatbot uses several custom functions to interact with the user, fetch calendar events, show available slots, and capture booking details. These include:
47 |
48 | - **getCalendarEvents**: Fetches current calendar events.
49 | - **showSlotSelectionForm**: Displays a form for slot selection.
50 | - **captureSlot**: Captures the selected slot for booking.
51 | - **showContactDetailsForm**: Displays a form to capture user contact details.
52 | - **captureDetails**: Captures the name and email of the person booking the appointment.
53 | - **bookAppointment**: Finalizes the booking and updates the calendar.
54 |
55 | ## Learn More
56 |
57 | To learn more about ChatBotKit and relevent SDKs look at the following resources:
58 |
59 | - [ChatBotKit Documentation](https://chatbotkit.com/docs) - learn about ChatBotKit
60 | - [ChatBotKit JavaScript SDKs](https://github.com/chatbotkit/node-sdk) - learn about used SDKs
61 |
62 | ## Deployment
63 |
64 | The easiest way to deploy this Next.js app is to use the [Vercel Platform](https://vercel.com).
65 |
66 | ## Contributing
67 |
68 | Contributions to enhance the chatbot's functionality or address issues are welcome. Please follow the standard pull request process for contributions.
69 |
70 | ## License
71 |
72 | This project is licensed under the MIT License - see the LICENSE file for details.
73 |
--------------------------------------------------------------------------------
/actions/conversation.jsx:
--------------------------------------------------------------------------------
1 | 'use server'
2 |
3 | import CaptureDetailsForm from '@/components/functions/CaptureDetailsForm'
4 | import SlowSelectionForm from '@/components/functions/SlotSelectionForm'
5 |
6 | import { streamComplete } from '@chatbotkit/react/actions/complete'
7 | import { ChatBotKit } from '@chatbotkit/sdk'
8 |
9 | const cbk = new ChatBotKit({
10 | secret: process.env.CHATBOTKIT_API_SECRET,
11 | })
12 |
13 | const calendar = [
14 | { id: 1, date: '2024-03-01', time: '11:00', duration: 60 },
15 | { id: 2, date: '2024-03-02', time: '14:00', duration: 30 },
16 | { id: 3, date: '2024-03-03', time: '15:00', duration: 45 },
17 | { id: 4, date: '2024-03-04', time: '16:00', duration: 30 },
18 | { id: 5, date: '2024-03-05', time: '17:00', duration: 60 },
19 | ]
20 |
21 | export async function complete({ messages }) {
22 | return streamComplete({
23 | client: cbk.conversation,
24 |
25 | // The backstory is the heart of the conversation. It provides the context
26 | // and rules for the conversational AI agent to follow. In this example, the
27 | // backstory is a simple appointment booking system for a virtual assistant.
28 |
29 | backstory: `You are a virtual assistant that help with managing calendar bookings with Dr. Smith.
30 |
31 | Today's date is 2024-03-01.
32 |
33 | RULES:
34 | - Always great the user by explaining your purpose.
35 | - Only book appointments between 11am and 5pm.
36 | - Ensure that Dr. Smith has at least 30 minutes between appointments.
37 | - Dr. Smith can only have a maximum of 3 appointments per day.
38 | - Dr. Smith can only have a maximum of 5 appointments per week.
39 | - Dr. Smith can only have a maximum of 10 appointments per month.
40 | - Each appointment is 30 minutes long.
41 | - Only show up-to 4 available slots at a time.
42 | - You can only book appointments 1 month in advance.
43 | - Do not disclose Dr. Smith's calendar to the user, only show available slots.
44 | - Be brief and to the point.
45 | - Do not ask for unnecessary information or repeat yourself.
46 |
47 | STEPS:
48 | 1. Great the user by explaining your purpose if you haven't done so already.
49 | 2. Try to find a suitable slot for booking an appointment.
50 | - Use the getCalendar function to get a list of the current calendar events.
51 | - Describe the calendar events to the user.
52 | - Use the showSlotSelectionForm function to show available slots for booking an appointment.
53 | 3. Ensure that the new appointment is within the rules.
54 | 4. Capture the name and email of the person booking the appointment with the capture details form.
55 | 5. Finally book the appointment.
56 | 6. Explain the appointment details to the user.
57 | 7. Warn that a confirmation email will be sent to the user.
58 |
59 | You have acccess to a number of UI functions to help you with getting information from the user. These function start with the prefix "show". The UI functions will display and interactive form to the user where user input is expected. Akways use these functions to get the required information from the user.
60 |
61 | Failure to follow these rules will result in a decline of the appointment and customer dissatisfaction.`,
62 |
63 | // We allow configuration of the model to be used for the conversation by
64 | // setting the CHATBOTKIT_MODEL environment variable. The default model is
65 | // GPT-3.5 Turbo.
66 |
67 | model: process.env.CHATBOTKIT_MODEL || 'gpt-3.5-turbo',
68 |
69 | // Pass the messages to the conversation.
70 |
71 | messages,
72 |
73 | // Pass a list of functions that the AI agent can call to interact with.
74 |
75 | functions: [
76 | // This function will be called to get a list of the current calendar events.
77 | {
78 | name: 'getCalendarEvents',
79 | description: 'Get a list of the current calendar events.',
80 | parameters: {},
81 | handler: async () => {
82 | return {
83 | result: {
84 | status: 'success',
85 | data: {
86 | calendar,
87 | },
88 | },
89 | }
90 | },
91 | },
92 |
93 | // This function will be called to show available slots for booking an appointment.
94 | {
95 | name: 'showSlotSelectionForm',
96 | description: 'Show slots selection form for booking an appointment.',
97 | parameters: {
98 | type: 'object',
99 | properties: {
100 | slots: {
101 | type: 'array',
102 | items: {
103 | type: 'object',
104 | properties: {
105 | slot: {
106 | type: 'string',
107 | description:
108 | 'A string representing the day plus time and duration of the slot. The day can be the day of the week (Monday to Friday) or date if the appointment is in the future. For example, "Monday 11:00 - 11:30" or "March 20th 11:00 - 11:30".',
109 | },
110 | },
111 | required: ['slot'],
112 | },
113 | },
114 | },
115 | required: ['slots'],
116 | },
117 | handler: async ({ slots }, { controllers }) => {
118 | controllers.continuation.abort()
119 |
120 | return {
121 | children: , // MAGIC
122 | result: {
123 | status: 'waiting for user input',
124 | },
125 | }
126 | },
127 | },
128 |
129 | // This function will be called to capture the slot for booking an appointment.
130 | {
131 | name: 'captureSlot',
132 | description: 'Capture the slot for booking an appointment.',
133 | parameters: {
134 | type: 'object',
135 | properties: {
136 | slot: {
137 | type: 'string',
138 | description:
139 | 'A string representing the day plus time and duration of the slot. The day can be the day of the week (Monday to Friday) or date if the appointment is in the future. For example, "Monday 11:00 - 11:30" or "March 20th 11:00 - 11:30".',
140 | },
141 | },
142 | required: ['date', 'time', 'duration'],
143 | },
144 | handler: async ({ slot }) => {
145 | return {
146 | result: {
147 | status: slot ? 'success' : 'failure',
148 | data: {
149 | slot,
150 | },
151 | },
152 | }
153 | },
154 | },
155 |
156 | // This function will be called to show a form to capture the name and email of the person booking the appointment.
157 | {
158 | name: 'showContactDetailsForm',
159 | description:
160 | 'Shows a form to capture the name and email of the person booking the appointment.',
161 | parameters: {},
162 | handler: async (_, { controllers }) => {
163 | controllers.continuation.abort()
164 |
165 | return {
166 | children: , // MAGIC
167 | result: {
168 | status: 'waiting for user input',
169 | },
170 | }
171 | },
172 | },
173 |
174 | // This function will be called to capture the name and email of the person booking the appointment.
175 | {
176 | name: 'captureDetails',
177 | description:
178 | 'Capture the name and email of the person booking the appointment.',
179 | parameters: {
180 | type: 'object',
181 | properties: {
182 | name: {
183 | type: 'string',
184 | },
185 | email: {
186 | type: 'string',
187 | },
188 | },
189 | required: ['name', 'email'],
190 | },
191 | handler: async ({ name, email }) => {
192 | return {
193 | result: {
194 | status: name && email ? 'success' : 'failure',
195 | data: {
196 | name,
197 | email,
198 | },
199 | },
200 | }
201 | },
202 | },
203 |
204 | // This is the final function that will be called to book the appointment.
205 | {
206 | name: 'bookAppointment',
207 | description: 'Book the appointment.',
208 | parameters: {
209 | type: 'object',
210 | properties: {
211 | date: {
212 | type: 'string',
213 | },
214 | time: {
215 | type: 'string',
216 | },
217 | duration: {
218 | type: 'number',
219 | },
220 | name: {
221 | type: 'string',
222 | },
223 | email: {
224 | type: 'string',
225 | },
226 | },
227 | required: ['date', 'time', 'duration', 'name', 'email'],
228 | },
229 | handler: async ({ date, time, duration, name, email }) => {
230 | calendar.push({ id: calendar.length + 1, date, time, duration })
231 |
232 | return {
233 | result: {
234 | status: 'success',
235 | data: {
236 | date,
237 | time,
238 | duration,
239 | },
240 | },
241 | }
242 | },
243 | },
244 | ],
245 | })
246 | }
247 |
--------------------------------------------------------------------------------