Skip to content

Real-Time Events

RTC Agent pushes real-time events via Centrifuge WebSocket, using a dual-channel architecture: the Topic channel ensures reliability, while the Live channel provides low latency. The frontend updates local state upon receiving events, achieving real-time frontend-backend synchronization.

ChannelIdentifierStoragePurposeFeatures
Topictopic:u=<userID>PersistedState change eventsReliable, ordered, supports offline recovery
Livelive:u=<userID>Non-persistedStreaming message intermediate chunksLow latency, fire-and-forget

💡 Why two channels? State changes (e.g., message creation, Turn completion) must not be lost — they need persistence and ordering guarantees. But streaming intermediate chunks only need to “arrive as fast as possible” — it’s fine if one is lost, because the complete message will eventually be received. Handling them separately leverages the strengths of each.


Event TypeTopic ChannelLive ChannelDescription
session.createdSession created
session.updatedSession updated (title, status, etc.)
turn.createdTurn created
turn.updatedTurn state changed
message.createdMessage created
message.updated (stream complete)Final complete version of a streamed message
message.updated (stream intermediate chunk)Real-time fragments for the typewriter effect
rtc.createdReserved (not currently emitted)
rtc.updatedRTC state changed

Each event is an Update — describing changes to an entity (Session / Turn / Message / RTC):

{
"id": "update-uuid",
"items": [
{ "entity": "message", "action": "created", "entity_id": "msg-uuid" }
],
"data_list": [{ "id": "msg-uuid", "role": "assistant", "..." : "..." }],
"offset": 42
}
FieldTypeDescription
idUUIDUpdate unique identifier
itemsarrayList of change entries
items[].entitystringEntity type: session / turn / message / rtc (file is reserved, currently unused)
items[].actionstringAction type: created / updated (deleted is reserved, currently unused; deletion is expressed via deleted_at in data_list)
items[].entity_idUUIDEntity ID
data_listarrayComplete entity data (optional, corresponds one-to-one with items)
offsetintegerMonotonically increasing offset per user

Offset is the core guarantee for event reliability — each Topic event is assigned a strictly increasing Offset, and the client detects lost events by checking Offset continuity.

FeatureDescription
Monotonically increasingTopic event Offsets for the same user are strictly increasing
Continuity detectionClient automatically backfills when an Offset gap is detected
PersistedOffset is stored in IndexedDB, restored after page refresh
Epoch mechanismWhen historical data is cleaned up, the Epoch changes and the client starts from the latest position
Gap placeholderDuring offline recovery, the server sends {"type": "gap", "data": {}} events to fill Offset gaps; the client only advances the Offset without any business processing

💡 Analogy: Offset is like the numbering on letters. If you receive letters #1, #2, and #4, you realize #3 is missing — then you go to the post office to claim it.


AI replies use streaming output. Intermediate chunks are pushed in real-time via the Live channel, and the final complete message is delivered via the Topic channel to ensure reliability.

PhaseChannelBehavior
First chunkTopicCreate message record, push message.created, also write to Redis buffer
Intermediate chunksLiveAppend to Redis buffer, push to Live channel for real-time display
Stream endsTopicRead all chunks from Redis, assemble complete content, update database, push message.updated

After a client reconnects following a network disconnection, the system automatically checks the Offset and backfills missing events.

ScenarioBehaviorUser Perception
Brief disconnectionAutomatically pushes messages from the offline periodSeamless; messages appear automatically
Extended disconnectionDetects Offset gap, fetches historyShort loading, then messages are filled in
History cleaned upEpoch changes, starts from the latest positionHistorical messages no longer displayed
ComponentResponsibility
Centrifuge SDKAuto-reconnection, Token refresh
IndexedDBPersist Offset, restore after page refresh
Topic ChannelEnsures offline events are not lost