mirror of
https://github.com/vercel/chat.git
synced 2026-09-14 18:32:29 +08:00
169788b65a
Adds `bot.history` as the canonical entry point for message history,
with three scopes: `user`, `thread`, and `channel`. `bot.transcripts`
stays as a deprecated alias, so nothing breaks.
## Why
History access was spread across `bot.transcripts`, `thread.messages` /
`thread.allMessages`, and per-adapter calls. `bot.history` puts the
promise-based read paths in one place, and the AI tools
(`fetchMessages`, `fetchChannelMessages`, `listThreads`) now route
through it.
## User scope
Cross-platform per-user persistence, identical in surface to
`bot.transcripts`:
```typescript
const bot = new Chat({
adapters: { slack, telegram },
state,
history: {
user: {
identity: ({ author }) => author.email ?? null,
retention: "30d",
maxPerUser: 200,
},
},
});
await bot.history.user.append(thread, message);
const entries = await bot.history.user.list({ userKey, limit: 20 });
await bot.history.user.delete({ userKey });
```
The new `toPromptEntries` helper turns those entries into `{ role,
content }` messages for an LLM call:
```typescript
import { toPromptEntries } from "chat";
const entries = await bot.history.user.list({ userKey });
const { text } = await generateText({
model,
messages: toPromptEntries(entries),
});
```
## Thread scope
Single-page reads and an auto-paginating generator:
```typescript
// One page, newest messages by default
const { messages, nextCursor } = await bot.history.thread.list(thread.id, {
limit: 20,
});
// Everything, oldest first, pagination handled for you
for await (const msg of bot.history.thread.collect(thread.id, { limit: 50 })) {
console.log(msg.text);
}
```
## Channel scope
```typescript
// Top-level channel messages (not thread replies)
const { messages } = await bot.history.channel.listMessages("slack:C123", {
limit: 20,
});
// Thread listings
const { threads } = await bot.history.channel.listThreads("slack:C123");
// Threads together with a page of messages each
const result = await bot.history.channel.listThreadsWithMessages("slack:C123", {
maxThreads: 5,
messagesPerThread: 10,
});
```
## Semantics
The read paths are strict about where data comes from:
- The adapter named in the ID prefix must be registered. A typo'd or
unknown prefix throws instead of reading as an empty conversation.
- The SDK-side `ThreadHistoryCache` only serves adapters that persist
history there (`persistThreadHistory: true`, e.g. Telegram, WhatsApp).
For every other adapter the platform response is authoritative, so an
empty page is a real empty page, and a `cursor` always returns the
adapter's response as-is.
- Cache reads honor the same windows as adapter reads: backward
(default) gives the newest N, forward the oldest N, and `collect()`
yields the oldest N on both paths.
- `channel.listMessages` throws a capability error on adapters without
`fetchChannelMessages` (persisting adapters are served from the
channel-keyed cache instead), and `listThreadsWithMessages` fetches
per-thread pages through `history.thread.list` a few threads at a time
to stay inside platform rate limits.
## Migration
```typescript
// Before
const bot = new Chat({
identity: ({ author }) => author.email ?? null,
transcripts: { retention: "30d", maxPerUser: 200 },
});
await bot.transcripts.append(thread, msg);
// After
const bot = new Chat({
history: {
user: {
identity: ({ author }) => author.email ?? null,
retention: "30d",
maxPerUser: 200,
},
},
});
await bot.history.user.append(thread, msg);
```
You can migrate one field at a time: when both `history.user` and the
legacy `transcripts` block are set they merge, with `history.user`
winning field by field, so settings left on `transcripts` keep applying
until you move them. `TranscriptEntry` is deprecated in favour of
`HistoryEntry` (also exported as `UserHistoryEntry`); all deprecated
names keep working in the current major version.
## Included
- New `packages/chat/src/history/` module with unit tests for every
scope
- AI tools rewired to `bot.history`, keeping their scope guards
- The nextjs example uses the new APIs throughout, with Thread History
and Channel History test buttons that exercise every scope
- Docs: `/docs/history` guide, `/docs/api/history` reference,
deprecation callouts on the transcripts pages
- Changeset (`minor` for `chat`)
---------
Co-authored-by: Ben Sabic <bensabic@users.noreply.github.com>