@ggui-ai/mcp-server-handlers 0.2.0-alpha.1 → 0.2.0-alpha.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -32,4 +32,16 @@
32
32
  * non-undefined `requested` still fails (no allow-list).
33
33
  */
34
34
  export declare function assertGeneratorRegistered(requested: string | undefined, defaultGenerator: string | undefined): void;
35
+ /**
36
+ * Non-throwing predicate form of {@link assertGeneratorRegistered}.
37
+ *
38
+ * Used by the FORGIVING `ggui_handshake` path: an unknown generator slug
39
+ * is DROPPED (the server default is used) + surfaced as a finding,
40
+ * rather than thrown — handshake never hard-fails on a fixable detail.
41
+ * The STRICT `ggui_render` override path keeps the throwing assert,
42
+ * because override commits the agent to its exact draft.
43
+ *
44
+ * `undefined` (use server default) is always registered.
45
+ */
46
+ export declare function isGeneratorRegistered(requested: string | undefined, defaultGenerator: string | undefined): boolean;
35
47
  //# sourceMappingURL=assert-generator.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"assert-generator.d.ts","sourceRoot":"","sources":["../../src/renders/assert-generator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wBAAgB,yBAAyB,CACvC,SAAS,EAAE,MAAM,GAAG,SAAS,EAC7B,gBAAgB,EAAE,MAAM,GAAG,SAAS,GACnC,IAAI,CASN"}
1
+ {"version":3,"file":"assert-generator.d.ts","sourceRoot":"","sources":["../../src/renders/assert-generator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wBAAgB,yBAAyB,CACvC,SAAS,EAAE,MAAM,GAAG,SAAS,EAC7B,gBAAgB,EAAE,MAAM,GAAG,SAAS,GACnC,IAAI,CAQN;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,qBAAqB,CACnC,SAAS,EAAE,MAAM,GAAG,SAAS,EAC7B,gBAAgB,EAAE,MAAM,GAAG,SAAS,GACnC,OAAO,CAGT"}
@@ -32,12 +32,26 @@
32
32
  * non-undefined `requested` still fails (no allow-list).
33
33
  */
34
34
  export function assertGeneratorRegistered(requested, defaultGenerator) {
35
- if (requested === undefined)
36
- return;
37
- if (requested === defaultGenerator)
35
+ if (isGeneratorRegistered(requested, defaultGenerator))
38
36
  return;
39
37
  const registered = defaultGenerator
40
38
  ? `['${defaultGenerator}']`
41
39
  : '[] (no generator registered)';
42
40
  throw new Error(`unknown_generator: '${requested}' is not registered on this server. Registered generators: ${registered}. Omit \`blueprintDraft.generator\` to use the server default.`);
43
41
  }
42
+ /**
43
+ * Non-throwing predicate form of {@link assertGeneratorRegistered}.
44
+ *
45
+ * Used by the FORGIVING `ggui_handshake` path: an unknown generator slug
46
+ * is DROPPED (the server default is used) + surfaced as a finding,
47
+ * rather than thrown — handshake never hard-fails on a fixable detail.
48
+ * The STRICT `ggui_render` override path keeps the throwing assert,
49
+ * because override commits the agent to its exact draft.
50
+ *
51
+ * `undefined` (use server default) is always registered.
52
+ */
53
+ export function isGeneratorRegistered(requested, defaultGenerator) {
54
+ if (requested === undefined)
55
+ return true;
56
+ return requested === defaultGenerator;
57
+ }
@@ -10,11 +10,23 @@ import type { CanvasLifecycleEmitter } from './canvas-lifecycle.js';
10
10
  * variance + optional generator hint). `forceCreate` short-circuits
11
11
  * cache search so the paired render always cold-gens.
12
12
  */
13
+ /**
14
+ * The agent's draft as it ENTERS the handshake. `contract` is `unknown`
15
+ * because a FORGIVING handshake accepts a possibly-malformed proposal and
16
+ * lets the negotiator validate / repair it — it is not yet a guaranteed
17
+ * `DataContract`. (The protocol {@link BlueprintDraft} keeps
18
+ * `contract: DataContract` for the STRICT `ggui_render` override path.)
19
+ */
20
+ export interface DraftInput {
21
+ readonly contract: unknown;
22
+ readonly variance?: BlueprintDraft['variance'];
23
+ readonly generator?: string;
24
+ }
13
25
  export interface HandshakeStoredInput {
14
26
  /** Concise semantic identity of the UI — drives intent-axis search keying. */
15
27
  readonly intent: string;
16
- /** Agent's draft — contract (required) + optional variance + generator. */
17
- readonly blueprintDraft: BlueprintDraft;
28
+ /** Agent's draft — contract (untrusted) + optional variance + generator. */
29
+ readonly blueprintDraft: DraftInput;
18
30
  /**
19
31
  * Skip blueprint search and route straight to validation (and on
20
32
  * pass, agent-mode suggestion). Used after an earlier handshake
@@ -103,8 +115,8 @@ export interface HandshakeNegotiator {
103
115
  decide(input: {
104
116
  /** Agent-authored intent — drives search intent-axis keying. */
105
117
  readonly intent: string;
106
- /** Agent's draft — see {@link BlueprintDraft}. */
107
- readonly blueprintDraft: BlueprintDraft;
118
+ /** Agent's draft — untrusted contract (see {@link DraftInput}). */
119
+ readonly blueprintDraft: DraftInput;
108
120
  /** Force-skip cache search; route to validation + agent/synth path. */
109
121
  readonly forceCreate?: boolean;
110
122
  /** Per-app gadget catalog — synth uses to populate gadgets. */
@@ -285,7 +297,7 @@ declare const inputSchema: {
285
297
  * judgement (contract validates? cache hits? synth amends?).
286
298
  */
287
299
  readonly blueprintDraft: z.ZodObject<{
288
- contract: z.ZodType<DataContract, unknown, z.core.$ZodTypeInternals<DataContract, unknown>>;
300
+ contract: z.ZodRecord<z.ZodString, z.ZodUnknown>;
289
301
  variance: z.ZodOptional<z.ZodObject<{
290
302
  persona: z.ZodOptional<z.ZodString>;
291
303
  aesthetic: z.ZodOptional<z.ZodString>;
@@ -1 +1 @@
1
- {"version":3,"file":"handshake.d.ts","sourceRoot":"","sources":["../../src/renders/handshake.ts"],"names":[],"mappings":"AAmCA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,OAAO,EAQL,KAAK,SAAS,EACd,KAAK,cAAc,EAEnB,KAAK,gBAAgB,EACrB,KAAK,YAAY,EACjB,KAAK,mBAAmB,EAExB,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACvB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EACV,gBAAgB,EAChB,aAAa,EACb,aAAa,EACb,uBAAuB,EACvB,wBAAwB,EACzB,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACjE,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAEpE;;;;;;GAMG;AACH,MAAM,WAAW,oBAAoB;IACnC,8EAA8E;IAC9E,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,2EAA2E;IAC3E,QAAQ,CAAC,cAAc,EAAE,cAAc,CAAC;IACxC;;;;OAIG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,OAAO,CAAC;CAChC;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,MAAM,EAAE,QAAQ,GAAG,OAAO,GAAG,QAAQ,GAAG,SAAS,GAAG,UAAU,CAAC;IACxE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,+EAA+E;IAC/E,QAAQ,CAAC,KAAK,EAAE,oBAAoB,CAAC;IACrC,oBAAoB;IACpB,QAAQ,CAAC,MAAM,EAAE,qBAAqB,CAAC;IACvC,wEAAwE;IACxE,QAAQ,CAAC,UAAU,EAAE,mBAAmB,CAAC;IACzC;;;;;;;;;;;;OAYG;IACH,QAAQ,CAAC,iBAAiB,EAAE,YAAY,CAAC;IACzC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,WAAW,mBAAmB;IAClC,MAAM,CAAC,KAAK,EAAE;QACZ,gEAAgE;QAChE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;QACxB,kDAAkD;QAClD,QAAQ,CAAC,cAAc,EAAE,cAAc,CAAC;QACxC,uEAAuE;QACvE,QAAQ,CAAC,WAAW,CAAC,EAAE,OAAO,CAAC;QAC/B,+DAA+D;QAC/D,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,gBAAgB,EAAE,CAAC;QAC/C,QAAQ,CAAC,GAAG,EAAE,cAAc,CAAC;KAC9B,GAAG,OAAO,CAAC,yBAAyB,CAAC,GAAG,yBAAyB,CAAC;IAEnE;;;;;;;;;;;;;;;;;;;;;;;;;OAyBG;IACH,aAAa,CAAC,CAAC,KAAK,EAAE;QACpB,gFAAgF;QAChF,QAAQ,CAAC,UAAU,EAAE,SAAS,SAAS,EAAE,CAAC;QAC1C,6DAA6D;QAC7D,QAAQ,CAAC,OAAO,EAAE,uBAAuB,CAAC;QAC1C,QAAQ,CAAC,GAAG,EAAE,cAAc,CAAC;KAC9B,GAAG,OAAO,CAAC,wBAAwB,CAAC,CAAC;CACvC;AAED,MAAM,WAAW,yBAAyB;IACxC,QAAQ,CAAC,MAAM,EAAE,QAAQ,GAAG,OAAO,GAAG,QAAQ,GAAG,SAAS,GAAG,UAAU,CAAC;IACxE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,UAAU,EAAE,mBAAmB,CAAC;IACzC;;;OAGG;IACH,QAAQ,CAAC,iBAAiB,EAAE,YAAY,CAAC;IACzC,oBAAoB;IACpB,QAAQ,CAAC,MAAM,CAAC,EAAE,qBAAqB,CAAC;IACxC,6DAA6D;IAC7D,QAAQ,CAAC,YAAY,CAAC,EAAE,SAAS,SAAS,EAAE,CAAC;CAC9C;AAED,MAAM,WAAW,wBAAwB;IACvC;;;;;OAKG;IACH,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC;IAChC;;;;;OAKG;IACH,QAAQ,CAAC,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IAC7C;;;;OAIG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,mBAAmB,CAAC;IAC1C;;;OAGG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B;;;OAGG;IACH,QAAQ,CAAC,mBAAmB,CAAC,EAAE,MAAM,MAAM,CAAC;IAC5C;;;;OAIG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,MAAM,CAAC;IACxC;;;OAGG;IACH,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IAC5B;;;OAGG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB;;;;OAIG;IACH,QAAQ,CAAC,kBAAkB,CAAC,EAAE,MAAM,kBAAkB,GAAG,SAAS,CAAC;IACnE;;;;OAIG;IACH,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IACnC;;;;;;;;;;;OAWG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,sBAAsB,CAAC;IAClD;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,aAAa,CAAC;CACxC;AAED,0EAA0E;AAC1E,eAAO,MAAM,wBAAwB,MAAM,CAAC;AAE5C,wEAAwE;AACxE,eAAO,MAAM,sBAAsB,6BAA6B,CAAC;AAEjE;;;;GAIG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,MAAM,GAClB,MAAM,CAER;AAmBD;;;GAGG;AACH,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,aAAa,EACtB,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CAGjC;AAED;;;GAGG;AACH,wBAAsB,sBAAsB,CAC1C,OAAO,EAAE,aAAa,EACtB,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CAGjC;AAED,qEAAqE;AACrE,QAAA,MAAM,WAAW;;IAEf;;;;OAIG;;;;;;;;;;;;CAwBK,CAAC;AAEX,sEAAsE;AACtE,QAAA,MAAM,YAAY;;;;;;;;;;;;;;CAUR,CAAC;AAEX,UAAU,eAAe;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,QAAQ,GAAG,OAAO,GAAG,QAAQ,GAAG,SAAS,GAAG,UAAU,CAAC;IAC/D;;;;OAIG;IACH,MAAM,EAAE,MAAM,CAAC;IACf,8DAA8D;IAC9D,MAAM,EAAE,qBAAqB,CAAC;IAC9B,UAAU,EAAE,mBAAmB,CAAC;IAChC,0CAA0C;IAC1C,YAAY,CAAC,EAAE,SAAS,SAAS,EAAE,CAAC;IACpC,gDAAgD;IAChD,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE;QACT,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;QAC7B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;KAC1B,CAAC;IACF,yEAAyE;IACzE,kBAAkB,CAAC,EAAE,kBAAkB,CAAC;CACzC;AAED;;;GAGG;AACH,wBAAgB,0BAA0B,CACxC,IAAI,EAAE,wBAAwB,GAC7B,aAAa,CAAC,OAAO,WAAW,EAAE,OAAO,YAAY,EAAE,eAAe,CAAC,CAsJzE;AA8ID;;;GAGG;AACH,qBAAa,sBAAuB,SAAQ,KAAK;aAEnB,WAAW,EAAE,MAAM;IAD/C,QAAQ,CAAC,IAAI,EAAG,qBAAqB,CAAU;gBACnB,WAAW,EAAE,MAAM;CAMhD;AAGD,YAAY,EAAE,iBAAiB,EAAE,CAAC;AAElC;;;GAGG;AACH,eAAO,MAAM,uBAAuB,sBAAsB,CAAC;AAE3D;;GAEG;AACH,MAAM,WAAW,0BAA0B;IACzC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,MAAM,EAAE,QAAQ,GAAG,OAAO,GAAG,QAAQ,GAAG,SAAS,GAAG,UAAU,CAAC;IACxE,QAAQ,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,GAAG,OAAO,CAAC;IAC7C,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAC;IACrC,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,mBAAmB,CAAC,EAAE,MAAM,CAAC;IACtC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAED;;;GAGG;AACH,wBAAgB,0BAA0B,CACxC,MAAM,EAAE,MAAM,GAAG,SAAS,GACzB,MAAM,GAAG,SAAS,CAOpB"}
1
+ {"version":3,"file":"handshake.d.ts","sourceRoot":"","sources":["../../src/renders/handshake.ts"],"names":[],"mappings":"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"}
@@ -14,12 +14,15 @@
14
14
  * 3. Delegates suggestion production to the bound
15
15
  * {@link HandshakeNegotiator} — which produces a
16
16
  * {@link HandshakeSuggestion} routed by `origin: cache | agent | synth`.
17
- * The negotiator implementation owns the search + validate
18
- * orchestration (the reference LLM-backed negotiator runs
19
- * `BlueprintSearch.search` and `validateContract` in parallel,
20
- * falling through to a `synth.amend` seam when validation fails).
17
+ * FORGIVING posture: the input draft is NOT validated/thrown here.
18
+ * The negotiator owns validity — it cache-matches a registered
19
+ * blueprint (origin: cache) OR runs `ensureConformingContract` on
20
+ * the agent's draft (origin: agent when already clean, synth when
21
+ * the bounded repair loop had to fix it), and ALWAYS returns a
22
+ * contract that passes the deterministic `validateContract` gate.
21
23
  * Absent negotiator → the seam stamps an `origin: 'agent'`
22
- * suggestion using the agent's draft verbatim (no enrichment).
24
+ * suggestion using the agent's draft verbatim (no repair; the
25
+ * backstop below validates it and a malformed draft fails closed).
23
26
  * 4. Persists a {@link HandshakeRecord} under a TTL-bounded
24
27
  * {@link KeyValueStore} key. Single-use: the paired `ggui_render`
25
28
  * consumes it via `getAndDelete`.
@@ -34,10 +37,9 @@
34
37
  */
35
38
  import { randomUUID } from 'node:crypto';
36
39
  import { z } from 'zod';
37
- import { assertContractNoRetiredFields } from './assert-contract-no-retired-fields.js';
38
- import { assertGeneratorRegistered } from './assert-generator.js';
40
+ import { isGeneratorRegistered } from './assert-generator.js';
39
41
  import { blueprintKey } from '@ggui-ai/protocol/blueprint-key';
40
- import { STDLIB_GADGETS, assertContractSchemasValid, assertCrossReferences, assertNameInvariants, assertSchemaCompat, dataContractSchema, handshakeSuggestionSchema, } from '@ggui-ai/protocol';
42
+ import { STDLIB_GADGETS, validateContract, lintContract, dataContractSchema, handshakeSuggestionSchema, } from '@ggui-ai/protocol';
41
43
  /** Default TTL (seconds). 10 minutes — same as the KV-store docstring. */
42
44
  export const HANDSHAKE_RECORD_TTL_SEC = 600;
43
45
  /** Default generator slug — matches the `GeneratorRegistry` default. */
@@ -94,7 +96,13 @@ const inputSchema = {
94
96
  */
95
97
  blueprintDraft: z
96
98
  .object({
97
- contract: dataContractSchema,
99
+ // Loose ON PURPOSE: a FORGIVING handshake accepts a possibly-
100
+ // malformed proposal (any JSON object) and lets the negotiator
101
+ // validate + repair it (ensureConformingContract). Strict
102
+ // `dataContractSchema` here would hard-fail the two most common
103
+ // malformations (wrapper-nesting, type-spelling) at the Zod layer
104
+ // BEFORE the negotiator runs — reviving the handshake-retry loop.
105
+ contract: z.record(z.string(), z.unknown()),
98
106
  variance: z
99
107
  .object({
100
108
  persona: z.string().optional(),
@@ -142,21 +150,35 @@ export function createGguiHandshakeHandler(deps) {
142
150
  title: 'Handshake',
143
151
  audience: ['agent'],
144
152
  description: deps.description ??
145
- "Negotiate a contract for a UI you want to deliver. Call BEFORE ggui_render. Input: {intent, blueprintDraft: {contract, variance?, generator?}}. CONTRACT SHAPE (DataContract) — every entry under propsSpec.properties / actionSpec / streamSpec / contextSpec is a WRAPPER that contains a JSON Schema in its `schema:` field; the JSON Schema does NOT sit flat at the entry level. ActionEntry uses OPTIONAL `nextStep: '<toolName>'` to hint the agent's intended next tool call — when present, the tool MUST also be declared in `agentCapabilities.tools`; OMIT it entirely when the agent should decide freely. Returns a `suggestion` with origin = cache | agent | synth — server matched an existing blueprint (cache), accepted your draft as-is (agent), or amended it (synth; diff in suggestion.amendments). On the paired ggui_render you send `decision: {kind: 'accept'}` (use the suggestion verbatim) or `decision: {kind: 'override', blueprintDraft}` (mint fresh against a NEW draft). Then ggui_consume → react → repeat. PLACEMENT RULE: actionSpec = events that drive the agent's next turn; contextSpec = observable state. Test: needs next-turn reasoning? actionSpec. No? contextSpec.",
153
+ "Negotiate a contract for a UI you want to deliver. Call BEFORE ggui_render. Input: {intent, blueprintDraft: {contract, variance?, generator?}}. CONTRACT SHAPE (DataContract) — every entry under propsSpec.properties / actionSpec / streamSpec / contextSpec is a WRAPPER that contains a JSON Schema in its `schema:` field; the JSON Schema does NOT sit flat at the entry level. ActionEntry uses OPTIONAL `nextStep: '<toolName>'` to hint the agent's intended next tool call — when present, the tool MUST also be declared in `agentCapabilities.tools`; OMIT it entirely when the agent should decide freely. FORGIVING: handshake ALWAYS returns a conforming contract — if your draft is malformed the server repairs it (handshake never hard-fails on contract content). The `suggestion` carries origin = cache (matched an existing blueprint) | agent (your draft was already clean) | synth (server repaired your draft; what was wrong is listed in suggestion.validationFindings). A synth result is READY — accept it; do NOT re-call ggui_handshake in a loop hoping for a different origin. On the paired ggui_render you send `decision: {kind: 'accept'}` (use the suggestion verbatim — the normal path) or `decision: {kind: 'override', blueprintDraft}` (commit to a NEW draft of your own; STRICT — it must already conform, the server will not repair an override). Then ggui_consume → react → repeat. PLACEMENT RULE: actionSpec = events that drive the agent's next turn; contextSpec = observable state. Test: needs next-turn reasoning? actionSpec. No? contextSpec.",
146
154
  inputSchema,
147
155
  outputSchema,
148
156
  async handler(input, ctx) {
149
157
  const parsed = z.object(inputSchema).parse(input);
150
- const normalizedInput = normalizeInput(parsed);
151
- // Semantic check on generator name — shared with render.ts's
152
- // override path so the two seams cannot drift.
153
- assertGeneratorRegistered(normalizedInput.blueprintDraft.generator, defaultGenerator);
154
- const draftContract = normalizedInput.blueprintDraft.contract;
155
- assertContractNoRetiredFields(draftContract);
156
- assertContractSchemasValid(draftContract);
157
- assertCrossReferences(draftContract);
158
- assertNameInvariants(draftContract);
159
- assertSchemaCompat(draftContract);
158
+ let normalizedInput = normalizeInput(parsed);
159
+ // Forgiving generator: an UNKNOWN generator slug is DROPPED (the
160
+ // server default is used) + surfaced as a finding, rather than
161
+ // thrown. Handshake never hard-fails on a fixable detail; the
162
+ // STRICT render-override path keeps the throwing assert.
163
+ const generatorFindings = [];
164
+ if (!isGeneratorRegistered(normalizedInput.blueprintDraft.generator, defaultGenerator)) {
165
+ generatorFindings.push({
166
+ code: 'GENERATOR_UNKNOWN',
167
+ severity: 'warn',
168
+ path: 'blueprintDraft.generator',
169
+ message: `generator '${normalizedInput.blueprintDraft.generator}' is not registered on this server; using the default '${defaultGenerator}'. Omit blueprintDraft.generator to silence.`,
170
+ });
171
+ const { generator: _droppedGenerator, ...draftWithoutGenerator } = normalizedInput.blueprintDraft;
172
+ normalizedInput = {
173
+ ...normalizedInput,
174
+ blueprintDraft: draftWithoutGenerator,
175
+ };
176
+ }
177
+ // The agent's draft is NOT validated/thrown here. The negotiator
178
+ // owns validity — it cache-matches OR repairs the draft
179
+ // (ensureConformingContract) and returns a contract that passes the
180
+ // deterministic gate. This is the forgiving-handshake posture: a
181
+ // malformed draft is a TRIGGER into repair, not a thrown error.
160
182
  // Per-app gadget catalog.
161
183
  const gadgets = deps.appMetadataStore
162
184
  ? ((await deps.appMetadataStore.get(ctx.appId))?.gadgets ??
@@ -176,16 +198,27 @@ export function createGguiHandshakeHandler(deps) {
176
198
  ctx,
177
199
  })
178
200
  : buildDefaultAgentSuggestion(normalizedInput.blueprintDraft, mintBlueprintId, defaultGenerator);
179
- // Re-run the same four contract invariants on the post-negotiation
180
- // `effectiveContract`. The agent-draft path above already passed
181
- // these on the input contract, but the negotiator may have
182
- // returned an amended contract (`suggestion.origin === 'synth'`)
183
- // OR a cached contract — both bypass the input gate.
184
- assertContractNoRetiredFields(negotiated.effectiveContract);
185
- assertContractSchemasValid(negotiated.effectiveContract);
186
- assertCrossReferences(negotiated.effectiveContract);
187
- assertNameInvariants(negotiated.effectiveContract);
188
- assertSchemaCompat(negotiated.effectiveContract);
201
+ // Backstop: the negotiator's effectiveContract MUST pass the
202
+ // single deterministic gate. For a bound negotiator this is
203
+ // GUARANTEED (ensureConformingContract loops until validateContract
204
+ // is green), so a throw here means the negotiator returned a
205
+ // non-conforming contract — a negotiator bug surfaced loudly rather
206
+ // than shipped downstream. The no-negotiator default path also
207
+ // lands here: an invalid draft with nothing bound to repair it
208
+ // fails closed with the deterministic findings (bind a negotiator
209
+ // to get the forgiving repair path).
210
+ validateContract(negotiated.effectiveContract);
211
+ // Merge handshake-level findings (e.g. a dropped generator) into
212
+ // the negotiator's suggestion so the agent sees every adjustment.
213
+ const finalSuggestion = generatorFindings.length > 0
214
+ ? {
215
+ ...negotiated.suggestion,
216
+ validationFindings: [
217
+ ...(negotiated.suggestion.validationFindings ?? []),
218
+ ...generatorFindings,
219
+ ],
220
+ }
221
+ : negotiated.suggestion;
189
222
  const handshakeId = mintHandshakeId();
190
223
  // Emit handshake_started so the canvas animator transitions to
191
224
  // its `handshake` state. Fire-and-forget; absent emitter is a
@@ -197,14 +230,17 @@ export function createGguiHandshakeHandler(deps) {
197
230
  });
198
231
  const target = negotiated.target ?? {};
199
232
  // Canonical hash of the AGENT'S DRAFT contract (pre-amendment).
200
- const draftHash = blueprintKey(normalizedInput.blueprintDraft.contract);
233
+ // Draft is untrusted (may be malformed) — hash only when it parses;
234
+ // blueprintKey tolerates `undefined`. Telemetry-only.
235
+ const draftHash = blueprintKey(dataContractSchema.safeParse(normalizedInput.blueprintDraft.contract)
236
+ .data);
201
237
  const record = {
202
238
  handshakeId,
203
239
  action: negotiated.action,
204
240
  reason: negotiated.reason,
205
241
  input: normalizedInput,
206
242
  target,
207
- suggestion: negotiated.suggestion,
243
+ suggestion: finalSuggestion,
208
244
  effectiveContract: negotiated.effectiveContract,
209
245
  appId: ctx.appId,
210
246
  createdAt: nowIso(),
@@ -254,13 +290,27 @@ export function createGguiHandshakeHandler(deps) {
254
290
  };
255
291
  }
256
292
  /**
257
- * Default `origin: 'agent'` suggestion when no negotiator is bound.
258
- * The agent's draft is taken at face value; no cache search, no
259
- * validation, no amendments. Useful for the OSS zero-config path
260
- * (deps without an LLM caller / vector store).
293
+ * Default `origin: 'agent'` suggestion when no negotiator is bound (OSS
294
+ * zero-config). No negotiator ⇒ no LLM ⇒ nothing can REPAIR a malformed
295
+ * draft. The handshake backstop (validateContract) would throw on one,
296
+ * so this still honors "handshake never hard-fails": a clean draft is
297
+ * used verbatim; a malformed draft is deterministically replaced by the
298
+ * trivially-conforming empty contract + loud findings (bind a
299
+ * HandshakeNegotiator to get the forgiving repair path instead).
261
300
  */
262
301
  function buildDefaultAgentSuggestion(blueprintDraft, mintBlueprintId, defaultGenerator) {
263
- const contract = blueprintDraft.contract;
302
+ const lint = lintContract(blueprintDraft.contract);
303
+ const clean = lint.errors.length === 0;
304
+ // `clean` ⇒ shape phase passed ⇒ strict parse cannot throw.
305
+ const contract = clean
306
+ ? dataContractSchema.parse(blueprintDraft.contract)
307
+ : {};
308
+ const findings = lint.errors.map((e) => ({
309
+ code: e.code,
310
+ severity: 'error',
311
+ path: e.path,
312
+ message: e.message,
313
+ }));
264
314
  const generator = blueprintDraft.generator ?? defaultGenerator;
265
315
  const blueprintMeta = {
266
316
  blueprintId: mintBlueprintId(),
@@ -283,8 +333,11 @@ function buildDefaultAgentSuggestion(blueprintDraft, mintBlueprintId, defaultGen
283
333
  };
284
334
  const suggestion = {
285
335
  origin: 'agent',
286
- rationale: 'no-negotiator-bound: OSS default routes the draft as origin=agent (no search, no validation, no amendments). Bind a HandshakeNegotiator to enable cache/synth routing.',
336
+ rationale: clean
337
+ ? 'no-negotiator-bound: OSS default routes the draft as origin=agent (no search, no repair). Bind a HandshakeNegotiator to enable cache/synth routing.'
338
+ : 'no-negotiator-bound: draft failed validation and no negotiator (LLM) is bound to repair it — returning a minimal conforming contract. Bind a HandshakeNegotiator to enable repair.',
287
339
  blueprintMeta,
340
+ ...(findings.length > 0 ? { validationFindings: findings } : {}),
288
341
  };
289
342
  return {
290
343
  action: 'create',
@@ -1 +1 @@
1
- {"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../../src/renders/render.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../../src/renders/render.ts"],"names":[],"mappings":"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"}
@@ -50,7 +50,6 @@ import { GGUI_RENDER_UI_META, toMcpAppEnvelope, } from '@ggui-ai/protocol/integr
50
50
  import { RateLimitedError } from '@ggui-ai/mcp-server-core';
51
51
  import { consumeHandshakeRecord, peekHandshakeRecord, HandshakeNotFoundError, } from './handshake.js';
52
52
  import { evaluateProvisionalPreviewGate, finalizeProvisionalPreview, kickoffProvisionalPreview, } from './provisional-preview.js';
53
- import { assertContractNoRetiredFields } from './assert-contract-no-retired-fields.js';
54
53
  import { assertGeneratorRegistered } from './assert-generator.js';
55
54
  import { assertNoDuplicateGadgetHooks } from './assert-no-duplicate-gadget-hooks.js';
56
55
  import { matchBlueprint } from './blueprint-matcher.js';
@@ -59,7 +58,7 @@ import { assertGadgetsRegistered, filterDescriptorsToContract, } from './assert-
59
58
  import { fetchGadgetTypes } from './fetch-gadget-types.js';
60
59
  import { assertPublicEnvSatisfied } from './assert-public-env.js';
61
60
  import { blueprintKey } from '@ggui-ai/protocol/blueprint-key';
62
- import { validatePropsData, ContractViolationError, assertCrossReferences, assertNameInvariants, assertSchemaCompat, assertContractSchemasValid, dataContractSchema, STDLIB_GADGETS, renderOutputSchema, } from '@ggui-ai/protocol';
61
+ import { validatePropsData, ContractViolationError, validateContract, dataContractSchema, STDLIB_GADGETS, renderOutputSchema, } from '@ggui-ai/protocol';
63
62
  import { emitCacheTraceEvent, newCacheTraceId, truncateCacheTraceIntent, } from './cache-trace-sink.js';
64
63
  import { emitPayloadTraceEvent } from './payload-trace-sink.js';
65
64
  import { deriveRenderMeta, derivePublicEnvProjection, deriveContractBundle, } from './slice-meta-derivation.js';
@@ -365,21 +364,30 @@ export function createGguiRenderHandler(deps) {
365
364
  throw new RateLimitedError(`ggui_render:${ctx.appId}`, decision);
366
365
  }
367
366
  }
368
- // Retired-field gate. The contract schema is `.passthrough()`
369
- // so unknown fields slip through silently; this hard-rejects
370
- // the known-retired names BEFORE the structural validators run
371
- // so the agent sees a precise migration message.
372
- assertContractNoRetiredFields(story.contract);
373
- // Duplicate-gadget-hook gate. Two bindings with the same
374
- // (package, hook) double-mount the wrapper; promoted from soft
375
- // hygiene warning to hard reject so the violation is
367
+ // Single deterministic contract gate — the SAME `validateContract`
368
+ // the handshake backstop runs (retired fields, inner-schema
369
+ // validity, cross-references, name invariants, schema-compat). On
370
+ // the ACCEPT path this re-checks an already-validated contract
371
+ // (defense-in-depth; never fires). On the OVERRIDE path it is the
372
+ // STRICT commit gate: a forced contract MUST conform — the server
373
+ // does not repair it ("use mine verbatim"). A failure is rethrown
374
+ // with a pointer back to ggui_handshake (which DOES repair), so the
375
+ // agent recovers instead of looping on override.
376
+ try {
377
+ validateContract(story.contract);
378
+ }
379
+ catch (err) {
380
+ if (acceptanceClassification === 'override') {
381
+ const detail = err instanceof Error ? err.message : String(err);
382
+ throw new Error(`override_contract_invalid: the forced contract failed validation — ${detail} Override COMMITS you to your exact contract; the server does not repair it. To get an auto-repaired or cache-matched contract, call ggui_handshake({intent, blueprintDraft}) and send decision:{kind:'accept'} — do NOT retry override with the same draft.`);
383
+ }
384
+ throw err;
385
+ }
386
+ // Duplicate-gadget-hook gate (gadget-specific; not part of the
387
+ // contract gate). Two bindings with the same (package, hook)
388
+ // double-mount the wrapper; hard reject so the violation is
376
389
  // observable rather than silently tolerated.
377
390
  assertNoDuplicateGadgetHooks(story.contract);
378
- assertContractSchemasValid(story.contract);
379
- // Cross-reference invariants — every `actionSpec[*].nextStep` and
380
- // `streamSpec[*].source.tool` MUST resolve to a key in the
381
- // contract's own `agentCapabilities.tools` catalog.
382
- assertCrossReferences(story.contract);
383
391
  // Gadget registry gate + enrichment. First: every
384
392
  // `(package, export name)` the contract references on
385
393
  // `clientCapabilities.gadgets` MUST resolve in `App.gadgets`.
@@ -394,13 +402,8 @@ export function createGguiRenderHandler(deps) {
394
402
  assertPublicEnvSatisfied(story.contract, appGadgets, appRecord?.publicEnv);
395
403
  resolvedAppLibraries = filterDescriptorsToContract(story.contract, appGadgets);
396
404
  }
397
- // Name-invariant rules: no name collisions across actionSpec /
398
- // streamSpec / contextSpec keys (boilerplate-identifier collision)
399
- // and no `_ggui:` reserved-prefix keys on actionSpec / contextSpec.
400
- assertNameInvariants(story.contract);
401
- // Protocol-level schema-compat invariant against the contract's
402
- // OWN catalog.
403
- assertSchemaCompat(story.contract);
405
+ // (Name-invariant + schema-compat invariants are covered by the
406
+ // single `validateContract` gate above — no separate asserts here.)
404
407
  // Schema-compat validation against the AUTHORED contract via the
405
408
  // server's registered tool registry. Defensive backstops at gen
406
409
  // and cache-hit commit phases (see `runGenerationIntoRender` +
@@ -420,7 +423,7 @@ export function createGguiRenderHandler(deps) {
420
423
  });
421
424
  }
422
425
  // Props validation against the agreed contract's propsSpec.
423
- const runtimeProps = parsed.props;
426
+ let runtimeProps = parsed.props;
424
427
  if (effectiveContract.propsSpec) {
425
428
  const propsToValidate = (runtimeProps ?? {});
426
429
  const propsValidation = validatePropsData(propsToValidate, effectiveContract.propsSpec);
@@ -434,18 +437,36 @@ export function createGguiRenderHandler(deps) {
434
437
  }
435
438
  else if (runtimeProps !== undefined &&
436
439
  Object.keys(runtimeProps).length > 0) {
437
- throw new ContractViolationError({
438
- tool: 'ggui_render',
439
- violations: [
440
- {
441
- field: 'props',
442
- message: 'props supplied but the agreed contract declares no propsSpec. Either refine the contract to declare a propsSpec covering these fields, or omit `props`.',
443
- expected: 'no props (contract has no propsSpec)',
444
- received: `props with keys: ${Object.keys(runtimeProps).join(', ')}`,
445
- },
446
- ],
447
- hint: 'Send a refined `contract` whose `props` declares a propsSpec for these fields, or drop the `props` field. The handshake record is preserved across this validation error — retry on the SAME handshakeId after fixing the input; no need to re-handshake.',
448
- });
440
+ if (acceptanceClassification === 'accept') {
441
+ // Forgiving ACCEPT: the negotiator may have RESHAPED the
442
+ // contract (e.g. synth moves a mutable collection like `todos`
443
+ // from propsSpec → contextSpec), so the agent's accept-path
444
+ // props — authored against its ORIGINAL draft — no longer fit.
445
+ // The agreed contract declares no propsSpec, so the props are
446
+ // unusable; DROP them (the UI starts from contextSpec defaults)
447
+ // rather than hard-failing. The agent populates live state via
448
+ // ggui_update after render. Override stays STRICT (below).
449
+ const droppedKeys = Object.keys(runtimeProps).join(', ');
450
+ // eslint-disable-next-line no-console -- operator-visible signal
451
+ console.warn(`[ggui_render] accept-path props dropped — the agreed contract declares no propsSpec ` +
452
+ `(synth likely reshaped propsSpec → contextSpec). Dropped keys: ${droppedKeys}. ` +
453
+ `Populate live state with ggui_update after render.`);
454
+ runtimeProps = undefined;
455
+ }
456
+ else {
457
+ throw new ContractViolationError({
458
+ tool: 'ggui_render',
459
+ violations: [
460
+ {
461
+ field: 'props',
462
+ message: 'props supplied but your override contract declares no propsSpec. Drop the `props` field, or add a propsSpec covering these fields.',
463
+ expected: 'no props (contract has no propsSpec)',
464
+ received: `props with keys: ${Object.keys(runtimeProps).join(', ')}`,
465
+ },
466
+ ],
467
+ hint: 'Your OVERRIDE draft has no propsSpec, so it takes no props. Drop `props`, add a propsSpec — or re-handshake and use decision:accept (the accept path tolerates mismatched props instead of failing). The handshake record is preserved; retry on the SAME handshakeId.',
468
+ });
469
+ }
449
470
  }
450
471
  // Atomically consume the handshake record now that input
451
472
  // validation has succeeded.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ggui-ai/mcp-server-handlers",
3
- "version": "0.2.0-alpha.1",
3
+ "version": "0.2.0-alpha.4",
4
4
  "description": "MCP tool handler logic for the ggui protocol. Pure over @ggui-ai/mcp-server-core seams and consumed by @ggui-ai/mcp-server. Never imports AWS, HTTP transports, or CLI concerns.",
5
5
  "keywords": [
6
6
  "ggui",
@@ -72,11 +72,11 @@
72
72
  }
73
73
  },
74
74
  "dependencies": {
75
- "@ggui-ai/mcp-server-core": "0.2.0-alpha.1",
76
- "@ggui-ai/negotiator": "0.2.0-alpha.1",
77
- "@ggui-ai/protocol": "0.2.0-alpha.1",
78
- "@ggui-ai/ui-gen": "0.2.0-alpha.1",
79
- "@ggui-ai/ui-registry": "0.2.0-alpha.1"
75
+ "@ggui-ai/mcp-server-core": "0.2.0-alpha.4",
76
+ "@ggui-ai/ui-gen": "0.2.0-alpha.4",
77
+ "@ggui-ai/ui-registry": "0.2.0-alpha.4",
78
+ "@ggui-ai/negotiator": "0.2.0-alpha.4",
79
+ "@ggui-ai/protocol": "0.2.0-alpha.4"
80
80
  },
81
81
  "peerDependencies": {
82
82
  "zod": ">=3.0.0"