@ggui-ai/negotiator 0.2.0-alpha.4 → 0.3.0-rc.0

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.
Files changed (73) hide show
  1. package/README.md +25 -19
  2. package/dist/contract-validators.d.ts +20 -16
  3. package/dist/contract-validators.d.ts.map +1 -1
  4. package/dist/contract-validators.js +11 -8
  5. package/dist/index.d.ts +20 -20
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +20 -14
  8. package/dist/llm-caller.d.ts +9 -9
  9. package/dist/llm-caller.d.ts.map +1 -1
  10. package/dist/llm-caller.js +8 -8
  11. package/dist/llm-rerank.d.ts +9 -8
  12. package/dist/llm-rerank.d.ts.map +1 -1
  13. package/dist/llm-rerank.js +4 -25
  14. package/dist/normalize-draft.d.ts.map +1 -1
  15. package/dist/normalize-draft.js +33 -9
  16. package/dist/normalize-schema.d.ts.map +1 -1
  17. package/dist/normalize-schema.js +12 -0
  18. package/dist/synth-bench/cache-key-probe.d.ts +3 -0
  19. package/dist/synth-bench/cache-key-probe.d.ts.map +1 -0
  20. package/dist/synth-bench/cache-key-probe.js +177 -0
  21. package/dist/synth-bench/corpus.d.ts.map +1 -1
  22. package/dist/synth-bench/corpus.js +28 -20
  23. package/dist/synth-bench/run-bench.js +2 -2
  24. package/dist/synthesize-contract.d.ts +2 -3
  25. package/dist/synthesize-contract.d.ts.map +1 -1
  26. package/dist/synthesize-contract.js +20 -15
  27. package/package.json +8 -7
  28. package/src/contract-validators.ts +21 -17
  29. package/src/index.ts +20 -33
  30. package/src/llm-caller.ts +9 -9
  31. package/src/llm-rerank.ts +12 -17
  32. package/src/normalize-draft.ts +35 -9
  33. package/src/normalize-schema.ts +11 -0
  34. package/src/synth-bench/cache-key-probe.ts +213 -0
  35. package/src/synth-bench/corpus.ts +28 -20
  36. package/src/synth-bench/run-bench.ts +2 -2
  37. package/src/synthesize-contract.ts +24 -20
  38. package/dist/decision-input.d.ts +0 -51
  39. package/dist/decision-input.d.ts.map +0 -1
  40. package/dist/decision-input.js +0 -17
  41. package/dist/decision.d.ts +0 -58
  42. package/dist/decision.d.ts.map +0 -1
  43. package/dist/decision.js +0 -501
  44. package/dist/intent.d.ts +0 -22
  45. package/dist/intent.d.ts.map +0 -1
  46. package/dist/intent.js +0 -28
  47. package/dist/negotiate.d.ts +0 -142
  48. package/dist/negotiate.d.ts.map +0 -1
  49. package/dist/negotiate.js +0 -163
  50. package/dist/pure.d.ts +0 -30
  51. package/dist/pure.d.ts.map +0 -1
  52. package/dist/pure.js +0 -43
  53. package/dist/rag-search.d.ts +0 -73
  54. package/dist/rag-search.d.ts.map +0 -1
  55. package/dist/rag-search.js +0 -192
  56. package/dist/render.d.ts +0 -57
  57. package/dist/render.d.ts.map +0 -1
  58. package/dist/render.js +0 -25
  59. package/dist/suggestion.d.ts +0 -38
  60. package/dist/suggestion.d.ts.map +0 -1
  61. package/dist/suggestion.js +0 -47
  62. package/dist/types.d.ts +0 -30
  63. package/dist/types.d.ts.map +0 -1
  64. package/dist/types.js +0 -13
  65. package/src/decision-input.ts +0 -52
  66. package/src/decision.ts +0 -581
  67. package/src/intent.ts +0 -37
  68. package/src/negotiate.ts +0 -314
  69. package/src/pure.ts +0 -46
  70. package/src/rag-search.ts +0 -274
  71. package/src/render.ts +0 -56
  72. package/src/suggestion.ts +0 -73
  73. package/src/types.ts +0 -31
package/README.md CHANGED
@@ -1,11 +1,19 @@
1
1
  # @ggui-ai/negotiator
2
2
 
3
- UI decision engine for [ggui](https://github.com/ggui-ai/ggui).
3
+ Contract-synthesis + match-judge engine for
4
+ [ggui](https://github.com/ggui-ai/ggui)'s handshake.
4
5
 
5
- Given an agent's signal (data, prompt, context, agent tools) and the current
6
- render state, the negotiator decides **which UI to render** — create a new
7
- interface, update an existing one, or replace it — and, on the cold path,
8
- synthesizes the data contract that drives it.
6
+ Given an agent's draft contract + intent, this package synthesizes (or
7
+ repairs) a conforming `DataContract`, judges blueprint-match candidates for
8
+ reuse, and validates contract structure + novelty — the primitives the
9
+ handshake composes to always return a valid contract.
10
+
11
+ > The handshake **decision** itself (find-similar → reuse vs synth-create)
12
+ > lives in the shared `decideHandshake` core in
13
+ > [`@ggui-ai/mcp-server-handlers`](../mcp-server-handlers), which composes
14
+ > the primitives below. The former in-package `negotiate()` RAG+decision
15
+ > pipeline was retired in favor of that unified, adapter-injected core —
16
+ > one decision spine; LLM and storage bindings plug in per deployment.
9
17
 
10
18
  The package is deployment-agnostic. It composes the storage interfaces
11
19
  defined in `@ggui-ai/mcp-server-core` (`EmbeddingProvider`, `VectorStore`),
@@ -20,28 +28,26 @@ pnpm add @ggui-ai/negotiator
20
28
 
21
29
  ## What's in the box
22
30
 
23
- - **`negotiate(deps, input)`** — top-level orchestrator. Runs RAG search over
24
- registered blueprints, reads render state, fast-paths exact blueprint
25
- hits, and otherwise calls the decision LLM.
26
- - **`makeDecision(...)`** — the decision step in isolation: pick an action
27
- (`create` / `update` / `replace`) and a blueprint from the
28
- candidate set.
29
31
  - **`synthesizeContract(...)`** — cold-path contract synthesizer. Turns an
30
32
  agent intent into a `DataContract` (props / context / action / stream
31
33
  specs, plus gadget references), with a repair loop and a schema-validation
32
34
  gate.
33
- - **`ragSearch(...)`** — embedding + vector-store retrieval over the
34
- blueprint corpus, composing the `@ggui-ai/mcp-server-core` interfaces.
35
- - **`rerankCandidates(...)`** — LLM re-rank of retrieval candidates.
36
- - **`validateContractStructure` / `validateContractNovelty`** — advisory
35
+ - **`ensureConformingContract(...)`** — the create-path guarantee: validates
36
+ an untrusted draft and, on errors, deterministically normalizes or
37
+ LLM-repairs it so the handshake always returns a contract that passes the
38
+ backstop. Never throws.
39
+ - **`rerankCandidates(...)`** — LLM judge that re-ranks blueprint-match
40
+ retrieval candidates (the semantic-match decision used by
41
+ `decideHandshake`).
42
+ - **`validateContractRedundancy` / `validateContractNovelty`** — advisory
37
43
  validators for the actions-vs-context placement rule.
38
44
 
39
45
  ```ts
40
- import { negotiate } from "@ggui-ai/negotiator";
46
+ import { ensureConformingContract } from "@ggui-ai/negotiator";
41
47
 
42
- const result = await negotiate(deps, input);
43
- // result.action — "create" | "update" | "replace"
44
- // result.blueprint — the picked blueprint, if any
48
+ const result = await ensureConformingContract({ llm }, { intent, draft });
49
+ // result.origin — "agent" (clean) | "synth" (repaired)
50
+ // result.contract — a DataContract guaranteed to pass the handshake backstop
45
51
  ```
46
52
 
47
53
  ## License
@@ -3,9 +3,12 @@
3
3
  *
4
4
  * Two detectors live here:
5
5
  *
6
- * - {@link validateContractStructure} — pure structural heuristics that
7
- * flag over-specified contracts without any runtime dependency. The
8
- * load-bearing finding is `redundant-action`: an empty-payload
6
+ * - {@link validateContractRedundancy} — pure redundancy heuristics that
7
+ * flag over-specified contracts without any runtime dependency.
8
+ * (Deliberately NOT named `validateContractStructure` — that name is
9
+ * owned by `@ggui-ai/protocol`'s normative structural validator,
10
+ * which returns `ContractViolation`s; this one returns advisory
11
+ * findings.) The load-bearing finding is `redundant-action`: an empty-payload
9
12
  * `actionSpec` entry whose name parses as a mutator of an existing
10
13
  * `contextSpec` slot. Real example that motivated this module: a
11
14
  * synthesizer emitted both `actionSpec.increment` (empty payload)
@@ -59,39 +62,40 @@ export interface ContractValidationResult {
59
62
  }
60
63
  /**
61
64
  * Dependencies the novelty detector needs. Embedding provider + vector
62
- * store are the same seams the negotiator's RAG path uses, so the
63
- * novelty check operates over the production index without any extra
64
- * infrastructure.
65
+ * store are the same seams the handshake's find-similar retrieval uses,
66
+ * so the novelty check operates over the production index without any
67
+ * extra infrastructure.
65
68
  */
66
69
  export interface ContractValidationNoveltyDeps {
67
70
  readonly embedding: EmbeddingProvider;
68
71
  readonly vectorStore: VectorStore;
69
72
  /** Tenant / partition the nearest-neighbor query runs against. Same
70
- * semantics as `RagSearchInput.scope`. */
73
+ * semantics as the `scope` argument on `VectorStore.query` — the
74
+ * tenant / index partition, typically `appId`. */
71
75
  readonly scope: string;
72
76
  }
73
77
  export interface ContractValidationNoveltyOptions {
74
78
  /**
75
79
  * Cosine distance threshold above which the contract is flagged as
76
- * novel. Distance is `1 - cosine_similarity`. Default `0.8` —
77
- * matches the negotiator's `RETRIEVAL_MIN_SCORE = 0.15` (=cosine
78
- * similarity 0.15, distance 0.85) one-tail boundary, with a small
79
- * buffer so contracts that hover near retrieval but slightly above
80
- * still flag for review.
80
+ * novel. Distance is `1 - cosine_similarity`. Default `0.8`: a
81
+ * contract whose nearest stored neighbor sits beyond distance 0.8
82
+ * is effectively outside retrieval range, with a small buffer below
83
+ * the hard one-tail boundary (distance 0.85) so contracts that
84
+ * hover near retrieval but slightly above still flag for review.
81
85
  */
82
86
  readonly thresholdCosine?: number;
83
87
  }
84
88
  /**
85
- * Run the synchronous structural detectors against `contract`.
89
+ * Run the synchronous redundancy detector against `contract`.
86
90
  *
87
- * Currently:
91
+ * One finding kind:
88
92
  * - `redundant-action`: empty-payload action whose name parses as a
89
93
  * mutator of an existing context slot.
90
94
  *
91
- * Returns an empty findings array for contracts that don't trip any
95
+ * Returns an empty findings array for contracts that don't trip the
92
96
  * heuristic.
93
97
  */
94
- export declare function validateContractStructure(contract: DataContract): ContractValidationResult;
98
+ export declare function validateContractRedundancy(contract: DataContract): ContractValidationResult;
95
99
  /**
96
100
  * Validate the actions-vs-context placement rule: actions drive agent
97
101
  * turns, context observes state. Findings 1-3 are advisory `warn`;
@@ -1 +1 @@
1
- {"version":3,"file":"contract-validators.d.ts","sourceRoot":"","sources":["../src/contract-validators.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAc,MAAM,mBAAmB,CAAC;AAElE,OAAO,KAAK,EACV,iBAAiB,EACjB,WAAW,EACZ,MAAM,0BAA0B,CAAC;AAMlC;;;;;;;;;GASG;AACH,MAAM,MAAM,6BAA6B,GACrC,kBAAkB,GAClB,aAAa,GACb,mCAAmC,GACnC,2BAA2B,GAC3B,6BAA6B,GAC7B,4BAA4B,GAC5B,8BAA8B,GAC9B,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;AAElB;;;;;;GAMG;AACH,MAAM,WAAW,yBAAyB;IACxC,QAAQ,CAAC,IAAI,EAAE,6BAA6B,CAAC;IAC7C,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;IACpC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,QAAQ,EAAE,SAAS,yBAAyB,EAAE,CAAC;CACzD;AAED;;;;;GAKG;AACH,MAAM,WAAW,6BAA6B;IAC5C,QAAQ,CAAC,SAAS,EAAE,iBAAiB,CAAC;IACtC,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAC;IAClC;8CAC0C;IAC1C,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,gCAAgC;IAC/C;;;;;;;OAOG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;CACnC;AAwJD;;;;;;;;;GASG;AACH,wBAAgB,yBAAyB,CACvC,QAAQ,EAAE,YAAY,GACrB,wBAAwB,CAkC1B;AAsCD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAgB,wBAAwB,CACtC,QAAQ,EAAE,YAAY,GACrB,wBAAwB,CA8D1B;AAiCD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,yBAAyB,CACvC,QAAQ,EAAE,YAAY,EACtB,MAAM,EAAE,MAAM,GACb,wBAAwB,CAoC1B;AAQD;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,uBAAuB,CAC3C,QAAQ,EAAE,YAAY,EACtB,IAAI,EAAE,6BAA6B,EACnC,OAAO,GAAE,gCAAqC,GAC7C,OAAO,CAAC,wBAAwB,CAAC,CAkCnC;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,wBAAwB,GAC/B,MAAM,CAKR"}
1
+ {"version":3,"file":"contract-validators.d.ts","sourceRoot":"","sources":["../src/contract-validators.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAc,MAAM,mBAAmB,CAAC;AAElE,OAAO,KAAK,EACV,iBAAiB,EACjB,WAAW,EACZ,MAAM,0BAA0B,CAAC;AAMlC;;;;;;;;;GASG;AACH,MAAM,MAAM,6BAA6B,GACrC,kBAAkB,GAClB,aAAa,GACb,mCAAmC,GACnC,2BAA2B,GAC3B,6BAA6B,GAC7B,4BAA4B,GAC5B,8BAA8B,GAC9B,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;AAElB;;;;;;GAMG;AACH,MAAM,WAAW,yBAAyB;IACxC,QAAQ,CAAC,IAAI,EAAE,6BAA6B,CAAC;IAC7C,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;IACpC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,QAAQ,EAAE,SAAS,yBAAyB,EAAE,CAAC;CACzD;AAED;;;;;GAKG;AACH,MAAM,WAAW,6BAA6B;IAC5C,QAAQ,CAAC,SAAS,EAAE,iBAAiB,CAAC;IACtC,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAC;IAClC;;sDAEkD;IAClD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,gCAAgC;IAC/C;;;;;;;OAOG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;CACnC;AAwJD;;;;;;;;;GASG;AACH,wBAAgB,0BAA0B,CACxC,QAAQ,EAAE,YAAY,GACrB,wBAAwB,CAkC1B;AAsCD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAgB,wBAAwB,CACtC,QAAQ,EAAE,YAAY,GACrB,wBAAwB,CA8D1B;AAiCD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,yBAAyB,CACvC,QAAQ,EAAE,YAAY,EACtB,MAAM,EAAE,MAAM,GACb,wBAAwB,CAoC1B;AAQD;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,uBAAuB,CAC3C,QAAQ,EAAE,YAAY,EACtB,IAAI,EAAE,6BAA6B,EACnC,OAAO,GAAE,gCAAqC,GAC7C,OAAO,CAAC,wBAAwB,CAAC,CAkCnC;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,wBAAwB,GAC/B,MAAM,CAKR"}
@@ -3,9 +3,12 @@
3
3
  *
4
4
  * Two detectors live here:
5
5
  *
6
- * - {@link validateContractStructure} — pure structural heuristics that
7
- * flag over-specified contracts without any runtime dependency. The
8
- * load-bearing finding is `redundant-action`: an empty-payload
6
+ * - {@link validateContractRedundancy} — pure redundancy heuristics that
7
+ * flag over-specified contracts without any runtime dependency.
8
+ * (Deliberately NOT named `validateContractStructure` — that name is
9
+ * owned by `@ggui-ai/protocol`'s normative structural validator,
10
+ * which returns `ContractViolation`s; this one returns advisory
11
+ * findings.) The load-bearing finding is `redundant-action`: an empty-payload
9
12
  * `actionSpec` entry whose name parses as a mutator of an existing
10
13
  * `contextSpec` slot. Real example that motivated this module: a
11
14
  * synthesizer emitted both `actionSpec.increment` (empty payload)
@@ -167,19 +170,19 @@ function isEmptyPayloadSchema(schema) {
167
170
  return Object.keys(schema.properties).length === 0;
168
171
  }
169
172
  // =============================================================================
170
- // Structural validator (synchronous, dependency-free)
173
+ // Redundancy validator (synchronous, dependency-free)
171
174
  // =============================================================================
172
175
  /**
173
- * Run the synchronous structural detectors against `contract`.
176
+ * Run the synchronous redundancy detector against `contract`.
174
177
  *
175
- * Currently:
178
+ * One finding kind:
176
179
  * - `redundant-action`: empty-payload action whose name parses as a
177
180
  * mutator of an existing context slot.
178
181
  *
179
- * Returns an empty findings array for contracts that don't trip any
182
+ * Returns an empty findings array for contracts that don't trip the
180
183
  * heuristic.
181
184
  */
182
- export function validateContractStructure(contract) {
185
+ export function validateContractRedundancy(contract) {
183
186
  const findings = [];
184
187
  const actionSpec = contract.actionSpec;
185
188
  const contextSpec = contract.contextSpec;
package/dist/index.d.ts CHANGED
@@ -1,38 +1,38 @@
1
1
  /**
2
- * @ggui-ai/negotiator — open-source UI decision engine for ggui.
2
+ * @ggui-ai/negotiator — open-source contract-synthesis + match-judge
3
+ * engine for ggui's handshake.
3
4
  *
4
- * Decides which UI to render (create/update/replace) given agent
5
- * signal (data/prompt/context/agentTools) and current render state.
5
+ * Given an agent's draft contract + intent, this package:
6
+ * - synthesizes / repairs a conforming `DataContract`
7
+ * (`synthesizeContract`, `ensureConformingContract`) so the
8
+ * handshake always returns a valid contract;
9
+ * - judges blueprint-match candidates for reuse (`rerankCandidates`);
10
+ * - validates contract structure + novelty (`contract-validators`);
11
+ * - hashes contracts into identity + variant keys (`hashContract`,
12
+ * `buildVariant`) and normalizes untrusted drafts (`normalizeDraft`).
13
+ *
14
+ * The HANDSHAKE DECISION itself (find-similar → reuse vs synth-create)
15
+ * lives in the shared `decideHandshake` core in
16
+ * `@ggui-ai/mcp-server-handlers`, which composes these primitives; the
17
+ * former in-package `negotiate()` RAG+decision pipeline was retired in
18
+ * favor of that unified, adapter-injected core.
6
19
  *
7
20
  * Composes the storage seams defined in `@ggui-ai/mcp-server-core`
8
- * (`EmbeddingProvider`, `VectorStore`, `Negotiator`). The decision
9
- * semantics are open here; concrete cloud-vendor bindings (e.g. a
10
- * managed embedding service or vector store) live behind those seams
11
- * so this package stays deployment-agnostic.
21
+ * (`EmbeddingProvider`, `VectorStore`) so this package stays
22
+ * deployment-agnostic.
12
23
  *
13
24
  * This barrel stays narrow — it exports only the minimum surface
14
25
  * consumers need. Each additive export carries semver weight.
15
26
  */
16
27
  export { hashContract, buildVariant } from './contract-hash.js';
17
- export { computeIntentId, shouldSuppressSuggestion } from './intent.js';
18
- export { detectDataPatterns, buildSuggestion } from './suggestion.js';
19
- export type { NegotiatorSuggestion } from './suggestion.js';
20
- export { inferInteractionMode, inferJsonSchemaType } from './pure.js';
21
- export { ragSearch } from './rag-search.js';
22
- export type { RagSearchDeps, RagSearchInput, RagSearchResult, } from './rag-search.js';
23
- export type { NegotiatorOption } from './types.js';
24
28
  export type { LLMCaller, LLMCallerConfig, ToolSchema } from './llm-caller.js';
25
- export type { RenderState, RenderEntry } from './render.js';
26
- export type { NegotiatorDecisionInput } from './decision-input.js';
27
- export { DECISION_SYSTEM_PROMPT, buildDecisionUserMessage, makeDecision, } from './decision.js';
28
- export { negotiate } from './negotiate.js';
29
- export type { NegotiateDeps, NegotiateInput, NegotiateConfig, NegotiateResult, } from './negotiate.js';
30
29
  export { rerankCandidates } from './llm-rerank.js';
31
30
  export type { RerankCandidate, RerankDecision, RerankQuery, } from './llm-rerank.js';
32
31
  export { synthesizeContract } from './synthesize-contract.js';
33
32
  export type { SynthesizeContractResult } from './synthesize-contract.js';
34
33
  export { ensureConformingContract } from './ensure-conforming-contract.js';
35
34
  export type { EnsureConformingResult } from './ensure-conforming-contract.js';
36
- export { validateContractStructure, validateContractNovelty, formatValidationFindings, } from './contract-validators.js';
35
+ export { normalizeDraft } from './normalize-draft.js';
36
+ export { validateContractRedundancy, validateContractNovelty, formatValidationFindings, } from './contract-validators.js';
37
37
  export type { ContractValidationFinding, ContractValidationFindingKind, ContractValidationResult, ContractValidationNoveltyDeps, ContractValidationNoveltyOptions, } from './contract-validators.js';
38
38
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAChE,OAAO,EAAE,eAAe,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAC;AACxE,OAAO,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AACtE,YAAY,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAC5D,OAAO,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AACtE,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,YAAY,EACV,aAAa,EACb,cAAc,EACd,eAAe,GAChB,MAAM,iBAAiB,CAAC;AACzB,YAAY,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AACnD,YAAY,EAAE,SAAS,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC9E,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC5D,YAAY,EAAE,uBAAuB,EAAE,MAAM,qBAAqB,CAAC;AACnE,OAAO,EACL,sBAAsB,EACtB,wBAAwB,EACxB,YAAY,GACb,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,YAAY,EACV,aAAa,EACb,cAAc,EACd,eAAe,EACf,eAAe,GAChB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,YAAY,EACV,eAAe,EACf,cAAc,EACd,WAAW,GACZ,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAC9D,YAAY,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;AACzE,OAAO,EAAE,wBAAwB,EAAE,MAAM,iCAAiC,CAAC;AAC3E,YAAY,EAAE,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AAC9E,OAAO,EACL,yBAAyB,EACzB,uBAAuB,EACvB,wBAAwB,GACzB,MAAM,0BAA0B,CAAC;AAClC,YAAY,EACV,yBAAyB,EACzB,6BAA6B,EAC7B,wBAAwB,EACxB,6BAA6B,EAC7B,gCAAgC,GACjC,MAAM,0BAA0B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAChE,YAAY,EAAE,SAAS,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC9E,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACnD,YAAY,EACV,eAAe,EACf,cAAc,EACd,WAAW,GACZ,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAC9D,YAAY,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;AACzE,OAAO,EAAE,wBAAwB,EAAE,MAAM,iCAAiC,CAAC;AAC3E,YAAY,EAAE,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AAC9E,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EACL,0BAA0B,EAC1B,uBAAuB,EACvB,wBAAwB,GACzB,MAAM,0BAA0B,CAAC;AAClC,YAAY,EACV,yBAAyB,EACzB,6BAA6B,EAC7B,wBAAwB,EACxB,6BAA6B,EAC7B,gCAAgC,GACjC,MAAM,0BAA0B,CAAC"}
package/dist/index.js CHANGED
@@ -1,26 +1,32 @@
1
1
  /**
2
- * @ggui-ai/negotiator — open-source UI decision engine for ggui.
2
+ * @ggui-ai/negotiator — open-source contract-synthesis + match-judge
3
+ * engine for ggui's handshake.
3
4
  *
4
- * Decides which UI to render (create/update/replace) given agent
5
- * signal (data/prompt/context/agentTools) and current render state.
5
+ * Given an agent's draft contract + intent, this package:
6
+ * - synthesizes / repairs a conforming `DataContract`
7
+ * (`synthesizeContract`, `ensureConformingContract`) so the
8
+ * handshake always returns a valid contract;
9
+ * - judges blueprint-match candidates for reuse (`rerankCandidates`);
10
+ * - validates contract structure + novelty (`contract-validators`);
11
+ * - hashes contracts into identity + variant keys (`hashContract`,
12
+ * `buildVariant`) and normalizes untrusted drafts (`normalizeDraft`).
13
+ *
14
+ * The HANDSHAKE DECISION itself (find-similar → reuse vs synth-create)
15
+ * lives in the shared `decideHandshake` core in
16
+ * `@ggui-ai/mcp-server-handlers`, which composes these primitives; the
17
+ * former in-package `negotiate()` RAG+decision pipeline was retired in
18
+ * favor of that unified, adapter-injected core.
6
19
  *
7
20
  * Composes the storage seams defined in `@ggui-ai/mcp-server-core`
8
- * (`EmbeddingProvider`, `VectorStore`, `Negotiator`). The decision
9
- * semantics are open here; concrete cloud-vendor bindings (e.g. a
10
- * managed embedding service or vector store) live behind those seams
11
- * so this package stays deployment-agnostic.
21
+ * (`EmbeddingProvider`, `VectorStore`) so this package stays
22
+ * deployment-agnostic.
12
23
  *
13
24
  * This barrel stays narrow — it exports only the minimum surface
14
25
  * consumers need. Each additive export carries semver weight.
15
26
  */
16
27
  export { hashContract, buildVariant } from './contract-hash.js';
17
- export { computeIntentId, shouldSuppressSuggestion } from './intent.js';
18
- export { detectDataPatterns, buildSuggestion } from './suggestion.js';
19
- export { inferInteractionMode, inferJsonSchemaType } from './pure.js';
20
- export { ragSearch } from './rag-search.js';
21
- export { DECISION_SYSTEM_PROMPT, buildDecisionUserMessage, makeDecision, } from './decision.js';
22
- export { negotiate } from './negotiate.js';
23
28
  export { rerankCandidates } from './llm-rerank.js';
24
29
  export { synthesizeContract } from './synthesize-contract.js';
25
30
  export { ensureConformingContract } from './ensure-conforming-contract.js';
26
- export { validateContractStructure, validateContractNovelty, formatValidationFindings, } from './contract-validators.js';
31
+ export { normalizeDraft } from './normalize-draft.js';
32
+ export { validateContractRedundancy, validateContractNovelty, formatValidationFindings, } from './contract-validators.js';
@@ -1,23 +1,23 @@
1
1
  /**
2
- * `LLMCaller` — the decision engine's LLM dispatcher.
2
+ * `LLMCaller` — the negotiator's LLM dispatcher.
3
3
  *
4
4
  * Narrow abstraction over "call a chat model, optionally with a forced
5
5
  * tool-use schema for guaranteed-JSON structured output." Kept public
6
6
  * so OSS consumers of `@ggui-ai/negotiator` can bring their own LLM
7
7
  * provider (Anthropic direct, OpenAI, Google, a local model, a
8
- * community LiteLLM wrapper) without touching the decision-engine
8
+ * community LiteLLM wrapper) without touching the synthesis / judge
9
9
  * source.
10
10
  *
11
11
  * **Why this lives in `@ggui-ai/negotiator`, not
12
12
  * `@ggui-ai/mcp-server-core`.** `mcp-server-core` contains the
13
13
  * storage + runtime seams an MCP server implementer binds against
14
14
  * (`VectorStore`, `EmbeddingProvider`, `KeyValueStore`,
15
- * `BlueprintProvider`, `Negotiator`). `LLMCaller` is an
16
- * engine-internal dispatcher — one level below `Negotiator` — so
17
- * lifting it to `mcp-server-core` would grow the public seam count
18
- * speculatively. If a second consumer outside the negotiator
19
- * surfaces later, the "where does `LLMCaller` live?" question can be
20
- * re-opened at that point.
15
+ * `BlueprintProvider`). `LLMCaller` is an engine-internal
16
+ * dispatcher — one level below the synthesis + judge primitives this
17
+ * package exports — so lifting it to `mcp-server-core` would grow the
18
+ * public seam count speculatively. If a second consumer outside the
19
+ * negotiator surfaces later, the "where does `LLMCaller` live?"
20
+ * question can be re-opened at that point.
21
21
  *
22
22
  * Normative semantics:
23
23
  * - `call(systemPrompt, userMessage, maxTokens?)` returns the raw
@@ -41,7 +41,7 @@ export interface ToolSchema {
41
41
  description: string;
42
42
  input_schema: Record<string, unknown>;
43
43
  }
44
- /** Chat-model dispatcher consumed by the negotiator decision engine. */
44
+ /** Chat-model dispatcher consumed by the negotiator's synthesis + judge primitives. */
45
45
  export interface LLMCaller {
46
46
  /**
47
47
  * Call the model in plain-text mode. `maxTokens` defaults to
@@ -1 +1 @@
1
- {"version":3,"file":"llm-caller.d.ts","sourceRoot":"","sources":["../src/llm-caller.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AAEH,6DAA6D;AAC7D,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACvC;AAED,wEAAwE;AACxE,MAAM,WAAW,SAAS;IACxB;;;OAGG;IACH,IAAI,CACF,YAAY,EAAE,MAAM,EACpB,WAAW,EAAE,MAAM,EACnB,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,MAAM,CAAC,CAAC;IAEnB;;;;;OAKG;IACH,cAAc,CAAC,CAAC,CAAC,EACf,YAAY,EAAE,MAAM,EACpB,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,UAAU,EAChB,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,CAAC,CAAC,CAAC;CACf;AAED;;;;;GAKG;AACH,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,WAAW,GAAG,QAAQ,GAAG,QAAQ,GAAG,YAAY,GAAG,SAAS,CAAC;IACvE,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB"}
1
+ {"version":3,"file":"llm-caller.d.ts","sourceRoot":"","sources":["../src/llm-caller.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AAEH,6DAA6D;AAC7D,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACvC;AAED,uFAAuF;AACvF,MAAM,WAAW,SAAS;IACxB;;;OAGG;IACH,IAAI,CACF,YAAY,EAAE,MAAM,EACpB,WAAW,EAAE,MAAM,EACnB,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,MAAM,CAAC,CAAC;IAEnB;;;;;OAKG;IACH,cAAc,CAAC,CAAC,CAAC,EACf,YAAY,EAAE,MAAM,EACpB,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,UAAU,EAChB,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,CAAC,CAAC,CAAC;CACf;AAED;;;;;GAKG;AACH,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,WAAW,GAAG,QAAQ,GAAG,QAAQ,GAAG,YAAY,GAAG,SAAS,CAAC;IACvE,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB"}
@@ -1,23 +1,23 @@
1
1
  /**
2
- * `LLMCaller` — the decision engine's LLM dispatcher.
2
+ * `LLMCaller` — the negotiator's LLM dispatcher.
3
3
  *
4
4
  * Narrow abstraction over "call a chat model, optionally with a forced
5
5
  * tool-use schema for guaranteed-JSON structured output." Kept public
6
6
  * so OSS consumers of `@ggui-ai/negotiator` can bring their own LLM
7
7
  * provider (Anthropic direct, OpenAI, Google, a local model, a
8
- * community LiteLLM wrapper) without touching the decision-engine
8
+ * community LiteLLM wrapper) without touching the synthesis / judge
9
9
  * source.
10
10
  *
11
11
  * **Why this lives in `@ggui-ai/negotiator`, not
12
12
  * `@ggui-ai/mcp-server-core`.** `mcp-server-core` contains the
13
13
  * storage + runtime seams an MCP server implementer binds against
14
14
  * (`VectorStore`, `EmbeddingProvider`, `KeyValueStore`,
15
- * `BlueprintProvider`, `Negotiator`). `LLMCaller` is an
16
- * engine-internal dispatcher — one level below `Negotiator` — so
17
- * lifting it to `mcp-server-core` would grow the public seam count
18
- * speculatively. If a second consumer outside the negotiator
19
- * surfaces later, the "where does `LLMCaller` live?" question can be
20
- * re-opened at that point.
15
+ * `BlueprintProvider`). `LLMCaller` is an engine-internal
16
+ * dispatcher — one level below the synthesis + judge primitives this
17
+ * package exports — so lifting it to `mcp-server-core` would grow the
18
+ * public seam count speculatively. If a second consumer outside the
19
+ * negotiator surfaces later, the "where does `LLMCaller` live?"
20
+ * question can be re-opened at that point.
21
21
  *
22
22
  * Normative semantics:
23
23
  * - `call(systemPrompt, userMessage, maxTokens?)` returns the raw
@@ -12,7 +12,6 @@
12
12
  * judge restores precision. Combined break-even hit rate is ~10%;
13
13
  * realistic workloads observe 30-70%.
14
14
  */
15
- import { summarizeContract } from '@ggui-ai/protocol';
16
15
  import type { LLMCaller, ToolSchema } from './llm-caller.js';
17
16
  /**
18
17
  * One candidate blueprint for the LLM judge to consider.
@@ -28,7 +27,7 @@ export interface RerankCandidate {
28
27
  readonly cachedIntent: string;
29
28
  /**
30
29
  * One-line summary of the blueprint's contract surface. Format
31
- * matches `summarizeContract()` below — `slots=...; actions=...;
30
+ * matches `@ggui-ai/protocol`'s `summarizeContract()` — `slots=...; actions=...;
32
31
  * streams=...; props=...` so the judge sees the structural shape
33
32
  * without the JSON noise.
34
33
  */
@@ -49,10 +48,13 @@ export interface RerankDecision {
49
48
  */
50
49
  readonly matchId: string | null;
51
50
  /**
52
- * Confidence on `[0, 1]`. Caller compares against a threshold (e.g.
53
- * 0.6) before treating the decision as a hit. Returned even when
54
- * matchId is null so callers can log "judge declined with
55
- * confidence X."
51
+ * Confidence on `[0, 1]` — how strongly the matched candidate is in
52
+ * the same task-and-shape family as the request, NOT how completely
53
+ * its fields cover the request. Field/slot/action deltas are
54
+ * reconciled and reported to the agent separately; they never lower
55
+ * this score. Caller compares against a threshold (e.g. 0.6) before
56
+ * treating the decision as a hit. Returned even when matchId is null
57
+ * so callers can log "judge declined with confidence X."
56
58
  */
57
59
  readonly confidence: number;
58
60
  /**
@@ -79,9 +81,8 @@ export interface RerankQuery {
79
81
  readonly intent: string;
80
82
  readonly contractSummary: string;
81
83
  }
82
- declare const RERANK_SYSTEM_PROMPT = "You match user UI requests against previously-generated UI blueprints. Each blueprint was produced for a past request and stored. Decide whether any candidate produces the SAME USEFUL UI for the current request.\n\nMATCH means the candidate would correctly satisfy the user's current request \u2014 same UI shape (component types, layout pattern), same wire surface (slot names, action names), same intended user task, and same load-bearing parameters (dates, months, ranges, enum values).\n\nNO-MATCH means the candidate would NOT satisfy the user's current request \u2014 different task (haiku composer vs tweet draft, login vs signup), different UI shape (form vs list vs dashboard), or load-bearing parameters differ (calendar-Jan vs calendar-Mar \u2014 same contract, different value).\n\nVisual style differences alone (minimal vs ornate, dense vs spacious) DO NOT block a match \u2014 the user can refine those after they get a working UI.\n\nOutput exactly ONE tool call with your decision. confidence is a number in [0, 1]. matchId is a string from the candidate ids, or null when no candidate matches. reason is a short sentence the operator can use to debug.";
84
+ declare const RERANK_SYSTEM_PROMPT = "You match user UI requests against previously-generated UI blueprints. Each blueprint was produced for a past request and stored. Decide whether any candidate belongs to the SAME FAMILY as the current request \u2014 i.e. it would serve as a reasonable starting point that the requester can refine, not a pixel-exact replica.\n\nMATCH means the candidate is the same intended user task AND the same broad UI shape (component types, layout pattern). A candidate still MATCHES when the current request adds or omits fields, slots, or actions relative to the cached blueprint \u2014 a superset, a subset, or an overlapping wire surface all still match. Added or omitted fields/slots/actions DO NOT block a match and are NOT yours to judge: those wire-surface deltas are reconciled and reported to the agent separately, after you decide. Judge similarity of task and shape, never coverage of fields.\n\nNO-MATCH means the candidate is a fundamentally different thing \u2014 a different intended task (haiku composer vs tweet draft, login vs signup), a different UI shape (form vs list vs dashboard), OR a conflicting load-bearing fixed VALUE baked into the blueprint (calendar pinned to Jan vs a request for Mar \u2014 same contract shape, but the fixed value conflicts). Reserve NO-MATCH for these; do not decline a candidate merely because its fields, slots, or actions differ from the request.\n\nVisual style differences alone (minimal vs ornate, dense vs spacious) DO NOT block a match \u2014 the user can refine those after they get a working UI.\n\nOutput exactly ONE tool call with your decision. confidence is a number in [0, 1] measuring how strongly the candidate is in the same task-and-shape family as the request (not how completely its fields cover the request). matchId is a string from the candidate ids, or null when no candidate matches. reason is a short sentence the operator can use to debug.";
83
85
  declare const RERANK_TOOL: ToolSchema;
84
- export { summarizeContract };
85
86
  /**
86
87
  * Run the rerank judge against a query + candidate list.
87
88
  *
@@ -1 +1 @@
1
- {"version":3,"file":"llm-rerank.d.ts","sourceRoot":"","sources":["../src/llm-rerank.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtD,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE7D;;;;;;GAMG;AACH,MAAM,WAAW,eAAe;IAC9B,+DAA+D;IAC/D,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,gEAAgE;IAChE,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B;;;;;OAKG;IACH,QAAQ,CAAC,qBAAqB,EAAE,MAAM,CAAC;IACvC;;;;;OAKG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,0CAA0C;AAC1C,MAAM,WAAW,cAAc;IAC7B;;;OAGG;IACH,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC;;;;;OAKG;IACH,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B;;;;OAIG;IACH,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,0CAA0C;IAC1C,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B;;;;;OAKG;IACH,QAAQ,CAAC,SAAS,EAAE;QAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;CACzE;AAED,8DAA8D;AAC9D,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;CAClC;AAED,QAAA,MAAM,oBAAoB,spCAQkM,CAAC;AAE7N,QAAA,MAAM,WAAW,EAAE,UA4BlB,CAAC;AAsCF,OAAO,EAAE,iBAAiB,EAAE,CAAC;AA8C7B;;;;;;;;;;;GAWG;AACH,wBAAsB,gBAAgB,CACpC,IAAI,EAAE;IAAE,QAAQ,CAAC,GAAG,EAAE,SAAS,CAAA;CAAE,EACjC,KAAK,EAAE,WAAW,EAClB,UAAU,EAAE,SAAS,eAAe,EAAE,GACrC,OAAO,CAAC,cAAc,CAAC,CAwDzB;AAGD,OAAO,EAAE,oBAAoB,EAAE,WAAW,EAAE,CAAC"}
1
+ {"version":3,"file":"llm-rerank.d.ts","sourceRoot":"","sources":["../src/llm-rerank.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE7D;;;;;;GAMG;AACH,MAAM,WAAW,eAAe;IAC9B,+DAA+D;IAC/D,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,gEAAgE;IAChE,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B;;;;;OAKG;IACH,QAAQ,CAAC,qBAAqB,EAAE,MAAM,CAAC;IACvC;;;;;OAKG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,0CAA0C;AAC1C,MAAM,WAAW,cAAc;IAC7B;;;OAGG;IACH,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC;;;;;;;;OAQG;IACH,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B;;;;OAIG;IACH,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,0CAA0C;IAC1C,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B;;;;;OAKG;IACH,QAAQ,CAAC,SAAS,EAAE;QAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;CACzE;AAED,8DAA8D;AAC9D,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;CAClC;AAED,QAAA,MAAM,oBAAoB,03DAQ6U,CAAC;AAExW,QAAA,MAAM,WAAW,EAAE,UA4BlB,CAAC;AA6EF;;;;;;;;;;;GAWG;AACH,wBAAsB,gBAAgB,CACpC,IAAI,EAAE;IAAE,QAAQ,CAAC,GAAG,EAAE,SAAS,CAAA;CAAE,EACjC,KAAK,EAAE,WAAW,EAClB,UAAU,EAAE,SAAS,eAAe,EAAE,GACrC,OAAO,CAAC,cAAc,CAAC,CAwDzB;AAGD,OAAO,EAAE,oBAAoB,EAAE,WAAW,EAAE,CAAC"}
@@ -1,27 +1,12 @@
1
- /**
2
- * LLM rerank — Tier-2 precision oracle for the blueprint registry.
3
- *
4
- * Given a user's UI request (intent + contract structure) and a set
5
- * of candidate cached blueprints retrieved by RAG, ask a fast LLM
6
- * (Haiku 4.5) which candidate (if any) matches. Returns a structured
7
- * decision so the caller can branch deterministically.
8
- *
9
- * This module is the precision half of the blueprint-first
10
- * architecture: RAG retrieval is high-recall but low-precision (bge-
11
- * small confuses topic-similar but UI-divergent prompts); the LLM
12
- * judge restores precision. Combined break-even hit rate is ~10%;
13
- * realistic workloads observe 30-70%.
14
- */
15
- import { summarizeContract } from '@ggui-ai/protocol';
16
- const RERANK_SYSTEM_PROMPT = `You match user UI requests against previously-generated UI blueprints. Each blueprint was produced for a past request and stored. Decide whether any candidate produces the SAME USEFUL UI for the current request.
1
+ const RERANK_SYSTEM_PROMPT = `You match user UI requests against previously-generated UI blueprints. Each blueprint was produced for a past request and stored. Decide whether any candidate belongs to the SAME FAMILY as the current request — i.e. it would serve as a reasonable starting point that the requester can refine, not a pixel-exact replica.
17
2
 
18
- MATCH means the candidate would correctly satisfy the user's current request — same UI shape (component types, layout pattern), same wire surface (slot names, action names), same intended user task, and same load-bearing parameters (dates, months, ranges, enum values).
3
+ MATCH means the candidate is the same intended user task AND the same broad UI shape (component types, layout pattern). A candidate still MATCHES when the current request adds or omits fields, slots, or actions relative to the cached blueprint — a superset, a subset, or an overlapping wire surface all still match. Added or omitted fields/slots/actions DO NOT block a match and are NOT yours to judge: those wire-surface deltas are reconciled and reported to the agent separately, after you decide. Judge similarity of task and shape, never coverage of fields.
19
4
 
20
- NO-MATCH means the candidate would NOT satisfy the user's current request — different task (haiku composer vs tweet draft, login vs signup), different UI shape (form vs list vs dashboard), or load-bearing parameters differ (calendar-Jan vs calendar-Mar — same contract, different value).
5
+ NO-MATCH means the candidate is a fundamentally different thing — a different intended task (haiku composer vs tweet draft, login vs signup), a different UI shape (form vs list vs dashboard), OR a conflicting load-bearing fixed VALUE baked into the blueprint (calendar pinned to Jan vs a request for Mar — same contract shape, but the fixed value conflicts). Reserve NO-MATCH for these; do not decline a candidate merely because its fields, slots, or actions differ from the request.
21
6
 
22
7
  Visual style differences alone (minimal vs ornate, dense vs spacious) DO NOT block a match — the user can refine those after they get a working UI.
23
8
 
24
- Output exactly ONE tool call with your decision. confidence is a number in [0, 1]. matchId is a string from the candidate ids, or null when no candidate matches. reason is a short sentence the operator can use to debug.`;
9
+ Output exactly ONE tool call with your decision. confidence is a number in [0, 1] measuring how strongly the candidate is in the same task-and-shape family as the request (not how completely its fields cover the request). matchId is a string from the candidate ids, or null when no candidate matches. reason is a short sentence the operator can use to debug.`;
25
10
  const RERANK_TOOL = {
26
11
  name: 'submit_rerank_decision',
27
12
  description: 'Submit your match-vs-no-match decision over the candidates.',
@@ -72,12 +57,6 @@ function truncate(text, max) {
72
57
  return text;
73
58
  return `${text.slice(0, max - 1)}…`;
74
59
  }
75
- // Re-export `summarizeContract` from protocol for backwards-compatible
76
- // access through `@ggui-ai/negotiator/llm-rerank` consumers (the
77
- // canonical home is `@ggui-ai/protocol` — both the registry storage
78
- // and the rerank prompt depend on it). Kept as a re-export so the
79
- // existing test imports here keep working.
80
- export { summarizeContract };
81
60
  function clampConfidence(value) {
82
61
  if (typeof value !== 'number' || !Number.isFinite(value))
83
62
  return 0;
@@ -1 +1 @@
1
- {"version":3,"file":"normalize-draft.d.ts","sourceRoot":"","sources":["../src/normalize-draft.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AA8EH;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CA+CtD"}
1
+ {"version":3,"file":"normalize-draft.d.ts","sourceRoot":"","sources":["../src/normalize-draft.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AA2GH;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CA4CtD"}
@@ -52,13 +52,12 @@ const ACTION_ENTRY_KEYS = new Set([
52
52
  'nextStep',
53
53
  ]);
54
54
  const STREAM_ENTRY_KEYS = new Set(['description', 'schema', 'source']);
55
- const AGENT_TOOL_KEYS = new Set([
56
- 'description',
57
- 'usage',
55
+ const AGENT_TOOL_KEYS = new Set(['serverInfo', 'toolInfo', 'usage', 'example']);
56
+ /** Inner keys of an {@link AgentToolEntry.toolInfo} (the MCP descriptor). */
57
+ const AGENT_TOOL_INFO_KEYS = new Set([
58
58
  'inputSchema',
59
+ 'description',
59
60
  'outputSchema',
60
- 'required',
61
- 'example',
62
61
  ]);
63
62
  function isRecord(value) {
64
63
  return typeof value === 'object' && value !== null && !Array.isArray(value);
@@ -87,6 +86,34 @@ function cleanEntryMap(map, allowed, schemaFields) {
87
86
  }
88
87
  return out;
89
88
  }
89
+ /** Clean a single `AgentToolEntry`: keep only the allowed outer keys
90
+ * ({@link AGENT_TOOL_KEYS}), then clean the nested `toolInfo` to its
91
+ * inner keys ({@link AGENT_TOOL_INFO_KEYS}) and normalize
92
+ * `toolInfo.inputSchema` / `toolInfo.outputSchema` so the `.strict()`
93
+ * schema doesn't reject a stray nested key. Non-record entries pass
94
+ * through untouched. */
95
+ function cleanAgentToolEntry(entry) {
96
+ if (!isRecord(entry))
97
+ return entry;
98
+ const out = {};
99
+ for (const [key, value] of Object.entries(entry)) {
100
+ if (!AGENT_TOOL_KEYS.has(key))
101
+ continue; // strip the illegal outer key
102
+ out[key] =
103
+ key === 'toolInfo'
104
+ ? cleanEntry(value, AGENT_TOOL_INFO_KEYS, ['inputSchema', 'outputSchema'])
105
+ : value;
106
+ }
107
+ return out;
108
+ }
109
+ /** Apply {@link cleanAgentToolEntry} across the agent-tool catalog. */
110
+ function cleanAgentToolMap(map) {
111
+ const out = {};
112
+ for (const [name, entry] of Object.entries(map)) {
113
+ out[name] = cleanAgentToolEntry(entry);
114
+ }
115
+ return out;
116
+ }
90
117
  /**
91
118
  * Return a structurally-normalized copy of an untrusted draft: illegal
92
119
  * wrapper/entry keys stripped, inner schemas canonicalized. Pure — never
@@ -132,10 +159,7 @@ export function normalizeDraft(draft) {
132
159
  if (isRecord(ac['tools'])) {
133
160
  out['agentCapabilities'] = {
134
161
  ...ac,
135
- tools: cleanEntryMap(ac['tools'], AGENT_TOOL_KEYS, [
136
- 'inputSchema',
137
- 'outputSchema',
138
- ]),
162
+ tools: cleanAgentToolMap(ac['tools']),
139
163
  };
140
164
  }
141
165
  }
@@ -1 +1 @@
1
- {"version":3,"file":"normalize-schema.d.ts","sourceRoot":"","sources":["../src/normalize-schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAkJH;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,CA2BxD"}
1
+ {"version":3,"file":"normalize-schema.d.ts","sourceRoot":"","sources":["../src/normalize-schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AA6JH;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,CA2BxD"}
@@ -106,6 +106,18 @@ function normalizeTypeValue(value, enumSibling) {
106
106
  const alias = TYPE_ALIASES[lower];
107
107
  if (alias !== undefined)
108
108
  return alias;
109
+ if (lower.includes('|')) {
110
+ // Pipe-union string (`"STRING|null"`). Some models emit the union
111
+ // as one pipe-delimited string rather than the JSON Schema array
112
+ // form; recover the first valid non-null member, mirroring the
113
+ // array branch below (drops the nullable arm).
114
+ for (const member of lower.split('|')) {
115
+ const norm = normalizeTypeValue(member, enumSibling);
116
+ if (norm !== undefined && norm !== 'null')
117
+ return norm;
118
+ }
119
+ return undefined;
120
+ }
109
121
  // Unrecognized garbage — drop the constraint rather than guess.
110
122
  return undefined;
111
123
  }
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cache-key-probe.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache-key-probe.d.ts","sourceRoot":"","sources":["../../src/synth-bench/cache-key-probe.ts"],"names":[],"mappings":""}