Skip to main content
The session event stream was rebuilt. Types are dotted (thread.item_posted), a record has one shape with a source, events are read by id instead of by time, and the WebSocket carries listeners instead of subscriptions. The model is described in Session Events; this page maps the old names to the new. There is no compatibility period. The backend, the worker, the CLI, the SDK and the web app moved together. A client installed before the cutover stops reading events until it is upgraded: the old commands and frames are gone, not deprecated. Upgrade every BlobHub client you run, the worker, the CLI and the SDK, to its current release. History was migrated. Stored session events kept their time and were renamed to the new types, and their source.kind is unknown, since the old rows did not say what caused them. Event ids are new: an id or cursor saved from before the cutover no longer resolves. Expired rows, rows of deleted sessions, rows of an unknown type and malformed rows were not migrated. execution_started and execution_ended were realtime frames only and never stored, so migrated history holds no execution.* records. The execution log was moved to a new table, and each of its rows kept its message, attributes and data as they were, so a data_id still downloads. Two things differ for a reader of list_execution_events: every migrated row has a new id (the old one is not served) and a source with kind unknown, and created_at is written with six fractional digits. The event types, flow.* and processor.*, are unchanged.

Types

The stream also raises types that had no old name: session.created, session.updated, session.reopened, execution.created and execution.stop_requested.

Parameters and keys

Executions now expose a public source, {kind, user_id?, listener?, client?, depth}, on get_execution, list_executions and create_execution. No earlier response carried a field for it. An existing execution whose internal trigger was api or scheduler carries the matching source, {kind: "api", depth: 0} or {kind: "scheduler", depth: 0}; one with any other trigger was left without a source. created_since is unchanged on list_session_thread_items.

WebSocket

listener/add returns a listener_id, and each listener/event frame carries it with the whole event record in event; the frame no longer repeats the scope and target. A repeated subscription/add for the same session merged its types into one subscription; each listener/add now creates its own listener, so keep every listener_id. See Listener.

What to change in your code

A poll loop. Before, a time cursor:
After, an id cursor, with the settle recipe applied by re-reading from an older boundary:
The response key is now events. Keep the last id you held, and every so often re-read from the boundary id of a timestamp a minute older, dropping ids you already have. A subscription. Before:
After:
A session_deleted handler. Before, the type was read from the frame’s params:
After, it is read from the event inside the frame:
Match on params.event.type equal to session.deleted. Add a filter of {"types": ["session.deleted"]} to receive only that type, and remember that the listeners of a deleted session are removed once the event is pushed.