Skip to content

Realtime

A stream holds one connection open and pushes Events as they happen; a client that drops resumes from the last sequence number it saw.

A stream holds one connection open and pushes Events the moment they happen. A client that drops reconnects with the last sequence number it saw and misses nothing.

Three ways to hear an Event

Every Event reaches code in one of three ways. They read the same Events, with the same selectors, under the same Permissions.

WayUse it whenSurvives a restart
WatchA server with a public URL must hear every EventYes: the platform retries for three days
StreamA browser, an App, a Dashboard or an agent session wants Events liveYes: the client resumes from its cursor
$.onA script or a long-running worker wants Events in processNo: it hears Events while it runs

Realtime is the capability behind streams. A stream is a read: it creates no Action and emits no Events of its own.

Open a stream

answerdesk.ai is an Agent as a Service that answers support email for small software companies. Its operator Dashboard shows each Conversation the moment it opens or closes:

Text
Show me each conversation as it happens.

Over HTTP the stream is server-sent events. Each frame carries the Event's sequence number as its id, its name as event, and the Event in the delivery shape as data:

Text
id: 40211
event: Conversation.answered
data: {"$id":"https://api.sb/answerdesk.ai/events/event_40211","name":"Conversation.answered","seq":40211,"data":{"conversation":{"$id":"https://api.sb/answerdesk.ai/conversations/conversation_9"}}}

A stream is the Event list held open: Accept: text/event-stream on GET /events. where takes the filter grammar lists and Watches share: name = Conversation.* and channel = channel_4. A caller sees only the Events its key may read, so a Customer's stream carries only its own Tenant.

An Agent connected over MCP subscribes to the same URL as a resource. The client receives an update notification per Event and reads it in the agent's context.

Resume from a cursor

seq increases by one per Event in a namespace, and Events are kept forever. Any seq is therefore a cursor into the full history.

A browser's EventSource reconnects by itself and sends the last id it saw as Last-Event-ID. The stream continues from the next Event, in order, with nothing skipped. Any other client passes cursor=40211 and gets the same result.

To load history and then go live, open the stream with an old cursor. It replays every matching Event since then at full speed, then keeps the connection open for new ones.

The server sends a comment line every 15 seconds. A client that hears nothing for 45 seconds reconnects with its cursor.

Two-way streams

Web sockets carry the same Events at wss://api.sb/<namespace>/events/stream, with the same select and cursor parameters. Use them when the client also talks back.

A web socket client changes its selection without reconnecting, and it sends presence and typing to a Channel's members. Presence and typing reach the Channel live and are never stored.

Stream a result token by token

A Verb whose result is generated text can stream it. answerdesk.ai drafts each help article with Content.draft, and its App shows the draft as it is written:

TypeScript
const call = $.Content.draft({ kind: 'article', brief: 'How to reset a password from the sign-in page' })
const editor = document.querySelector('#draft')!

for await (const chunk of call.stream()) {
  editor.append(chunk.delta)
}

const action = await call.settled

Over HTTP, send Accept: text/event-stream with the call. Frames named delta carry the text as it is generated, and a last frame named action carries the finished Action.

The streamed text is a preview of the result, not a second result. The Action records the final text once, and only that version emits Events or reaches a Watch.

Limits

Open connections count against a Limit per Tenant, set by the Startup's plan. One Channel carries 1,000 Messages a second, then shards by Thread. A stream over its rate closes with a rate-limited frame and a retry hint, and the client resumes from its cursor.

Next