import type { DataContract, InferActionNames, InferActionPayload, InferStreamNames, InferStreamPayload, StreamChannelMode } from '@ggui-ai/protocol/wire'; /** * One delivery on a stream channel, forwarded to a `subscribe` * handler. Carries the per-delivery semantics a subscriber needs to * fold state correctly — `mode` (append vs replace) and the optional * `complete` terminal marker — without leaking transport plumbing * (sessionId, requestId). * * Maps 1:1 onto the `payload`/`mode`/`complete` fields of the * outbound {@link import('@ggui-ai/protocol').StreamEnvelope}. The * envelope's `sessionId` + `channel` are resolved by the provider * before dispatch, so handlers never see them. */ export interface StreamDelivery { /** Channel payload — matches the delivery's `payload` field. */ readonly payload: T; /** * State-folding mode declared by the sender on this delivery. * Consumers MUST honor it — `'append'` accumulates, `'replace'` * overwrites the channel's current value. */ readonly mode: StreamChannelMode; /** * Terminal marker — truthy on the final delivery of a completable * channel. Subscribers use this to transition into a "channel * closed" state. Absent on non-terminal deliveries. */ readonly complete?: boolean; } /** * Expected `data` type for `dispatch(name, data)` given the contract * generic `T` and the resolved action name `N`. Post-Item-3b, an empty * `InferActionNames` (no `actionSpec`) collapses the typed branch to * the broad `unknown` fallback, keeping untyped callers ergonomic. A * NAME that does not appear in the contract narrows to `never` — * compile-time enforcement the brief requires. */ export type WireDispatchData = [ InferActionNames ] extends [never] ? unknown : N extends InferActionNames ? InferActionPayload : never; /** Expected handler-payload generic for `subscribe(channel, handler)`. */ export type WireStreamPayload = [ InferStreamNames ] extends [never] ? unknown : N extends InferStreamNames ? InferStreamPayload : never; /** * Configuration injected by the provider — the renderer inside the * iframe. * * Every method is typed against the contract generic `T` so typed * callers get compile-time enforcement: * - `dispatch(name, data)` — `name` MUST be a declared actionSpec * key; `data` MUST satisfy that action's schema. * - `subscribe(channel, handler)` — same discipline for streamSpec. * * Untyped callers (`T = DataContract` default) degrade to the broad * shape via the conditional `WireDispatchData` / `WireStreamPayload` * aliases — no call-site break. * * The contract's `agentCapabilities.tools` catalog declares tools the AGENT * invokes (not the component); user gestures fire via * `dispatch(name, data)` and the optional `nextStep` field on the * action entry names the tool the agent SHOULD invoke next. * * The renderer mounts exactly ONE GguiSession per iframe — `render.sessionId` * is the stable identity the WireProvider was constructed with. No * per-item scoping factory; with a one-GguiSession-per-mount lifecycle, * "scope" collapses to identity. */ export interface WireConfig { readonly app: { readonly appId: string; readonly appName: string; readonly appDescription?: string; readonly appIcon?: string; }; readonly render: { readonly sessionId: string; readonly isConnected: boolean; }; readonly auth: { readonly userId?: string; readonly isAuthenticated: boolean; }; /** * Fire an action to the agent (fire-and-forget over WS). Typed * callers get compile-time checked `name` + `data`; untyped callers * (`T = DataContract`) keep the broad shape. */ readonly dispatch: (actionName: N, data: WireDispatchData) => void; /** * Subscribe to deliveries on a named stream channel. */ readonly subscribe: (channelName: N, handler: (delivery: StreamDelivery>) => void) => () => void; /** * Optional structured observability for the runtime's two dispatch- * suppression invariants — the task-scoped duplicate backstop * (`reason: 'duplicate-dispatch'`, fired by `useAction`) and the * render-lifetime one-shot guard (`reason: 'one-shot-spent'`, fired by * the config's own `dispatch` when a declared `oneShot` action is * gestured a second time, ggui#1108). Both fire ALONGSIDE the always-on * `console.warn`; neither reaches the agent. * * Reachability constraint: the first-party renderers do NOT set this * field — `buildRootWireConfig` (`@ggui-ai/iframe-runtime`) and * ``'s internal config both omit it. It fires only when a * host hand-builds a complete `WireConfig` (or passes * `onDispatchSuppressed` to `buildWireConfig`). On every first-party * render path the `console.warn` is the sole suppression signal — which * is what the `oneShot` contract requires as its minimum trace. */ readonly onDispatchSuppressed?: (info: DispatchSuppressedInfo) => void; } /** * Payload for the {@link WireConfig.onDispatchSuppressed} callback. */ export interface DispatchSuppressedInfo { /** * Why the dispatch was suppressed. Two distinct runtime invariants share * one sink: * - `'duplicate-dispatch'` — the task-scoped backstop: a same-`(name, * payload)` re-dispatch within one event-loop task (the nested- * interactive double-fire). See `dispatch-dedup.ts`. * - `'one-shot-spent'` — a SECOND gesture on an action the contract * declared `oneShot` (ggui#1108): the action already fired for this * render's lifetime, so the repeat is not sent to the agent. Keyed on * the marker (the action's `oneShot` flag), never inferred from a name. */ readonly reason: 'duplicate-dispatch' | 'one-shot-spent'; /** The action name that was suppressed. */ readonly actionName: string; /** * The dedup signature (`${actionName}::${JSON.stringify(payload)}`) * computed for this dispatch. `null` when the payload was * un-serializable (no signature, dedup bypassed) — though in that * branch suppression cannot fire anyway, so `null` is observable * here only if a future code path changes that invariant. */ readonly payloadSignature: string | null; /** The raw payload as supplied to the dispatch call. */ readonly payload: unknown; /** `Date.now()` at the moment suppression was decided. */ readonly suppressedAt: number; } export declare const WireContext: import("react").Context | null>; /** Access the WireContext. Must be called inside a WireProvider. */ export declare function useWireContext(): WireConfig; //# sourceMappingURL=context.d.ts.map