diff options
Diffstat (limited to '.dispatch/ui-contract.reference.md')
| -rw-r--r-- | .dispatch/ui-contract.reference.md | 54 |
1 files changed, 51 insertions, 3 deletions
diff --git a/.dispatch/ui-contract.reference.md b/.dispatch/ui-contract.reference.md index 3962fc1..00d354f 100644 --- a/.dispatch/ui-contract.reference.md +++ b/.dispatch/ui-contract.reference.md @@ -6,6 +6,13 @@ > file is for READING only. > > **Orchestrator:** this is a SNAPSHOT — regenerate it whenever `ui-contract` changes. +> +> **2026-06 delta (cache-warming handoff):** adds the `NumberField` variant (`kind:"number"`) to +> the `SurfaceField` union, and an OPTIONAL `conversationId?` to `SubscribeMessage` / +> `UnsubscribeMessage` / `InvokeMessage` / `SurfaceMessage` / `SurfaceUpdate` so a surface can be +> CONVERSATION-SCOPED (state differs per conversation, e.g. `cache-warming`) vs GLOBAL (one state for +> all, e.g. `loaded-extensions`). All additive / backward-compatible: a global surface omits +> `conversationId` and behaves exactly as before. (Backend left the package version at `0.1.0`.) ```ts /** @@ -37,6 +44,7 @@ export type SurfaceField = | ProgressField | SelectorField | StatField + | NumberField | ButtonField | CustomField; @@ -71,6 +79,24 @@ export interface StatField { readonly value: string; } +/** + * A settable numeric value plus the action that sets it — the free-value + * counterpart to `selector` (which is a fixed enum). Optional `min`/`max`/`step` + * are SEMANTIC bounds a client may use to validate/step input; `unit` is a + * display hint (e.g. "ms", "s"). The client posts the new number as the action + * payload. Unlike `progress`/`stat` (read-only), this field is interactive. + */ +export interface NumberField { + readonly kind: "number"; + readonly label: string; + readonly value: number; + readonly min?: number; + readonly max?: number; + readonly step?: number; + readonly unit?: string; + readonly action: ActionRef; +} + /** A labelled action trigger. */ export interface ButtonField { readonly kind: "button"; @@ -106,10 +132,15 @@ export interface SurfaceCatalogEntry { /** The surface catalog: the list of available surfaces a client can choose to show. */ export type SurfaceCatalog = readonly SurfaceCatalogEntry[]; -/** A live update for a subscribed surface. v1 carries the full new spec. */ +/** + * A live update for a subscribed surface. v1 carries the full new spec. + * `conversationId` is present only for a CONVERSATION-SCOPED surface (tells the + * client which conversation this update is for); a global surface omits it. + */ export interface SurfaceUpdate { readonly surfaceId: string; readonly spec: SurfaceSpec; + readonly conversationId?: string; } // ── Surface WebSocket protocol (slice 1: surfaces only) ────────────────────── @@ -117,22 +148,34 @@ export interface SurfaceUpdate { /** A client → server message on the surface channel. */ export type SurfaceClientMessage = SubscribeMessage | UnsubscribeMessage | InvokeMessage; +/** + * Begin receiving live updates for a surface. For a CONVERSATION-SCOPED surface, + * include the `conversationId` whose state you want; omit it for a global surface. + */ export interface SubscribeMessage { readonly type: "subscribe"; readonly surfaceId: string; + readonly conversationId?: string; } +/** Stop receiving updates for a surface (and the same `conversationId`, if scoped). */ export interface UnsubscribeMessage { readonly type: "unsubscribe"; readonly surfaceId: string; + readonly conversationId?: string; } -/** Invoke a field's action; `payload` is the new value (e.g. a toggle's boolean). */ +/** + * Invoke a field's action; `payload` is the new value (e.g. a toggle's boolean, a + * `number` field's new number). For a conversation-scoped surface, include the + * `conversationId` the action targets. + */ export interface InvokeMessage { readonly type: "invoke"; readonly surfaceId: string; readonly actionId: string; readonly payload?: unknown; + readonly conversationId?: string; } /** A server → client message on the surface channel. */ @@ -148,10 +191,15 @@ export interface CatalogMessage { readonly catalog: SurfaceCatalog; } -/** The full current spec for a surface the client just subscribed to. */ +/** + * The full current spec for a surface the client just subscribed to. + * `conversationId` echoes the subscribe's conversation for a conversation-scoped + * surface (so the client routes it), and is absent for a global surface. + */ export interface SurfaceMessage { readonly type: "surface"; readonly spec: SurfaceSpec; + readonly conversationId?: string; } /** A live update for a subscribed surface. */ |
