WebSocketGateway enforces the fan-out, and each observer’s OperatorScope decides which events it receives.
Quick Start
1
Default — private, 1:1 (nothing to configure)
Today’s behaviour is unchanged. A session is
private and stays bound to its single owner.2
Share a session read-only
Set
read_only so an extra client may attach as a viewer to watch the stream, but not send.3
Share a session for co-driving
Set
shared so an extra client may attach as a member and send turns alongside the owner.Sharing is additive. A session with no
visibility stays private with a single owner — everything that worked before still works.How It Works
A member drives a turn, and the stream reaches the owner and every scoped observer — but only the owner’s copy is recorded for replay.- The owner creates the session — it is
privateunlessvisibilitysays otherwise. - Other clients
attachasmemberorviewer, as the visibility allows. - A
memberis bound to the session, so itsmessageframes co-drive it. Avieweris never bound, so it can never send. - Every stream event and the final
responsefan out to the owner plus each connected observer whose scope allows it.
Visibility
Visibility decides whether a second authorised client may attach on top of scope authorisation.Roles
A role decides what an attached client may do inside a shared session.Which visibility should I pick?
Visibility Enforcement (Dynamic Changes)
Callcreate_session again with the same session_id to change visibility on a live session — the gateway revokes any access the new setting no longer allows.
Fan-out and Scopes
Visibility and role layer on top ofOperatorScope — they are not authorisation.
- Streaming events (tokens, tool calls, tool results) and the final
responseframe fan out to the owner plus every attached observer whoseOperatorScopeallows that event. - An observer without
READreceives nothing, whatever its role. - A
memberstill needsWRITEto send amessageframe — attaching alone does not grant it. - The owner always receives its own session’s stream, even when a
memberdrives the turn. - Only the owner’s copy is written to the session’s replay buffer — observer copies are never recorded a second time.
Gateway Operator Scopes
Role-based access control that visibility and roles build on top of
Owner Leaving vs. Observer Leaving
An observer leaving only detaches it — the owner’s session stays open and the roster shrinks. This holds for every exit path: aleave frame, disconnect, the idle reaper, slow-consumer eviction, and credential rotation.
The owner leaving closes the session (persisted for resumption) and drops the whole observer roster. On a leave frame only the owner gets a {"type": "left", ...} reply; an observer’s leave just detaches it.
Observers Cannot Rebind as Owner
A client attached as an observer cannot take over the session by sendinghello or join with that session’s id.
hello the gateway sends a HelloError with code=AUTH_UNAUTHORIZED, next_step=DO_NOT_RETRY and next_action="start_new_session".
Rules & Errors
Configuration
Every value maps to a wire string used on the protocol.SessionVisibility
SessionSharingRole
Both accept the enum or its wire string. All imports use the friendly top-level path:
Server API
WebSocketGateway implements SessionObserverProtocol.
visibility is saved with the session and round-trips through to_dict / from_dict; older snapshots without it load as private.
Gateway SDK Reference
Full definitions of
SessionVisibility, SessionSharingRole, and SessionObserverProtocolUser Interaction Flow
Alice starts a research session on her laptop, watches it read-only from her phone, then opens it up so Bob can help steer the next turn.Best Practices
Default to PRIVATE
Default to PRIVATE
Keep sessions
private unless a real collaboration case exists. Sharing is opt-in and additive.Detach observers when done
Detach observers when done
Call
detach when a client no longer needs the stream so the roster stays clean and fan-out stays cheap. Disconnects detach automatically.Combine with OperatorScope
Combine with OperatorScope
Visibility is not authorisation. Pair sharing with scopes so an observer without
READ receives nothing and a member without WRITE cannot send.Tighten visibility to revoke access live
Tighten visibility to revoke access live
Call
create_session(..., session_id=sid, visibility="read_only") or "private" on a live session — the gateway demotes or drops observers for you.Observers never block the owner
Observers never block the owner
An observer leaving by any path — disconnect,
leave, reaper — never closes the owner’s session. Only the owner leaving does.Related
Operator Scopes
Scopes gate which shared events each observer receives
Session Continuity
One owner reconnecting to one session
Session Persistence
Durable session state —
visibility round-trips through to_dict / from_dictHandshake Protocol
Attached observers cannot rebind through
hello / join
