# Durable streaming

> Resume an interrupted stream from the last received event.

Source: https://maincode.com/docs/client-sdk-durable-streaming
Section: Client SDK · Matilda documentation

---

Durable streaming lets a client disconnect mid-stream and resume from where it left off. The server buffers events in a Redis stream, keyed by a `streamId` advertised at stream start.

## Durable streaming lifecycle

1. Start a stream — `chat.stream()` emits a `response.created` event with a `streamId`.
2. Persist the `streamId` and `conversationId` immediately.
3. If disconnected, call `chat.activeStream(conversationId)` to check if the stream is still live.
4. Call `chat.resume({ streamId, lastEventId })` to replay buffered events from `lastEventId` onwards.

## `chat.resume(params, options?)`

Resumes a previously detached stream by replaying buffered events from `lastEventId`. Returns an async generator of `MatildaChatStreamEvent`.

```ts
for await (const event of client.chat.resume({
  streamId: savedStreamId,
  lastEventId: savedLastEventId,
})) {
  if (event.type === 'response.output_text.delta') {
    process.stdout.write(event.delta);
  }
}
```

### `ChatResumeParams`

| Field | Type | Description |
| - | - | - |
| `streamId` | `string` | The stream ID from response.created. |
| `lastEventId` | `string` | The last Redis stream entry ID received. Omit to replay from the start. |

## `chat.activeStream(conversationId, options?)`

Checks whether a conversation has an active stream.

```ts
const result = await client.chat.activeStream('conv-123');
// { stream_id: 'abc-123' | null, status: 'active' | 'done' | 'error' | null }
```

Returns `Promise<ActiveStreamLookup>`:

```ts
interface ActiveStreamLookup {
  stream_id: string | null;
  status: 'active' | 'done' | 'error' | null;
}
```

## `chat.notifyOnCompletion(streamId, enabled?, options?)`

Request a push notification when a backgrounded stream completes.

```ts
await client.chat.notifyOnCompletion(streamId, true);
```

| Field | Type | Description |
| - | - | - |
| `streamId` | `string` | The stream to watch. |
| `enabled` | `boolean` | Enable or disable the notification. Defaults to true. |

Returns `Promise<{ status: string }>`.

## Full resume example

```ts title="resume.ts"
import Matilda from '@maincode-ai/matilda-client-sdk';

const client = new Matilda({
  baseUrl: 'https://matilda.maincode.com/api',
  accessToken: process.env.MATILDA_ACCESS_TOKEN!,
});

let streamId: string | null = null;
let lastEventId: string | undefined;

// Start streaming
for await (const event of client.chat.stream({
  input: 'Write a long essay about Australia.',
  conversationId: 'conv-123',
})) {
  if (event.type === 'response.created') {
    streamId = event.streamId;
  }
  if (event.type === 'response.cursor') {
    lastEventId = event.lastEventId;
  }
  if (event.type === 'response.output_text.delta') {
    process.stdout.write(event.delta);
  }
}

// Later — check if the stream is still active, then resume
const active = await client.chat.activeStream('conv-123');
if (active.status === 'active' && streamId) {
  console.log('\n--- Resuming ---');
  for await (const event of client.chat.resume({ streamId, lastEventId })) {
    if (event.type === 'response.output_text.delta') {
      process.stdout.write(event.delta);
    }
  }
}
```
