Expand description
Wire frames for the daemon UDS (PLAN-phase2 §2.9, S289 D-2 amended).
Framing is synaps rpc’s: one JSON object per \n, at most
DAEMON_MAX_FRAME_BYTES (64 MiB — distinct from rpc’s 1 MiB because
Attached carries the whole api_messages). Enforced symmetrically:
encode_line refuses to build an oversize frame, decode_line and both
readers refuse to accept one. WireSessionEvent is a serde mirror of
SessionEventWire — StreamEvent/TurnError/ExtensionLoaderEvent are
not Serialize, so they are mirrored variant-for-variant here and
converted only at the socket boundary. In-process transports never touch
this module.
The one lossy mirror is Conversation: on the wire it is a
ConversationDigest (len + hash + tokens/cost), never the messages.
Full history travels only in Attached and QueryResult{Messages};
SocketTransport rebuilds the snapshot from its local mirror
(Attached + Stream(MessageHistory)) and re-queries on a hash miss.
Security: nothing in here carries a credential. Welcome/Attached are
summaries; ClientFrame’s Debug redacts Answer.value and
Submit.text so a frame can be traced by type without leaking bodies.
Structs§
- Attached
Wire AttachSnapshotwith a serialisable replay.- Client
Reconnect - Who this connection used to be, so the daemon can restore ownership by
reconnect order +
was_owner. - Conversation
Digest ConversationSnapshotminusapi_messages: whatConversationcarries on the wire.messages_hashis FNV-1a over each message’s JSON so a client can tell whether its local mirror is current.- Hello
- Welcome
- Auth-status summary only — never key material.
- Wire
Envelope - Wire
Load Failure
Enums§
- Attach
- ByeReason
- Client
Frame - Client → daemon. First frame on a connection MUST be
Hello. - Daemon
Frame - Refuse
Reason - Wire
Agent Event - Wire
LlmEvent - Wire
Loader Event - Wire
Session Event - Wire
Session Stream Event - Wire
Stream Event
Constants§
- CHECKPOINT_
QUERY_ ID CheckpointrepliesQueryResult{id: CHECKPOINT_QUERY_ID, {ok:true}}soreload.rscan await it per session.- DAEMON_
MAX_ FRAME_ BYTES - Hard cap on one daemon frame, both directions (
Attachedships the whole conversation; 64 MiB is well past any context window’s JSON). - DIGEST_
RESYNC_ QUERY_ ID SocketTransportre-fetchesapi_messagesunder this id on a digest miss.- IDLE_
PROBE_ QUERY_ ID - The daemon’s idle monitor probes
Statusunder this id. - MAX_
FRAME_ BYTES - Alias used by the readers/writers of this protocol.
- PROTOCOL_
MAX - PROTOCOL_
MIN - Exact-match policy today (
min == max == PROTOCOL_VERSION). - PROTOCOL_
VERSION - Separate from
RPC_PROTOCOL_VERSION; bump on any non-additive change. v2 (phase 3):Setbecame a struct variant,Byegained a reason. v3 (E-P0): driver events (DriverArmed,DriverRevoked,DriverTurnOutcome); old clients skip unknown via#[serde(other)]. Protocol stays exact-match; only binary versions compare directionally (reload, §2.8). - RESERVED_
QUERY_ ID_ BASE - Query ids at or above this are reserved for the transport/daemon and
never surfaced to a client as
QueryResult. - RPC_
MAX_ FRAME_ BYTES - rpc’s cap, kept for reference; daemon frames use
DAEMON_MAX_FRAME_BYTES.
Functions§
- binary_
version - The binary version the daemon/client report in the handshake.
- decode_
line - Decode one line, enforcing
DAEMON_MAX_FRAME_BYTES. - encode_
line - Encode one frame as a single line (no embedded newline: serde_json
escapes them). Refuses to produce a line over
DAEMON_MAX_FRAME_BYTES. - frame_
limit_ msg - Human-readable form of the cap for error frames.
- messages_
hash - FNV-1a 64 over the canonical JSON of every message (stable across
binaries, unlike
DefaultHasher).