Reconnect and Sync
Build a Session client that does not lose streaming events with snapshots and Mutations
Reconnect and Sync
subscribe() only sends future changes and messages() returns a point-in-time snapshot. Combining them in the wrong order creates a race: a Delta can be lost between loading the snapshot and establishing the subscription.
The reliable sequence is subscribe and buffer first, load snapshots second, then merge the buffered events.
Recommended algorithm
const buffered: SessionMutation[] = [];
let snapshot_ready = false;
const unsubscribe = session.subscribe((mutation) => {
if (!snapshot_ready) {
buffered.push(mutation);
return;
}
apply_mutation(mutation);
});
const [message_page, info] = await Promise.all([
session.messages(),
session.get_info(),
]);
replace_message_state(message_page.items);
replace_session_info(info);
for (const mutation of buffered) {
apply_mutation(mutation);
}
snapshot_ready = true;A real UI should process buffered and set snapshot_ready = true in one serialized state transition so a new event cannot arrive in another gap.
Merge rules
| Mutation | Merge strategy |
|---|---|
message | Upsert by message_id; apply only a greater revision |
part | Upsert by part_id in its Assistant Message; apply only a greater revision |
delta | Append delta only to the matching text/reasoning Part |
turn | Update runtime state by turn_id |
session | Update Session metadata such as the title |
After a disconnect, do not assume Deltas can be replayed. Lost Deltas have already been merged into assistant_message.json or a final Message snapshot, so reloading messages() is what restores correct state.
RemoteSession disconnects
When a remote connection closes:
- Retain the current UI snapshot for temporary display, but do not treat it as final truth.
- Clean up the old subscription.
- Establish a new subscription and buffer Mutations.
- Reload
messages()andget_info(). - Apply buffered events under the merge rules above.
If a client is awaiting turn.finished when the connection breaks, handle its failed result and restore the UI by reloading the Session. Do not synthesize Assistant completion from client-side timers.
Segment history
The initial snapshot loads all Active Messages. To load earlier history, pass the current result's next_before_sequence to read the previous whole Segment. Live Mutations update Active only; do not use them to replace already loaded Segments.
Deduplication
Events from one connection are normally ordered, but a client should still be idempotent:
- Use
message_id + revisionto reject old snapshots. - Use the parent Message revision for Parts.
- Append Deltas only while the stream is continuous; after reconnect, prefer the snapshot.
mutation_idcan deduplicate repeated delivery of the same event.
This approach works for local and remote Sessions. Only the remote transport commonly disconnects.