Channel ABC¶
Channel ¶
Bases: ABC
Base class for all channels.
sender_is_participant
class-attribute
instance-attribute
¶
Whether this channel's sender_id is a room Participant.id.
An identity resolver maps an address — a number, an email, a handle — to
an Identity. Most channels carry one: what arrives on sender_id is how
the sender is reachable, and who that is remains to be looked up. A channel
that sets this declares the opposite: its senders are named by the room
itself, so there is no address to look up and identity resolution (RFC §11)
is skipped for its messages.
Declaring it wrongly is not a small mistake: a channel that does carry addresses would stop resolving them, and every sender would stay unidentified.
recent_events_window
property
¶
How many recent room events this channel reads per turn.
Drives how many events the framework loads into RoomContext for a
room. Transport-only channels (WebSocket, realtime voice) don't consume
room history, so the default is 0; AI channels override it with their
memory provider's window.
supports_streaming_delivery
property
¶
Whether this channel can accept streaming text delivery.
on_trace ¶
Register a protocol trace observer.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
callback
|
TraceCallback
|
Called with each :class: |
required |
protocols
|
list[str] | None
|
Optional allowlist of protocol names (e.g.
|
None
|
resolve_trace_room ¶
Resolve a room ID for a trace with the given session.
Override in session-based channels (voice, realtime voice) to
map session IDs to room IDs. Returns None by default.
handle_inbound
abstractmethod
async
¶
Process an inbound message into a RoomEvent.
on_event
async
¶
React to an event. Default: no-op for transport channels.
supports_streaming_delivery_for ¶
Whether this channel can stream into a specific room.
Defaults to the channel-wide answer, which is right for a channel whose capability does not vary by room — a voice session, a terminal. A channel that holds per-room client connections overrides this, so a room whose clients cannot stream does not take the streaming path only to fall back at the end.
deliver_stream
async
¶
Deliver a streaming text response to this channel.
Default: accumulate text, deliver as complete event.
connect_session
async
¶
Accept a long-lived session after inbound processing.
Called by process_inbound when message.session is present
and hooks did not block. Override in session-based channels
(voice, persistent WebSocket, etc.). Default: no-op.
disconnect_session
async
¶
Clean up a session on remote disconnect.
Override in session-based channels to release resources. Default: no-op.
update_binding ¶
Notify the channel that a room's binding has changed.
Called by the framework after mute(), unmute(), or
set_access() update the store. Override in session-based
channels (voice, realtime voice) to update cached binding state
used for audio gating. Default: no-op.
on_room_attached
async
¶
Establish whatever the new binding claims exists.
Awaited by attach_channel() after the binding is written and before
anything has observed it — no system event, no hook. This is where a
channel does the outside-world work an attachment implies: a conference
channel creates the SFU room here (RFC §12.10.4 step 1).
Raising cancels the attachment. The framework takes the binding back and re-raises, so the caller learns that the channel refused rather than receiving a binding to something that was never built. Which is why this is not a hook: a lifecycle hook is observation, its errors are logged and never raised, and the room would go on believing it was attached. Default: no-op.
on_room_detached
async
¶
Take down what :meth:on_room_attached established.
Awaited by detach_channel() before the ON_CHANNEL_DETACHED
hooks, so an integrator's handler runs after the channel has finished
letting go rather than alongside it.
Nothing is rolled back if this raises — the binding is already gone and the detach already announced — but the error reaches the caller instead of disappearing into a log. Default: no-op.