@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.
- package/README.md +25 -19
- package/dist/contract-validators.d.ts +20 -16
- package/dist/contract-validators.d.ts.map +1 -1
- package/dist/contract-validators.js +11 -8
- package/dist/index.d.ts +20 -20
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +20 -14
- package/dist/llm-caller.d.ts +9 -9
- package/dist/llm-caller.d.ts.map +1 -1
- package/dist/llm-caller.js +8 -8
- package/dist/llm-rerank.d.ts +9 -8
- package/dist/llm-rerank.d.ts.map +1 -1
- package/dist/llm-rerank.js +4 -25
- package/dist/normalize-draft.d.ts.map +1 -1
- package/dist/normalize-draft.js +33 -9
- package/dist/normalize-schema.d.ts.map +1 -1
- package/dist/normalize-schema.js +12 -0
- package/dist/synth-bench/cache-key-probe.d.ts +3 -0
- package/dist/synth-bench/cache-key-probe.d.ts.map +1 -0
- package/dist/synth-bench/cache-key-probe.js +177 -0
- package/dist/synth-bench/corpus.d.ts.map +1 -1
- package/dist/synth-bench/corpus.js +28 -20
- package/dist/synth-bench/run-bench.js +2 -2
- package/dist/synthesize-contract.d.ts +2 -3
- package/dist/synthesize-contract.d.ts.map +1 -1
- package/dist/synthesize-contract.js +20 -15
- package/package.json +8 -7
- package/src/contract-validators.ts +21 -17
- package/src/index.ts +20 -33
- package/src/llm-caller.ts +9 -9
- package/src/llm-rerank.ts +12 -17
- package/src/normalize-draft.ts +35 -9
- package/src/normalize-schema.ts +11 -0
- package/src/synth-bench/cache-key-probe.ts +213 -0
- package/src/synth-bench/corpus.ts +28 -20
- package/src/synth-bench/run-bench.ts +2 -2
- package/src/synthesize-contract.ts +24 -20
- package/dist/decision-input.d.ts +0 -51
- package/dist/decision-input.d.ts.map +0 -1
- package/dist/decision-input.js +0 -17
- package/dist/decision.d.ts +0 -58
- package/dist/decision.d.ts.map +0 -1
- package/dist/decision.js +0 -501
- package/dist/intent.d.ts +0 -22
- package/dist/intent.d.ts.map +0 -1
- package/dist/intent.js +0 -28
- package/dist/negotiate.d.ts +0 -142
- package/dist/negotiate.d.ts.map +0 -1
- package/dist/negotiate.js +0 -163
- package/dist/pure.d.ts +0 -30
- package/dist/pure.d.ts.map +0 -1
- package/dist/pure.js +0 -43
- package/dist/rag-search.d.ts +0 -73
- package/dist/rag-search.d.ts.map +0 -1
- package/dist/rag-search.js +0 -192
- package/dist/render.d.ts +0 -57
- package/dist/render.d.ts.map +0 -1
- package/dist/render.js +0 -25
- package/dist/suggestion.d.ts +0 -38
- package/dist/suggestion.d.ts.map +0 -1
- package/dist/suggestion.js +0 -47
- package/dist/types.d.ts +0 -30
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js +0 -13
- package/src/decision-input.ts +0 -52
- package/src/decision.ts +0 -581
- package/src/intent.ts +0 -37
- package/src/negotiate.ts +0 -314
- package/src/pure.ts +0 -46
- package/src/rag-search.ts +0 -274
- package/src/render.ts +0 -56
- package/src/suggestion.ts +0 -73
- package/src/types.ts +0 -31
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Blueprint cache-key stability probe.
|
|
4
|
+
*
|
|
5
|
+
* The handshake blueprint cache hits ONLY on exact canonical-contract
|
|
6
|
+
* equality: `blueprintKey(contract)` = sha256 of `canonicalizeContracts`
|
|
7
|
+
* (RFC 8785), which preserves spec placement, action/slot/tool NAMES and
|
|
8
|
+
* schema shapes (it only normalizes key order / whitespace and strips
|
|
9
|
+
* `description`/`usage`). The semantic/fuzzy match is disabled whenever a
|
|
10
|
+
* contract is present. So two requests for the SAME intent reuse a cached
|
|
11
|
+
* blueprint only if the LLM authored a byte-identical canonical contract
|
|
12
|
+
* both times.
|
|
13
|
+
*
|
|
14
|
+
* This probe synthesizes one intent N times and reports:
|
|
15
|
+
* 1. how many DISTINCT blueprintKeys result (distinct > 1 ⇒ the
|
|
16
|
+
* exact-key cache structurally cannot hit on re-runs);
|
|
17
|
+
* 2. the KEY-AFFECTING diff — every leaf path where the runs disagree
|
|
18
|
+
* (descriptions/usage stripped, since the key ignores them) — so we
|
|
19
|
+
* can see WHETHER the variance is trivial (normalizable: required
|
|
20
|
+
* order, additionalProperties, optional fields) or semantic
|
|
21
|
+
* (property names / structure → only a semantic match can bridge it).
|
|
22
|
+
*
|
|
23
|
+
* Usage:
|
|
24
|
+
* pnpm -F @ggui-ai/negotiator cache-probe -- --intent "my todo items" --n 5
|
|
25
|
+
* pnpm -F @ggui-ai/negotiator cache-probe -- --n 5 --dump /tmp/cache-probe.json
|
|
26
|
+
*/
|
|
27
|
+
import { writeFileSync } from 'node:fs';
|
|
28
|
+
import { blueprintKey } from '@ggui-ai/protocol/blueprint-key';
|
|
29
|
+
import { synthesizeContract } from '../synthesize-contract.js';
|
|
30
|
+
import { DEFAULT_MODEL, buildAnthropicLlmCaller, resolveAnthropicKey, } from './cli-llm.js';
|
|
31
|
+
function parseArgs(argv) {
|
|
32
|
+
let intent = 'my todo items';
|
|
33
|
+
let n = 3;
|
|
34
|
+
let model = DEFAULT_MODEL;
|
|
35
|
+
let dump;
|
|
36
|
+
for (let i = 0; i < argv.length; i++) {
|
|
37
|
+
const a = argv[i];
|
|
38
|
+
if (a === '--intent' && argv[i + 1])
|
|
39
|
+
intent = argv[++i];
|
|
40
|
+
else if (a === '--n' && argv[i + 1])
|
|
41
|
+
n = Number(argv[++i]);
|
|
42
|
+
else if (a === '--model' && argv[i + 1])
|
|
43
|
+
model = argv[++i];
|
|
44
|
+
else if (a === '--dump' && argv[i + 1])
|
|
45
|
+
dump = argv[++i];
|
|
46
|
+
}
|
|
47
|
+
return { intent, n, model, ...(dump !== undefined ? { dump } : {}) };
|
|
48
|
+
}
|
|
49
|
+
/** One-line canonical-surface summary — the bits blueprintKey is sensitive to. */
|
|
50
|
+
function shapeSummary(c) {
|
|
51
|
+
const parts = [];
|
|
52
|
+
const props = Object.keys(c.propsSpec?.properties ?? {});
|
|
53
|
+
const ctx = Object.keys(c.contextSpec ?? {});
|
|
54
|
+
const act = Object.keys(c.actionSpec ?? {});
|
|
55
|
+
const str = Object.keys(c.streamSpec ?? {});
|
|
56
|
+
const tools = Object.keys(c.agentCapabilities?.tools ?? {});
|
|
57
|
+
if (props.length)
|
|
58
|
+
parts.push(`props{${props.join(',')}}`);
|
|
59
|
+
if (ctx.length)
|
|
60
|
+
parts.push(`context{${ctx.join(',')}}`);
|
|
61
|
+
if (act.length)
|
|
62
|
+
parts.push(`action{${act.join(',')}}`);
|
|
63
|
+
if (str.length)
|
|
64
|
+
parts.push(`stream{${str.join(',')}}`);
|
|
65
|
+
if (tools.length)
|
|
66
|
+
parts.push(`tools{${tools.join(',')}}`);
|
|
67
|
+
return parts.join(' ') || '(empty)';
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Flatten a contract to `path → json-encoded leaf`, applying the same
|
|
71
|
+
* domain rule the cache key does: drop string-valued `description` /
|
|
72
|
+
* `usage` (informational — `canonicalizeContracts` strips them). Objects
|
|
73
|
+
* recurse; arrays are encoded whole (order is key-affecting under JCS,
|
|
74
|
+
* which sorts object keys but NOT array elements).
|
|
75
|
+
*/
|
|
76
|
+
function flattenKeyAffecting(value, prefix, out) {
|
|
77
|
+
if (Array.isArray(value)) {
|
|
78
|
+
out.set(prefix, JSON.stringify(value));
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
if (value !== null && typeof value === 'object') {
|
|
82
|
+
for (const [k, v] of Object.entries(value)) {
|
|
83
|
+
if ((k === 'description' || k === 'usage') && typeof v === 'string') {
|
|
84
|
+
continue; // stripped by the cache key
|
|
85
|
+
}
|
|
86
|
+
flattenKeyAffecting(v, prefix ? `${prefix}.${k}` : k, out);
|
|
87
|
+
}
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
out.set(prefix, JSON.stringify(value));
|
|
91
|
+
}
|
|
92
|
+
/** Every leaf path where the N contracts do not all agree, with the
|
|
93
|
+
* distinct per-run values (or `∅` when a run omits the path). */
|
|
94
|
+
function crossRunDiff(contracts) {
|
|
95
|
+
const flat = contracts.map((c) => {
|
|
96
|
+
const m = new Map();
|
|
97
|
+
flattenKeyAffecting(c, '', m);
|
|
98
|
+
return m;
|
|
99
|
+
});
|
|
100
|
+
const allPaths = new Set();
|
|
101
|
+
for (const m of flat)
|
|
102
|
+
for (const p of m.keys())
|
|
103
|
+
allPaths.add(p);
|
|
104
|
+
const divergent = [];
|
|
105
|
+
for (const path of [...allPaths].sort()) {
|
|
106
|
+
const values = flat.map((m) => m.get(path) ?? '∅');
|
|
107
|
+
if (new Set(values).size > 1)
|
|
108
|
+
divergent.push({ path, values });
|
|
109
|
+
}
|
|
110
|
+
return divergent;
|
|
111
|
+
}
|
|
112
|
+
async function main() {
|
|
113
|
+
const args = parseArgs(process.argv.slice(2));
|
|
114
|
+
const llm = buildAnthropicLlmCaller(resolveAnthropicKey('cache-probe'), args.model);
|
|
115
|
+
process.stdout.write(`cache-probe: intent=${JSON.stringify(args.intent)} n=${args.n} model=${args.model}\n\n`);
|
|
116
|
+
const contracts = [];
|
|
117
|
+
const keys = [];
|
|
118
|
+
for (let i = 0; i < args.n; i++) {
|
|
119
|
+
const synth = await synthesizeContract({ llm }, args.intent);
|
|
120
|
+
if (synth.contract === null) {
|
|
121
|
+
process.stdout.write(` run ${i + 1}: synth declined — ${synth.reason}\n`);
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
const key = blueprintKey(synth.contract);
|
|
125
|
+
contracts.push(synth.contract);
|
|
126
|
+
keys.push(key);
|
|
127
|
+
process.stdout.write(` run ${i + 1}: ${key} ${shapeSummary(synth.contract)}\n`);
|
|
128
|
+
}
|
|
129
|
+
const distinct = new Set(keys);
|
|
130
|
+
process.stdout.write(`\nDistinct blueprintKeys: ${distinct.size}/${keys.length}\n`);
|
|
131
|
+
if (distinct.size <= 1 && keys.length > 1) {
|
|
132
|
+
process.stdout.write('STABLE → the exact-key cache WOULD hit on a re-run of this intent.\n');
|
|
133
|
+
}
|
|
134
|
+
else if (keys.length > 1) {
|
|
135
|
+
process.stdout.write('UNSTABLE → same intent yields different canonical contracts → the exact-key\n' +
|
|
136
|
+
'cache cannot hit; each request cold-gens a new blueprint.\n');
|
|
137
|
+
}
|
|
138
|
+
// Key-affecting cross-run diff — the "what varies" the user asked for.
|
|
139
|
+
if (contracts.length > 1) {
|
|
140
|
+
const diff = crossRunDiff(contracts);
|
|
141
|
+
process.stdout.write(`\n=== KEY-AFFECTING DIFF (${diff.length} divergent paths; descriptions stripped) ===\n`);
|
|
142
|
+
for (const { path, values } of diff) {
|
|
143
|
+
process.stdout.write(` ${path}\n`);
|
|
144
|
+
values.forEach((v, i) => {
|
|
145
|
+
const capped = v.length > 100 ? `${v.slice(0, 100)}…` : v;
|
|
146
|
+
process.stdout.write(` run${i + 1}: ${capped}\n`);
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
// Heuristic taxonomy hint.
|
|
150
|
+
const isArrayOrderOnly = diff.every(({ values }) => {
|
|
151
|
+
const parsed = values
|
|
152
|
+
.filter((v) => v !== '∅')
|
|
153
|
+
.map((v) => {
|
|
154
|
+
try {
|
|
155
|
+
return JSON.stringify([...JSON.parse(v)].sort());
|
|
156
|
+
}
|
|
157
|
+
catch {
|
|
158
|
+
return v;
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
return new Set(parsed).size === 1;
|
|
162
|
+
});
|
|
163
|
+
process.stdout.write(`\nHint: ${diff.length === 0
|
|
164
|
+
? 'no key-affecting differences — variance must be elsewhere'
|
|
165
|
+
: isArrayOrderOnly
|
|
166
|
+
? 'ALL divergent paths are arrays differing only in ORDER → a canonical sort in canonicalizeContracts would collapse these keys (cheap fix, no semantic match needed).'
|
|
167
|
+
: 'divergent paths include non-array-order differences (names / types / structure / presence) → a semantic intent-match is needed to bridge them (canonicalization alone cannot).'}\n`);
|
|
168
|
+
}
|
|
169
|
+
if (args.dump !== undefined) {
|
|
170
|
+
writeFileSync(args.dump, JSON.stringify({ intent: args.intent, model: args.model, keys, contracts }, null, 2));
|
|
171
|
+
process.stdout.write(`\nDumped ${contracts.length} contracts → ${args.dump}\n`);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
main().catch((err) => {
|
|
175
|
+
process.stderr.write(`cache-probe failed: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
176
|
+
process.exit(1);
|
|
177
|
+
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"corpus.d.ts","sourceRoot":"","sources":["../../src/synth-bench/corpus.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAC1D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAElE,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,CAAC;IACpC;;;;;;;;;;;OAWG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;IACzB;;;;;;OAMG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,oBAAoB,CAAC;IAC1C;;;;;;;;;;;;;;;OAeG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,SAAS,gBAAgB,EAAE,CAAC;CACnD;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC;IAChC,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAC;IACjC,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC;IAChC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B;;;;OAIG;IACH,QAAQ,CAAC,qBAAqB,CAAC,EAAE,OAAO,CAAC;IACzC,QAAQ,CAAC,aAAa,CAAC,EAAE,OAAO,CAAC;IACjC;;;+DAG2D;IAC3D,QAAQ,CAAC,WAAW,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACzC;;;;2DAIuD;IACvD,QAAQ,CAAC,YAAY,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC1C;;;0EAGsE;IACtE,QAAQ,CAAC,eAAe,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC7C;;;;;;;;;OASG;IACH,QAAQ,CAAC,wBAAwB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACtD;;;;;sEAKkE;IAClE,QAAQ,CAAC,cAAc,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC5C;;qDAEiD;IACjD,QAAQ,CAAC,mBAAmB,CAAC,EAAE,OAAO,CAAC;IACvC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,gBAAgB,GAAG,MAAM,CAOhE;AAoDD,eAAO,MAAM,YAAY,EAAE,SAAS,UAAU,EAs8B7C,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,eAAO,MAAM,aAAa,EAAE,SAAS,UAAU,
|
|
1
|
+
{"version":3,"file":"corpus.d.ts","sourceRoot":"","sources":["../../src/synth-bench/corpus.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAC1D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAElE,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,CAAC;IACpC;;;;;;;;;;;OAWG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;IACzB;;;;;;OAMG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,oBAAoB,CAAC;IAC1C;;;;;;;;;;;;;;;OAeG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,SAAS,gBAAgB,EAAE,CAAC;CACnD;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC;IAChC,QAAQ,CAAC,cAAc,EAAE,OAAO,CAAC;IACjC,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC;IAChC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B;;;;OAIG;IACH,QAAQ,CAAC,qBAAqB,CAAC,EAAE,OAAO,CAAC;IACzC,QAAQ,CAAC,aAAa,CAAC,EAAE,OAAO,CAAC;IACjC;;;+DAG2D;IAC3D,QAAQ,CAAC,WAAW,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACzC;;;;2DAIuD;IACvD,QAAQ,CAAC,YAAY,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC1C;;;0EAGsE;IACtE,QAAQ,CAAC,eAAe,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC7C;;;;;;;;;OASG;IACH,QAAQ,CAAC,wBAAwB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACtD;;;;;sEAKkE;IAClE,QAAQ,CAAC,cAAc,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC5C;;qDAEiD;IACjD,QAAQ,CAAC,mBAAmB,CAAC,EAAE,OAAO,CAAC;IACvC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,gBAAgB,GAAG,MAAM,CAOhE;AAoDD,eAAO,MAAM,YAAY,EAAE,SAAS,UAAU,EAs8B7C,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,eAAO,MAAM,aAAa,EAAE,SAAS,UAAU,EAsR9C,CAAC"}
|
|
@@ -1091,19 +1091,23 @@ export const REPAIR_CORPUS = [
|
|
|
1091
1091
|
agentCapabilities: {
|
|
1092
1092
|
tools: {
|
|
1093
1093
|
todo_toggle: {
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1094
|
+
toolInfo: {
|
|
1095
|
+
description: 'Flip a todo done/undone',
|
|
1096
|
+
inputSchema: {
|
|
1097
|
+
type: 'object',
|
|
1098
|
+
properties: { id: { type: 'string' } },
|
|
1099
|
+
required: ['id'],
|
|
1100
|
+
},
|
|
1099
1101
|
},
|
|
1100
1102
|
},
|
|
1101
1103
|
todo_add: {
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1104
|
+
toolInfo: {
|
|
1105
|
+
description: 'Append a new todo',
|
|
1106
|
+
inputSchema: {
|
|
1107
|
+
type: 'object',
|
|
1108
|
+
properties: { text: { type: 'string' } },
|
|
1109
|
+
required: ['text'],
|
|
1110
|
+
},
|
|
1107
1111
|
},
|
|
1108
1112
|
},
|
|
1109
1113
|
},
|
|
@@ -1178,19 +1182,23 @@ export const REPAIR_CORPUS = [
|
|
|
1178
1182
|
agentCapabilities: {
|
|
1179
1183
|
tools: {
|
|
1180
1184
|
todo_toggle: {
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1185
|
+
toolInfo: {
|
|
1186
|
+
description: 'Flip a todo done/undone',
|
|
1187
|
+
inputSchema: {
|
|
1188
|
+
type: 'object',
|
|
1189
|
+
properties: { id: { type: 'string' } },
|
|
1190
|
+
required: ['id'],
|
|
1191
|
+
},
|
|
1186
1192
|
},
|
|
1187
1193
|
},
|
|
1188
1194
|
todo_add: {
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1195
|
+
toolInfo: {
|
|
1196
|
+
description: 'Append a new todo',
|
|
1197
|
+
inputSchema: {
|
|
1198
|
+
type: 'object',
|
|
1199
|
+
properties: { text: { type: 'string' } },
|
|
1200
|
+
required: ['text'],
|
|
1201
|
+
},
|
|
1194
1202
|
},
|
|
1195
1203
|
},
|
|
1196
1204
|
},
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
*/
|
|
35
35
|
import { listContractGadgets } from '@ggui-ai/protocol';
|
|
36
36
|
import { synthesizeContract } from '../synthesize-contract.js';
|
|
37
|
-
import {
|
|
37
|
+
import { validateContractRedundancy, } from '../contract-validators.js';
|
|
38
38
|
import { BENCH_CORPUS, contractShape, } from './corpus.js';
|
|
39
39
|
/**
|
|
40
40
|
* Failure kinds that are ADVISORY — surfaced in the report but do NOT
|
|
@@ -246,7 +246,7 @@ export async function evaluateAgainstCorpus(deps, options = {}, corpus = BENCH_C
|
|
|
246
246
|
};
|
|
247
247
|
}
|
|
248
248
|
else {
|
|
249
|
-
const findings =
|
|
249
|
+
const findings = validateContractRedundancy(synth.contract).findings;
|
|
250
250
|
const score = scoreSynthesizedContract(synth.contract, entry.expected);
|
|
251
251
|
outcome = {
|
|
252
252
|
entry,
|
|
@@ -56,7 +56,7 @@ export interface SynthesizeContractResult {
|
|
|
56
56
|
readonly attempts: number;
|
|
57
57
|
/**
|
|
58
58
|
* Structural-validator findings produced when the synthesizer ran the
|
|
59
|
-
* `
|
|
59
|
+
* `validateContractRedundancy` gate against its assembled contract.
|
|
60
60
|
* Empty when validator didn't run (early skip / decline). Surfaced
|
|
61
61
|
* so callers (cache-trace emit site, ops dashboards) can render
|
|
62
62
|
* findings without re-running the detector.
|
|
@@ -136,8 +136,7 @@ export declare function synthesizeContract(deps: {
|
|
|
136
136
|
}): Promise<SynthesizeContractResult>;
|
|
137
137
|
/**
|
|
138
138
|
* Compose the "AVAILABLE GADGETS" section appended to synth's user
|
|
139
|
-
* prompt
|
|
140
|
-
* this one composer). Flattens the package-keyed
|
|
139
|
+
* prompt. Flattens the package-keyed
|
|
141
140
|
* {@link GadgetDescriptor} catalog into one line per export:
|
|
142
141
|
*
|
|
143
142
|
* - hook `useGeolocation` (package `@ggui-ai/gadgets`) — <desc> (usage: <usage>)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"synthesize-contract.d.ts","sourceRoot":"","sources":["../src/synthesize-contract.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,OAAO,
|
|
1
|
+
{"version":3,"file":"synthesize-contract.d.ts","sourceRoot":"","sources":["../src/synthesize-contract.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,OAAO,EAIL,KAAK,YAAY,EACjB,KAAK,gBAAgB,EAEtB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAM7D,OAAO,EAKL,KAAK,yBAAyB,EAC/B,MAAM,0BAA0B,CAAC;AAsBlC,uCAAuC;AACvC,MAAM,WAAW,wBAAwB;IACvC,wEAAwE;IACxE,QAAQ,CAAC,QAAQ,EAAE,YAAY,GAAG,IAAI,CAAC;IACvC,wDAAwD;IACxD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,+CAA+C;IAC/C,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B;;;;;OAKG;IACH,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B;;;;;;OAMG;IACH,QAAQ,CAAC,QAAQ,EAAE,SAAS,yBAAyB,EAAE,CAAC;CACzD;AAuOD;;;;;GAKG;AACH,eAAO,MAAM,eAAe,EAAE,UA+I7B,CAAC;AAwRF;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAsB,kBAAkB,CACtC,IAAI,EAAE;IAAE,QAAQ,CAAC,GAAG,EAAE,SAAS,CAAA;CAAE,EACjC,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE;IACR;;;;;;;;;;;;;OAaG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,SAAS,gBAAgB,EAAE,CAAC;IAClD;;;;;;;;;;;OAWG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;IACzB;;;;;OAKG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS;QAChC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;KAC1B,EAAE,CAAC;CACL,GACA,OAAO,CAAC,wBAAwB,CAAC,CAyMnC;AAmUD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,8BAA8B,CAC5C,OAAO,EAAE,SAAS,gBAAgB,EAAE,GAAG,SAAS,GAC/C,MAAM,GAAG,SAAS,CA+CpB"}
|
|
@@ -40,7 +40,7 @@ import { dataContractSchema, gadgetExportName, } from '@ggui-ai/protocol';
|
|
|
40
40
|
import { lintContract } from '@ggui-ai/protocol';
|
|
41
41
|
import { normalizeSchema } from './normalize-schema.js';
|
|
42
42
|
import { draftSeedPropKeys, findDroppedSeedSurfaces, } from './preserve-seed-surfaces.js';
|
|
43
|
-
import { formatValidationFindings, validateActionsVsContext, validateContractCoherence,
|
|
43
|
+
import { formatValidationFindings, validateActionsVsContext, validateContractCoherence, validateContractRedundancy, } from './contract-validators.js';
|
|
44
44
|
/**
|
|
45
45
|
* Map a protocol-linter {@link ContractIssue} into the negotiator's
|
|
46
46
|
* existing {@link ContractValidationFinding} shape so phase-2/3/4
|
|
@@ -257,7 +257,7 @@ Several retired field/hook names appear in older training data. The cross-ref li
|
|
|
257
257
|
- clientCapabilities.capabilities (retired inner key; use clientCapabilities.gadgets)
|
|
258
258
|
- useWiredTool(...) / useClientTool(...) / useAgentTool(...) (retired hooks; the contract layer doesn't reference these at all)
|
|
259
259
|
- "@ggui-ai/client-tools" as a package import (retired package; use @ggui-ai/gadgets)
|
|
260
|
-
- PushStory / story.* on handshake input (retired wire shape; handshake input is flat — {
|
|
260
|
+
- PushStory / story.* on handshake input (retired wire shape; handshake input is flat — {sessionId, intent, contract?, hint?, forceCreate?})
|
|
261
261
|
- story.adapters / declaredAdapters (retired adapter gate; permissions are a registry-side descriptor field — the wire clientCapabilities.gadgets map carries identity only)
|
|
262
262
|
- dispatch: {kind: 'tool', tool: ...} (retired discriminated union on actionSpec entries — actions carry NO tool wiring)
|
|
263
263
|
- dispatch: {kind: 'agent', intendedTool: ...} (retired — same; do not wire actions to tools)
|
|
@@ -622,7 +622,7 @@ function pruneRedundantActions(contract) {
|
|
|
622
622
|
if (actionSpec === undefined)
|
|
623
623
|
return contract;
|
|
624
624
|
const redundant = new Set();
|
|
625
|
-
for (const f of
|
|
625
|
+
for (const f of validateContractRedundancy(contract).findings) {
|
|
626
626
|
if (f.kind === 'redundant-action' && typeof f.actionName === 'string') {
|
|
627
627
|
redundant.add(f.actionName);
|
|
628
628
|
}
|
|
@@ -764,7 +764,7 @@ export async function synthesizeContract(deps, intent, options) {
|
|
|
764
764
|
// get it right every draw. Subtractive, so the contract stays
|
|
765
765
|
// schema-valid.
|
|
766
766
|
const validatedContract = pruneRedundantActions(validated.data);
|
|
767
|
-
const structureSafety =
|
|
767
|
+
const structureSafety = validateContractRedundancy(validatedContract);
|
|
768
768
|
const placementSafety = validateActionsVsContext(validatedContract);
|
|
769
769
|
// Intent-aware coherence — the one validator that reads `trimmed`.
|
|
770
770
|
// Catches the degenerate "actionSpec-only, no data surface"
|
|
@@ -1015,20 +1015,26 @@ function buildContract(input) {
|
|
|
1015
1015
|
for (const [name, entry] of Object.entries(input.agentCapabilities.tools)) {
|
|
1016
1016
|
if (!entry || typeof entry !== 'object')
|
|
1017
1017
|
continue;
|
|
1018
|
+
// The LLM authors the ergonomic flat shape ({inputSchema?,
|
|
1019
|
+
// outputSchema?, usage?}); the wire shape nests the MCP descriptor
|
|
1020
|
+
// under `toolInfo` with a REQUIRED `inputSchema` (default the
|
|
1021
|
+
// void-object schema when the LLM omitted it). `usage` stays on the
|
|
1022
|
+
// ggui authoring layer alongside the descriptor.
|
|
1023
|
+
const inputSchema = (entry.inputSchema !== undefined
|
|
1024
|
+
? normalizeSchema(entry.inputSchema)
|
|
1025
|
+
: { type: 'object' });
|
|
1018
1026
|
built[name] = {
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1027
|
+
toolInfo: {
|
|
1028
|
+
inputSchema,
|
|
1029
|
+
...(entry.outputSchema !== undefined
|
|
1030
|
+
? { outputSchema: normalizeSchema(entry.outputSchema) }
|
|
1031
|
+
: {}),
|
|
1032
|
+
},
|
|
1025
1033
|
...(typeof entry.usage === 'string' ? { usage: entry.usage } : {}),
|
|
1026
1034
|
};
|
|
1027
1035
|
}
|
|
1028
1036
|
if (Object.keys(built).length > 0) {
|
|
1029
|
-
contract.agentCapabilities = {
|
|
1030
|
-
tools: built,
|
|
1031
|
-
};
|
|
1037
|
+
contract.agentCapabilities = { tools: built };
|
|
1032
1038
|
}
|
|
1033
1039
|
}
|
|
1034
1040
|
// clientCapabilities.gadgets — browser-capability gadgets the
|
|
@@ -1090,8 +1096,7 @@ const SYNTH_PER_LIBRARY_BUDGET = 300;
|
|
|
1090
1096
|
const SYNTH_TOTAL_BUDGET = 3_000;
|
|
1091
1097
|
/**
|
|
1092
1098
|
* Compose the "AVAILABLE GADGETS" section appended to synth's user
|
|
1093
|
-
* prompt
|
|
1094
|
-
* this one composer). Flattens the package-keyed
|
|
1099
|
+
* prompt. Flattens the package-keyed
|
|
1095
1100
|
* {@link GadgetDescriptor} catalog into one line per export:
|
|
1096
1101
|
*
|
|
1097
1102
|
* - hook `useGeolocation` (package `@ggui-ai/gadgets`) — <desc> (usage: <usage>)
|
package/package.json
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ggui-ai/negotiator",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.3.0-rc.0",
|
|
4
|
+
"description": "Contract-synthesis + match-judge engine for ggui's handshake. Synthesizes or repairs a conforming DataContract from an agent's draft, judges blueprint-match candidates for reuse, and validates contract structure + novelty — the primitives composed by decideHandshake in @ggui-ai/mcp-server-handlers. Deployment-agnostic: concrete embedding and vector-store bindings plug in via the storage interfaces from @ggui-ai/mcp-server-core.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"ggui",
|
|
8
8
|
"mcp",
|
|
9
9
|
"generative-ui",
|
|
10
10
|
"ai-agents",
|
|
11
|
-
"
|
|
11
|
+
"contract-synthesis"
|
|
12
12
|
],
|
|
13
13
|
"homepage": "https://github.com/ggui-ai/ggui/tree/main/packages/negotiator",
|
|
14
14
|
"repository": {
|
|
@@ -47,8 +47,8 @@
|
|
|
47
47
|
}
|
|
48
48
|
},
|
|
49
49
|
"dependencies": {
|
|
50
|
-
"@ggui-ai/
|
|
51
|
-
"@ggui-ai/
|
|
50
|
+
"@ggui-ai/protocol": "0.3.0-rc.0",
|
|
51
|
+
"@ggui-ai/mcp-server-core": "0.3.0-rc.0"
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
54
|
"@types/node": "^24.0.0",
|
|
@@ -63,13 +63,14 @@
|
|
|
63
63
|
},
|
|
64
64
|
"author": "ggui contributors <hello@ggui.ai>",
|
|
65
65
|
"scripts": {
|
|
66
|
-
"build": "tsc -p tsconfig.build.json",
|
|
66
|
+
"build": "rm -rf dist && tsc -p tsconfig.build.json",
|
|
67
67
|
"dev": "tsc --watch",
|
|
68
68
|
"typecheck": "tsc --noEmit",
|
|
69
69
|
"test": "vitest run",
|
|
70
70
|
"test:watch": "vitest",
|
|
71
71
|
"probe-rerank": "tsx src/rerank-eval/run-probe-cli.ts",
|
|
72
72
|
"bench-synth": "tsx src/synth-bench/run-bench-cli.ts",
|
|
73
|
-
"bench-repair": "tsx src/synth-bench/run-repair-bench-cli.ts"
|
|
73
|
+
"bench-repair": "tsx src/synth-bench/run-repair-bench-cli.ts",
|
|
74
|
+
"cache-probe": "tsx src/synth-bench/cache-key-probe.ts"
|
|
74
75
|
}
|
|
75
76
|
}
|
|
@@ -3,9 +3,12 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Two detectors live here:
|
|
5
5
|
*
|
|
6
|
-
* - {@link
|
|
7
|
-
* flag over-specified contracts without any runtime dependency.
|
|
8
|
-
*
|
|
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)
|
|
@@ -80,26 +83,27 @@ export interface ContractValidationResult {
|
|
|
80
83
|
|
|
81
84
|
/**
|
|
82
85
|
* Dependencies the novelty detector needs. Embedding provider + vector
|
|
83
|
-
* store are the same seams the
|
|
84
|
-
* novelty check operates over the production index without any
|
|
85
|
-
* infrastructure.
|
|
86
|
+
* store are the same seams the handshake's find-similar retrieval uses,
|
|
87
|
+
* so the novelty check operates over the production index without any
|
|
88
|
+
* extra infrastructure.
|
|
86
89
|
*/
|
|
87
90
|
export interface ContractValidationNoveltyDeps {
|
|
88
91
|
readonly embedding: EmbeddingProvider;
|
|
89
92
|
readonly vectorStore: VectorStore;
|
|
90
93
|
/** Tenant / partition the nearest-neighbor query runs against. Same
|
|
91
|
-
* semantics as `
|
|
94
|
+
* semantics as the `scope` argument on `VectorStore.query` — the
|
|
95
|
+
* tenant / index partition, typically `appId`. */
|
|
92
96
|
readonly scope: string;
|
|
93
97
|
}
|
|
94
98
|
|
|
95
99
|
export interface ContractValidationNoveltyOptions {
|
|
96
100
|
/**
|
|
97
101
|
* Cosine distance threshold above which the contract is flagged as
|
|
98
|
-
* novel. Distance is `1 - cosine_similarity`. Default `0.8
|
|
99
|
-
*
|
|
100
|
-
*
|
|
101
|
-
*
|
|
102
|
-
* still flag for review.
|
|
102
|
+
* novel. Distance is `1 - cosine_similarity`. Default `0.8`: a
|
|
103
|
+
* contract whose nearest stored neighbor sits beyond distance 0.8
|
|
104
|
+
* is effectively outside retrieval range, with a small buffer below
|
|
105
|
+
* the hard one-tail boundary (distance 0.85) so contracts that
|
|
106
|
+
* hover near retrieval but slightly above still flag for review.
|
|
103
107
|
*/
|
|
104
108
|
readonly thresholdCosine?: number;
|
|
105
109
|
}
|
|
@@ -251,20 +255,20 @@ function isEmptyPayloadSchema(schema: JsonSchema | undefined): boolean {
|
|
|
251
255
|
}
|
|
252
256
|
|
|
253
257
|
// =============================================================================
|
|
254
|
-
//
|
|
258
|
+
// Redundancy validator (synchronous, dependency-free)
|
|
255
259
|
// =============================================================================
|
|
256
260
|
|
|
257
261
|
/**
|
|
258
|
-
* Run the synchronous
|
|
262
|
+
* Run the synchronous redundancy detector against `contract`.
|
|
259
263
|
*
|
|
260
|
-
*
|
|
264
|
+
* One finding kind:
|
|
261
265
|
* - `redundant-action`: empty-payload action whose name parses as a
|
|
262
266
|
* mutator of an existing context slot.
|
|
263
267
|
*
|
|
264
|
-
* Returns an empty findings array for contracts that don't trip
|
|
268
|
+
* Returns an empty findings array for contracts that don't trip the
|
|
265
269
|
* heuristic.
|
|
266
270
|
*/
|
|
267
|
-
export function
|
|
271
|
+
export function validateContractRedundancy(
|
|
268
272
|
contract: DataContract,
|
|
269
273
|
): ContractValidationResult {
|
|
270
274
|
const findings: ContractValidationFinding[] = [];
|
package/src/index.ts
CHANGED
|
@@ -1,46 +1,32 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @ggui-ai/negotiator — open-source
|
|
2
|
+
* @ggui-ai/negotiator — open-source contract-synthesis + match-judge
|
|
3
|
+
* engine for ggui's handshake.
|
|
3
4
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
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
|
|
9
|
-
*
|
|
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
|
|
|
17
28
|
export { hashContract, buildVariant } from './contract-hash.js';
|
|
18
|
-
export { computeIntentId, shouldSuppressSuggestion } from './intent.js';
|
|
19
|
-
export { detectDataPatterns, buildSuggestion } from './suggestion.js';
|
|
20
|
-
export type { NegotiatorSuggestion } from './suggestion.js';
|
|
21
|
-
export { inferInteractionMode, inferJsonSchemaType } from './pure.js';
|
|
22
|
-
export { ragSearch } from './rag-search.js';
|
|
23
|
-
export type {
|
|
24
|
-
RagSearchDeps,
|
|
25
|
-
RagSearchInput,
|
|
26
|
-
RagSearchResult,
|
|
27
|
-
} from './rag-search.js';
|
|
28
|
-
export type { NegotiatorOption } from './types.js';
|
|
29
29
|
export type { LLMCaller, LLMCallerConfig, ToolSchema } from './llm-caller.js';
|
|
30
|
-
export type { RenderState, RenderEntry } from './render.js';
|
|
31
|
-
export type { NegotiatorDecisionInput } from './decision-input.js';
|
|
32
|
-
export {
|
|
33
|
-
DECISION_SYSTEM_PROMPT,
|
|
34
|
-
buildDecisionUserMessage,
|
|
35
|
-
makeDecision,
|
|
36
|
-
} from './decision.js';
|
|
37
|
-
export { negotiate } from './negotiate.js';
|
|
38
|
-
export type {
|
|
39
|
-
NegotiateDeps,
|
|
40
|
-
NegotiateInput,
|
|
41
|
-
NegotiateConfig,
|
|
42
|
-
NegotiateResult,
|
|
43
|
-
} from './negotiate.js';
|
|
44
30
|
export { rerankCandidates } from './llm-rerank.js';
|
|
45
31
|
export type {
|
|
46
32
|
RerankCandidate,
|
|
@@ -51,8 +37,9 @@ export { synthesizeContract } from './synthesize-contract.js';
|
|
|
51
37
|
export type { SynthesizeContractResult } from './synthesize-contract.js';
|
|
52
38
|
export { ensureConformingContract } from './ensure-conforming-contract.js';
|
|
53
39
|
export type { EnsureConformingResult } from './ensure-conforming-contract.js';
|
|
40
|
+
export { normalizeDraft } from './normalize-draft.js';
|
|
54
41
|
export {
|
|
55
|
-
|
|
42
|
+
validateContractRedundancy,
|
|
56
43
|
validateContractNovelty,
|
|
57
44
|
formatValidationFindings,
|
|
58
45
|
} from './contract-validators.js';
|
package/src/llm-caller.ts
CHANGED
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `LLMCaller` — the
|
|
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
|
|
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
|
|
16
|
-
*
|
|
17
|
-
* lifting it to `mcp-server-core` would grow the
|
|
18
|
-
* speculatively. If a second consumer outside the
|
|
19
|
-
* surfaces later, the "where does `LLMCaller` live?"
|
|
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
|
|
@@ -43,7 +43,7 @@ export interface ToolSchema {
|
|
|
43
43
|
input_schema: Record<string, unknown>;
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
-
/** Chat-model dispatcher consumed by the negotiator
|
|
46
|
+
/** Chat-model dispatcher consumed by the negotiator's synthesis + judge primitives. */
|
|
47
47
|
export interface LLMCaller {
|
|
48
48
|
/**
|
|
49
49
|
* Call the model in plain-text mode. `maxTokens` defaults to
|