chat 4.13.1 → 4.13.2
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 +19 -31
- package/dist/{chunk-WKJEG4FE.js → chunk-THM4ACIE.js} +12 -4
- package/dist/chunk-THM4ACIE.js.map +1 -0
- package/dist/index.d.ts +409 -415
- package/dist/index.js +63 -29
- package/dist/index.js.map +1 -1
- package/dist/{jsx-runtime-COVsDskT.d.ts → jsx-runtime-Bdt1Dwzf.d.ts} +71 -71
- package/dist/jsx-runtime.d.ts +1 -1
- package/dist/jsx-runtime.js +1 -1
- package/docs/actions.mdx +98 -0
- package/docs/adapters/discord.mdx +217 -0
- package/docs/adapters/gchat.mdx +232 -0
- package/docs/adapters/github.mdx +225 -0
- package/docs/adapters/index.mdx +110 -0
- package/docs/adapters/linear.mdx +207 -0
- package/docs/adapters/meta.json +12 -0
- package/docs/adapters/slack.mdx +293 -0
- package/docs/adapters/teams.mdx +225 -0
- package/docs/api/cards.mdx +217 -0
- package/docs/api/channel.mdx +176 -0
- package/docs/api/chat.mdx +469 -0
- package/docs/api/index.mdx +29 -0
- package/docs/api/markdown.mdx +235 -0
- package/docs/api/message.mdx +163 -0
- package/docs/api/meta.json +14 -0
- package/docs/api/modals.mdx +222 -0
- package/docs/api/postable-message.mdx +166 -0
- package/docs/api/thread.mdx +186 -0
- package/docs/cards.mdx +213 -0
- package/docs/direct-messages.mdx +56 -0
- package/docs/emoji.mdx +77 -0
- package/docs/ephemeral-messages.mdx +77 -0
- package/docs/error-handling.mdx +147 -0
- package/docs/files.mdx +77 -0
- package/docs/getting-started.mdx +12 -0
- package/docs/guides/code-review-hono.mdx +248 -0
- package/docs/guides/discord-nuxt.mdx +237 -0
- package/docs/guides/meta.json +4 -0
- package/docs/guides/slack-nextjs.mdx +245 -0
- package/docs/index.mdx +92 -0
- package/docs/meta.json +20 -0
- package/docs/modals.mdx +208 -0
- package/docs/posting-messages.mdx +177 -0
- package/docs/slash-commands.mdx +110 -0
- package/docs/state/index.mdx +31 -0
- package/docs/state/ioredis.mdx +81 -0
- package/docs/state/memory.mdx +52 -0
- package/docs/state/meta.json +9 -0
- package/docs/state/redis.mdx +93 -0
- package/docs/streaming.mdx +99 -0
- package/docs/usage.mdx +338 -0
- package/package.json +10 -10
- package/dist/chunk-WKJEG4FE.js.map +0 -1
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Discord support bot with Nuxt and Redis
|
|
3
|
+
description: This guide walks through building a Discord support bot with Nuxt, covering project setup, Discord app configuration, Gateway forwarding, AI-powered responses, and deployment.
|
|
4
|
+
type: guide
|
|
5
|
+
prerequisites: []
|
|
6
|
+
related:
|
|
7
|
+
- /docs/adapters/discord
|
|
8
|
+
- /docs/cards
|
|
9
|
+
- /docs/actions
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Prerequisites
|
|
13
|
+
|
|
14
|
+
- Node.js 18+
|
|
15
|
+
- [pnpm](https://pnpm.io) (or npm/yarn)
|
|
16
|
+
- A Discord server where you have admin access
|
|
17
|
+
- A Redis instance for state management
|
|
18
|
+
|
|
19
|
+
## Create a Nuxt app
|
|
20
|
+
|
|
21
|
+
Scaffold a new Nuxt project and install Chat SDK dependencies:
|
|
22
|
+
|
|
23
|
+
```sh title="Terminal"
|
|
24
|
+
npx nuxi@latest init my-discord-bot
|
|
25
|
+
cd my-discord-bot
|
|
26
|
+
pnpm add chat @chat-adapter/discord @chat-adapter/state-redis ai @ai-sdk/anthropic
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Create a Discord app
|
|
30
|
+
|
|
31
|
+
1. Go to [discord.com/developers/applications](https://discord.com/developers/applications)
|
|
32
|
+
2. Click **New Application**, give it a name, and click **Create**
|
|
33
|
+
3. Go to **Bot** in the sidebar and click **Reset Token** — copy the token, you'll need this as `DISCORD_BOT_TOKEN`
|
|
34
|
+
4. Under **Privileged Gateway Intents**, enable **Message Content Intent**
|
|
35
|
+
5. Go to **General Information** and copy the **Application ID** and **Public Key** — you'll need these as `DISCORD_APPLICATION_ID` and `DISCORD_PUBLIC_KEY`
|
|
36
|
+
|
|
37
|
+
### Set up the Interactions endpoint
|
|
38
|
+
|
|
39
|
+
1. In **General Information**, set the **Interactions Endpoint URL** to `https://your-domain.com/api/webhooks/discord`
|
|
40
|
+
2. Discord will send a PING to verify the endpoint — you'll need to deploy first or use a tunnel
|
|
41
|
+
|
|
42
|
+
### Invite the bot to your server
|
|
43
|
+
|
|
44
|
+
1. Go to **OAuth2** in the sidebar
|
|
45
|
+
2. Under **OAuth2 URL Generator**, select the `bot` scope
|
|
46
|
+
3. Under **Bot Permissions**, select:
|
|
47
|
+
- Send Messages
|
|
48
|
+
- Create Public Threads
|
|
49
|
+
- Send Messages in Threads
|
|
50
|
+
- Read Message History
|
|
51
|
+
- Add Reactions
|
|
52
|
+
- Use Slash Commands
|
|
53
|
+
4. Copy the generated URL and open it in your browser to invite the bot
|
|
54
|
+
|
|
55
|
+
## Configure environment variables
|
|
56
|
+
|
|
57
|
+
Create a `.env` file in your project root:
|
|
58
|
+
|
|
59
|
+
```bash title=".env"
|
|
60
|
+
DISCORD_BOT_TOKEN=your_bot_token
|
|
61
|
+
DISCORD_PUBLIC_KEY=your_public_key
|
|
62
|
+
DISCORD_APPLICATION_ID=your_application_id
|
|
63
|
+
REDIS_URL=redis://localhost:6379
|
|
64
|
+
ANTHROPIC_API_KEY=your_anthropic_api_key
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Create the bot
|
|
68
|
+
|
|
69
|
+
Create `server/lib/bot.ts` with a `Chat` instance configured with the Discord adapter. This bot uses AI SDK to answer support questions:
|
|
70
|
+
|
|
71
|
+
```typescript title="server/lib/bot.tsx" lineNumbers
|
|
72
|
+
import { Chat, ConsoleLogger, Card, CardText as Text, Actions, Button, Divider } from "chat";
|
|
73
|
+
import { createDiscordAdapter } from "@chat-adapter/discord";
|
|
74
|
+
import { createRedisState } from "@chat-adapter/state-redis";
|
|
75
|
+
import { generateText } from "ai";
|
|
76
|
+
import { anthropic } from "@ai-sdk/anthropic";
|
|
77
|
+
|
|
78
|
+
const logger = new ConsoleLogger();
|
|
79
|
+
|
|
80
|
+
export const bot = new Chat({
|
|
81
|
+
userName: "support-bot",
|
|
82
|
+
adapters: {
|
|
83
|
+
discord: createDiscordAdapter({
|
|
84
|
+
botToken: process.env.DISCORD_BOT_TOKEN!,
|
|
85
|
+
publicKey: process.env.DISCORD_PUBLIC_KEY!,
|
|
86
|
+
applicationId: process.env.DISCORD_APPLICATION_ID!,
|
|
87
|
+
logger,
|
|
88
|
+
}),
|
|
89
|
+
},
|
|
90
|
+
state: createRedisState({
|
|
91
|
+
url: process.env.REDIS_URL!,
|
|
92
|
+
logger,
|
|
93
|
+
}),
|
|
94
|
+
logger,
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
bot.onNewMention(async (thread) => {
|
|
98
|
+
await thread.subscribe();
|
|
99
|
+
await thread.post(
|
|
100
|
+
<Card title="Support">
|
|
101
|
+
<Text>Hey! I'm here to help. Ask your question in this thread and I'll do my best to answer it.</Text>
|
|
102
|
+
<Divider />
|
|
103
|
+
<Actions>
|
|
104
|
+
<Button id="escalate" style="danger">Escalate to Human</Button>
|
|
105
|
+
</Actions>
|
|
106
|
+
</Card>
|
|
107
|
+
);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
bot.onSubscribedMessage(async (thread, message) => {
|
|
111
|
+
await thread.startTyping();
|
|
112
|
+
|
|
113
|
+
const { text } = await generateText({
|
|
114
|
+
model: anthropic("claude-sonnet-4-5-20250514"),
|
|
115
|
+
system: "You are a friendly support bot. Answer questions concisely. If you don't know the answer, say so and suggest the user click 'Escalate to Human'.",
|
|
116
|
+
prompt: message.text,
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
await thread.post(text);
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
bot.onAction("escalate", async (event) => {
|
|
123
|
+
await event.thread.post(
|
|
124
|
+
`${event.user.fullName} requested human support. A team member will follow up shortly.`
|
|
125
|
+
);
|
|
126
|
+
});
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
<Callout type="info">
|
|
130
|
+
The file extension must be `.tsx` (not `.ts`) when using JSX components like `Card` and `Button`. Make sure your `tsconfig.json` has `"jsx": "react-jsx"` and `"jsxImportSource": "chat"`.
|
|
131
|
+
</Callout>
|
|
132
|
+
|
|
133
|
+
`onNewMention` fires when a user @mentions the bot. Calling `thread.subscribe()` tells the SDK to track that thread, so subsequent messages trigger `onSubscribedMessage` where AI SDK generates a response.
|
|
134
|
+
|
|
135
|
+
## Create the webhook route
|
|
136
|
+
|
|
137
|
+
Create a server route that handles incoming Discord webhooks:
|
|
138
|
+
|
|
139
|
+
```typescript title="server/api/webhooks/[platform].post.ts" lineNumbers
|
|
140
|
+
import { bot } from "../lib/bot";
|
|
141
|
+
|
|
142
|
+
type Platform = keyof typeof bot.webhooks;
|
|
143
|
+
|
|
144
|
+
export default defineEventHandler(async (event) => {
|
|
145
|
+
const platform = getRouterParam(event, "platform") as Platform;
|
|
146
|
+
|
|
147
|
+
const handler = bot.webhooks[platform];
|
|
148
|
+
if (!handler) {
|
|
149
|
+
throw createError({ statusCode: 404, message: `Unknown platform: ${platform}` });
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const request = toWebRequest(event);
|
|
153
|
+
|
|
154
|
+
return handler(request, {
|
|
155
|
+
waitUntil: (task) => event.waitUntil(task),
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
This creates a `POST /api/webhooks/discord` endpoint. The `waitUntil` option ensures message processing completes after the HTTP response is sent.
|
|
161
|
+
|
|
162
|
+
## Set up the Gateway forwarder
|
|
163
|
+
|
|
164
|
+
Discord doesn't push messages to webhooks like Slack does. Instead, messages arrive through the Gateway WebSocket. The Discord adapter includes a built-in Gateway listener that connects to the WebSocket and forwards events to your webhook endpoint.
|
|
165
|
+
|
|
166
|
+
Create a route that starts the Gateway listener:
|
|
167
|
+
|
|
168
|
+
```typescript title="server/api/discord/gateway.get.ts" lineNumbers
|
|
169
|
+
import { bot } from "../../lib/bot";
|
|
170
|
+
|
|
171
|
+
export default defineEventHandler(async (event) => {
|
|
172
|
+
await bot.initialize();
|
|
173
|
+
|
|
174
|
+
const discord = bot.getAdapter("discord");
|
|
175
|
+
if (!discord) {
|
|
176
|
+
throw createError({ statusCode: 404, message: "Discord adapter not configured" });
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
const baseUrl = process.env.NUXT_PUBLIC_SITE_URL || "http://localhost:3000";
|
|
180
|
+
const webhookUrl = `${baseUrl}/api/webhooks/discord`;
|
|
181
|
+
|
|
182
|
+
const durationMs = 10 * 60 * 1000; // 10 minutes
|
|
183
|
+
|
|
184
|
+
return discord.startGatewayListener(
|
|
185
|
+
{ waitUntil: (task: Promise<unknown>) => event.waitUntil(task) },
|
|
186
|
+
durationMs,
|
|
187
|
+
undefined,
|
|
188
|
+
webhookUrl,
|
|
189
|
+
);
|
|
190
|
+
});
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
The Gateway listener connects to Discord's WebSocket, receives messages, and forwards them to your webhook endpoint for processing. In production, you'll want a cron job to restart it periodically.
|
|
194
|
+
|
|
195
|
+
## Test locally
|
|
196
|
+
|
|
197
|
+
1. Start your development server (`pnpm dev`)
|
|
198
|
+
2. Trigger the Gateway listener by visiting `http://localhost:3000/api/discord/gateway` in your browser
|
|
199
|
+
3. Expose your server with a tunnel (e.g. `ngrok http 3000`)
|
|
200
|
+
4. Update the **Interactions Endpoint URL** in your Discord app settings to your tunnel URL (e.g. `https://abc123.ngrok.io/api/webhooks/discord`)
|
|
201
|
+
5. @mention the bot in your Discord server — it should respond with a support card
|
|
202
|
+
6. Reply in the thread — AI SDK should generate a response
|
|
203
|
+
7. Click **Escalate to Human** — the bot should post an escalation message
|
|
204
|
+
|
|
205
|
+
## Add a cron job for production
|
|
206
|
+
|
|
207
|
+
The Gateway listener runs for a fixed duration. In production, set up a cron job to restart it automatically. If you're deploying to Vercel, add a `vercel.json`:
|
|
208
|
+
|
|
209
|
+
```json title="vercel.json"
|
|
210
|
+
{
|
|
211
|
+
"crons": [
|
|
212
|
+
{
|
|
213
|
+
"path": "/api/discord/gateway",
|
|
214
|
+
"schedule": "*/9 * * * *"
|
|
215
|
+
}
|
|
216
|
+
]
|
|
217
|
+
}
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
This restarts the Gateway listener every 9 minutes, ensuring continuous connectivity. Protect the endpoint with a `CRON_SECRET` environment variable in production.
|
|
221
|
+
|
|
222
|
+
## Deploy to Vercel
|
|
223
|
+
|
|
224
|
+
Deploy your bot to Vercel:
|
|
225
|
+
|
|
226
|
+
```sh title="Terminal"
|
|
227
|
+
vercel deploy
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
After deployment, set your environment variables in the Vercel dashboard (`DISCORD_BOT_TOKEN`, `DISCORD_PUBLIC_KEY`, `DISCORD_APPLICATION_ID`, `REDIS_URL`, `ANTHROPIC_API_KEY`). Update the **Interactions Endpoint URL** in your Discord app settings to your production URL.
|
|
231
|
+
|
|
232
|
+
## Next steps
|
|
233
|
+
|
|
234
|
+
- [Cards](/docs/cards) — Build rich interactive messages with buttons, fields, and selects
|
|
235
|
+
- [Actions](/docs/actions) — Handle button clicks, select menus, and other interactions
|
|
236
|
+
- [Streaming](/docs/streaming) — Stream AI-generated responses to chat
|
|
237
|
+
- [Discord adapter](/docs/adapters/discord) — Full configuration reference and Gateway setup
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Slack bot with Next.js and Redis
|
|
3
|
+
description: This guide walks through building a Slack bot with Next.js, covering project setup, Slack app configuration, event handling, interactive features, and deployment.
|
|
4
|
+
type: guide
|
|
5
|
+
prerequisites: []
|
|
6
|
+
related:
|
|
7
|
+
- /docs/adapters/slack
|
|
8
|
+
- /docs/cards
|
|
9
|
+
- /docs/modals
|
|
10
|
+
- /docs/streaming
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Prerequisites
|
|
14
|
+
|
|
15
|
+
- Node.js 18+
|
|
16
|
+
- [pnpm](https://pnpm.io) (or npm/yarn)
|
|
17
|
+
- A Slack workspace where you can install apps
|
|
18
|
+
- A Redis instance for state management
|
|
19
|
+
|
|
20
|
+
## Create a Next.js app
|
|
21
|
+
|
|
22
|
+
Scaffold a new Next.js project and install Chat SDK dependencies:
|
|
23
|
+
|
|
24
|
+
```sh title="Terminal"
|
|
25
|
+
npx create-next-app@latest my-slack-bot --typescript --app
|
|
26
|
+
cd my-slack-bot
|
|
27
|
+
pnpm add chat @chat-adapter/slack @chat-adapter/state-redis
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Create a Slack app
|
|
31
|
+
|
|
32
|
+
1. Go to [api.slack.com/apps](https://api.slack.com/apps)
|
|
33
|
+
2. Click **Create New App** then **From an app manifest**
|
|
34
|
+
3. Select your workspace and paste the following manifest:
|
|
35
|
+
|
|
36
|
+
```yaml title="slack-manifest.yml"
|
|
37
|
+
display_information:
|
|
38
|
+
name: My Bot
|
|
39
|
+
description: A bot built with Chat SDK
|
|
40
|
+
|
|
41
|
+
features:
|
|
42
|
+
bot_user:
|
|
43
|
+
display_name: My Bot
|
|
44
|
+
always_online: true
|
|
45
|
+
|
|
46
|
+
oauth_config:
|
|
47
|
+
scopes:
|
|
48
|
+
bot:
|
|
49
|
+
- app_mentions:read
|
|
50
|
+
- channels:history
|
|
51
|
+
- channels:read
|
|
52
|
+
- chat:write
|
|
53
|
+
- groups:history
|
|
54
|
+
- groups:read
|
|
55
|
+
- im:history
|
|
56
|
+
- im:read
|
|
57
|
+
- mpim:history
|
|
58
|
+
- mpim:read
|
|
59
|
+
- reactions:read
|
|
60
|
+
- reactions:write
|
|
61
|
+
- users:read
|
|
62
|
+
|
|
63
|
+
settings:
|
|
64
|
+
event_subscriptions:
|
|
65
|
+
request_url: https://your-domain.com/api/webhooks/slack
|
|
66
|
+
bot_events:
|
|
67
|
+
- app_mention
|
|
68
|
+
- message.channels
|
|
69
|
+
- message.groups
|
|
70
|
+
- message.im
|
|
71
|
+
- message.mpim
|
|
72
|
+
interactivity:
|
|
73
|
+
is_enabled: true
|
|
74
|
+
request_url: https://your-domain.com/api/webhooks/slack
|
|
75
|
+
org_deploy_enabled: false
|
|
76
|
+
socket_mode_enabled: false
|
|
77
|
+
token_rotation_enabled: false
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
4. Replace `https://your-domain.com/api/webhooks/slack` with your deployed webhook URL
|
|
81
|
+
5. Click **Create**
|
|
82
|
+
|
|
83
|
+
### Get credentials
|
|
84
|
+
|
|
85
|
+
After creating the app:
|
|
86
|
+
|
|
87
|
+
1. Go to **OAuth & Permissions**, click **Install to Workspace**, and copy the **Bot User OAuth Token** (`xoxb-...`) — you'll need this as `SLACK_BOT_TOKEN`
|
|
88
|
+
2. Go to **Basic Information** → **App Credentials** and copy the **Signing Secret** — you'll need this as `SLACK_SIGNING_SECRET`
|
|
89
|
+
|
|
90
|
+
## Configure environment variables
|
|
91
|
+
|
|
92
|
+
Create a `.env.local` file in your project root:
|
|
93
|
+
|
|
94
|
+
```bash title=".env.local"
|
|
95
|
+
SLACK_BOT_TOKEN=xoxb-your-bot-token
|
|
96
|
+
SLACK_SIGNING_SECRET=your-signing-secret
|
|
97
|
+
REDIS_URL=redis://localhost:6379
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Create the bot
|
|
101
|
+
|
|
102
|
+
Create `lib/bot.ts` with a `Chat` instance configured with the Slack adapter:
|
|
103
|
+
|
|
104
|
+
```typescript title="lib/bot.ts" lineNumbers
|
|
105
|
+
import { Chat } from "chat";
|
|
106
|
+
import { createSlackAdapter } from "@chat-adapter/slack";
|
|
107
|
+
import { createRedisState } from "@chat-adapter/state-redis";
|
|
108
|
+
|
|
109
|
+
export const bot = new Chat({
|
|
110
|
+
userName: "mybot",
|
|
111
|
+
adapters: {
|
|
112
|
+
slack: createSlackAdapter({
|
|
113
|
+
botToken: process.env.SLACK_BOT_TOKEN!,
|
|
114
|
+
signingSecret: process.env.SLACK_SIGNING_SECRET!,
|
|
115
|
+
logger: new ConsoleLogger(),
|
|
116
|
+
}),
|
|
117
|
+
},
|
|
118
|
+
state: createRedisState({
|
|
119
|
+
url: process.env.REDIS_URL!,
|
|
120
|
+
logger: new ConsoleLogger(),
|
|
121
|
+
}),
|
|
122
|
+
logger: new ConsoleLogger(),
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
// Respond when someone @mentions the bot
|
|
126
|
+
bot.onNewMention(async (thread) => {
|
|
127
|
+
await thread.subscribe();
|
|
128
|
+
await thread.post("Hello! I'm listening to this thread now.");
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
// Respond to follow-up messages in subscribed threads
|
|
132
|
+
bot.onSubscribedMessage(async (thread, message) => {
|
|
133
|
+
await thread.post(`You said: ${message.text}`);
|
|
134
|
+
});
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
`onNewMention` fires when a user @mentions your bot. Calling `thread.subscribe()` tells the SDK to track that thread, so subsequent messages trigger `onSubscribedMessage`.
|
|
138
|
+
|
|
139
|
+
## Create the webhook route
|
|
140
|
+
|
|
141
|
+
Create a dynamic API route that handles incoming webhooks:
|
|
142
|
+
|
|
143
|
+
```typescript title="app/api/webhooks/[platform]/route.ts" lineNumbers
|
|
144
|
+
import { after } from "next/server";
|
|
145
|
+
import { bot } from "@/lib/bot";
|
|
146
|
+
|
|
147
|
+
type Platform = keyof typeof bot.webhooks;
|
|
148
|
+
|
|
149
|
+
export async function POST(
|
|
150
|
+
request: Request,
|
|
151
|
+
context: RouteContext<"/api/webhooks/[platform]">
|
|
152
|
+
) {
|
|
153
|
+
const { platform } = await context.params;
|
|
154
|
+
|
|
155
|
+
const handler = bot.webhooks[platform as Platform];
|
|
156
|
+
if (!handler) {
|
|
157
|
+
return new Response(`Unknown platform: ${platform}`, { status: 404 });
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
return handler(request, {
|
|
161
|
+
waitUntil: (task) => after(() => task),
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
This creates a `POST /api/webhooks/slack` endpoint. The `waitUntil` option ensures message processing completes after the HTTP response is sent — required on serverless platforms where the function would otherwise terminate before your handlers finish.
|
|
167
|
+
|
|
168
|
+
## Test locally
|
|
169
|
+
|
|
170
|
+
1. Start your development server (`pnpm dev`)
|
|
171
|
+
2. Expose it with a tunnel (e.g. `ngrok http 3000`)
|
|
172
|
+
3. Update the Slack Event Subscriptions **Request URL** to your tunnel URL
|
|
173
|
+
4. Invite your bot to a Slack channel (`/invite @mybot`)
|
|
174
|
+
5. @mention the bot — it should respond with "Hello! I'm listening to this thread now."
|
|
175
|
+
6. Reply in the thread — it should echo your message back
|
|
176
|
+
|
|
177
|
+
## Add interactive features
|
|
178
|
+
|
|
179
|
+
Chat SDK supports rich interactive messages using a JSX-like syntax. Update your bot to send cards with buttons:
|
|
180
|
+
|
|
181
|
+
```typescript title="lib/bot.ts" lineNumbers
|
|
182
|
+
import { Chat, Card, CardText as Text, Actions, Button, Divider } from "chat";
|
|
183
|
+
import { createSlackAdapter } from "@chat-adapter/slack";
|
|
184
|
+
import { createRedisState } from "@chat-adapter/state-redis";
|
|
185
|
+
|
|
186
|
+
export const bot = new Chat({
|
|
187
|
+
userName: "mybot",
|
|
188
|
+
adapters: {
|
|
189
|
+
slack: createSlackAdapter({
|
|
190
|
+
botToken: process.env.SLACK_BOT_TOKEN!,
|
|
191
|
+
signingSecret: process.env.SLACK_SIGNING_SECRET!,
|
|
192
|
+
logger: new ConsoleLogger(),
|
|
193
|
+
}),
|
|
194
|
+
},
|
|
195
|
+
state: createRedisState({
|
|
196
|
+
url: process.env.REDIS_URL!,
|
|
197
|
+
logger: new ConsoleLogger(),
|
|
198
|
+
}),
|
|
199
|
+
logger: new ConsoleLogger(),
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
bot.onNewMention(async (thread) => {
|
|
203
|
+
await thread.subscribe();
|
|
204
|
+
await thread.post(
|
|
205
|
+
<Card title="Welcome!">
|
|
206
|
+
<Text>I'm now listening to this thread. Try clicking a button:</Text>
|
|
207
|
+
<Divider />
|
|
208
|
+
<Actions>
|
|
209
|
+
<Button id="hello" style="primary">Say Hello</Button>
|
|
210
|
+
<Button id="info">Show Info</Button>
|
|
211
|
+
</Actions>
|
|
212
|
+
</Card>
|
|
213
|
+
);
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
bot.onAction("hello", async (event) => {
|
|
217
|
+
await event.thread.post(`Hello, ${event.user.fullName}!`);
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
bot.onAction("info", async (event) => {
|
|
221
|
+
await event.thread.post(`You're on ${event.thread.adapter.name}.`);
|
|
222
|
+
});
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
<Callout type="info">
|
|
226
|
+
The file extension must be `.tsx` (not `.ts`) when using JSX components like `Card` and `Button`. Make sure your `tsconfig.json` has `"jsx": "react-jsx"` and `"jsxImportSource": "chat"`.
|
|
227
|
+
</Callout>
|
|
228
|
+
|
|
229
|
+
## Deploy to Vercel
|
|
230
|
+
|
|
231
|
+
Deploy your bot to Vercel:
|
|
232
|
+
|
|
233
|
+
```sh title="Terminal"
|
|
234
|
+
vercel deploy
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
After deployment, set your environment variables in the Vercel dashboard (`SLACK_BOT_TOKEN`, `SLACK_SIGNING_SECRET`, `REDIS_URL`). If your manifest used a placeholder URL, update the **Event Subscriptions** and **Interactivity** Request URLs in your [Slack app settings](https://api.slack.com/apps) to your production URL.
|
|
238
|
+
|
|
239
|
+
## Next steps
|
|
240
|
+
|
|
241
|
+
- [Cards](/docs/cards) — Build rich interactive messages with buttons, fields, and selects
|
|
242
|
+
- [Modals](/docs/modals) — Open forms and dialogs from button clicks
|
|
243
|
+
- [Streaming](/docs/streaming) — Stream AI-generated responses to chat
|
|
244
|
+
- [Actions](/docs/actions) — Handle button clicks, select menus, and other interactions
|
|
245
|
+
- [Slack adapter](/docs/adapters/slack) — Multi-workspace OAuth, token encryption, and full configuration reference
|
package/docs/index.mdx
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Introduction
|
|
3
|
+
description: A unified SDK for building chat bots across Slack, Microsoft Teams, Google Chat, Discord, and more.
|
|
4
|
+
type: overview
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
Chat SDK is a TypeScript library for building chat bots that work across multiple platforms with a single codebase. Write your bot logic once and deploy it to Slack, Microsoft Teams, Google Chat, Discord, GitHub, and Linear.
|
|
8
|
+
|
|
9
|
+
## Why Chat SDK?
|
|
10
|
+
|
|
11
|
+
Building a chat bot that works across multiple platforms typically means maintaining separate codebases, learning different APIs, and handling platform-specific quirks individually. Chat SDK abstracts these differences behind a unified interface.
|
|
12
|
+
|
|
13
|
+
- **Single codebase** for all platforms
|
|
14
|
+
- **Type-safe** adapters and event handlers with full TypeScript support
|
|
15
|
+
- **Event-driven** architecture with handlers for mentions, messages, reactions, button clicks, slash commands, and modals
|
|
16
|
+
- **Thread subscriptions** for multi-turn conversations
|
|
17
|
+
- **Rich UI** with JSX cards, buttons, and modals that render natively on each platform
|
|
18
|
+
- **AI streaming** with first-class support for streaming LLM responses
|
|
19
|
+
- **Serverless-ready** with distributed state via Redis and message deduplication
|
|
20
|
+
|
|
21
|
+
## How it works
|
|
22
|
+
|
|
23
|
+
Chat SDK has three core concepts:
|
|
24
|
+
|
|
25
|
+
1. **Chat** — the main entry point that coordinates adapters and routes events to your handlers
|
|
26
|
+
2. **Adapters** — platform-specific implementations that handle webhook parsing, message formatting, and API calls
|
|
27
|
+
3. **State** — a pluggable persistence layer for thread subscriptions and distributed locking
|
|
28
|
+
|
|
29
|
+
```typescript title="lib/bot.ts" lineNumbers
|
|
30
|
+
import { Chat } from "chat";
|
|
31
|
+
import { createSlackAdapter } from "@chat-adapter/slack";
|
|
32
|
+
import { createRedisState } from "@chat-adapter/state-redis";
|
|
33
|
+
|
|
34
|
+
const bot = new Chat({
|
|
35
|
+
userName: "mybot",
|
|
36
|
+
adapters: {
|
|
37
|
+
slack: createSlackAdapter({
|
|
38
|
+
botToken: process.env.SLACK_BOT_TOKEN!,
|
|
39
|
+
signingSecret: process.env.SLACK_SIGNING_SECRET!,
|
|
40
|
+
logger: new ConsoleLogger(),
|
|
41
|
+
}),
|
|
42
|
+
},
|
|
43
|
+
state: createRedisState({
|
|
44
|
+
url: process.env.REDIS_URL!,
|
|
45
|
+
logger: new ConsoleLogger(),
|
|
46
|
+
}),
|
|
47
|
+
logger: new ConsoleLogger(),
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
bot.onNewMention(async (thread) => {
|
|
51
|
+
await thread.subscribe();
|
|
52
|
+
await thread.post("Hello! I'm listening to this thread.");
|
|
53
|
+
});
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Supported platforms
|
|
57
|
+
|
|
58
|
+
| Platform | Package | Mentions | Reactions | Cards | Modals | Streaming | DMs |
|
|
59
|
+
|----------|---------|----------|-----------|-------|--------|-----------|-----|
|
|
60
|
+
| Slack | `@chat-adapter/slack` | Yes | Yes | Yes | Yes | Native | Yes |
|
|
61
|
+
| Microsoft Teams | `@chat-adapter/teams` | Yes | Read-only | Yes | No | Post+Edit | Yes |
|
|
62
|
+
| Google Chat | `@chat-adapter/gchat` | Yes | Yes | Yes | No | Post+Edit | Yes |
|
|
63
|
+
| Discord | `@chat-adapter/discord` | Yes | Yes | Yes | No | Post+Edit | Yes |
|
|
64
|
+
| GitHub | `@chat-adapter/github` | Yes | Yes | No | No | No | No |
|
|
65
|
+
| Linear | `@chat-adapter/linear` | Yes | Yes | No | No | No | No |
|
|
66
|
+
|
|
67
|
+
## AI coding agent support
|
|
68
|
+
|
|
69
|
+
If you use an AI coding agent like [Claude Code](https://docs.anthropic.com/en/docs/claude-code), you can teach it about Chat SDK by installing the skill:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
npx skills add vercel/chat
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
This gives your agent access to Chat SDK's documentation, patterns, and best practices so it can help you build bots more effectively.
|
|
76
|
+
|
|
77
|
+
## Packages
|
|
78
|
+
|
|
79
|
+
The SDK is distributed as a set of packages you install based on your needs:
|
|
80
|
+
|
|
81
|
+
| Package | Description |
|
|
82
|
+
|---------|-------------|
|
|
83
|
+
| `chat` | Core SDK with `Chat` class, types, JSX runtime, and utilities |
|
|
84
|
+
| `@chat-adapter/slack` | Slack adapter |
|
|
85
|
+
| `@chat-adapter/teams` | Microsoft Teams adapter |
|
|
86
|
+
| `@chat-adapter/gchat` | Google Chat adapter |
|
|
87
|
+
| `@chat-adapter/discord` | Discord adapter |
|
|
88
|
+
| `@chat-adapter/github` | GitHub Issues adapter |
|
|
89
|
+
| `@chat-adapter/linear` | Linear Issues adapter |
|
|
90
|
+
| `@chat-adapter/state-redis` | Redis state adapter (production) |
|
|
91
|
+
| `@chat-adapter/state-ioredis` | ioredis state adapter (alternative) |
|
|
92
|
+
| `@chat-adapter/state-memory` | In-memory state adapter (development) |
|
package/docs/meta.json
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"title": "Documentation",
|
|
3
|
+
"pages": [
|
|
4
|
+
"index",
|
|
5
|
+
"getting-started",
|
|
6
|
+
"usage",
|
|
7
|
+
"posting-messages",
|
|
8
|
+
"---Features---",
|
|
9
|
+
"...",
|
|
10
|
+
"error-handling",
|
|
11
|
+
"---Platform Adapters---",
|
|
12
|
+
"...adapters",
|
|
13
|
+
"---State Adapters---",
|
|
14
|
+
"...state",
|
|
15
|
+
"---Guides---",
|
|
16
|
+
"...guides",
|
|
17
|
+
"---API Reference---",
|
|
18
|
+
"...api"
|
|
19
|
+
]
|
|
20
|
+
}
|