import type { BrokerToClient, ClientRole, RpcExtensionUIRequest, RpcSessionState, WelcomeFrame } from '../runtime/broker-protocol.js'; /** A retained `ctx.ui.setWidget` entry. */ export interface DisplayWidget { lines: string[]; placement: 'aboveEditor' | 'belowEditor'; } /** The broker-owned display levels (`ctx.ui.setStatus/setWidget/setTitle`), * insertion-ordered per key exactly as the broker retains them. */ export interface DisplayState { statuses: Record; widgets: Record; title: string | undefined; } export interface SessionState { /** This viewer's broker-assigned role. */ role: ClientRole; /** The client_id currently holding control, or null when nobody does. */ controllerId: string | null; /** The broker process's pi agent dir, from `welcome` — lets a viewer point an * AuthStorage/ModelRegistry at the SAME auth.json. */ agentDir: string | undefined; /** pi's own `get_state` payload. `undefined` until the first welcome. */ engine: RpcSessionState | undefined; /** Live context occupancy in prompt tokens: seeded from the snapshot's * contextUsage, then tracked off each assistant `message_end`. */ contextTokens: number | undefined; /** Queued steering + follow-up message TEXT, from `queue_update`. A fresh * broker with an empty queue emits no `queue_update`, so every welcome resets * this rather than leaving a dead broker's rows on screen. */ queued: string[]; display: DisplayState; /** The blocking dialog awaiting an answer, or null. Only a controller is ever * sent one; `welcome.pending_dialog` carries one in flight at attach time, and * a welcome is a COMPLETE catch-up, so a welcome naming none clears it. * (The terminal viewer does not read this field: its overlay is owned by * `InputController`, which holds a live TUI handle rather than data. The field * is still session state — it is derived solely from broker frames — and the * web SPA renders straight off it.) */ dialog: RpcExtensionUIRequest | null; } export declare function initialSessionState(role?: ClientRole): SessionState; /** The whole session state a `welcome` determines, in ONE step. This is why D1 * had to land first: before the broker carried its retained display levels in * `snapshot.display`, catch-up was `welcome` plus N replayed edges and this * function could not be total. */ export declare function applySnapshot(frame: WelcomeFrame): SessionState; /** Fold one broker frame into the session state. Pure and total: a frame that * carries no session state returns `state` UNCHANGED (same reference). */ export declare function reduce(state: SessionState, frame: BrokerToClient, clientId: string): SessionState;