chat 4.20.0 → 4.20.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/dist/index.d.ts +90 -5
- package/dist/index.js +139 -9
- package/dist/index.js.map +1 -1
- package/docs/api/index.mdx +6 -0
- package/docs/api/message.mdx +48 -0
- package/docs/handling-events.mdx +5 -5
- package/docs/streaming.mdx +54 -7
- package/package.json +1 -1
package/docs/api/index.mdx
CHANGED
|
@@ -20,6 +20,12 @@ import { Chat, root, paragraph, text, Card, Button, emoji } from "chat";
|
|
|
20
20
|
| [`Message`](/docs/api/message) | Normalized message with text, AST, author, and metadata |
|
|
21
21
|
| [`ScheduledMessage`](/docs/api/thread#scheduledmessage) | Returned by `thread.schedule()` / `channel.schedule()` with `cancel()` |
|
|
22
22
|
|
|
23
|
+
## Utilities
|
|
24
|
+
|
|
25
|
+
| Export | Description |
|
|
26
|
+
|--------|-------------|
|
|
27
|
+
| [`toAiMessages`](/docs/streaming#toaimessagesmessages-options) | Convert `Message[]` to AI SDK `{ role, content }[]` format |
|
|
28
|
+
|
|
23
29
|
## Message formats
|
|
24
30
|
|
|
25
31
|
| Export | Description |
|
package/docs/api/message.mdx
CHANGED
|
@@ -46,6 +46,10 @@ import { Message } from "chat";
|
|
|
46
46
|
description: 'File attachments.',
|
|
47
47
|
type: 'Attachment[]',
|
|
48
48
|
},
|
|
49
|
+
links: {
|
|
50
|
+
description: 'Links found in the message, with optional preview metadata.',
|
|
51
|
+
type: 'LinkPreview[]',
|
|
52
|
+
},
|
|
49
53
|
isMention: {
|
|
50
54
|
description: 'Whether the bot was @-mentioned in this message.',
|
|
51
55
|
type: 'boolean | undefined',
|
|
@@ -148,6 +152,50 @@ All adapters return `false` if the bot ID isn't known yet. This is a safe defaul
|
|
|
148
152
|
}}
|
|
149
153
|
/>
|
|
150
154
|
|
|
155
|
+
## LinkPreview
|
|
156
|
+
|
|
157
|
+
Links found in incoming messages are extracted and exposed as `LinkPreview` objects. On platforms that support it (currently Slack), links pointing to other chat messages include a `fetchMessage()` callback to retrieve the full linked message.
|
|
158
|
+
|
|
159
|
+
<TypeTable
|
|
160
|
+
type={{
|
|
161
|
+
url: {
|
|
162
|
+
description: 'The URL.',
|
|
163
|
+
type: 'string',
|
|
164
|
+
},
|
|
165
|
+
title: {
|
|
166
|
+
description: 'Title from unfurl metadata (if available).',
|
|
167
|
+
type: 'string | undefined',
|
|
168
|
+
},
|
|
169
|
+
description: {
|
|
170
|
+
description: 'Description from unfurl metadata (if available).',
|
|
171
|
+
type: 'string | undefined',
|
|
172
|
+
},
|
|
173
|
+
imageUrl: {
|
|
174
|
+
description: 'Preview image URL (if available).',
|
|
175
|
+
type: 'string | undefined',
|
|
176
|
+
},
|
|
177
|
+
siteName: {
|
|
178
|
+
description: 'Site name, e.g. "Vercel" (if available).',
|
|
179
|
+
type: 'string | undefined',
|
|
180
|
+
},
|
|
181
|
+
'fetchMessage()': {
|
|
182
|
+
description: 'Fetch the linked chat message. Available when the URL points to a message on the same platform (e.g. a Slack message link).',
|
|
183
|
+
type: '() => Promise<Message> | undefined',
|
|
184
|
+
},
|
|
185
|
+
}}
|
|
186
|
+
/>
|
|
187
|
+
|
|
188
|
+
<Callout type="info">
|
|
189
|
+
When using [`toAiMessages()`](/docs/streaming#toaimessagesmessages-options), link metadata is automatically appended to the message content. Embedded message links are labeled as `[Embedded message: ...]` so the AI model understands the context.
|
|
190
|
+
</Callout>
|
|
191
|
+
|
|
192
|
+
### Platform support
|
|
193
|
+
|
|
194
|
+
| Platform | Link extraction | `fetchMessage()` |
|
|
195
|
+
|----------|----------------|-------------------|
|
|
196
|
+
| Slack | URLs from `rich_text` blocks or `<url>` text patterns | Slack message links (`*.slack.com/archives/...`) |
|
|
197
|
+
| Others | Not yet — `links` is always `[]` | — |
|
|
198
|
+
|
|
151
199
|
## Serialization
|
|
152
200
|
|
|
153
201
|
Messages can be serialized for workflow engines and external systems.
|
package/docs/handling-events.mdx
CHANGED
|
@@ -94,18 +94,18 @@ Messages sent by the bot itself do not trigger this handler. You don't need to f
|
|
|
94
94
|
### Example: Conversational AI with history
|
|
95
95
|
|
|
96
96
|
```typescript title="lib/bot.ts" lineNumbers
|
|
97
|
+
import { toAiMessages } from "chat";
|
|
98
|
+
|
|
97
99
|
bot.onSubscribedMessage(async (thread, message) => {
|
|
98
100
|
await thread.startTyping();
|
|
99
101
|
|
|
100
102
|
// Build conversation history from thread messages
|
|
101
|
-
const
|
|
103
|
+
const messages = [];
|
|
102
104
|
for await (const msg of thread.allMessages) {
|
|
103
|
-
|
|
104
|
-
role: msg.author.isMe ? "assistant" : "user",
|
|
105
|
-
content: msg.text,
|
|
106
|
-
});
|
|
105
|
+
messages.push(msg);
|
|
107
106
|
}
|
|
108
107
|
|
|
108
|
+
const history = await toAiMessages(messages);
|
|
109
109
|
const response = await generateAIResponse(history);
|
|
110
110
|
await thread.post(response);
|
|
111
111
|
});
|
package/docs/streaming.mdx
CHANGED
|
@@ -183,21 +183,68 @@ await thread.stream(textStream, {
|
|
|
183
183
|
|
|
184
184
|
## Streaming with conversation history
|
|
185
185
|
|
|
186
|
-
Combine message history with streaming for multi-turn AI conversations
|
|
186
|
+
Combine message history with streaming for multi-turn AI conversations.
|
|
187
|
+
Use `toAiMessages()` to convert chat messages into the `{ role, content }` format expected by AI SDKs:
|
|
187
188
|
|
|
188
189
|
```typescript title="lib/bot.ts" lineNumbers
|
|
190
|
+
import { toAiMessages } from "chat";
|
|
191
|
+
|
|
189
192
|
bot.onSubscribedMessage(async (thread, message) => {
|
|
190
193
|
// Fetch recent messages for context
|
|
191
194
|
const result = await thread.adapter.fetchMessages(thread.id, { limit: 20 });
|
|
192
195
|
|
|
193
|
-
const history = result.messages
|
|
194
|
-
.filter((msg) => msg.text.trim())
|
|
195
|
-
.map((msg) => ({
|
|
196
|
-
role: msg.author.isMe ? "assistant" as const : "user" as const,
|
|
197
|
-
content: msg.text,
|
|
198
|
-
}));
|
|
196
|
+
const history = await toAiMessages(result.messages);
|
|
199
197
|
|
|
200
198
|
const response = await agent.stream({ prompt: history });
|
|
201
199
|
await thread.post(response.fullStream);
|
|
202
200
|
});
|
|
203
201
|
```
|
|
202
|
+
|
|
203
|
+
### `toAiMessages(messages, options?)`
|
|
204
|
+
|
|
205
|
+
Converts an array of `Message` objects into AI SDK conversation format:
|
|
206
|
+
|
|
207
|
+
- Maps `author.isMe` to `"assistant"` role, all others to `"user"`
|
|
208
|
+
- Filters out empty messages
|
|
209
|
+
- Sorts chronologically (oldest first)
|
|
210
|
+
- Appends link metadata (URLs, titles, descriptions) when present
|
|
211
|
+
- Labels embedded message links (e.g. shared Slack messages) as `[Embedded message: ...]`
|
|
212
|
+
|
|
213
|
+
| Option | Type | Default | Description |
|
|
214
|
+
|--------|------|---------|-------------|
|
|
215
|
+
| `includeNames` | `boolean` | `false` | Prefix user messages with `[username]: ` for multi-user context |
|
|
216
|
+
| `transformMessage` | `(aiMessage, source) => AiMessage \| Promise<AiMessage \| null> \| null` | — | Transform or filter each message after default processing. Return `null` to skip. |
|
|
217
|
+
| `onUnsupportedAttachment` | `(attachment, message) => void` | `console.warn` | Called when an attachment type is not supported |
|
|
218
|
+
|
|
219
|
+
### Customizing messages with `transformMessage`
|
|
220
|
+
|
|
221
|
+
Use `transformMessage` to modify, enrich, or filter messages after default processing:
|
|
222
|
+
|
|
223
|
+
```typescript title="lib/bot.ts" lineNumbers
|
|
224
|
+
import { toAiMessages } from "chat";
|
|
225
|
+
|
|
226
|
+
const history = await toAiMessages(result.messages, {
|
|
227
|
+
transformMessage: (aiMessage, source) => {
|
|
228
|
+
// Replace bot user IDs with readable names
|
|
229
|
+
if (typeof aiMessage.content === "string") {
|
|
230
|
+
return {
|
|
231
|
+
...aiMessage,
|
|
232
|
+
content: aiMessage.content.replace(/<@U123>/g, "@VercelBot"),
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
return aiMessage;
|
|
236
|
+
},
|
|
237
|
+
});
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
Return `null` to skip a message entirely:
|
|
241
|
+
|
|
242
|
+
```typescript
|
|
243
|
+
const history = await toAiMessages(result.messages, {
|
|
244
|
+
transformMessage: (aiMessage, source) => {
|
|
245
|
+
// Skip messages from a specific user
|
|
246
|
+
if (source.author.userId === "U_NOISY_BOT") return null;
|
|
247
|
+
return aiMessage;
|
|
248
|
+
},
|
|
249
|
+
});
|
|
250
|
+
```
|