chat 4.15.0 → 4.16.1
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/dist/{chunk-VGF42GJ2.js → chunk-A2J5CUHD.js} +368 -9
- package/dist/chunk-A2J5CUHD.js.map +1 -0
- package/dist/index.d.ts +196 -12
- package/dist/index.js +444 -250
- package/dist/index.js.map +1 -1
- package/dist/{jsx-runtime-Wowykq7Z.d.ts → jsx-runtime-Bokk9xw5.d.ts} +47 -2
- package/dist/jsx-runtime.d.ts +1 -1
- package/dist/jsx-runtime.js +1 -1
- package/docs/actions.mdx +1 -1
- package/docs/adapters/discord.mdx +1 -0
- package/docs/adapters/index.mdx +16 -0
- package/docs/adapters/slack.mdx +3 -0
- package/docs/adapters/telegram.mdx +60 -0
- package/docs/api/cards.mdx +35 -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/postable-message.mdx +12 -4
- package/docs/api/thread.mdx +6 -3
- package/docs/cards.mdx +24 -0
- 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 +402 -0
- package/docs/meta.json +6 -1
- package/docs/posting-messages.mdx +14 -11
- package/docs/slash-commands.mdx +23 -0
- package/docs/state/meta.json +1 -6
- package/docs/streaming.mdx +108 -4
- package/docs/threads-messages-channels.mdx +237 -0
- package/docs/usage.mdx +82 -276
- package/package.json +4 -3
- package/dist/chunk-VGF42GJ2.js.map +0 -1
|
@@ -145,6 +145,8 @@ type ButtonStyle = "primary" | "danger" | "default";
|
|
|
145
145
|
type TextStyle = "plain" | "bold" | "muted";
|
|
146
146
|
/** Button element for interactive actions */
|
|
147
147
|
interface ButtonElement {
|
|
148
|
+
/** If true, the button is displayed in an inactive state and doesn't respond to user actions */
|
|
149
|
+
disabled?: boolean;
|
|
148
150
|
/** Unique action ID for callback routing */
|
|
149
151
|
id: string;
|
|
150
152
|
/** Button label text */
|
|
@@ -219,8 +221,20 @@ interface FieldsElement {
|
|
|
219
221
|
children: FieldElement[];
|
|
220
222
|
type: "fields";
|
|
221
223
|
}
|
|
224
|
+
/** Column alignment for table elements */
|
|
225
|
+
type TableAlignment = "left" | "center" | "right";
|
|
226
|
+
/** Table element for structured data display */
|
|
227
|
+
interface TableElement {
|
|
228
|
+
/** Column alignment */
|
|
229
|
+
align?: TableAlignment[];
|
|
230
|
+
/** Column header labels */
|
|
231
|
+
headers: string[];
|
|
232
|
+
/** Data rows (each row is an array of cell strings) */
|
|
233
|
+
rows: string[][];
|
|
234
|
+
type: "table";
|
|
235
|
+
}
|
|
222
236
|
/** Union of all card child element types */
|
|
223
|
-
type CardChild = TextElement | ImageElement | DividerElement | ActionsElement | SectionElement | FieldsElement | LinkElement;
|
|
237
|
+
type CardChild = TextElement | ImageElement | DividerElement | ActionsElement | SectionElement | FieldsElement | LinkElement | TableElement;
|
|
224
238
|
/** Union of all element types (including nested children) */
|
|
225
239
|
type AnyCardElement = CardChild | CardElement | ButtonElement | LinkButtonElement | LinkElement | FieldElement | SelectElement | RadioSelectElement;
|
|
226
240
|
/** Root card element */
|
|
@@ -318,6 +332,8 @@ declare function Section(children: CardChild[]): SectionElement;
|
|
|
318
332
|
declare function Actions(children: (ButtonElement | LinkButtonElement | SelectElement | RadioSelectElement)[]): ActionsElement;
|
|
319
333
|
/** Options for Button */
|
|
320
334
|
interface ButtonOptions {
|
|
335
|
+
/** If true, the button is displayed in an inactive state and doesn't respond to user actions */
|
|
336
|
+
disabled?: boolean;
|
|
321
337
|
/** Unique action ID for callback routing */
|
|
322
338
|
id: string;
|
|
323
339
|
/** Button label text */
|
|
@@ -380,6 +396,30 @@ declare function Field(options: {
|
|
|
380
396
|
* ```
|
|
381
397
|
*/
|
|
382
398
|
declare function Fields(children: FieldElement[]): FieldsElement;
|
|
399
|
+
/** Options for Table */
|
|
400
|
+
interface TableOptions {
|
|
401
|
+
/** Column alignment */
|
|
402
|
+
align?: TableAlignment[];
|
|
403
|
+
/** Column header labels */
|
|
404
|
+
headers: string[];
|
|
405
|
+
/** Data rows */
|
|
406
|
+
rows: string[][];
|
|
407
|
+
}
|
|
408
|
+
/**
|
|
409
|
+
* Create a Table element for structured data display.
|
|
410
|
+
*
|
|
411
|
+
* @example
|
|
412
|
+
* ```ts
|
|
413
|
+
* Table({
|
|
414
|
+
* headers: ["Name", "Age", "Role"],
|
|
415
|
+
* rows: [
|
|
416
|
+
* ["Alice", "30", "Engineer"],
|
|
417
|
+
* ["Bob", "25", "Designer"],
|
|
418
|
+
* ],
|
|
419
|
+
* })
|
|
420
|
+
* ```
|
|
421
|
+
*/
|
|
422
|
+
declare function Table(options: TableOptions): TableElement;
|
|
383
423
|
/**
|
|
384
424
|
* Create a CardLink element for inline hyperlinks.
|
|
385
425
|
*
|
|
@@ -412,6 +452,11 @@ declare function CardLink(options: {
|
|
|
412
452
|
* ```
|
|
413
453
|
*/
|
|
414
454
|
declare function fromReactElement(element: unknown): AnyCardElement | null;
|
|
455
|
+
/**
|
|
456
|
+
* Generate fallback text from a card child element.
|
|
457
|
+
* Exported so adapter card converters can call it for unknown types.
|
|
458
|
+
*/
|
|
459
|
+
declare function cardChildToFallbackText(child: CardChild): string | null;
|
|
415
460
|
|
|
416
461
|
/**
|
|
417
462
|
* Custom JSX runtime for chat cards.
|
|
@@ -590,4 +635,4 @@ declare namespace JSX {
|
|
|
590
635
|
}
|
|
591
636
|
}
|
|
592
637
|
|
|
593
|
-
export { type
|
|
638
|
+
export { type FieldProps as $, Actions as A, Button as B, type CardElement as C, Divider as D, type ImageElement as E, Field as F, type LinkButtonElement as G, type LinkButtonOptions as H, Image as I, type LinkElement as J, type SectionElement as K, LinkButton as L, type ModalElement as M, type TableAlignment as N, type TableElement as O, type TableOptions as P, type TextElement as Q, RadioSelect as R, Section as S, Text as T, type TextStyle as U, type ButtonProps as V, type CardJSXProps as W, type CardLinkProps as X, type CardProps as Y, type ContainerProps as Z, type DividerProps as _, type CardJSXElement as a, type ImageProps as a0, type LinkButtonProps as a1, type TextProps as a2, type ModalChild as a3, type ModalOptions as a4, type RadioSelectElement as a5, type RadioSelectOptions as a6, type SelectElement as a7, type SelectOptionElement as a8, type SelectOptions as a9, type TextInputElement as aa, type TextInputOptions as ab, type ModalProps as ac, type TextInputProps as ad, type SelectProps as ae, type SelectOptionProps as af, isCardLinkProps as ag, jsx as ah, jsxs as ai, jsxDEV as aj, Fragment as ak, JSX as al, type CardChild as b, Card as c, cardChildToFallbackText as d, CardLink as e, Fields as f, fromReactElement as g, isJSX as h, isCardElement as i, Table as j, toModalElement as k, fromReactModalElement as l, isModalElement as m, Modal as n, Select as o, SelectOption as p, TextInput as q, type ActionsElement as r, type ButtonElement as s, toCardElement as t, type ButtonOptions as u, type ButtonStyle as v, type CardOptions as w, type DividerElement as x, type FieldElement as y, type FieldsElement as z };
|
package/dist/jsx-runtime.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { V as ButtonProps, a as CardJSXElement, W as CardJSXProps, X as CardLinkProps, Y as CardProps, Z as ContainerProps, _ as DividerProps, $ as FieldProps, ak as Fragment, a0 as ImageProps, al as JSX, a1 as LinkButtonProps, ac as ModalProps, af as SelectOptionProps, ae as SelectProps, ad as TextInputProps, a2 as TextProps, ag as isCardLinkProps, h as isJSX, ah as jsx, aj as jsxDEV, ai as jsxs, t as toCardElement, k as toModalElement } from './jsx-runtime-Bokk9xw5.js';
|
package/dist/jsx-runtime.js
CHANGED
package/docs/actions.mdx
CHANGED
|
@@ -46,7 +46,7 @@ The `event` object passed to action handlers:
|
|
|
46
46
|
| `actionId` | `string` | The `id` from the Button or Select component |
|
|
47
47
|
| `value` | `string` (optional) | The `value` from the Button or selected option |
|
|
48
48
|
| `user` | `Author` | The user who clicked |
|
|
49
|
-
| `thread` | `Thread` | The thread containing the card |
|
|
49
|
+
| `thread` | `Thread \| null` | The thread containing the card (null for view-based actions like home tab buttons) |
|
|
50
50
|
| `messageId` | `string` | The message containing the card |
|
|
51
51
|
| `threadId` | `string` | Thread ID |
|
|
52
52
|
| `adapter` | `Adapter` | The platform adapter |
|
package/docs/adapters/index.mdx
CHANGED
|
@@ -28,6 +28,7 @@ Adapters handle webhook verification, message parsing, and API calls for each pl
|
|
|
28
28
|
| Buttons | ✅ | ✅ | ✅ | ✅ | ⚠️ Inline keyboard callbacks | ❌ | ❌ |
|
|
29
29
|
| Link buttons | ✅ | ✅ | ✅ | ✅ | ⚠️ Inline keyboard URLs | ❌ | ❌ |
|
|
30
30
|
| Select menus | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ |
|
|
31
|
+
| Tables | ✅ Block Kit | ✅ GFM | ⚠️ ASCII | ✅ GFM | ⚠️ ASCII | ✅ GFM | ✅ GFM |
|
|
31
32
|
| Fields | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
|
32
33
|
| Images in cards | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | ❌ |
|
|
33
34
|
| Modals | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
|
|
@@ -36,6 +37,7 @@ Adapters handle webhook verification, message parsing, and API calls for each pl
|
|
|
36
37
|
|
|
37
38
|
| Feature | Slack | Teams | Google Chat | Discord | Telegram | GitHub | Linear |
|
|
38
39
|
|---------|-------|-------|-------------|---------|----------|--------|--------|
|
|
40
|
+
| Slash commands | ✅ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ |
|
|
39
41
|
| Mentions | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
|
40
42
|
| Add reactions | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
|
41
43
|
| Remove reactions | ✅ | ❌ | ✅ | ✅ | ✅ | ⚠️ | ⚠️ |
|
|
@@ -71,6 +73,20 @@ Adapters handle webhook verification, message parsing, and API calls for each pl
|
|
|
71
73
|
| [GitHub](/docs/adapters/github) | `@chat-adapter/github` |
|
|
72
74
|
| [Linear](/docs/adapters/linear) | `@chat-adapter/linear` |
|
|
73
75
|
|
|
76
|
+
## Community adapters
|
|
77
|
+
|
|
78
|
+
Beyond the Vercel-maintained adapters listed above, you can build adapters for any messaging platform. Community adapters use the same `Adapter` interface and get full access to Chat SDK features like cards, actions, streaming, and state management.
|
|
79
|
+
|
|
80
|
+
| Tier | Description |
|
|
81
|
+
|------|-------------|
|
|
82
|
+
| Vercel-maintained | Published under `@chat-adapter/*` by Vercel |
|
|
83
|
+
| Community official | Built and maintained by the platform company itself (e.g., Resend building a Resend adapter) |
|
|
84
|
+
| Community | Built by third-party developers |
|
|
85
|
+
|
|
86
|
+
Community adapters are expected to meet the same testing bar as first-party adapters — unit tests for all public methods, integration tests for end-to-end message flows.
|
|
87
|
+
|
|
88
|
+
Ready to build one? Follow the [building](/docs/contributing/building) guide.
|
|
89
|
+
|
|
74
90
|
## How adapters work
|
|
75
91
|
|
|
76
92
|
Each adapter implements a standard interface that the `Chat` class uses to route events and send messages. When a webhook arrives:
|
package/docs/adapters/slack.mdx
CHANGED
|
@@ -139,6 +139,7 @@ settings:
|
|
|
139
139
|
request_url: https://your-domain.com/api/webhooks/slack
|
|
140
140
|
bot_events:
|
|
141
141
|
- app_mention
|
|
142
|
+
- member_joined_channel
|
|
142
143
|
- message.channels
|
|
143
144
|
- message.groups
|
|
144
145
|
- message.im
|
|
@@ -187,6 +188,7 @@ All options are auto-detected from environment variables when not provided. You
|
|
|
187
188
|
| `clientId` | No | App client ID for multi-workspace OAuth. Auto-detected from `SLACK_CLIENT_ID` |
|
|
188
189
|
| `clientSecret` | No | App client secret for multi-workspace OAuth. Auto-detected from `SLACK_CLIENT_SECRET` |
|
|
189
190
|
| `encryptionKey` | No | AES-256-GCM key for encrypting stored tokens. Auto-detected from `SLACK_ENCRYPTION_KEY` |
|
|
191
|
+
| `installationKeyPrefix` | No | Prefix for the state key used to store workspace installations. Defaults to `slack:installation`. The full key is `{prefix}:{teamId}` |
|
|
190
192
|
| `logger` | No | Logger instance (defaults to `ConsoleLogger("info")`) |
|
|
191
193
|
|
|
192
194
|
*`signingSecret` is required — either via config or `SLACK_SIGNING_SECRET` env var.
|
|
@@ -218,6 +220,7 @@ SLACK_ENCRYPTION_KEY=... # Optional, for token encryption
|
|
|
218
220
|
| Message history | Yes |
|
|
219
221
|
| Assistants API | Yes |
|
|
220
222
|
| App Home tab | Yes |
|
|
223
|
+
| Member joined channel | Yes |
|
|
221
224
|
|
|
222
225
|
## Slack Assistants API
|
|
223
226
|
|
|
@@ -53,6 +53,60 @@ curl -X POST "https://api.telegram.org/bot$TELEGRAM_BOT_TOKEN/setWebhook" \
|
|
|
53
53
|
}'
|
|
54
54
|
```
|
|
55
55
|
|
|
56
|
+
## Polling (local development)
|
|
57
|
+
|
|
58
|
+
When developing locally you typically can't expose a public URL for Telegram to deliver webhooks to. Polling mode uses `getUpdates` to fetch messages directly from Telegram instead — no public endpoint needed.
|
|
59
|
+
|
|
60
|
+
The `longPolling` option is entirely optional. Sensible defaults are applied when omitted.
|
|
61
|
+
|
|
62
|
+
```typescript title="lib/bot.ts" lineNumbers
|
|
63
|
+
import { Chat } from "chat";
|
|
64
|
+
import { createTelegramAdapter } from "@chat-adapter/telegram";
|
|
65
|
+
import { createMemoryState } from "@chat-adapter/state-memory";
|
|
66
|
+
|
|
67
|
+
const telegram = createTelegramAdapter({
|
|
68
|
+
mode: "polling",
|
|
69
|
+
// Optional — fine-tune polling behavior:
|
|
70
|
+
// longPolling: { timeout: 30, dropPendingUpdates: false },
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
const bot = new Chat({
|
|
74
|
+
userName: "mybot",
|
|
75
|
+
adapters: { telegram },
|
|
76
|
+
state: createMemoryState(),
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
// Optional manual lifecycle control:
|
|
80
|
+
// await telegram.resetWebhook();
|
|
81
|
+
// await telegram.startPolling();
|
|
82
|
+
// await telegram.stopPolling();
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Auto mode
|
|
86
|
+
|
|
87
|
+
With `mode: "auto"` (the default), the adapter picks the right strategy for you. When deployed to a serverless environment like Vercel it uses webhooks; everywhere else (e.g. local dev) it falls back to polling automatically.
|
|
88
|
+
|
|
89
|
+
```typescript title="lib/bot.ts" lineNumbers
|
|
90
|
+
import { Chat } from "chat";
|
|
91
|
+
import { createTelegramAdapter } from "@chat-adapter/telegram";
|
|
92
|
+
import { createMemoryState } from "@chat-adapter/state-memory";
|
|
93
|
+
|
|
94
|
+
const telegram = createTelegramAdapter({
|
|
95
|
+
mode: "auto", // default
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
export const bot = new Chat({
|
|
99
|
+
userName: "mybot",
|
|
100
|
+
adapters: { telegram },
|
|
101
|
+
state: createMemoryState(),
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
// Call initialize() so polling can start in long-running local processes:
|
|
105
|
+
void bot.initialize();
|
|
106
|
+
|
|
107
|
+
console.log(telegram.runtimeMode); // "webhook" | "polling"
|
|
108
|
+
```
|
|
109
|
+
|
|
56
110
|
## Configuration
|
|
57
111
|
|
|
58
112
|
All options are auto-detected from environment variables when not provided.
|
|
@@ -61,6 +115,8 @@ All options are auto-detected from environment variables when not provided.
|
|
|
61
115
|
|--------|----------|-------------|
|
|
62
116
|
| `botToken` | No* | Telegram bot token. Auto-detected from `TELEGRAM_BOT_TOKEN` |
|
|
63
117
|
| `secretToken` | No | Optional webhook secret token. Auto-detected from `TELEGRAM_WEBHOOK_SECRET_TOKEN` |
|
|
118
|
+
| `mode` | No | Adapter mode: `auto` (default), `webhook`, or `polling` |
|
|
119
|
+
| `longPolling` | No | Optional long polling config for `getUpdates` (`timeout`, `limit`, `allowedUpdates`, `deleteWebhook`, `dropPendingUpdates`, `retryDelayMs`) |
|
|
64
120
|
| `userName` | No | Bot username used for mention detection. Auto-detected from `TELEGRAM_BOT_USERNAME` or `getMe` |
|
|
65
121
|
| `apiBaseUrl` | No | Telegram API base URL. Auto-detected from `TELEGRAM_API_BASE_URL` |
|
|
66
122
|
| `logger` | No | Logger instance (defaults to `ConsoleLogger("info")`) |
|
|
@@ -96,6 +152,10 @@ TELEGRAM_API_BASE_URL=https://api.telegram.org
|
|
|
96
152
|
|
|
97
153
|
- Telegram does not expose full historical message APIs to bots. `fetchMessages` / `fetchChannelMessages` return adapter-cached messages from the current process.
|
|
98
154
|
- `listThreads` is not available for Telegram chats.
|
|
155
|
+
- Polling and webhooks are mutually exclusive in Telegram.
|
|
156
|
+
- `mode: "polling"` deletes webhook by default before calling `getUpdates`.
|
|
157
|
+
- `mode: "auto"` checks `getWebhookInfo`: if a webhook URL exists it uses webhook mode; if it is empty it falls back to polling on non-serverless runtimes without deleting webhook.
|
|
158
|
+
- If `getWebhookInfo` fails in `mode: "auto"`, the adapter stays in webhook mode (safe fallback).
|
|
99
159
|
- `Button` and `LinkButton` in card `Actions` render as inline keyboard buttons.
|
|
100
160
|
- Telegram callback data is limited to 64 bytes. Keep button `id`/`value` payloads short.
|
|
101
161
|
- Other rich card elements (images/select menus/radios) render as fallback text only.
|
package/docs/api/cards.mdx
CHANGED
|
@@ -7,7 +7,7 @@ type: reference
|
|
|
7
7
|
Card components render natively on each platform — Block Kit on Slack, Adaptive Cards on Teams, Embeds on Discord, and Google Chat Cards.
|
|
8
8
|
|
|
9
9
|
```typescript
|
|
10
|
-
import { Card, Text, CardLink, Button, Actions, Section, Fields, Field, Divider, Image, LinkButton } from "chat";
|
|
10
|
+
import { Card, Text, CardLink, Button, Actions, Section, Fields, Field, Divider, Image, LinkButton, Table } from "chat";
|
|
11
11
|
```
|
|
12
12
|
|
|
13
13
|
All components support both function-call and JSX syntax. Function-call syntax is recommended for better type inference.
|
|
@@ -216,6 +216,39 @@ Image({ url: "https://example.com/screenshot.png", alt: "Screenshot" })
|
|
|
216
216
|
}}
|
|
217
217
|
/>
|
|
218
218
|
|
|
219
|
+
## Table
|
|
220
|
+
|
|
221
|
+
Structured data display with column headers and rows.
|
|
222
|
+
|
|
223
|
+
```typescript
|
|
224
|
+
Table({
|
|
225
|
+
headers: ["Name", "Age", "Role"],
|
|
226
|
+
rows: [
|
|
227
|
+
["Alice", "30", "Engineer"],
|
|
228
|
+
["Bob", "25", "Designer"],
|
|
229
|
+
],
|
|
230
|
+
})
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
<TypeTable
|
|
234
|
+
type={{
|
|
235
|
+
headers: {
|
|
236
|
+
description: 'Column header labels.',
|
|
237
|
+
type: 'string[]',
|
|
238
|
+
},
|
|
239
|
+
rows: {
|
|
240
|
+
description: 'Data rows (each row is an array of cell strings).',
|
|
241
|
+
type: 'string[][]',
|
|
242
|
+
},
|
|
243
|
+
align: {
|
|
244
|
+
description: 'Column alignment.',
|
|
245
|
+
type: '"left" | "center" | "right"[]',
|
|
246
|
+
},
|
|
247
|
+
}}
|
|
248
|
+
/>
|
|
249
|
+
|
|
250
|
+
On platforms with native table support (Teams, GitHub, Linear), tables render as formatted tables. On other platforms (Slack, Google Chat, Discord, Telegram), tables render as padded ASCII text.
|
|
251
|
+
|
|
219
252
|
## Divider
|
|
220
253
|
|
|
221
254
|
A visual separator between sections.
|
|
@@ -237,3 +270,4 @@ The `children` array in `Card` and `Section` accepts these element types:
|
|
|
237
270
|
| `ActionsElement` | `Actions()` |
|
|
238
271
|
| `SectionElement` | `Section()` |
|
|
239
272
|
| `FieldsElement` | `Fields()` |
|
|
273
|
+
| `TableElement` | `Table()` |
|
package/docs/api/channel.mdx
CHANGED
|
@@ -161,10 +161,13 @@ await channel.postEphemeral(userId, "Only you can see this", {
|
|
|
161
161
|
|
|
162
162
|
## startTyping
|
|
163
163
|
|
|
164
|
-
Show a typing indicator. No-op on platforms that don't support it.
|
|
164
|
+
Show a typing indicator. No-op on platforms that don't support it. On Slack, you can pass an optional `status` string to show a custom loading message (requires `assistant:write` scope).
|
|
165
165
|
|
|
166
166
|
```typescript
|
|
167
167
|
await channel.startTyping();
|
|
168
|
+
|
|
169
|
+
// With custom status (Slack only)
|
|
170
|
+
await channel.startTyping("Searching documents...");
|
|
168
171
|
```
|
|
169
172
|
|
|
170
173
|
## mentionUser
|
package/docs/api/chat.mdx
CHANGED
|
@@ -26,6 +26,11 @@ const bot = new Chat(config);
|
|
|
26
26
|
description: 'Map of adapter name to adapter instance.',
|
|
27
27
|
type: 'Record<string, Adapter>',
|
|
28
28
|
},
|
|
29
|
+
dedupeTtlMs: {
|
|
30
|
+
description: 'TTL for message deduplication entries in milliseconds. Increase if webhook cold starts cause platform retries after the default window.',
|
|
31
|
+
type: 'number',
|
|
32
|
+
default: '300000',
|
|
33
|
+
},
|
|
29
34
|
state: {
|
|
30
35
|
description: 'State adapter for subscriptions, locking, and caching.',
|
|
31
36
|
type: 'StateAdapter',
|
package/docs/api/markdown.mdx
CHANGED
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
root, paragraph, text, strong, emphasis, strikethrough,
|
|
12
12
|
inlineCode, codeBlock, link, blockquote,
|
|
13
13
|
parseMarkdown, stringifyMarkdown, toPlainText, walkAst,
|
|
14
|
+
tableToAscii, tableElementToAscii,
|
|
14
15
|
} from "chat";
|
|
15
16
|
```
|
|
16
17
|
|
|
@@ -204,6 +205,9 @@ Functions for checking node types:
|
|
|
204
205
|
| `isBlockquoteNode(node)` | Blockquote |
|
|
205
206
|
| `isListNode(node)` | List |
|
|
206
207
|
| `isListItemNode(node)` | List item |
|
|
208
|
+
| `isTableNode(node)` | Table |
|
|
209
|
+
| `isTableRowNode(node)` | Table row |
|
|
210
|
+
| `isTableCellNode(node)` | Table cell |
|
|
207
211
|
|
|
208
212
|
### getNodeChildren / getNodeValue
|
|
209
213
|
|
|
@@ -214,6 +218,43 @@ const children = getNodeChildren(node); // Content[] | undefined
|
|
|
214
218
|
const value = getNodeValue(node); // string | undefined
|
|
215
219
|
```
|
|
216
220
|
|
|
221
|
+
## Table utilities
|
|
222
|
+
|
|
223
|
+
### tableToAscii
|
|
224
|
+
|
|
225
|
+
Render an mdast `Table` node as a padded ASCII table string. Used by adapters that lack native table support (Slack, Google Chat, Discord, Telegram).
|
|
226
|
+
|
|
227
|
+
```typescript
|
|
228
|
+
import { parseMarkdown, tableToAscii, isTableNode } from "chat";
|
|
229
|
+
|
|
230
|
+
const ast = parseMarkdown("| Name | Role |\n|------|------|\n| Alice | Engineer |");
|
|
231
|
+
// Find the table node and convert it
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
Output:
|
|
235
|
+
|
|
236
|
+
```
|
|
237
|
+
Name | Role
|
|
238
|
+
------|--------
|
|
239
|
+
Alice | Engineer
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
### tableElementToAscii
|
|
243
|
+
|
|
244
|
+
Render a table from headers and string row arrays as a padded ASCII table. Used for card `TableElement` fallback rendering.
|
|
245
|
+
|
|
246
|
+
```typescript
|
|
247
|
+
import { tableElementToAscii } from "chat";
|
|
248
|
+
|
|
249
|
+
const ascii = tableElementToAscii(
|
|
250
|
+
["Name", "Age", "Role"],
|
|
251
|
+
[
|
|
252
|
+
["Alice", "30", "Engineer"],
|
|
253
|
+
["Bob", "25", "Designer"],
|
|
254
|
+
]
|
|
255
|
+
);
|
|
256
|
+
```
|
|
257
|
+
|
|
217
258
|
## Platform formatting
|
|
218
259
|
|
|
219
260
|
The SDK uses mdast as the canonical format and each adapter converts it to the platform's native syntax. You write standard markdown and the SDK handles the translation — but it helps to know how each platform renders common formatting.
|
|
@@ -228,6 +269,7 @@ The SDK uses mdast as the canonical format and each adapter converts it to the p
|
|
|
228
269
|
| Links | `<url\|text>` | `[text](url)` | `[text](url)` |
|
|
229
270
|
| Lists | Supported | Supported | Supported |
|
|
230
271
|
| Blockquotes | `>` | `>` | Simulated with `>` prefix |
|
|
272
|
+
| Tables | ASCII fallback | Native GFM | ASCII fallback |
|
|
231
273
|
| Mentions | `<@USER>` | `<at>name</at>` | `<users/{id}>` |
|
|
232
274
|
|
|
233
275
|
<Callout type="info">
|
|
@@ -7,7 +7,7 @@ type: reference
|
|
|
7
7
|
`PostableMessage` is the union of all message formats accepted by `thread.post()` and `sent.edit()`.
|
|
8
8
|
|
|
9
9
|
```typescript
|
|
10
|
-
type PostableMessage = AdapterPostableMessage | AsyncIterable<string>;
|
|
10
|
+
type PostableMessage = AdapterPostableMessage | AsyncIterable<string | StreamChunk | StreamEvent>;
|
|
11
11
|
```
|
|
12
12
|
|
|
13
13
|
## String
|
|
@@ -135,15 +135,23 @@ await thread.post({
|
|
|
135
135
|
|
|
136
136
|
## AsyncIterable (streaming)
|
|
137
137
|
|
|
138
|
-
An async iterable of strings,
|
|
138
|
+
An async iterable of strings, `StreamChunk` objects, or stream events. The SDK streams the message in real time using platform-native APIs where available.
|
|
139
|
+
|
|
140
|
+
You can yield structured `StreamChunk` objects for rich content like task progress cards on platforms that support it (Slack). See [Streaming](/docs/streaming#structured-streaming-chunks-slack-only) for details.
|
|
141
|
+
|
|
142
|
+
Both AI SDK stream types are supported:
|
|
139
143
|
|
|
140
144
|
```typescript
|
|
141
|
-
|
|
145
|
+
// fullStream (recommended) — preserves step boundaries in multi-step agents
|
|
146
|
+
const result = await agent.stream({ prompt: message.text });
|
|
147
|
+
await thread.post(result.fullStream);
|
|
142
148
|
|
|
143
|
-
|
|
149
|
+
// textStream — plain string chunks
|
|
144
150
|
await thread.post(result.textStream);
|
|
145
151
|
```
|
|
146
152
|
|
|
153
|
+
When using `fullStream`, the SDK auto-detects `text-delta` and `step-finish` events, extracting text and inserting paragraph breaks between agent steps.
|
|
154
|
+
|
|
147
155
|
## FileUpload
|
|
148
156
|
|
|
149
157
|
Used in the `files` field of any structured message format.
|
package/docs/api/thread.mdx
CHANGED
|
@@ -54,8 +54,8 @@ await thread.post({ ast: root([paragraph([text("Hello")])]) });
|
|
|
54
54
|
// Card
|
|
55
55
|
await thread.post(Card({ title: "Hi", children: [Text("Hello")] }));
|
|
56
56
|
|
|
57
|
-
// Stream
|
|
58
|
-
await thread.post(result.
|
|
57
|
+
// Stream (fullStream recommended for multi-step agents)
|
|
58
|
+
await thread.post(result.fullStream);
|
|
59
59
|
```
|
|
60
60
|
|
|
61
61
|
**Parameters:** `message: string | PostableMessage | CardJSXElement`
|
|
@@ -122,10 +122,13 @@ await thread.setState({ aiMode: false }, { replace: true });
|
|
|
122
122
|
|
|
123
123
|
## startTyping
|
|
124
124
|
|
|
125
|
-
Show a typing indicator in the thread. No-op on platforms that don't support it.
|
|
125
|
+
Show a typing indicator in the thread. No-op on platforms that don't support it. On Slack, you can pass an optional `status` string to show a custom loading message (requires `assistant:write` scope).
|
|
126
126
|
|
|
127
127
|
```typescript
|
|
128
128
|
await thread.startTyping();
|
|
129
|
+
|
|
130
|
+
// With custom status (Slack only)
|
|
131
|
+
await thread.startTyping("Searching documents...");
|
|
129
132
|
```
|
|
130
133
|
|
|
131
134
|
## messages / allMessages
|
package/docs/cards.mdx
CHANGED
|
@@ -177,6 +177,30 @@ Radio button group for mutually exclusive choices.
|
|
|
177
177
|
</Actions>
|
|
178
178
|
```
|
|
179
179
|
|
|
180
|
+
### Table
|
|
181
|
+
|
|
182
|
+
Structured data display with column headers and rows. Renders as a native table on platforms that support it (Teams, GitHub, Linear) and as padded ASCII text elsewhere.
|
|
183
|
+
|
|
184
|
+
```tsx title="lib/bot.tsx" lineNumbers
|
|
185
|
+
<Table
|
|
186
|
+
headers={["Name", "Age", "Role"]}
|
|
187
|
+
rows={[
|
|
188
|
+
["Alice", "30", "Engineer"],
|
|
189
|
+
["Bob", "25", "Designer"],
|
|
190
|
+
]}
|
|
191
|
+
/>
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
Optional column alignment:
|
|
195
|
+
|
|
196
|
+
```tsx title="lib/bot.tsx"
|
|
197
|
+
<Table
|
|
198
|
+
headers={["Name", "Amount"]}
|
|
199
|
+
rows={[["Alice", "$100"], ["Bob", "$200"]]}
|
|
200
|
+
align={["left", "right"]}
|
|
201
|
+
/>
|
|
202
|
+
```
|
|
203
|
+
|
|
180
204
|
### Image
|
|
181
205
|
|
|
182
206
|
Embeds an image in the card.
|