@ggui-ai/negotiator 0.24.0 → 0.26.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.
- package/README.md +9 -2
- package/dist/ensure-conforming-contract.d.ts +14 -1
- package/dist/ensure-conforming-contract.d.ts.map +1 -1
- package/dist/ensure-conforming-contract.js +45 -6
- package/dist/index.d.ts +7 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -4
- package/dist/llm-caller.d.ts +26 -0
- package/dist/llm-caller.d.ts.map +1 -1
- package/dist/llm-caller.js +9 -0
- package/dist/llm-rerank.d.ts +8 -9
- package/dist/llm-rerank.d.ts.map +1 -1
- package/dist/llm-rerank.js +14 -7
- package/dist/normalize-draft.d.ts +20 -0
- package/dist/normalize-draft.d.ts.map +1 -1
- package/dist/normalize-draft.js +63 -39
- package/dist/preserve-declared-members.d.ts +89 -0
- package/dist/preserve-declared-members.d.ts.map +1 -0
- package/dist/preserve-declared-members.js +427 -0
- package/dist/rerank-eval/run-probe.js +1 -1
- package/dist/synthesize-contract.d.ts +11 -0
- package/dist/synthesize-contract.d.ts.map +1 -1
- package/dist/synthesize-contract.js +35 -3
- package/package.json +3 -3
- package/src/ensure-conforming-contract.ts +60 -7
- package/src/index.ts +7 -5
- package/src/llm-caller.ts +34 -0
- package/src/llm-rerank.ts +21 -18
- package/src/normalize-draft.ts +70 -39
- package/src/preserve-declared-members.ts +521 -0
- package/src/rerank-eval/run-probe.ts +1 -1
- package/src/synthesize-contract.ts +54 -4
- package/dist/contract-hash.d.ts +0 -54
- package/dist/contract-hash.d.ts.map +0 -1
- package/dist/contract-hash.js +0 -96
- package/src/contract-hash.ts +0 -102
package/dist/contract-hash.d.ts
DELETED
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Contract Hashing — deterministic cache key from data contract.
|
|
3
|
-
*
|
|
4
|
-
* Uses RFC 8785 (JSON Canonicalization Scheme) for deterministic
|
|
5
|
-
* serialization, then SHA-256 for the hash.
|
|
6
|
-
*
|
|
7
|
-
* What's in the hash: intent only (the semantic identity).
|
|
8
|
-
* What's NOT in the hash: props, actions, stream (including per-channel source), adaptations.
|
|
9
|
-
*
|
|
10
|
-
* Why intent-only: The LLM generates slightly different prop descriptions
|
|
11
|
-
* each call, but the INTENT is deterministic (provided by the agent or
|
|
12
|
-
* generated once). Same intent = same component = same cached code.
|
|
13
|
-
* Props are passed at render time, not baked into the component.
|
|
14
|
-
*
|
|
15
|
-
* The `interaction` field was removed from `DataContract` in pre-launch
|
|
16
|
-
* cleanup (the four-spec surface — props/action/context/stream —
|
|
17
|
-
* describes the wire exhaustively); this function used to factor it in
|
|
18
|
-
* but no longer does. Old goldens were rotated when the field went away.
|
|
19
|
-
*/
|
|
20
|
-
import type { DataContract } from '@ggui-ai/protocol';
|
|
21
|
-
/**
|
|
22
|
-
* Hash a data contract to a deterministic cache key.
|
|
23
|
-
*
|
|
24
|
-
* Hashes intent only — the semantic identity of the UI. Props,
|
|
25
|
-
* actions, stream specs are for code generation, not caching.
|
|
26
|
-
*
|
|
27
|
-
* `intent` is passed separately because `DataContract` itself does
|
|
28
|
-
* not carry an `intent` field — the outer pipeline owns intent
|
|
29
|
-
* (`story.intent` on `ggui_render`, the operator prompt for harness
|
|
30
|
-
* benchmarks). Threading intent into the hash keeps cache identity
|
|
31
|
-
* stable across negotiations: different intents produce different
|
|
32
|
-
* generated code (labels, copy, layout) even when the wire surface is
|
|
33
|
-
* identical.
|
|
34
|
-
*
|
|
35
|
-
* The `contract` argument is retained on the signature for forward
|
|
36
|
-
* compatibility — future cache-key fields (e.g., a structural
|
|
37
|
-
* fingerprint of the four specs) can be folded in without breaking
|
|
38
|
-
* call sites — but is not consulted by the current implementation.
|
|
39
|
-
*
|
|
40
|
-
* @param contract - The data contract from negotiation (unused today)
|
|
41
|
-
* @param intent - The outer pipeline's intent (story.intent on
|
|
42
|
-
* ggui_render). Empty/falsy values are dropped from the hash input.
|
|
43
|
-
* @returns Contract hash prefixed with `ch_` (e.g., `ch_a3f8b2c1e9d04567`)
|
|
44
|
-
*/
|
|
45
|
-
export declare function hashContract(_contract: DataContract, intent: string): string;
|
|
46
|
-
/**
|
|
47
|
-
* Build a variant key from shell type and device category.
|
|
48
|
-
*
|
|
49
|
-
* @param shellType - Shell type (default: 'universal')
|
|
50
|
-
* @param deviceCategory - Device category (default: 'universal')
|
|
51
|
-
* @returns Variant string (e.g., 'fullscreen:mobile', 'universal:universal')
|
|
52
|
-
*/
|
|
53
|
-
export declare function buildVariant(shellType?: string, deviceCategory?: string): string;
|
|
54
|
-
//# sourceMappingURL=contract-hash.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"contract-hash.d.ts","sourceRoot":"","sources":["../src/contract-hash.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAiCtD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,YAAY,CAC1B,SAAS,EAAE,YAAY,EACvB,MAAM,EAAE,MAAM,GACb,MAAM,CAMR;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAC1B,SAAS,SAAc,EACvB,cAAc,SAAc,GAC3B,MAAM,CAER"}
|
package/dist/contract-hash.js
DELETED
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Contract Hashing — deterministic cache key from data contract.
|
|
3
|
-
*
|
|
4
|
-
* Uses RFC 8785 (JSON Canonicalization Scheme) for deterministic
|
|
5
|
-
* serialization, then SHA-256 for the hash.
|
|
6
|
-
*
|
|
7
|
-
* What's in the hash: intent only (the semantic identity).
|
|
8
|
-
* What's NOT in the hash: props, actions, stream (including per-channel source), adaptations.
|
|
9
|
-
*
|
|
10
|
-
* Why intent-only: The LLM generates slightly different prop descriptions
|
|
11
|
-
* each call, but the INTENT is deterministic (provided by the agent or
|
|
12
|
-
* generated once). Same intent = same component = same cached code.
|
|
13
|
-
* Props are passed at render time, not baked into the component.
|
|
14
|
-
*
|
|
15
|
-
* The `interaction` field was removed from `DataContract` in pre-launch
|
|
16
|
-
* cleanup (the four-spec surface — props/action/context/stream —
|
|
17
|
-
* describes the wire exhaustively); this function used to factor it in
|
|
18
|
-
* but no longer does. Old goldens were rotated when the field went away.
|
|
19
|
-
*/
|
|
20
|
-
import { createHash } from 'node:crypto';
|
|
21
|
-
/**
|
|
22
|
-
* RFC 8785 JSON Canonicalization Scheme.
|
|
23
|
-
*
|
|
24
|
-
* Produces deterministic JSON by:
|
|
25
|
-
* - Sorting object keys lexicographically (recursive)
|
|
26
|
-
* - Normalizing numbers (no trailing zeros, no +0)
|
|
27
|
-
* - Removing undefined values
|
|
28
|
-
* - No whitespace
|
|
29
|
-
*/
|
|
30
|
-
function canonicalize(value) {
|
|
31
|
-
if (value === null || value === undefined)
|
|
32
|
-
return 'null';
|
|
33
|
-
if (typeof value === 'boolean')
|
|
34
|
-
return value ? 'true' : 'false';
|
|
35
|
-
if (typeof value === 'number') {
|
|
36
|
-
if (!isFinite(value))
|
|
37
|
-
return 'null';
|
|
38
|
-
return Object.is(value, -0) ? '0' : String(value);
|
|
39
|
-
}
|
|
40
|
-
if (typeof value === 'string')
|
|
41
|
-
return JSON.stringify(value);
|
|
42
|
-
if (Array.isArray(value)) {
|
|
43
|
-
return '[' + value.map((v) => canonicalize(v)).join(',') + ']';
|
|
44
|
-
}
|
|
45
|
-
if (typeof value === 'object') {
|
|
46
|
-
const obj = value;
|
|
47
|
-
const keys = Object.keys(obj)
|
|
48
|
-
.filter((k) => obj[k] !== undefined)
|
|
49
|
-
.sort();
|
|
50
|
-
const entries = keys.map((k) => JSON.stringify(k) + ':' + canonicalize(obj[k]));
|
|
51
|
-
return '{' + entries.join(',') + '}';
|
|
52
|
-
}
|
|
53
|
-
return 'null';
|
|
54
|
-
}
|
|
55
|
-
/**
|
|
56
|
-
* Hash a data contract to a deterministic cache key.
|
|
57
|
-
*
|
|
58
|
-
* Hashes intent only — the semantic identity of the UI. Props,
|
|
59
|
-
* actions, stream specs are for code generation, not caching.
|
|
60
|
-
*
|
|
61
|
-
* `intent` is passed separately because `DataContract` itself does
|
|
62
|
-
* not carry an `intent` field — the outer pipeline owns intent
|
|
63
|
-
* (`story.intent` on `ggui_render`, the operator prompt for harness
|
|
64
|
-
* benchmarks). Threading intent into the hash keeps cache identity
|
|
65
|
-
* stable across negotiations: different intents produce different
|
|
66
|
-
* generated code (labels, copy, layout) even when the wire surface is
|
|
67
|
-
* identical.
|
|
68
|
-
*
|
|
69
|
-
* The `contract` argument is retained on the signature for forward
|
|
70
|
-
* compatibility — future cache-key fields (e.g., a structural
|
|
71
|
-
* fingerprint of the four specs) can be folded in without breaking
|
|
72
|
-
* call sites — but is not consulted by the current implementation.
|
|
73
|
-
*
|
|
74
|
-
* @param contract - The data contract from negotiation (unused today)
|
|
75
|
-
* @param intent - The outer pipeline's intent (story.intent on
|
|
76
|
-
* ggui_render). Empty/falsy values are dropped from the hash input.
|
|
77
|
-
* @returns Contract hash prefixed with `ch_` (e.g., `ch_a3f8b2c1e9d04567`)
|
|
78
|
-
*/
|
|
79
|
-
export function hashContract(_contract, intent) {
|
|
80
|
-
const input = {};
|
|
81
|
-
if (intent)
|
|
82
|
-
input.intent = intent;
|
|
83
|
-
const canonical = canonicalize(input);
|
|
84
|
-
const hash = createHash('sha256').update(canonical).digest('hex');
|
|
85
|
-
return `ch_${hash.slice(0, 16)}`;
|
|
86
|
-
}
|
|
87
|
-
/**
|
|
88
|
-
* Build a variant key from shell type and device category.
|
|
89
|
-
*
|
|
90
|
-
* @param shellType - Shell type (default: 'universal')
|
|
91
|
-
* @param deviceCategory - Device category (default: 'universal')
|
|
92
|
-
* @returns Variant string (e.g., 'fullscreen:mobile', 'universal:universal')
|
|
93
|
-
*/
|
|
94
|
-
export function buildVariant(shellType = 'universal', deviceCategory = 'universal') {
|
|
95
|
-
return `${shellType}:${deviceCategory}`;
|
|
96
|
-
}
|
package/src/contract-hash.ts
DELETED
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Contract Hashing — deterministic cache key from data contract.
|
|
3
|
-
*
|
|
4
|
-
* Uses RFC 8785 (JSON Canonicalization Scheme) for deterministic
|
|
5
|
-
* serialization, then SHA-256 for the hash.
|
|
6
|
-
*
|
|
7
|
-
* What's in the hash: intent only (the semantic identity).
|
|
8
|
-
* What's NOT in the hash: props, actions, stream (including per-channel source), adaptations.
|
|
9
|
-
*
|
|
10
|
-
* Why intent-only: The LLM generates slightly different prop descriptions
|
|
11
|
-
* each call, but the INTENT is deterministic (provided by the agent or
|
|
12
|
-
* generated once). Same intent = same component = same cached code.
|
|
13
|
-
* Props are passed at render time, not baked into the component.
|
|
14
|
-
*
|
|
15
|
-
* The `interaction` field was removed from `DataContract` in pre-launch
|
|
16
|
-
* cleanup (the four-spec surface — props/action/context/stream —
|
|
17
|
-
* describes the wire exhaustively); this function used to factor it in
|
|
18
|
-
* but no longer does. Old goldens were rotated when the field went away.
|
|
19
|
-
*/
|
|
20
|
-
|
|
21
|
-
import { createHash } from 'node:crypto';
|
|
22
|
-
import type { DataContract } from '@ggui-ai/protocol';
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* RFC 8785 JSON Canonicalization Scheme.
|
|
26
|
-
*
|
|
27
|
-
* Produces deterministic JSON by:
|
|
28
|
-
* - Sorting object keys lexicographically (recursive)
|
|
29
|
-
* - Normalizing numbers (no trailing zeros, no +0)
|
|
30
|
-
* - Removing undefined values
|
|
31
|
-
* - No whitespace
|
|
32
|
-
*/
|
|
33
|
-
function canonicalize(value: unknown): string {
|
|
34
|
-
if (value === null || value === undefined) return 'null';
|
|
35
|
-
if (typeof value === 'boolean') return value ? 'true' : 'false';
|
|
36
|
-
if (typeof value === 'number') {
|
|
37
|
-
if (!isFinite(value)) return 'null';
|
|
38
|
-
return Object.is(value, -0) ? '0' : String(value);
|
|
39
|
-
}
|
|
40
|
-
if (typeof value === 'string') return JSON.stringify(value);
|
|
41
|
-
if (Array.isArray(value)) {
|
|
42
|
-
return '[' + value.map((v) => canonicalize(v)).join(',') + ']';
|
|
43
|
-
}
|
|
44
|
-
if (typeof value === 'object') {
|
|
45
|
-
const obj = value as Record<string, unknown>;
|
|
46
|
-
const keys = Object.keys(obj)
|
|
47
|
-
.filter((k) => obj[k] !== undefined)
|
|
48
|
-
.sort();
|
|
49
|
-
const entries = keys.map((k) => JSON.stringify(k) + ':' + canonicalize(obj[k]));
|
|
50
|
-
return '{' + entries.join(',') + '}';
|
|
51
|
-
}
|
|
52
|
-
return 'null';
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* Hash a data contract to a deterministic cache key.
|
|
57
|
-
*
|
|
58
|
-
* Hashes intent only — the semantic identity of the UI. Props,
|
|
59
|
-
* actions, stream specs are for code generation, not caching.
|
|
60
|
-
*
|
|
61
|
-
* `intent` is passed separately because `DataContract` itself does
|
|
62
|
-
* not carry an `intent` field — the outer pipeline owns intent
|
|
63
|
-
* (`story.intent` on `ggui_render`, the operator prompt for harness
|
|
64
|
-
* benchmarks). Threading intent into the hash keeps cache identity
|
|
65
|
-
* stable across negotiations: different intents produce different
|
|
66
|
-
* generated code (labels, copy, layout) even when the wire surface is
|
|
67
|
-
* identical.
|
|
68
|
-
*
|
|
69
|
-
* The `contract` argument is retained on the signature for forward
|
|
70
|
-
* compatibility — future cache-key fields (e.g., a structural
|
|
71
|
-
* fingerprint of the four specs) can be folded in without breaking
|
|
72
|
-
* call sites — but is not consulted by the current implementation.
|
|
73
|
-
*
|
|
74
|
-
* @param contract - The data contract from negotiation (unused today)
|
|
75
|
-
* @param intent - The outer pipeline's intent (story.intent on
|
|
76
|
-
* ggui_render). Empty/falsy values are dropped from the hash input.
|
|
77
|
-
* @returns Contract hash prefixed with `ch_` (e.g., `ch_a3f8b2c1e9d04567`)
|
|
78
|
-
*/
|
|
79
|
-
export function hashContract(
|
|
80
|
-
_contract: DataContract,
|
|
81
|
-
intent: string,
|
|
82
|
-
): string {
|
|
83
|
-
const input: Record<string, unknown> = {};
|
|
84
|
-
if (intent) input.intent = intent;
|
|
85
|
-
const canonical = canonicalize(input);
|
|
86
|
-
const hash = createHash('sha256').update(canonical).digest('hex');
|
|
87
|
-
return `ch_${hash.slice(0, 16)}`;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* Build a variant key from shell type and device category.
|
|
92
|
-
*
|
|
93
|
-
* @param shellType - Shell type (default: 'universal')
|
|
94
|
-
* @param deviceCategory - Device category (default: 'universal')
|
|
95
|
-
* @returns Variant string (e.g., 'fullscreen:mobile', 'universal:universal')
|
|
96
|
-
*/
|
|
97
|
-
export function buildVariant(
|
|
98
|
-
shellType = 'universal',
|
|
99
|
-
deviceCategory = 'universal',
|
|
100
|
-
): string {
|
|
101
|
-
return `${shellType}:${deviceCategory}`;
|
|
102
|
-
}
|