fed8b2eed7
Build and push multi-arch DocsGPT Docker image / build (linux/amd64, ubuntu-latest, amd64) (push) Has been cancelled
Backend release / release (push) Has been cancelled
Bandit Security Scan / bandit_scan (push) Has been cancelled
Build and push multi-arch DocsGPT Docker image / build (linux/arm64, ubuntu-24.04-arm, arm64) (push) Has been cancelled
Build and push multi-arch DocsGPT Docker image / manifest (push) Has been cancelled
Build and push DocsGPT FE Docker image for development / build (linux/amd64, ubuntu-latest, amd64) (push) Has been cancelled
Build and push DocsGPT FE Docker image for development / build (linux/arm64, ubuntu-24.04-arm, arm64) (push) Has been cancelled
Build and push DocsGPT FE Docker image for development / manifest (push) Has been cancelled
Python linting / ruff (push) Has been cancelled
Run python tests with pytest / Run tests and count coverage (3.12) (push) Has been cancelled
React Widget Build / build (push) Has been cancelled
92 lines
4.6 KiB
Plaintext
92 lines
4.6 KiB
Plaintext
---
|
||
title: Realtime Events & Notifications (SSE)
|
||
description: Subscribe to DocsGPT's server-sent events channel for live notifications — ingestion progress, tool approvals, MCP OAuth completion — and reconnect to an in-flight chat answer.
|
||
---
|
||
|
||
import { Callout } from 'nextra/components'
|
||
|
||
# Realtime Events & Notifications
|
||
|
||
DocsGPT pushes realtime updates to the browser over **Server-Sent Events (SSE)**. This is what powers the upload toasts, tool-approval prompts, and other live notifications in the UI. There are two channels:
|
||
|
||
- **User events** — `GET /api/events`: a per-user notification stream (ingestion progress, tool approvals, MCP OAuth completion, …).
|
||
- **Chat reconnect** — `GET /api/messages/<message_id>/events`: resume an answer stream that was interrupted mid-generation.
|
||
|
||
<Callout type="info" emoji="ℹ️">
|
||
Both channels require Redis (already a DocsGPT dependency). The publisher can be turned off instance-wide with `ENABLE_SSE_PUSH=false`.
|
||
</Callout>
|
||
|
||
## User events channel
|
||
|
||
Open an SSE connection to receive notifications for the authenticated user:
|
||
|
||
```text
|
||
GET /api/events
|
||
Accept: text/event-stream
|
||
Authorization: Bearer <token>
|
||
```
|
||
|
||
Each event is a JSON object with a `type` field, for example:
|
||
|
||
```text
|
||
id: 1718900000000-0
|
||
data: {"type":"source.ingest.queued","scope":{"id":"<source_id>"}, ...}
|
||
```
|
||
|
||
Common event types:
|
||
|
||
| Type | Meaning |
|
||
| --- | --- |
|
||
| `source.ingest.queued` | A source ingestion task was enqueued (drives the upload toast). |
|
||
| `mcp.oauth.completed` | An MCP server's OAuth handshake finished. |
|
||
| tool-approval events | An agent is requesting approval to run a tool. |
|
||
| `backlog.truncated` | The client's cursor slid off the retained backlog window — clear your cursor and refetch state. |
|
||
|
||
### Reconnecting and backlog replay
|
||
|
||
Events are journaled per user in a Redis Stream so a client that reconnects can catch up on what it missed. Send the last id you processed and DocsGPT replays everything after it:
|
||
|
||
```text
|
||
GET /api/events
|
||
Last-Event-ID: 1718900000000-0
|
||
```
|
||
|
||
(You may also pass it as a `last_event_id` query parameter.) Each delivered event carries its own `id:`, so your cursor advances as you read. If you fall a long way behind, the snapshot is delivered across several reconnects rather than all at once.
|
||
|
||
A few bounded behaviors to be aware of:
|
||
|
||
- The backlog is capped at `EVENTS_STREAM_MAXLEN` entries (default 1000). If your `Last-Event-ID` is older than the oldest retained entry, you receive a `backlog.truncated` event — reset your cursor and refetch current state.
|
||
- Each snapshot is capped at `EVENTS_REPLAY_MAX_PER_REQUEST` entries per request (default 200); reconnect to continue.
|
||
- There is a per-user cap on simultaneous connections (`SSE_MAX_CONCURRENT_PER_USER`, default 8) and a windowed replay budget. Exceeding either returns **HTTP 429** — back off and retry.
|
||
|
||
## Chat answer reconnect
|
||
|
||
When an answer is streaming and the connection drops, resume it without losing the in-progress generation:
|
||
|
||
```text
|
||
GET /api/messages/<message_id>/events
|
||
```
|
||
|
||
This replays the message's events past your last-seen sequence number and tails the rest live. It is backed by the Postgres `message_events` journal (retained for `MESSAGE_EVENTS_RETENTION_DAYS`, default 14).
|
||
|
||
<Callout type="warning" emoji="⚠️">
|
||
The chat reconnect endpoint is a native-async route served by the ASGI entrypoint. Under a plain `flask run` dev server it returns `404`; run the backend via the ASGI app (`uvicorn application.asgi:asgi_app`) or the production gunicorn uvicorn worker to use it. See the [Development Environment](/Deploying/Development-Environment) guide.
|
||
</Callout>
|
||
|
||
## Settings
|
||
|
||
| Setting | Default | Purpose |
|
||
| --- | --- | --- |
|
||
| `ENABLE_SSE_PUSH` | `true` | Master switch for the publisher and channel. |
|
||
| `EVENTS_STREAM_MAXLEN` | `1000` | Per-user backlog cap (approximate). |
|
||
| `SSE_KEEPALIVE_SECONDS` | `15` | Keepalive comment-frame cadence (keep below your proxy's idle timeout). |
|
||
| `SSE_MAX_CONCURRENT_PER_USER` | `8` | Max simultaneous SSE connections per user (`0` disables the cap). |
|
||
| `EVENTS_REPLAY_MAX_PER_REQUEST` | `200` | Max backlog entries per replay request. |
|
||
| `EVENTS_REPLAY_BUDGET_REQUESTS_PER_WINDOW` | `30` | Per-user replay requests per window (`0` disables). |
|
||
| `EVENTS_REPLAY_BUDGET_WINDOW_SECONDS` | `60` | Replay budget window length. |
|
||
| `MESSAGE_EVENTS_RETENTION_DAYS` | `14` | Retention for the chat-stream `message_events` journal. |
|
||
|
||
<Callout type="info" emoji="ℹ️">
|
||
Operators debugging delivery issues ("the toast never appeared", "the answer didn't reconnect") can follow the SSE notifications runbook in the repository at `docs/runbooks/sse-notifications.md`.
|
||
</Callout>
|