You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat (ui/react): support resuming an ongoing stream (vercel#6053)
## Background
This pull request adds the ability for clients to resume an ongoing chat
generation stream after a network disconnect.
## Summary
This pull request adds support for the `useChat` hook to resume an
ongoing chat generation stream by exposing `experimental_resume()` that
can be called by any client, typically during the initial mount of the
hook.
The `experimental_resume` function makes a `GET` request to the api
endpoint you've initialized the hook with (or `/api/chat` by default)
and streams the contents of the stream if it is active or fails silently
if it has ended.
In order for `experimental_resume` to work as intended, it requires the
usage of the
[`resumable-stream`](https://www.npmjs.com/package/resumable-stream)
package for stream creation and a redis instance for the package to
manage the pub/sub mechanism.
## Verification
An example has been added at `examples/next-openai/app/use-chat-resume`
to test the feature. Follow the following steps to test it end-to-end:
1. Run the development server
2. Navigate to `http://localhost:3000/use-chat-resume`
3. Send a message that will have a longer generation duration, example
"Write an essay about Michael Jordan"
4. Once the generation starts, click the chat id above to open the
conversation in a new tab
5. Verify the stream gets resumed
## Tasks
- [x] Tests have been added / updated (for bug fixes / features)
- [x] Documentation has been added / updated (for bug fixes / features)
- [x] A _patch_ changeset for relevant packages has been added
- [x] Formatting issues have been fixed (run `pnpm prettier-fix` in the
project root)
Copy file name to clipboardExpand all lines: content/docs/04-ai-sdk-ui/03-chatbot-message-persistence.mdx
+162Lines changed: 162 additions & 0 deletions
Original file line number
Diff line number
Diff line change
@@ -325,3 +325,165 @@ When the client reloads the page after a disconnect, the chat will be restored f
325
325
the case where the client reloads the page after a disconnection, but the
326
326
streaming is not yet complete.
327
327
</Note>
328
+
329
+
## Resuming ongoing streams
330
+
331
+
<Note>This feature is experimental and may change in future versions.</Note>
332
+
333
+
The `useChat` hook has experimental support for resuming an ongoing chat generation stream by any client, either after a network disconnect or by reloading the chat page. This can be useful for building applications that involve long-running conversations or for ensuring that messages are not lost in case of network failures.
334
+
335
+
The following are the pre-requisities for your chat application to support resumable streams:
336
+
337
+
- Installing the [`resumable-stream`](https://www.npmjs.com/package/resumable-stream) package that helps create and manage the publisher/subscriber mechanism of the streams.
338
+
- Creating a [Redis](https://vercel.com/marketplace/redis) instance to store the stream state.
339
+
- Creating a table that tracks the stream IDs associated with a chat.
340
+
341
+
To resume a chat stream, you will use the `experimental_resume` function returned by the `useChat` hook. You will call this function during the initial mount of the hook inside the main chat component.
342
+
343
+
```tsx filename="app/components/chat.tsx"
344
+
'use client'
345
+
346
+
import { useChat } from"@ai-sdk/react";
347
+
import { Input } from"@/components/input";
348
+
import { Messages } from"@/components/messages";
349
+
350
+
exportfunction Chat() {
351
+
const { experimental_resume } =useChat({id});
352
+
353
+
useEffect(() => {
354
+
experimental_resume();
355
+
356
+
// we use an empty dependency array to
357
+
// ensure this effect runs only once
358
+
}, [])
359
+
360
+
return (
361
+
<div>
362
+
<Messages>
363
+
<Input/>
364
+
</div>
365
+
)
366
+
}
367
+
```
368
+
369
+
The `experimental_resume` function makes a `GET` request to your configured chat endpoint (or `/api/chat` by default) whenever your client calls it. If there’s an active stream, it will pick up where it left off, otherwise it simply finishes without error.
370
+
371
+
The `GET` request automatically appends the `chatId` query parameter to the URL to help identify the chat the request belongs to. Using the `chatId`, you can look up the most recent stream ID from the database and resume the stream.
372
+
373
+
```bash
374
+
GET /api/chat?chatId=<your-chat-id>
375
+
```
376
+
377
+
Earlier, you must've implemented the `POST` handler for the `/api/chat` route to create new chat generations. When using `experimental_resume`, you must also implement the `GET` handler for `/api/chat` route to resume streams.
378
+
379
+
### 1. Implement the GET handler
380
+
381
+
Add a `GET` method to `/api/chat` that:
382
+
383
+
1. Reads `chatId` from the query string
384
+
2. Validates it’s present
385
+
3. Loads any stored stream IDs for that chat
386
+
4. Returns the latest one to `streamContext.resumableStream()`
387
+
5. Falls back to an empty stream if it’s already closed
388
+
389
+
```ts filename="app/api/chat/route.ts"
390
+
import {loadStreams} from '@/util/chat-store';
391
+
import {createDataStream} from 'ai';
392
+
import {after} from 'next/server';
393
+
import {createResumableStreamContext} from 'resumable-stream';
0 commit comments