/** * Handshake-suggestion shapes (2026-05-12). * * The three-step handshake protocol replaces the older `match` + `plan` * framing on the handshake output. * * Step 1 — the agent posts a `BlueprintDraft` (its idea: contract + * optional variance + optional generator hint). * * Step 2 — the server runs `BlueprintSearch` + contract validation in * parallel and returns a {@link HandshakeSuggestion}. The suggestion's * `origin` enum routes the agent's next decision: * * - `cache` — search-score crossed the per-app threshold; cached * code wins. `blueprintMeta.codeHash` is present. * - `agent` — search missed but validation passed; gen pending * against the agent's draft. Provisional blueprintId. * - `synth` — search missed AND validation failed; synth amended * the contract. Provisional blueprintId; `amendments` * carries the diff vs the agent's draft. * * Step 3 — the agent renders, optionally posting an `override` * (re-aim the contract and/or variance). Omitting `override` accepts the * suggestion as-is and resolves the proposed `(contractKey, variantKey)`; * an `override` re-resolves the effective identity. * * Locked decisions: * * - `blueprintMeta` is ALWAYS present on a successful handshake * (Option B from §D5). `codeHash` + `source` are absent on * non-cache origins (gen pending — no code, no provenance). * - `amendments` is populated only on `origin: 'synth'`. On `cache` * and `agent` origins it MUST be omitted. * - `validationFindings` is populated only when validators ran AND * produced findings — on cache hits these surface as a soft * warning ("your draft would've had X issue — using cached * blueprint instead"); on agent/synth they're carried for * telemetry only (synth's amendment already addressed them). */ import type { Blueprint, BlueprintVariance } from './blueprint.js'; import type { BlueprintSource } from './blueprint-source.js'; import type { DataContract, JsonValue } from './data-contract.js'; /** * Where the handshake's `blueprintMeta` came from. Routes the agent's * cognitive model: * * - `cache` — an existing blueprint matched at or above the per-app * threshold. `blueprintMeta.codeHash` is present; the * paired `ggui_render({handshakeId, props})` (no `override`) * short-circuits to cache delivery. * - `agent` — no cache hit, but the agent's draft validated cleanly. * `codeHash` absent; gen runs on render against the * agent's draft contract verbatim. * - `synth` — no cache hit AND validation failed. The synth * amender produced a new contract; the diff vs the * agent's draft is in `amendments.contractDiff`. */ export type SuggestionOrigin = 'cache' | 'agent' | 'synth'; /** * Agent's draft on the handshake input — what the agent wants to * build. The contract is required; variance + generator are optional * hints. The server combines this with its own render/app context * (cached blueprints, validator outcomes, operator pins) to produce * a {@link HandshakeSuggestion}. */ export interface BlueprintDraft { /** * Agent-authored DataContract. Drives both the blueprint-search * embed/structural axes and the contract validators. The agent is * the contract authority; synth amends only when validation fails. */ readonly contract: DataContract; /** * Optional variance tags. Carried through to the suggestion's * `blueprintMeta.variance` field; if `decision: 'accept'` lands on a * fresh-gen path (origin === 'agent' or 'synth'), the persisted * Blueprint row inherits these tags. */ readonly variance?: { /** Free-form persona tag (e.g. 'minimalist', 'data-dense'). */ readonly persona?: string; /** Aesthetic tag — promoted to first-class in a future slice. */ readonly aesthetic?: string; /** Small structured signal — JSON-safe. */ readonly context?: { readonly [key: string]: JsonValue | undefined; }; /** Raw style hint / seed prompt. */ readonly seedPrompt?: string; }; /** * Generator identity hint (e.g. `'ui-gen-advanced'` — de-modeled, ggui#924). The * server resolves the effective generator as: * * 1. Operator app-pin (`App.pinnedGenerator`) — wins if set. * 2. This hint — if registered in the GeneratorRegistry. * 3. Registry default (`ui-gen-default`). * * Hint-only; unknown slugs fall through to the registry default. */ readonly generator?: string; } /** * Blueprint metadata projected onto the handshake response. The agent * uses this to decide whether to accept (reuse the provisional id) or * override (mint a fresh id with its own new draft). * * `blueprintId` is PROVISIONAL — it becomes durable iff the paired * render sends `decision: 'accept'`. An override discards it. */ export interface BlueprintMeta { /** * Stored blueprint id (`bp_`). Present only when a cached * blueprint backs the suggestion (`origin === 'cache'`) — that is the * durable UUID minted at its first render-time registration. ABSENT on * `agent` / `synth` origins (D4): the UUID is minted at render-time * registration, not at handshake, so there is no id to report yet. * Consumers MUST tolerate absence (the telemetry reader omits the * clause; the agent falls back to `contractHash`). */ readonly blueprintId?: string; /** Canonical RFC 8785 (JCS) hash of the suggestion's contract. */ readonly contractHash: string; /** * Content hash of the cached code body. Present iff `origin === * 'cache'`. Absent for `agent` / `synth` (gen pending). */ readonly codeHash?: string; /** * Provenance of the cached code backing this suggestion — the single * {@link BlueprintSource} vocabulary, read from the matched * blueprint's stored row. Present iff `origin === 'cache'` (same * presence rule as {@link codeHash}). ABSENT on `agent` / `synth` * origins: generation has not happened yet, so no provenance exists * to report — the paired render mints the real `llm` arm from the * engine's own metadata stamp at registration time. Fabricating a * value here is banned. */ readonly source?: BlueprintSource; /** Variance tags carried through from the suggestion. */ readonly variance: BlueprintVariance; /** * Optional matcher telemetry — why this blueprint was selected. * Operator-readable; LLM-readable. E.g. `'contract-hash, persona → * score 0.92'`. */ readonly selectedReason?: string; } /** * Validator finding surfaced on the suggestion. Mirrors * `@ggui-ai/protocol/validation/lint-contract`'s `ContractIssue` shape * loosely — kept structural here so the suggestion contract doesn't * import from the linter module and create a tight cycle. * * Each finding has a stable `code`, a severity, the dotted-path * location, and a human-readable `message`. */ export interface SuggestionFinding { /** Stable error code (e.g. `'CTR_REF_NEXT_STEP'`, `'CTR_DUP_NAME'`). */ readonly code: string; readonly severity: 'error' | 'warn'; /** Dotted JS-style path into the contract. */ readonly path: string; /** Human-readable violation prose. */ readonly message: string; } /** * Synth's amendment — the diff vs the agent's draft. Populated only on * `origin: 'synth'`. * * `contractDiff` is an RFC 6902 JSON-Patch-style array; the diff * applied to the agent's draft yields the suggestion's contract. * Helpers in `@ggui-ai/protocol/validation/contract-diff` produce and * apply the diff. * * `reasoning` is the synth model's natural-language explanation — * "added required `submit` action so the form completion is * observable", etc. */ export interface SuggestionAmendments { readonly contractDiff: JsonPatch; readonly reasoning: string; } /** * Minimal RFC 6902 JSON-Patch shape carried in handshake-suggestion * amendments. The protocol re-exports this so consumers can apply / * inspect patches without an external dependency. * * Subset support — every emitter MUST honor `add` / `remove` / * `replace`; `move` / `copy` / `test` are reserved for future use * (consumers MAY reject unrecognized ops). */ export type JsonPatch = readonly JsonPatchOp[]; export type JsonPatchOp = { readonly op: 'add'; readonly path: string; readonly value: JsonValue; } | { readonly op: 'remove'; readonly path: string; } | { readonly op: 'replace'; readonly path: string; readonly value: JsonValue; }; /** * The full handshake suggestion. Produced by the server in step-2 of * the three-step handshake; the agent reads this in the response and * branches its render decision on `origin` (accept vs override). */ export interface HandshakeSuggestion { /** Routing discriminator — see {@link SuggestionOrigin}. */ readonly origin: SuggestionOrigin; /** Operator-readable + LLM-readable rationale ("contract-hash → score 0.92"). */ readonly rationale: string; /** Provisional blueprint metadata — see {@link BlueprintMeta}. */ readonly blueprintMeta: BlueprintMeta; /** * Agent-readable projection of the contract the server proposes the * agent build against. Parties: the SERVER produces it from the * effective contract; the AGENT consumes it to make ONE accept-vs- * override decision knowingly. * * Obligation: when set, it equals `summarizeContract(effectiveContract)` * (the same lossy summary the matcher's judge feeds — one source of * truth). OPTIONAL (D5): a malformed/absent contract → omitted (never * throws); the agent then falls back to `blueprintMeta.contractHash`. * Builders set it whenever a contract is available. * * This is the agent-readable projection only — the full contract still * rides on the handshake record's stored `effectiveContract` for * render-time generation. */ readonly proposedContractSummary?: string; /** * Populated iff `origin === 'synth'`. Carries the JSON-Patch diff * vs the agent's draft and the synth model's reasoning. */ readonly amendments?: SuggestionAmendments; /** * Deterministic-gate findings surfaced to the agent so it learns what * its draft got wrong (even though the server repaired it). Populated: * - `origin: 'agent'` — hygiene WARN findings on the (already-valid) * draft, if any. * - `origin: 'synth'` — the ERROR findings that rejected the draft * and triggered the repair loop. * - `origin: 'cache'` — absent (a registered blueprint is served; * the draft was not the basis). * The repaired contract itself is delivered via `blueprintMeta` / * the handshake's stored effectiveContract — these findings are * advisory, not the contract. */ readonly validationFindings?: readonly SuggestionFinding[]; } /** * Build a minimal JSON-Patch RFC 6902 diff between two contracts. * * Algorithm: shallow walk over the union of top-level keys; for each * key, recurse into nested objects, otherwise emit `add` / `remove` / * `replace` at the appropriate path. Arrays are diffed as whole values * (no LCS) — sufficient for the synth-amendment use case where the * synth model rewrites slot/action maps wholesale rather than * splicing single array elements. * * Output is a {@link JsonPatch}; applying it to `before` produces * `after` (modulo array-element identity). * * Pure / deterministic. Exposed so synth implementations don't need * to ship their own diff helper. */ export declare function jsonPatch(before: unknown, after: unknown): JsonPatch; /** * Top-N alternative blueprints surfaced on the handshake response. * Agents can override into one of these (render with `decision: * 'override'`) — the alternatives are full {@link Blueprint} rows so * the agent inspects everything it needs to decide. * * Sorted by descending match score; the suggestion's primary * `blueprintMeta` is NOT duplicated here (the alternatives are * what the search returned EXCLUDING the top result that became the * primary). */ export type SuggestionAlternatives = readonly Blueprint[]; //# sourceMappingURL=handshake-suggestion.d.ts.map