Skip to main content
When building chat interfaces, it’s common to encounter network interruptions, page refreshes, or serverless function timeouts that can break the connection to an in-progress agent. Where a standard chat implementation would require the user to resend their message and wait for the entire response again, workflow runs are durable, and so are the streams attached to them. This means a stream can be resumed at any point, optionally only syncing the data that was missed since the last connection. Resumable streams come out of the box with Workflow DevKit. The WorkflowChatTransport helper provides a drop-in transport for the AI SDK that handles client-side resumption logic automatically.

Implementing Stream Resumption

Let’s add stream resumption to a basic durable agent:
1

Return the Run ID from Your API

Modify your chat endpoint to include the workflow run ID in a response header:
app/api/chat/route.ts
2

Add a Stream Reconnection Endpoint

Create a new API route that returns the stream for an existing run:
app/api/chat/[id]/stream/route.ts
The startIndex parameter ensures the client can resume from exactly where it left off.
3

Use WorkflowChatTransport in the Client

Replace the default transport in useChat with WorkflowChatTransport:
app/page.tsx
Now try refreshing the page during a response, or simulate a network interruption. The client will automatically reconnect to the same stream and continue from where it left off.

How It Works

  1. Initial request: When the user sends a message, WorkflowChatTransport makes a POST to /api/chat
  2. Run ID storage: The API starts a workflow and returns the run ID in the x-workflow-run-id header
  3. Callback execution: onChatSendMessage stores this run ID in localStorage
  4. Automatic reconnection: If the stream is interrupted before receiving a “finish” chunk, the transport automatically reconnects
  5. URL construction: prepareReconnectToStreamRequest builds the reconnection URL using the stored run ID
  6. Resume from index: The reconnection endpoint returns the stream from the last known position
  7. Cleanup: When the stream completes, onChatEnd clears the stored run ID
This approach also handles page refreshes. The client will automatically reconnect to the stream from the last known position when the UI loads with a stored run ID.

Advanced Configuration

Custom Run ID Storage

Instead of localStorage, store the run ID in a database:
lineNumbers

Error Handling

Handle reconnection errors gracefully:
lineNumbers

Authentication

Add authentication headers to reconnection requests:
lineNumbers

Manual Reconnection

Trigger reconnection manually:
lineNumbers

Testing Resumability

Simulate Network Interruption

Test stream resumption by artificially interrupting the connection:
lineNumbers

Simulate Function Timeout

Test resumption after serverless function timeout:
app/api/chat/route.ts