chat 4.14.0 → 4.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -0
- package/dist/{chunk-THM4ACIE.js → chunk-7S5DLTN2.js} +372 -9
- package/dist/chunk-7S5DLTN2.js.map +1 -0
- package/dist/index.d.ts +122 -5
- package/dist/index.js +367 -235
- package/dist/index.js.map +1 -1
- package/dist/{jsx-runtime-Bdt1Dwzf.d.ts → jsx-runtime-Bokk9xw5.d.ts} +80 -5
- package/dist/jsx-runtime.d.ts +1 -1
- package/dist/jsx-runtime.js +3 -1
- package/docs/adapters/discord.mdx +1 -0
- package/docs/adapters/index.mdx +51 -34
- package/docs/adapters/meta.json +1 -0
- package/docs/adapters/slack.mdx +16 -0
- package/docs/adapters/telegram.mdx +161 -0
- package/docs/api/cards.mdx +57 -1
- package/docs/api/channel.mdx +4 -1
- package/docs/api/chat.mdx +5 -0
- package/docs/api/markdown.mdx +42 -0
- package/docs/api/thread.mdx +4 -1
- package/docs/cards.mdx +44 -1
- package/docs/contributing/building.mdx +626 -0
- package/docs/contributing/documenting.mdx +218 -0
- package/docs/contributing/meta.json +4 -0
- package/docs/contributing/publishing.mdx +161 -0
- package/docs/contributing/testing.mdx +494 -0
- package/docs/error-handling.mdx +1 -1
- package/docs/getting-started.mdx +23 -1
- package/docs/handling-events.mdx +375 -0
- package/docs/index.mdx +4 -2
- package/docs/meta.json +6 -1
- package/docs/posting-messages.mdx +7 -7
- package/docs/slash-commands.mdx +23 -0
- package/docs/state/meta.json +1 -6
- package/docs/streaming.mdx +32 -0
- package/docs/threads-messages-channels.mdx +237 -0
- package/docs/usage.mdx +82 -276
- package/package.json +4 -3
- package/dist/chunk-THM4ACIE.js.map +0 -1
|
@@ -0,0 +1,375 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Handling Events
|
|
3
|
+
description: Register handlers for mentions, messages, reactions, and platform-specific events.
|
|
4
|
+
type: guide
|
|
5
|
+
prerequisites:
|
|
6
|
+
- /docs/getting-started
|
|
7
|
+
related:
|
|
8
|
+
- /docs/slash-commands
|
|
9
|
+
- /docs/actions
|
|
10
|
+
- /docs/modals
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
Chat SDK uses an event-driven architecture. You register handlers for different event types, and the SDK routes incoming webhooks to the appropriate handler.
|
|
14
|
+
|
|
15
|
+
## How routing works
|
|
16
|
+
|
|
17
|
+
When a message arrives, the SDK evaluates handlers in this order:
|
|
18
|
+
|
|
19
|
+
1. **Subscribed threads** — if the thread is subscribed, `onSubscribedMessage` fires and no other message handler runs.
|
|
20
|
+
2. **Mentions** — if the bot is @-mentioned in an unsubscribed thread, `onNewMention` fires.
|
|
21
|
+
3. **Pattern matches** — if the message text matches any `onNewMessage` regex patterns, those handlers fire.
|
|
22
|
+
|
|
23
|
+
Reactions, slash commands, actions, and modals have their own dedicated routing and are not affected by subscription state.
|
|
24
|
+
|
|
25
|
+
## Handling @-mentions
|
|
26
|
+
|
|
27
|
+
`onNewMention` fires when your bot is @-mentioned in a thread it hasn't subscribed to. This is the primary entry point for new conversations.
|
|
28
|
+
|
|
29
|
+
```typescript title="lib/bot.ts" lineNumbers
|
|
30
|
+
bot.onNewMention(async (thread, message) => {
|
|
31
|
+
await thread.subscribe();
|
|
32
|
+
await thread.post("Hello! I'm now listening to this thread.");
|
|
33
|
+
});
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
The handler receives a [`Thread`](/docs/api/thread) and a [`Message`](/docs/api/message). Once you call `thread.subscribe()`, future messages in that thread route to `onSubscribedMessage` instead.
|
|
37
|
+
|
|
38
|
+
### When to use
|
|
39
|
+
|
|
40
|
+
- **AI assistants** — subscribe on first mention, then respond to all follow-up messages in the thread.
|
|
41
|
+
- **Ticket bots** — create a ticket when mentioned, then track the conversation.
|
|
42
|
+
- **One-shot commands** — respond to a mention without subscribing for bots that don't need ongoing context.
|
|
43
|
+
|
|
44
|
+
### Example: AI assistant with context
|
|
45
|
+
|
|
46
|
+
```typescript title="lib/bot.ts" lineNumbers
|
|
47
|
+
bot.onNewMention(async (thread, message) => {
|
|
48
|
+
await thread.subscribe();
|
|
49
|
+
await thread.startTyping();
|
|
50
|
+
|
|
51
|
+
const response = await generateAIResponse(message.text);
|
|
52
|
+
await thread.post(response);
|
|
53
|
+
});
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Example: Triage bot
|
|
57
|
+
|
|
58
|
+
```typescript title="lib/bot.ts" lineNumbers
|
|
59
|
+
bot.onNewMention(async (thread, message) => {
|
|
60
|
+
const ticket = await createTicket({
|
|
61
|
+
title: message.text.slice(0, 100),
|
|
62
|
+
reporter: message.author.fullName,
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
await thread.post(`Ticket created: ${ticket.url}`);
|
|
66
|
+
});
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Handling subscribed messages
|
|
70
|
+
|
|
71
|
+
`onSubscribedMessage` fires for every new message in a thread your bot has subscribed to. Once subscribed, all messages (including @-mentions) route here instead of `onNewMention`.
|
|
72
|
+
|
|
73
|
+
```typescript title="lib/bot.ts" lineNumbers
|
|
74
|
+
bot.onSubscribedMessage(async (thread, message) => {
|
|
75
|
+
if (message.isMention) {
|
|
76
|
+
await thread.post("You mentioned me!");
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
await thread.post(`Got your message: ${message.text}`);
|
|
81
|
+
});
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
<Callout type="info">
|
|
85
|
+
Messages sent by the bot itself do not trigger this handler. You don't need to filter out your own messages.
|
|
86
|
+
</Callout>
|
|
87
|
+
|
|
88
|
+
### When to use
|
|
89
|
+
|
|
90
|
+
- **Conversational AI** — maintain a back-and-forth conversation with message history.
|
|
91
|
+
- **Thread monitoring** — watch a thread for updates and react to specific keywords or patterns.
|
|
92
|
+
- **Collaborative workflows** — track all messages in a thread to update external systems.
|
|
93
|
+
|
|
94
|
+
### Example: Conversational AI with history
|
|
95
|
+
|
|
96
|
+
```typescript title="lib/bot.ts" lineNumbers
|
|
97
|
+
bot.onSubscribedMessage(async (thread, message) => {
|
|
98
|
+
await thread.startTyping();
|
|
99
|
+
|
|
100
|
+
// Build conversation history from thread messages
|
|
101
|
+
const history = [];
|
|
102
|
+
for await (const msg of thread.allMessages) {
|
|
103
|
+
history.push({
|
|
104
|
+
role: msg.author.isMe ? "assistant" : "user",
|
|
105
|
+
content: msg.text,
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const response = await generateAIResponse(history);
|
|
110
|
+
await thread.post(response);
|
|
111
|
+
});
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### Example: Unsubscribe on keyword
|
|
115
|
+
|
|
116
|
+
```typescript title="lib/bot.ts" lineNumbers
|
|
117
|
+
bot.onSubscribedMessage(async (thread, message) => {
|
|
118
|
+
if (message.text.toLowerCase().includes("stop")) {
|
|
119
|
+
await thread.unsubscribe();
|
|
120
|
+
await thread.post("Got it, I'll stop watching this thread.");
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Handle other messages...
|
|
125
|
+
});
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### Example: Thread state for multi-step flows
|
|
129
|
+
|
|
130
|
+
```typescript title="lib/bot.ts" lineNumbers
|
|
131
|
+
interface ThreadState {
|
|
132
|
+
step: "awaiting_name" | "awaiting_email" | "done";
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const bot = new Chat<typeof adapters, ThreadState>({ /* ...config */ });
|
|
136
|
+
|
|
137
|
+
bot.onNewMention(async (thread) => {
|
|
138
|
+
await thread.subscribe();
|
|
139
|
+
await thread.setState({ step: "awaiting_name" });
|
|
140
|
+
await thread.post("Let's get you set up. What's your name?");
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
bot.onSubscribedMessage(async (thread, message) => {
|
|
144
|
+
const state = await thread.state;
|
|
145
|
+
|
|
146
|
+
switch (state?.step) {
|
|
147
|
+
case "awaiting_name":
|
|
148
|
+
await thread.setState({ step: "awaiting_email" });
|
|
149
|
+
await thread.post(`Thanks, ${message.text}! What's your email?`);
|
|
150
|
+
break;
|
|
151
|
+
case "awaiting_email":
|
|
152
|
+
await thread.setState({ step: "done" });
|
|
153
|
+
await thread.post("All set! Your account has been created.");
|
|
154
|
+
await thread.unsubscribe();
|
|
155
|
+
break;
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
## Handling pattern matches
|
|
161
|
+
|
|
162
|
+
`onNewMessage` fires for messages matching a regex pattern in threads the bot is **not** subscribed to. Use it for keyword-triggered responses without requiring an @-mention.
|
|
163
|
+
|
|
164
|
+
```typescript title="lib/bot.ts" lineNumbers
|
|
165
|
+
bot.onNewMessage(/^help$/i, async (thread, message) => {
|
|
166
|
+
await thread.post("Here's how I can help...");
|
|
167
|
+
});
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
The first argument is a `RegExp` that's tested against the message text. Only messages in unsubscribed threads are evaluated.
|
|
171
|
+
|
|
172
|
+
### When to use
|
|
173
|
+
|
|
174
|
+
- **Keyword triggers** — respond to specific words or phrases without requiring a mention.
|
|
175
|
+
- **Auto-responders** — detect common questions and provide instant answers.
|
|
176
|
+
- **Escalation detection** — watch for urgent language and alert the right people.
|
|
177
|
+
|
|
178
|
+
### Example: FAQ auto-responder
|
|
179
|
+
|
|
180
|
+
```typescript title="lib/bot.ts" lineNumbers
|
|
181
|
+
bot.onNewMessage(/\b(deploy|deployment|ship)\b/i, async (thread, message) => {
|
|
182
|
+
await thread.post(
|
|
183
|
+
"Deployments run automatically on push to `main`. " +
|
|
184
|
+
"Check status at https://dashboard.example.com/deploys"
|
|
185
|
+
);
|
|
186
|
+
});
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
### Example: Incident detection
|
|
190
|
+
|
|
191
|
+
```typescript title="lib/bot.ts" lineNumbers
|
|
192
|
+
bot.onNewMessage(/\b(outage|down|incident|p[01])\b/i, async (thread, message) => {
|
|
193
|
+
await thread.subscribe();
|
|
194
|
+
await thread.post(
|
|
195
|
+
"I've flagged this as a potential incident and I'm monitoring this thread."
|
|
196
|
+
);
|
|
197
|
+
|
|
198
|
+
await notifyOnCallTeam({
|
|
199
|
+
channel: thread.channel.id,
|
|
200
|
+
reporter: message.author.fullName,
|
|
201
|
+
text: message.text,
|
|
202
|
+
});
|
|
203
|
+
});
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
## Handling reactions
|
|
207
|
+
|
|
208
|
+
`onReaction` fires when users add or remove emoji reactions to messages. You can handle all reactions or filter by specific emoji.
|
|
209
|
+
|
|
210
|
+
```typescript title="lib/bot.ts" lineNumbers
|
|
211
|
+
import { emoji } from "chat";
|
|
212
|
+
|
|
213
|
+
// Handle specific emoji
|
|
214
|
+
bot.onReaction(["thumbs_up", "heart"], async (event) => {
|
|
215
|
+
if (!event.added) return;
|
|
216
|
+
|
|
217
|
+
await event.adapter.addReaction(
|
|
218
|
+
event.threadId,
|
|
219
|
+
event.messageId,
|
|
220
|
+
emoji.raised_hands
|
|
221
|
+
);
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
// Handle all reactions
|
|
225
|
+
bot.onReaction(async (event) => {
|
|
226
|
+
console.log(`${event.user.userName} ${event.added ? "added" : "removed"} ${event.emoji}`);
|
|
227
|
+
});
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
### ReactionEvent
|
|
231
|
+
|
|
232
|
+
| Property | Type | Description |
|
|
233
|
+
|----------|------|-------------|
|
|
234
|
+
| `emoji` | `EmojiValue` | Normalized emoji name for cross-platform comparison |
|
|
235
|
+
| `rawEmoji` | `string` | Platform-specific emoji string |
|
|
236
|
+
| `added` | `boolean` | `true` if added, `false` if removed |
|
|
237
|
+
| `user` | `Author` | The user who reacted |
|
|
238
|
+
| `message` | `Message` (optional) | The message that was reacted to |
|
|
239
|
+
| `thread` | `Thread` | Thread for posting replies |
|
|
240
|
+
| `messageId` | `string` | ID of the message that was reacted to |
|
|
241
|
+
| `threadId` | `string` | Thread ID |
|
|
242
|
+
| `adapter` | `Adapter` | The platform adapter |
|
|
243
|
+
| `raw` | `unknown` | Platform-specific event payload |
|
|
244
|
+
|
|
245
|
+
### When to use
|
|
246
|
+
|
|
247
|
+
- **Approval workflows** — use thumbs up/down as lightweight approve/reject signals.
|
|
248
|
+
- **Bookmarking** — save messages to an external system when a specific emoji is added.
|
|
249
|
+
- **Polls and voting** — count reactions as votes.
|
|
250
|
+
|
|
251
|
+
### Example: Approval workflow
|
|
252
|
+
|
|
253
|
+
```typescript title="lib/bot.ts" lineNumbers
|
|
254
|
+
bot.onReaction(["thumbs_up", "thumbs_down"], async (event) => {
|
|
255
|
+
if (!event.added) return;
|
|
256
|
+
|
|
257
|
+
const approved = event.emoji === "thumbs_up";
|
|
258
|
+
const status = approved ? "approved" : "rejected";
|
|
259
|
+
|
|
260
|
+
await event.thread.post(
|
|
261
|
+
`Request ${status} by ${event.user.fullName}`
|
|
262
|
+
);
|
|
263
|
+
|
|
264
|
+
await updateRequestStatus(event.messageId, status, event.user.userId);
|
|
265
|
+
});
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
### Example: Save to external system
|
|
269
|
+
|
|
270
|
+
```typescript title="lib/bot.ts" lineNumbers
|
|
271
|
+
bot.onReaction(["bookmark"], async (event) => {
|
|
272
|
+
if (!event.added || !event.message) return;
|
|
273
|
+
|
|
274
|
+
await saveToDatabase({
|
|
275
|
+
text: event.message.text,
|
|
276
|
+
savedBy: event.user.userId,
|
|
277
|
+
source: event.threadId,
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
await event.thread.post(
|
|
281
|
+
`Bookmarked by ${event.user.fullName}`
|
|
282
|
+
);
|
|
283
|
+
});
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
## Handling interactions
|
|
287
|
+
|
|
288
|
+
For button clicks, slash commands, and modal forms, see the dedicated guides:
|
|
289
|
+
|
|
290
|
+
- **[Slash Commands](/docs/slash-commands)** — handle `/command` invocations from the message composer.
|
|
291
|
+
- **[Actions](/docs/actions)** — handle button clicks and interactive card events.
|
|
292
|
+
- **[Modals](/docs/modals)** — collect structured input through modal dialogs with validation.
|
|
293
|
+
|
|
294
|
+
## Handling Slack-specific events
|
|
295
|
+
|
|
296
|
+
These handlers are specific to the Slack platform and require the Slack adapter.
|
|
297
|
+
|
|
298
|
+
### Handling assistant threads
|
|
299
|
+
|
|
300
|
+
`onAssistantThreadStarted` fires when a user opens a new assistant thread in Slack. Use it with the [Slack Assistants API](/adapters/slack#slack-assistants-api) to set suggested prompts and status indicators.
|
|
301
|
+
|
|
302
|
+
```typescript title="lib/bot.ts" lineNumbers
|
|
303
|
+
bot.onAssistantThreadStarted(async (event) => {
|
|
304
|
+
const slack = bot.getAdapter("slack") as SlackAdapter;
|
|
305
|
+
await slack.setSuggestedPrompts(event.channelId, event.threadTs, [
|
|
306
|
+
{ title: "Get started", message: "What can you help me with?" },
|
|
307
|
+
{ title: "Summarize", message: "Summarize the current channel" },
|
|
308
|
+
]);
|
|
309
|
+
});
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
The `event` object includes:
|
|
313
|
+
|
|
314
|
+
| Property | Type | Description |
|
|
315
|
+
|----------|------|-------------|
|
|
316
|
+
| `channelId` | `string` | The assistant thread's channel |
|
|
317
|
+
| `threadTs` | `string` | Thread timestamp |
|
|
318
|
+
| `threadId` | `string` | Thread ID |
|
|
319
|
+
| `userId` | `string` | User who started the thread |
|
|
320
|
+
| `context` | `object` | Assistant context (channelId, teamId, enterpriseId, threadEntryPoint) |
|
|
321
|
+
| `adapter` | `Adapter` | The Slack adapter |
|
|
322
|
+
|
|
323
|
+
### Handling assistant context changes
|
|
324
|
+
|
|
325
|
+
`onAssistantContextChanged` fires when the assistant context changes, for example when a user navigates to a different channel while the assistant thread is open.
|
|
326
|
+
|
|
327
|
+
```typescript title="lib/bot.ts" lineNumbers
|
|
328
|
+
bot.onAssistantContextChanged(async (event) => {
|
|
329
|
+
const slack = bot.getAdapter("slack") as SlackAdapter;
|
|
330
|
+
await slack.setStatus(event.channelId, event.threadTs, "Updating context...");
|
|
331
|
+
|
|
332
|
+
// Update prompts based on new context
|
|
333
|
+
const channelName = event.context.channelId ?? "general";
|
|
334
|
+
await slack.setSuggestedPrompts(event.channelId, event.threadTs, [
|
|
335
|
+
{ title: "Summarize", message: `Summarize #${channelName}` },
|
|
336
|
+
]);
|
|
337
|
+
});
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
### Handling App Home opens
|
|
341
|
+
|
|
342
|
+
`onAppHomeOpened` fires when a user opens your bot's Home tab in Slack. Use it to publish a dynamic view.
|
|
343
|
+
|
|
344
|
+
```typescript title="lib/bot.ts" lineNumbers
|
|
345
|
+
bot.onAppHomeOpened(async (event) => {
|
|
346
|
+
const slack = bot.getAdapter("slack") as SlackAdapter;
|
|
347
|
+
await slack.publishHomeView(event.userId, {
|
|
348
|
+
type: "home",
|
|
349
|
+
blocks: [
|
|
350
|
+
{
|
|
351
|
+
type: "section",
|
|
352
|
+
text: { type: "mrkdwn", text: `Welcome, <@${event.userId}>!` },
|
|
353
|
+
},
|
|
354
|
+
{
|
|
355
|
+
type: "actions",
|
|
356
|
+
elements: [
|
|
357
|
+
{
|
|
358
|
+
type: "button",
|
|
359
|
+
text: { type: "plain_text", text: "Open Dashboard" },
|
|
360
|
+
url: "https://dashboard.example.com",
|
|
361
|
+
},
|
|
362
|
+
],
|
|
363
|
+
},
|
|
364
|
+
],
|
|
365
|
+
});
|
|
366
|
+
});
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
The `event` object includes:
|
|
370
|
+
|
|
371
|
+
| Property | Type | Description |
|
|
372
|
+
|----------|------|-------------|
|
|
373
|
+
| `userId` | `string` | User who opened the Home tab |
|
|
374
|
+
| `channelId` | `string` | Channel context |
|
|
375
|
+
| `adapter` | `Adapter` | The Slack adapter |
|
package/docs/index.mdx
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: Introduction
|
|
3
|
-
description: A unified SDK for building chat bots across Slack, Microsoft Teams, Google Chat, Discord, and more.
|
|
3
|
+
description: A unified SDK for building chat bots across Slack, Microsoft Teams, Google Chat, Discord, Telegram, and more.
|
|
4
4
|
type: overview
|
|
5
5
|
---
|
|
6
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.
|
|
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, Telegram, GitHub, and Linear.
|
|
8
8
|
|
|
9
9
|
## Why Chat SDK?
|
|
10
10
|
|
|
@@ -55,6 +55,7 @@ Each adapter factory auto-detects credentials from environment variables (`SLACK
|
|
|
55
55
|
| Microsoft Teams | `@chat-adapter/teams` | Yes | Read-only | Yes | No | Post+Edit | Yes |
|
|
56
56
|
| Google Chat | `@chat-adapter/gchat` | Yes | Yes | Yes | No | Post+Edit | Yes |
|
|
57
57
|
| Discord | `@chat-adapter/discord` | Yes | Yes | Yes | No | Post+Edit | Yes |
|
|
58
|
+
| Telegram | `@chat-adapter/telegram` | Yes | Yes | Partial | No | Post+Edit | Yes |
|
|
58
59
|
| GitHub | `@chat-adapter/github` | Yes | Yes | No | No | No | No |
|
|
59
60
|
| Linear | `@chat-adapter/linear` | Yes | Yes | No | No | No | No |
|
|
60
61
|
|
|
@@ -79,6 +80,7 @@ The SDK is distributed as a set of packages you install based on your needs:
|
|
|
79
80
|
| `@chat-adapter/teams` | Microsoft Teams adapter |
|
|
80
81
|
| `@chat-adapter/gchat` | Google Chat adapter |
|
|
81
82
|
| `@chat-adapter/discord` | Discord adapter |
|
|
83
|
+
| `@chat-adapter/telegram` | Telegram adapter |
|
|
82
84
|
| `@chat-adapter/github` | GitHub Issues adapter |
|
|
83
85
|
| `@chat-adapter/linear` | Linear Issues adapter |
|
|
84
86
|
| `@chat-adapter/state-redis` | Redis state adapter (production) |
|
package/docs/meta.json
CHANGED
|
@@ -3,7 +3,10 @@
|
|
|
3
3
|
"pages": [
|
|
4
4
|
"index",
|
|
5
5
|
"getting-started",
|
|
6
|
+
"---Usage---",
|
|
6
7
|
"usage",
|
|
8
|
+
"threads-messages-channels",
|
|
9
|
+
"handling-events",
|
|
7
10
|
"posting-messages",
|
|
8
11
|
"---Features---",
|
|
9
12
|
"...",
|
|
@@ -15,6 +18,8 @@
|
|
|
15
18
|
"---Guides---",
|
|
16
19
|
"...guides",
|
|
17
20
|
"---API Reference---",
|
|
18
|
-
"...api"
|
|
21
|
+
"...api",
|
|
22
|
+
"---Contributing---",
|
|
23
|
+
"...contributing"
|
|
19
24
|
]
|
|
20
25
|
}
|
|
@@ -16,7 +16,7 @@ related:
|
|
|
16
16
|
|
|
17
17
|
The simplest option. Pass a string and it goes through as-is to the platform.
|
|
18
18
|
|
|
19
|
-
```typescript title="lib/bot.ts"
|
|
19
|
+
```typescript title="lib/bot.ts" lineNumbers
|
|
20
20
|
await thread.post("Hello world");
|
|
21
21
|
```
|
|
22
22
|
|
|
@@ -26,7 +26,7 @@ This sends the string directly without any formatting conversion.
|
|
|
26
26
|
|
|
27
27
|
Pass a `{ markdown }` object to have the SDK convert standard markdown to each platform's native format — mrkdwn for Slack, HTML for Teams, and so on.
|
|
28
28
|
|
|
29
|
-
```typescript title="lib/bot.ts"
|
|
29
|
+
```typescript title="lib/bot.ts" lineNumbers
|
|
30
30
|
await thread.post({
|
|
31
31
|
markdown: "**Bold**, _italic_, and `code`",
|
|
32
32
|
});
|
|
@@ -38,7 +38,7 @@ Under the hood, the SDK parses the markdown into an mdast AST, then each adapter
|
|
|
38
38
|
|
|
39
39
|
For programmatic control over message formatting, use the mdast AST builder functions exported from `chat`. This is the recommended approach for most use cases — it gives you fine-grained control without the overhead of card rendering.
|
|
40
40
|
|
|
41
|
-
```typescript title="lib/bot.ts"
|
|
41
|
+
```typescript title="lib/bot.ts" lineNumbers
|
|
42
42
|
import { root, paragraph, text, strong, link } from "chat";
|
|
43
43
|
|
|
44
44
|
await thread.post({
|
|
@@ -71,7 +71,7 @@ await thread.post({
|
|
|
71
71
|
|
|
72
72
|
You can also parse a markdown string into an AST, manipulate it, then send it:
|
|
73
73
|
|
|
74
|
-
```typescript title="lib/bot.ts"
|
|
74
|
+
```typescript title="lib/bot.ts" lineNumbers
|
|
75
75
|
import { parseMarkdown, stringifyMarkdown } from "chat";
|
|
76
76
|
|
|
77
77
|
const ast = parseMarkdown("**Hello** world");
|
|
@@ -87,7 +87,7 @@ When you need interactive elements like buttons, dropdowns, or structured layout
|
|
|
87
87
|
|
|
88
88
|
Use the function-call API for type-safe card construction:
|
|
89
89
|
|
|
90
|
-
```typescript title="lib/bot.ts"
|
|
90
|
+
```typescript title="lib/bot.ts" lineNumbers
|
|
91
91
|
import { Card, Text, Actions, Button } from "chat";
|
|
92
92
|
|
|
93
93
|
await thread.post(
|
|
@@ -141,7 +141,7 @@ See the [Cards](/docs/cards) page for the full list of card components.
|
|
|
141
141
|
|
|
142
142
|
Pass an `AsyncIterable<string>` (like the AI SDK's `textStream`) to stream a message in real time. The SDK uses platform-native streaming where available and falls back to post-then-edit on other platforms.
|
|
143
143
|
|
|
144
|
-
```typescript title="lib/bot.ts"
|
|
144
|
+
```typescript title="lib/bot.ts" lineNumbers
|
|
145
145
|
import { streamText } from "ai";
|
|
146
146
|
|
|
147
147
|
const result = streamText({ model, prompt: message.text });
|
|
@@ -154,7 +154,7 @@ See the [Streaming](/docs/streaming) page for details on platform behavior and c
|
|
|
154
154
|
|
|
155
155
|
Any structured message format (`markdown`, `ast`, or `card`) supports `files` for uploading attachments alongside the message:
|
|
156
156
|
|
|
157
|
-
```typescript title="lib/bot.ts"
|
|
157
|
+
```typescript title="lib/bot.ts" lineNumbers
|
|
158
158
|
await thread.post({
|
|
159
159
|
markdown: "Here's the report:",
|
|
160
160
|
files: [{ data: buffer, filename: "report.pdf" }],
|
package/docs/slash-commands.mdx
CHANGED
|
@@ -7,10 +7,13 @@ prerequisites:
|
|
|
7
7
|
related:
|
|
8
8
|
- /docs/modals
|
|
9
9
|
- /docs/adapters/slack
|
|
10
|
+
- /docs/adapters/discord
|
|
10
11
|
---
|
|
11
12
|
|
|
12
13
|
Slash commands let users invoke your bot with `/command` syntax. Register handlers with `onSlashCommand` to respond.
|
|
13
14
|
|
|
15
|
+
Slash commands are supported on [Slack](/docs/adapters/slack) and [Discord](/docs/adapters/discord).
|
|
16
|
+
|
|
14
17
|
## Handle a specific command
|
|
15
18
|
|
|
16
19
|
```typescript title="lib/bot.ts" lineNumbers
|
|
@@ -108,3 +111,23 @@ bot.onModalSubmit("feedback_form", async (event) => {
|
|
|
108
111
|
}
|
|
109
112
|
});
|
|
110
113
|
```
|
|
114
|
+
|
|
115
|
+
## Discord
|
|
116
|
+
|
|
117
|
+
Discord slash commands are received via [HTTP Interactions](/docs/adapters/discord#architecture-http-interactions-vs-gateway) — no Gateway connection is needed. The adapter automatically sends a deferred response to Discord, then resolves it when your handler calls `event.channel.post()`.
|
|
118
|
+
|
|
119
|
+
### Subcommands
|
|
120
|
+
|
|
121
|
+
Discord supports subcommand groups and subcommands. The adapter flattens these into the `event.command` path:
|
|
122
|
+
|
|
123
|
+
| Discord command | `event.command` | `event.text` |
|
|
124
|
+
|-----------------|-----------------|--------------|
|
|
125
|
+
| `/status` | `/status` | `""` |
|
|
126
|
+
| `/project create --name="Acme"` | `/project create` | `Acme` |
|
|
127
|
+
| `/project issue list --status="open"` | `/project issue list` | `open` |
|
|
128
|
+
|
|
129
|
+
For full option details (names, types), use `event.raw` to access the original Discord interaction payload.
|
|
130
|
+
|
|
131
|
+
### Registering commands with Discord
|
|
132
|
+
|
|
133
|
+
You need to register slash commands with the [Discord API](https://discord.com/developers/docs/interactions/application-commands) before they appear in the client. The Chat SDK handles incoming commands but does not register them for you.
|
package/docs/state/meta.json
CHANGED
package/docs/streaming.mdx
CHANGED
|
@@ -58,6 +58,38 @@ const bot = new Chat({
|
|
|
58
58
|
});
|
|
59
59
|
```
|
|
60
60
|
|
|
61
|
+
### Disabling the placeholder message
|
|
62
|
+
|
|
63
|
+
By default, post+edit adapters send an initial `"..."` placeholder message before the first chunk arrives. You can disable this to wait for real content before posting:
|
|
64
|
+
|
|
65
|
+
```typescript title="lib/bot.ts" lineNumbers
|
|
66
|
+
const bot = new Chat({
|
|
67
|
+
// ...
|
|
68
|
+
fallbackStreamingPlaceholderText: null,
|
|
69
|
+
});
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
You can also customize the placeholder text:
|
|
73
|
+
|
|
74
|
+
```typescript title="lib/bot.ts"
|
|
75
|
+
const bot = new Chat({
|
|
76
|
+
// ...
|
|
77
|
+
fallbackStreamingPlaceholderText: "Thinking...",
|
|
78
|
+
});
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Markdown healing
|
|
82
|
+
|
|
83
|
+
During streaming, chunks often arrive mid-word or mid-syntax — for example, `**bold` before the closing `**` arrives. The SDK automatically heals incomplete markdown in intermediate renders using [remend](https://www.npmjs.com/package/remend), so messages always display with correct formatting while streaming.
|
|
84
|
+
|
|
85
|
+
The final message uses the raw accumulated text without healing, so the original markdown is preserved.
|
|
86
|
+
|
|
87
|
+
## Table buffering
|
|
88
|
+
|
|
89
|
+
When streaming content that contains GFM tables (e.g. from an LLM), the SDK automatically buffers potential table headers until a separator line (`|---|---|`) confirms them. This prevents tables from briefly flashing as raw pipe-delimited text before the table structure is complete.
|
|
90
|
+
|
|
91
|
+
This happens transparently — no configuration needed.
|
|
92
|
+
|
|
61
93
|
## Stop blocks (Slack only)
|
|
62
94
|
|
|
63
95
|
When streaming in Slack, you can attach Block Kit elements to the final message using `stopBlocks`. This is useful for adding action buttons after a streamed response completes:
|