@ggui-ai/negotiator 0.1.0-rc.1
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/LICENSE +201 -0
- package/README.md +49 -0
- package/dist/contract-hash.d.ts +54 -0
- package/dist/contract-hash.d.ts.map +1 -0
- package/dist/contract-hash.js +96 -0
- package/dist/contract-validators.d.ts +171 -0
- package/dist/contract-validators.d.ts.map +1 -0
- package/dist/contract-validators.js +478 -0
- package/dist/decision-input.d.ts +48 -0
- package/dist/decision-input.d.ts.map +1 -0
- package/dist/decision-input.js +14 -0
- package/dist/decision.d.ts +54 -0
- package/dist/decision.d.ts.map +1 -0
- package/dist/decision.js +500 -0
- package/dist/index.d.ts +36 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +25 -0
- package/dist/intent.d.ts +22 -0
- package/dist/intent.d.ts.map +1 -0
- package/dist/intent.js +28 -0
- package/dist/llm-caller.d.ts +70 -0
- package/dist/llm-caller.d.ts.map +1 -0
- package/dist/llm-caller.js +38 -0
- package/dist/llm-rerank.d.ts +101 -0
- package/dist/llm-rerank.d.ts.map +1 -0
- package/dist/llm-rerank.js +178 -0
- package/dist/negotiate.d.ts +141 -0
- package/dist/negotiate.d.ts.map +1 -0
- package/dist/negotiate.js +161 -0
- package/dist/normalize-schema.d.ts +22 -0
- package/dist/normalize-schema.d.ts.map +1 -0
- package/dist/normalize-schema.js +191 -0
- package/dist/pure.d.ts +30 -0
- package/dist/pure.d.ts.map +1 -0
- package/dist/pure.js +43 -0
- package/dist/rag-search.d.ts +73 -0
- package/dist/rag-search.d.ts.map +1 -0
- package/dist/rag-search.js +192 -0
- package/dist/rerank-eval/pairs.d.ts +28 -0
- package/dist/rerank-eval/pairs.d.ts.map +1 -0
- package/dist/rerank-eval/pairs.js +531 -0
- package/dist/rerank-eval/run-probe-cli.d.ts +3 -0
- package/dist/rerank-eval/run-probe-cli.d.ts.map +1 -0
- package/dist/rerank-eval/run-probe-cli.js +146 -0
- package/dist/rerank-eval/run-probe.d.ts +68 -0
- package/dist/rerank-eval/run-probe.d.ts.map +1 -0
- package/dist/rerank-eval/run-probe.js +113 -0
- package/dist/session.d.ts +42 -0
- package/dist/session.d.ts.map +1 -0
- package/dist/session.js +21 -0
- package/dist/suggestion.d.ts +38 -0
- package/dist/suggestion.d.ts.map +1 -0
- package/dist/suggestion.js +47 -0
- package/dist/synth-bench/corpus.d.ts +106 -0
- package/dist/synth-bench/corpus.d.ts.map +1 -0
- package/dist/synth-bench/corpus.js +994 -0
- package/dist/synth-bench/run-bench-cli.d.ts +3 -0
- package/dist/synth-bench/run-bench-cli.d.ts.map +1 -0
- package/dist/synth-bench/run-bench-cli.js +181 -0
- package/dist/synth-bench/run-bench.d.ts +101 -0
- package/dist/synth-bench/run-bench.d.ts.map +1 -0
- package/dist/synth-bench/run-bench.js +374 -0
- package/dist/synthesize-contract.d.ts +131 -0
- package/dist/synthesize-contract.d.ts.map +1 -0
- package/dist/synthesize-contract.js +948 -0
- package/dist/types.d.ts +30 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +13 -0
- package/package.json +74 -0
- package/src/contract-hash.ts +102 -0
- package/src/contract-validators.ts +604 -0
- package/src/decision-input.ts +49 -0
- package/src/decision.ts +581 -0
- package/src/index.ts +63 -0
- package/src/intent.ts +37 -0
- package/src/llm-caller.ts +82 -0
- package/src/llm-rerank.ts +280 -0
- package/src/negotiate.ts +312 -0
- package/src/normalize-schema.ts +193 -0
- package/src/pure.ts +46 -0
- package/src/rag-search.ts +274 -0
- package/src/rerank-eval/pairs.ts +624 -0
- package/src/rerank-eval/run-probe-cli.ts +197 -0
- package/src/rerank-eval/run-probe.ts +198 -0
- package/src/session.ts +41 -0
- package/src/suggestion.ts +73 -0
- package/src/synth-bench/corpus.ts +1126 -0
- package/src/synth-bench/run-bench-cli.ts +237 -0
- package/src/synth-bench/run-bench.ts +525 -0
- package/src/synthesize-contract.ts +1161 -0
- package/src/types.ts +31 -0
|
@@ -0,0 +1,531 @@
|
|
|
1
|
+
export const EVAL_PAIRS = [
|
|
2
|
+
// ─── should-match: paraphrases of the same UI ───
|
|
3
|
+
{
|
|
4
|
+
id: 'sm-notepad-1',
|
|
5
|
+
kind: 'should-match',
|
|
6
|
+
query: {
|
|
7
|
+
intent: 'Build a notepad with a topic select and a note textarea',
|
|
8
|
+
contractSummary: 'interaction=collect; slots=noteText,topic; actions=∅; streams=∅',
|
|
9
|
+
},
|
|
10
|
+
candidates: [
|
|
11
|
+
{
|
|
12
|
+
id: 'bp-notepad',
|
|
13
|
+
cachedIntent: 'Live notepad panel — topic enum + textarea — context-mirrored',
|
|
14
|
+
cachedContractSummary: 'interaction=collect; slots=noteText,topic; actions=∅; streams=∅',
|
|
15
|
+
cosine: 0.92,
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
id: 'bp-todo',
|
|
19
|
+
cachedIntent: 'Todo list with add/remove items',
|
|
20
|
+
cachedContractSummary: 'interaction=collect; slots=items; actions=add,remove; streams=∅',
|
|
21
|
+
cosine: 0.41,
|
|
22
|
+
},
|
|
23
|
+
],
|
|
24
|
+
goldMatchId: 'bp-notepad',
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
id: 'sm-feedback-1',
|
|
28
|
+
kind: 'should-match',
|
|
29
|
+
query: {
|
|
30
|
+
intent: 'Form to gather user feedback with a 5-star rating and a free-text comment',
|
|
31
|
+
contractSummary: 'interaction=collect; slots=∅; actions=submit; streams=∅; props=comment,rating',
|
|
32
|
+
},
|
|
33
|
+
candidates: [
|
|
34
|
+
{
|
|
35
|
+
id: 'bp-rate-comment',
|
|
36
|
+
cachedIntent: 'Rate-and-comment feedback form — five-star rating, comment box, submit button',
|
|
37
|
+
cachedContractSummary: 'interaction=collect; slots=∅; actions=submit; streams=∅; props=comment,rating',
|
|
38
|
+
cosine: 0.88,
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
id: 'bp-survey',
|
|
42
|
+
cachedIntent: 'Multi-step survey with NPS + open-ended question + tags',
|
|
43
|
+
cachedContractSummary: 'interaction=collect; slots=∅; actions=next,prev,submit; streams=∅; props=nps,openText,tags',
|
|
44
|
+
cosine: 0.55,
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
id: 'bp-login',
|
|
48
|
+
cachedIntent: 'Login form with email + password',
|
|
49
|
+
cachedContractSummary: 'interaction=collect; slots=∅; actions=submit; streams=∅; props=email,password',
|
|
50
|
+
cosine: 0.31,
|
|
51
|
+
},
|
|
52
|
+
],
|
|
53
|
+
goldMatchId: 'bp-rate-comment',
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
id: 'sm-weather-1',
|
|
57
|
+
kind: 'should-match',
|
|
58
|
+
query: {
|
|
59
|
+
intent: 'Weather card showing current conditions for Tokyo',
|
|
60
|
+
contractSummary: 'interaction=display; slots=∅; actions=∅; streams=∅; props=city,conditions,temp',
|
|
61
|
+
},
|
|
62
|
+
candidates: [
|
|
63
|
+
{
|
|
64
|
+
id: 'bp-weather',
|
|
65
|
+
cachedIntent: 'Current weather widget — city name, temp, conditions',
|
|
66
|
+
cachedContractSummary: 'interaction=display; slots=∅; actions=∅; streams=∅; props=city,conditions,temp',
|
|
67
|
+
cosine: 0.95,
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
id: 'bp-stock',
|
|
71
|
+
cachedIntent: 'Stock ticker — symbol + price',
|
|
72
|
+
cachedContractSummary: 'interaction=display; slots=∅; actions=∅; streams=∅; props=price,symbol',
|
|
73
|
+
cosine: 0.45,
|
|
74
|
+
},
|
|
75
|
+
],
|
|
76
|
+
goldMatchId: 'bp-weather',
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
id: 'sm-todo-1',
|
|
80
|
+
kind: 'should-match',
|
|
81
|
+
query: {
|
|
82
|
+
intent: 'Todo list — user can add items, mark them complete, remove them',
|
|
83
|
+
contractSummary: 'interaction=collect; slots=items; actions=add,remove,toggle; streams=∅',
|
|
84
|
+
},
|
|
85
|
+
candidates: [
|
|
86
|
+
{
|
|
87
|
+
id: 'bp-todo-mvc',
|
|
88
|
+
cachedIntent: 'Classic todo MVC — add input, items list with checkboxes, delete buttons',
|
|
89
|
+
cachedContractSummary: 'interaction=collect; slots=items; actions=add,remove,toggle; streams=∅',
|
|
90
|
+
cosine: 0.91,
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
id: 'bp-shopping',
|
|
94
|
+
cachedIntent: 'Shopping cart with quantity + checkout',
|
|
95
|
+
cachedContractSummary: 'interaction=collect; slots=cart; actions=add,checkout,remove,setQty; streams=∅',
|
|
96
|
+
cosine: 0.62,
|
|
97
|
+
},
|
|
98
|
+
],
|
|
99
|
+
goldMatchId: 'bp-todo-mvc',
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
id: 'sm-search-1',
|
|
103
|
+
kind: 'should-match',
|
|
104
|
+
query: {
|
|
105
|
+
intent: 'Search bar with autocomplete — typing suggests options live',
|
|
106
|
+
contractSummary: 'interaction=collect; slots=query; actions=select; streams=suggestions',
|
|
107
|
+
},
|
|
108
|
+
candidates: [
|
|
109
|
+
{
|
|
110
|
+
id: 'bp-autocomplete',
|
|
111
|
+
cachedIntent: 'Search input with live-suggestion dropdown',
|
|
112
|
+
cachedContractSummary: 'interaction=collect; slots=query; actions=select; streams=suggestions',
|
|
113
|
+
cosine: 0.94,
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
id: 'bp-filter',
|
|
117
|
+
cachedIntent: 'Filter panel with multi-select facets',
|
|
118
|
+
cachedContractSummary: 'interaction=collect; slots=filters; actions=apply,clear; streams=∅',
|
|
119
|
+
cosine: 0.48,
|
|
120
|
+
},
|
|
121
|
+
],
|
|
122
|
+
goldMatchId: 'bp-autocomplete',
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
id: 'sm-chat-1',
|
|
126
|
+
kind: 'should-match',
|
|
127
|
+
query: {
|
|
128
|
+
intent: 'Chat interface — message list, input box, send button',
|
|
129
|
+
contractSummary: 'interaction=converse; slots=draft; actions=send; streams=messages',
|
|
130
|
+
},
|
|
131
|
+
candidates: [
|
|
132
|
+
{
|
|
133
|
+
id: 'bp-chat',
|
|
134
|
+
cachedIntent: 'Chat panel — scrolling message list, composer textarea, send action',
|
|
135
|
+
cachedContractSummary: 'interaction=converse; slots=draft; actions=send; streams=messages',
|
|
136
|
+
cosine: 0.93,
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
id: 'bp-comments',
|
|
140
|
+
cachedIntent: 'Comments thread with replies',
|
|
141
|
+
cachedContractSummary: 'interaction=converse; slots=draft; actions=post,reply; streams=messages',
|
|
142
|
+
cosine: 0.7,
|
|
143
|
+
},
|
|
144
|
+
],
|
|
145
|
+
goldMatchId: 'bp-chat',
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
id: 'sm-dashboard-1',
|
|
149
|
+
kind: 'should-match',
|
|
150
|
+
query: {
|
|
151
|
+
intent: 'Dashboard with KPI cards — revenue, users, churn',
|
|
152
|
+
contractSummary: 'interaction=display; slots=∅; actions=∅; streams=∅; props=churn,revenue,users',
|
|
153
|
+
},
|
|
154
|
+
candidates: [
|
|
155
|
+
{
|
|
156
|
+
id: 'bp-kpi',
|
|
157
|
+
cachedIntent: 'KPI dashboard — revenue card, user count card, churn percent',
|
|
158
|
+
cachedContractSummary: 'interaction=display; slots=∅; actions=∅; streams=∅; props=churn,revenue,users',
|
|
159
|
+
cosine: 0.93,
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
id: 'bp-table',
|
|
163
|
+
cachedIntent: 'Data table with sortable columns',
|
|
164
|
+
cachedContractSummary: 'interaction=display; slots=∅; actions=sort; streams=∅; props=columns,rows',
|
|
165
|
+
cosine: 0.42,
|
|
166
|
+
},
|
|
167
|
+
],
|
|
168
|
+
goldMatchId: 'bp-kpi',
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
id: 'sm-settings-1',
|
|
172
|
+
kind: 'should-match',
|
|
173
|
+
query: {
|
|
174
|
+
intent: 'Settings page with toggles for notifications, dark mode, autoplay',
|
|
175
|
+
contractSummary: 'interaction=collect; slots=autoplay,darkMode,notifications; actions=∅; streams=∅',
|
|
176
|
+
},
|
|
177
|
+
candidates: [
|
|
178
|
+
{
|
|
179
|
+
id: 'bp-settings',
|
|
180
|
+
cachedIntent: 'User preferences panel — notification toggle, theme toggle, autoplay toggle',
|
|
181
|
+
cachedContractSummary: 'interaction=collect; slots=autoplay,darkMode,notifications; actions=∅; streams=∅',
|
|
182
|
+
cosine: 0.9,
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
id: 'bp-profile',
|
|
186
|
+
cachedIntent: 'Profile edit form — name, email, avatar',
|
|
187
|
+
cachedContractSummary: 'interaction=collect; slots=∅; actions=save; streams=∅; props=avatar,email,name',
|
|
188
|
+
cosine: 0.5,
|
|
189
|
+
},
|
|
190
|
+
],
|
|
191
|
+
goldMatchId: 'bp-settings',
|
|
192
|
+
},
|
|
193
|
+
{
|
|
194
|
+
id: 'sm-modal-1',
|
|
195
|
+
kind: 'should-match',
|
|
196
|
+
query: {
|
|
197
|
+
intent: 'Confirmation modal — "Delete this item?" with Cancel and Delete buttons',
|
|
198
|
+
contractSummary: 'interaction=approve; slots=∅; actions=cancel,confirm; streams=∅; props=message,title',
|
|
199
|
+
},
|
|
200
|
+
candidates: [
|
|
201
|
+
{
|
|
202
|
+
id: 'bp-confirm',
|
|
203
|
+
cachedIntent: 'Confirmation dialog — title, message, two buttons (cancel + confirm)',
|
|
204
|
+
cachedContractSummary: 'interaction=approve; slots=∅; actions=cancel,confirm; streams=∅; props=message,title',
|
|
205
|
+
cosine: 0.94,
|
|
206
|
+
},
|
|
207
|
+
{
|
|
208
|
+
id: 'bp-alert',
|
|
209
|
+
cachedIntent: 'Alert banner with single dismiss button',
|
|
210
|
+
cachedContractSummary: 'interaction=approve; slots=∅; actions=dismiss; streams=∅; props=message',
|
|
211
|
+
cosine: 0.6,
|
|
212
|
+
},
|
|
213
|
+
],
|
|
214
|
+
goldMatchId: 'bp-confirm',
|
|
215
|
+
},
|
|
216
|
+
{
|
|
217
|
+
id: 'sm-onboarding-1',
|
|
218
|
+
kind: 'should-match',
|
|
219
|
+
query: {
|
|
220
|
+
intent: 'Multi-step onboarding wizard — welcome, profile, preferences, finish',
|
|
221
|
+
contractSummary: 'interaction=flow; slots=currentStep; actions=back,next,skip; streams=∅',
|
|
222
|
+
},
|
|
223
|
+
candidates: [
|
|
224
|
+
{
|
|
225
|
+
id: 'bp-wizard',
|
|
226
|
+
cachedIntent: 'Step-by-step wizard with progress indicator',
|
|
227
|
+
cachedContractSummary: 'interaction=flow; slots=currentStep; actions=back,next,skip; streams=∅',
|
|
228
|
+
cosine: 0.89,
|
|
229
|
+
},
|
|
230
|
+
{
|
|
231
|
+
id: 'bp-stepper',
|
|
232
|
+
cachedIntent: 'Linear stepper for checkout',
|
|
233
|
+
cachedContractSummary: 'interaction=flow; slots=step; actions=back,next; streams=∅',
|
|
234
|
+
cosine: 0.78,
|
|
235
|
+
},
|
|
236
|
+
],
|
|
237
|
+
goldMatchId: 'bp-wizard',
|
|
238
|
+
},
|
|
239
|
+
// ─── no-match: queries with no good fit in candidates ───
|
|
240
|
+
{
|
|
241
|
+
id: 'nm-novel-1',
|
|
242
|
+
kind: 'no-match',
|
|
243
|
+
query: {
|
|
244
|
+
intent: 'Periodic table viewer with hoverable element details',
|
|
245
|
+
contractSummary: 'interaction=display; slots=∅; actions=hover; streams=∅; props=elements',
|
|
246
|
+
},
|
|
247
|
+
candidates: [
|
|
248
|
+
{
|
|
249
|
+
id: 'bp-todo',
|
|
250
|
+
cachedIntent: 'Todo list',
|
|
251
|
+
cachedContractSummary: 'interaction=collect; slots=items; actions=add,remove; streams=∅',
|
|
252
|
+
cosine: 0.32,
|
|
253
|
+
},
|
|
254
|
+
{
|
|
255
|
+
id: 'bp-form',
|
|
256
|
+
cachedIntent: 'Generic form with text inputs',
|
|
257
|
+
cachedContractSummary: 'interaction=collect; slots=∅; actions=submit; streams=∅; props=fields',
|
|
258
|
+
cosine: 0.28,
|
|
259
|
+
},
|
|
260
|
+
],
|
|
261
|
+
goldMatchId: null,
|
|
262
|
+
},
|
|
263
|
+
{
|
|
264
|
+
id: 'nm-novel-2',
|
|
265
|
+
kind: 'no-match',
|
|
266
|
+
query: {
|
|
267
|
+
intent: 'Code editor with syntax highlighting and line numbers',
|
|
268
|
+
contractSummary: 'interaction=collect; slots=code; actions=run; streams=output',
|
|
269
|
+
},
|
|
270
|
+
candidates: [
|
|
271
|
+
{
|
|
272
|
+
id: 'bp-notepad',
|
|
273
|
+
cachedIntent: 'Plain notepad — single textarea, no syntax highlighting',
|
|
274
|
+
cachedContractSummary: 'interaction=collect; slots=text; actions=∅; streams=∅',
|
|
275
|
+
cosine: 0.55,
|
|
276
|
+
},
|
|
277
|
+
{
|
|
278
|
+
id: 'bp-search',
|
|
279
|
+
cachedIntent: 'Search bar with autocomplete',
|
|
280
|
+
cachedContractSummary: 'interaction=collect; slots=query; actions=select; streams=suggestions',
|
|
281
|
+
cosine: 0.3,
|
|
282
|
+
},
|
|
283
|
+
],
|
|
284
|
+
goldMatchId: null,
|
|
285
|
+
note: 'notepad shares "type into a textarea" but lacks syntax/run/output — should not match',
|
|
286
|
+
},
|
|
287
|
+
{
|
|
288
|
+
id: 'nm-novel-3',
|
|
289
|
+
kind: 'no-match',
|
|
290
|
+
query: {
|
|
291
|
+
intent: 'Map view showing user location with nearby points of interest',
|
|
292
|
+
contractSummary: 'interaction=display; slots=∅; actions=panTo,zoom; streams=pois; props=center,zoom',
|
|
293
|
+
},
|
|
294
|
+
candidates: [
|
|
295
|
+
{
|
|
296
|
+
id: 'bp-list',
|
|
297
|
+
cachedIntent: 'Generic list view',
|
|
298
|
+
cachedContractSummary: 'interaction=display; slots=∅; actions=∅; streams=∅; props=items',
|
|
299
|
+
cosine: 0.36,
|
|
300
|
+
},
|
|
301
|
+
],
|
|
302
|
+
goldMatchId: null,
|
|
303
|
+
},
|
|
304
|
+
{
|
|
305
|
+
id: 'nm-novel-4',
|
|
306
|
+
kind: 'no-match',
|
|
307
|
+
query: {
|
|
308
|
+
intent: 'File uploader with drag-and-drop and progress bars',
|
|
309
|
+
contractSummary: 'interaction=collect; slots=files; actions=cancel,upload; streams=progress',
|
|
310
|
+
},
|
|
311
|
+
candidates: [
|
|
312
|
+
{
|
|
313
|
+
id: 'bp-form',
|
|
314
|
+
cachedIntent: 'Login form',
|
|
315
|
+
cachedContractSummary: 'interaction=collect; slots=∅; actions=submit; streams=∅; props=email,password',
|
|
316
|
+
cosine: 0.25,
|
|
317
|
+
},
|
|
318
|
+
{
|
|
319
|
+
id: 'bp-feedback',
|
|
320
|
+
cachedIntent: 'Feedback form',
|
|
321
|
+
cachedContractSummary: 'interaction=collect; slots=∅; actions=submit; streams=∅; props=comment,rating',
|
|
322
|
+
cosine: 0.3,
|
|
323
|
+
},
|
|
324
|
+
],
|
|
325
|
+
goldMatchId: null,
|
|
326
|
+
},
|
|
327
|
+
{
|
|
328
|
+
id: 'nm-novel-5',
|
|
329
|
+
kind: 'no-match',
|
|
330
|
+
query: {
|
|
331
|
+
intent: 'Audio player with play/pause, seek, volume',
|
|
332
|
+
contractSummary: 'interaction=collect; slots=position; actions=pause,play,seek,setVolume; streams=∅',
|
|
333
|
+
},
|
|
334
|
+
candidates: [
|
|
335
|
+
{
|
|
336
|
+
id: 'bp-todo',
|
|
337
|
+
cachedIntent: 'Todo list',
|
|
338
|
+
cachedContractSummary: 'interaction=collect; slots=items; actions=add,remove; streams=∅',
|
|
339
|
+
cosine: 0.22,
|
|
340
|
+
},
|
|
341
|
+
],
|
|
342
|
+
goldMatchId: null,
|
|
343
|
+
},
|
|
344
|
+
// ─── adversarial: structurally identical, intent-divergent ───
|
|
345
|
+
{
|
|
346
|
+
id: 'ad-haiku-vs-tweet',
|
|
347
|
+
kind: 'adversarial',
|
|
348
|
+
query: {
|
|
349
|
+
intent: 'Haiku composer with serif font and seasonal-mood placeholder',
|
|
350
|
+
contractSummary: 'interaction=collect; slots=text; actions=∅; streams=∅',
|
|
351
|
+
},
|
|
352
|
+
candidates: [
|
|
353
|
+
{
|
|
354
|
+
id: 'bp-tweet-draft',
|
|
355
|
+
cachedIntent: 'Tweet draft composer with character count and 280-char limit',
|
|
356
|
+
cachedContractSummary: 'interaction=collect; slots=text; actions=∅; streams=∅',
|
|
357
|
+
cosine: 0.82,
|
|
358
|
+
},
|
|
359
|
+
],
|
|
360
|
+
goldMatchId: null,
|
|
361
|
+
note: 'identical contract surface but the user intent is a HAIKU (visual style + framing matters)',
|
|
362
|
+
},
|
|
363
|
+
{
|
|
364
|
+
id: 'ad-calendar-jan-vs-mar',
|
|
365
|
+
kind: 'adversarial',
|
|
366
|
+
query: {
|
|
367
|
+
intent: 'Calendar showing March 2026 with selectable dates',
|
|
368
|
+
contractSummary: 'interaction=collect; slots=selectedDate; actions=∅; streams=∅; props=month,year',
|
|
369
|
+
},
|
|
370
|
+
candidates: [
|
|
371
|
+
{
|
|
372
|
+
id: 'bp-calendar-jan',
|
|
373
|
+
cachedIntent: 'Calendar showing January 2026 with selectable dates',
|
|
374
|
+
cachedContractSummary: 'interaction=collect; slots=selectedDate; actions=∅; streams=∅; props=month,year',
|
|
375
|
+
cosine: 0.96,
|
|
376
|
+
},
|
|
377
|
+
],
|
|
378
|
+
goldMatchId: null,
|
|
379
|
+
note: 'load-bearing parameter (month) differs — generated UI would show wrong month',
|
|
380
|
+
},
|
|
381
|
+
{
|
|
382
|
+
id: 'ad-login-vs-signup',
|
|
383
|
+
kind: 'adversarial',
|
|
384
|
+
query: {
|
|
385
|
+
intent: 'Sign-up form for new account — email, password, confirm password, terms checkbox',
|
|
386
|
+
contractSummary: 'interaction=collect; slots=∅; actions=submit; streams=∅; props=confirmPassword,email,password,termsAccepted',
|
|
387
|
+
},
|
|
388
|
+
candidates: [
|
|
389
|
+
{
|
|
390
|
+
id: 'bp-login',
|
|
391
|
+
cachedIntent: 'Login form — email + password fields, submit button',
|
|
392
|
+
cachedContractSummary: 'interaction=collect; slots=∅; actions=submit; streams=∅; props=email,password',
|
|
393
|
+
cosine: 0.85,
|
|
394
|
+
},
|
|
395
|
+
],
|
|
396
|
+
goldMatchId: null,
|
|
397
|
+
note: 'similar contract but signup needs confirmPassword + terms — login UI would miss them',
|
|
398
|
+
},
|
|
399
|
+
{
|
|
400
|
+
id: 'ad-chat-vs-comments',
|
|
401
|
+
kind: 'adversarial',
|
|
402
|
+
query: {
|
|
403
|
+
intent: 'Comments thread under a blog post — flat list, post a reply, no real-time',
|
|
404
|
+
contractSummary: 'interaction=converse; slots=draft; actions=post; streams=∅',
|
|
405
|
+
},
|
|
406
|
+
candidates: [
|
|
407
|
+
{
|
|
408
|
+
id: 'bp-chat',
|
|
409
|
+
cachedIntent: 'Real-time chat panel with WebSocket-driven message stream',
|
|
410
|
+
cachedContractSummary: 'interaction=converse; slots=draft; actions=send; streams=messages',
|
|
411
|
+
cosine: 0.79,
|
|
412
|
+
},
|
|
413
|
+
],
|
|
414
|
+
goldMatchId: null,
|
|
415
|
+
note: 'chat has streamSpec.messages — comments do not. Different liveness model.',
|
|
416
|
+
},
|
|
417
|
+
{
|
|
418
|
+
id: 'ad-light-vs-dark',
|
|
419
|
+
kind: 'adversarial',
|
|
420
|
+
query: {
|
|
421
|
+
intent: 'Dashboard with metrics — render in dark mode for night ops use',
|
|
422
|
+
contractSummary: 'interaction=display; slots=∅; actions=∅; streams=∅; props=metrics',
|
|
423
|
+
},
|
|
424
|
+
candidates: [
|
|
425
|
+
{
|
|
426
|
+
id: 'bp-dashboard-light',
|
|
427
|
+
cachedIntent: 'Marketing dashboard for executive review — bright, ornate, colorful KPI cards',
|
|
428
|
+
cachedContractSummary: 'interaction=display; slots=∅; actions=∅; streams=∅; props=metrics',
|
|
429
|
+
cosine: 0.78,
|
|
430
|
+
},
|
|
431
|
+
],
|
|
432
|
+
goldMatchId: 'bp-dashboard-light',
|
|
433
|
+
note: 'visual style alone (dark vs light) is NOT load-bearing per spec — should match',
|
|
434
|
+
// NOTE: this is actually a should-match disguised as adversarial — verifies
|
|
435
|
+
// the judge doesn't over-reject on cosmetic style. If precision drops here,
|
|
436
|
+
// the prompt is over-strict.
|
|
437
|
+
},
|
|
438
|
+
{
|
|
439
|
+
id: 'ad-form-fields-different',
|
|
440
|
+
kind: 'adversarial',
|
|
441
|
+
query: {
|
|
442
|
+
intent: 'Contact form — name, email, message, subject',
|
|
443
|
+
contractSummary: 'interaction=collect; slots=∅; actions=submit; streams=∅; props=email,message,name,subject',
|
|
444
|
+
},
|
|
445
|
+
candidates: [
|
|
446
|
+
{
|
|
447
|
+
id: 'bp-feedback',
|
|
448
|
+
cachedIntent: 'Feedback form with rating + comment',
|
|
449
|
+
cachedContractSummary: 'interaction=collect; slots=∅; actions=submit; streams=∅; props=comment,rating',
|
|
450
|
+
cosine: 0.7,
|
|
451
|
+
},
|
|
452
|
+
],
|
|
453
|
+
goldMatchId: null,
|
|
454
|
+
note: 'different fields (name/email/message/subject vs rating/comment) — different UI',
|
|
455
|
+
},
|
|
456
|
+
{
|
|
457
|
+
id: 'ad-step-count',
|
|
458
|
+
kind: 'adversarial',
|
|
459
|
+
query: {
|
|
460
|
+
intent: '5-step onboarding wizard — welcome, profile, preferences, integrations, finish',
|
|
461
|
+
contractSummary: 'interaction=flow; slots=currentStep; actions=back,next,skip; streams=∅; props=stepCount',
|
|
462
|
+
},
|
|
463
|
+
candidates: [
|
|
464
|
+
{
|
|
465
|
+
id: 'bp-3step-wizard',
|
|
466
|
+
cachedIntent: '3-step setup wizard — name, plan, payment',
|
|
467
|
+
cachedContractSummary: 'interaction=flow; slots=currentStep; actions=back,next,skip; streams=∅; props=stepCount',
|
|
468
|
+
cosine: 0.86,
|
|
469
|
+
},
|
|
470
|
+
],
|
|
471
|
+
goldMatchId: null,
|
|
472
|
+
note: 'step count + step contents differ — wizard reuse forces wrong step labels',
|
|
473
|
+
},
|
|
474
|
+
{
|
|
475
|
+
id: 'ad-list-vs-grid',
|
|
476
|
+
kind: 'adversarial',
|
|
477
|
+
query: {
|
|
478
|
+
intent: 'Photo grid view — 3 columns, lightbox on click',
|
|
479
|
+
contractSummary: 'interaction=display; slots=∅; actions=open; streams=∅; props=items',
|
|
480
|
+
},
|
|
481
|
+
candidates: [
|
|
482
|
+
{
|
|
483
|
+
id: 'bp-list',
|
|
484
|
+
cachedIntent: 'Linear text list with one item per row',
|
|
485
|
+
cachedContractSummary: 'interaction=display; slots=∅; actions=open; streams=∅; props=items',
|
|
486
|
+
cosine: 0.72,
|
|
487
|
+
},
|
|
488
|
+
],
|
|
489
|
+
goldMatchId: null,
|
|
490
|
+
note: 'grid vs list is a layout/visual difference — but a photo grid + lightbox is a different UI',
|
|
491
|
+
},
|
|
492
|
+
{
|
|
493
|
+
id: 'ad-prop-types',
|
|
494
|
+
kind: 'adversarial',
|
|
495
|
+
query: {
|
|
496
|
+
intent: 'Inventory table — columns: SKU, name, quantity, price, last-restocked',
|
|
497
|
+
contractSummary: 'interaction=display; slots=∅; actions=sort; streams=∅; props=columns,rows',
|
|
498
|
+
},
|
|
499
|
+
candidates: [
|
|
500
|
+
{
|
|
501
|
+
id: 'bp-user-table',
|
|
502
|
+
cachedIntent: 'User directory table — columns: name, email, role, last-login',
|
|
503
|
+
cachedContractSummary: 'interaction=display; slots=∅; actions=sort; streams=∅; props=columns,rows',
|
|
504
|
+
cosine: 0.84,
|
|
505
|
+
},
|
|
506
|
+
],
|
|
507
|
+
goldMatchId: null,
|
|
508
|
+
note: 'same shape (sortable table) but the columns are different domain data — reuse misleads',
|
|
509
|
+
},
|
|
510
|
+
{
|
|
511
|
+
id: 'ad-default-vs-explicit',
|
|
512
|
+
kind: 'adversarial',
|
|
513
|
+
query: {
|
|
514
|
+
intent: 'Calculator with scientific functions — sin, cos, tan, log, exp, sqrt, pi',
|
|
515
|
+
contractSummary: 'interaction=collect; slots=display; actions=clear,evaluate,press; streams=∅',
|
|
516
|
+
},
|
|
517
|
+
candidates: [
|
|
518
|
+
{
|
|
519
|
+
id: 'bp-basic-calc',
|
|
520
|
+
cachedIntent: 'Basic calculator — digits, +, -, ×, ÷, =, clear',
|
|
521
|
+
cachedContractSummary: 'interaction=collect; slots=display; actions=clear,evaluate,press; streams=∅',
|
|
522
|
+
cosine: 0.9,
|
|
523
|
+
},
|
|
524
|
+
],
|
|
525
|
+
goldMatchId: null,
|
|
526
|
+
note: 'same contract but scientific calc has way more buttons — basic-calc UI insufficient',
|
|
527
|
+
},
|
|
528
|
+
];
|
|
529
|
+
export function pairsByKind(kind) {
|
|
530
|
+
return EVAL_PAIRS.filter((p) => p.kind === kind);
|
|
531
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-probe-cli.d.ts","sourceRoot":"","sources":["../../src/rerank-eval/run-probe-cli.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Rerank quality probe CLI.
|
|
4
|
+
*
|
|
5
|
+
* Reads `~/.ggui/credentials.json` for the Anthropic API key, runs
|
|
6
|
+
* the probe against `claude-haiku-4-5`, prints the report.
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* pnpm -F @ggui-ai/negotiator probe-rerank
|
|
10
|
+
* ANTHROPIC_API_KEY=sk-... pnpm -F @ggui-ai/negotiator probe-rerank
|
|
11
|
+
* pnpm -F @ggui-ai/negotiator probe-rerank -- --limit 5
|
|
12
|
+
*
|
|
13
|
+
* Cost: ~$0.025 for the full 25-pair run with Haiku 4.5.
|
|
14
|
+
*
|
|
15
|
+
* Eval-only — not exported from the package index.
|
|
16
|
+
*/
|
|
17
|
+
import { readFileSync } from 'node:fs';
|
|
18
|
+
import { homedir } from 'node:os';
|
|
19
|
+
import { resolve as pathResolve } from 'node:path';
|
|
20
|
+
import { runProbe, formatReport } from './run-probe.js';
|
|
21
|
+
const ANTHROPIC_API = 'https://api.anthropic.com/v1/messages';
|
|
22
|
+
const DEFAULT_MODEL = 'claude-haiku-4-5';
|
|
23
|
+
function resolveAnthropicKey() {
|
|
24
|
+
const envKey = process.env['ANTHROPIC_API_KEY'];
|
|
25
|
+
if (envKey && envKey.length > 0)
|
|
26
|
+
return envKey;
|
|
27
|
+
const credsPath = pathResolve(homedir(), '.ggui', 'credentials.json');
|
|
28
|
+
let parsed;
|
|
29
|
+
try {
|
|
30
|
+
parsed = JSON.parse(readFileSync(credsPath, 'utf8'));
|
|
31
|
+
}
|
|
32
|
+
catch (err) {
|
|
33
|
+
throw new Error(`probe-rerank: could not read ${credsPath} (${err instanceof Error ? err.message : String(err)}). Set ANTHROPIC_API_KEY env var or run \`ggui auth set anthropic\`.`);
|
|
34
|
+
}
|
|
35
|
+
const key = parsed.apps?.global?.anthropic;
|
|
36
|
+
if (typeof key !== 'string' || key.length === 0) {
|
|
37
|
+
throw new Error(`probe-rerank: no anthropic key found at apps.global.anthropic in ${credsPath}.`);
|
|
38
|
+
}
|
|
39
|
+
return key;
|
|
40
|
+
}
|
|
41
|
+
let totalInputTokens = 0;
|
|
42
|
+
let totalOutputTokens = 0;
|
|
43
|
+
function buildAnthropicLlmCaller(apiKey, model) {
|
|
44
|
+
return {
|
|
45
|
+
async call() {
|
|
46
|
+
throw new Error('probe-cli: text-mode not exercised — use callStructured');
|
|
47
|
+
},
|
|
48
|
+
async callStructured(systemPrompt, userMessage, tool, maxTokens) {
|
|
49
|
+
const body = {
|
|
50
|
+
model,
|
|
51
|
+
max_tokens: maxTokens ?? 1024,
|
|
52
|
+
system: systemPrompt,
|
|
53
|
+
messages: [{ role: 'user', content: userMessage }],
|
|
54
|
+
tools: [
|
|
55
|
+
{
|
|
56
|
+
name: tool.name,
|
|
57
|
+
description: tool.description,
|
|
58
|
+
input_schema: tool.input_schema,
|
|
59
|
+
},
|
|
60
|
+
],
|
|
61
|
+
tool_choice: { type: 'tool', name: tool.name },
|
|
62
|
+
};
|
|
63
|
+
const res = await fetch(ANTHROPIC_API, {
|
|
64
|
+
method: 'POST',
|
|
65
|
+
headers: {
|
|
66
|
+
'content-type': 'application/json',
|
|
67
|
+
'x-api-key': apiKey,
|
|
68
|
+
'anthropic-version': '2023-06-01',
|
|
69
|
+
},
|
|
70
|
+
body: JSON.stringify(body),
|
|
71
|
+
});
|
|
72
|
+
const json = (await res.json());
|
|
73
|
+
if (!res.ok) {
|
|
74
|
+
const errType = json.error?.type ?? 'unknown';
|
|
75
|
+
const errMsg = json.error?.message ?? `HTTP ${res.status}`;
|
|
76
|
+
throw new Error(`anthropic ${errType}: ${errMsg}`);
|
|
77
|
+
}
|
|
78
|
+
if (json.usage) {
|
|
79
|
+
totalInputTokens += json.usage.input_tokens ?? 0;
|
|
80
|
+
totalOutputTokens += json.usage.output_tokens ?? 0;
|
|
81
|
+
}
|
|
82
|
+
const toolBlock = json.content?.find((b) => b.type === 'tool_use');
|
|
83
|
+
if (!toolBlock || toolBlock.input === undefined) {
|
|
84
|
+
throw new Error(`anthropic: no tool_use block in response (stop_reason=${json.stop_reason ?? 'unknown'})`);
|
|
85
|
+
}
|
|
86
|
+
return toolBlock.input;
|
|
87
|
+
},
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
function parseArgs(argv) {
|
|
91
|
+
let limit;
|
|
92
|
+
let threshold;
|
|
93
|
+
let model = DEFAULT_MODEL;
|
|
94
|
+
for (let i = 0; i < argv.length; i++) {
|
|
95
|
+
const a = argv[i];
|
|
96
|
+
if (a === '--limit' && argv[i + 1]) {
|
|
97
|
+
limit = Number(argv[++i]);
|
|
98
|
+
}
|
|
99
|
+
else if (a === '--threshold' && argv[i + 1]) {
|
|
100
|
+
threshold = Number(argv[++i]);
|
|
101
|
+
}
|
|
102
|
+
else if (a === '--model' && argv[i + 1]) {
|
|
103
|
+
model = argv[++i];
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
const result = { model };
|
|
107
|
+
if (limit !== undefined)
|
|
108
|
+
result.limit = limit;
|
|
109
|
+
if (threshold !== undefined)
|
|
110
|
+
result.threshold = threshold;
|
|
111
|
+
return result;
|
|
112
|
+
}
|
|
113
|
+
// Approximate Haiku 4.5 pricing as of 2026-05.
|
|
114
|
+
// Input: $1.00 / Mtok, output: $5.00 / Mtok.
|
|
115
|
+
const HAIKU_4_5_PRICE_INPUT_PER_TOKEN = 1.0 / 1_000_000;
|
|
116
|
+
const HAIKU_4_5_PRICE_OUTPUT_PER_TOKEN = 5.0 / 1_000_000;
|
|
117
|
+
async function main() {
|
|
118
|
+
const args = parseArgs(process.argv.slice(2));
|
|
119
|
+
const apiKey = resolveAnthropicKey();
|
|
120
|
+
const llm = buildAnthropicLlmCaller(apiKey, args.model);
|
|
121
|
+
process.stdout.write(`probe: model=${args.model}\n\n`);
|
|
122
|
+
const report = await runProbe({ llm }, {
|
|
123
|
+
...(args.limit !== undefined ? { limit: args.limit } : {}),
|
|
124
|
+
...(args.threshold !== undefined ? { threshold: args.threshold } : {}),
|
|
125
|
+
onProgress: (outcome, idx, total) => {
|
|
126
|
+
const status = outcome.correct ? 'OK ' : 'NO ';
|
|
127
|
+
const conf = outcome.decision.confidence.toFixed(2);
|
|
128
|
+
const id = outcome.pair.id.padEnd(24);
|
|
129
|
+
process.stdout.write(`[${status}] ${(idx + 1).toString().padStart(2)}/${total} ${id} conf=${conf} pred=${outcome.predictedMatchId ?? 'null'} gold=${outcome.pair.goldMatchId ?? 'null'}\n`);
|
|
130
|
+
},
|
|
131
|
+
});
|
|
132
|
+
process.stdout.write('\n');
|
|
133
|
+
process.stdout.write(formatReport(report));
|
|
134
|
+
process.stdout.write('\n\n');
|
|
135
|
+
const totalCost = totalInputTokens * HAIKU_4_5_PRICE_INPUT_PER_TOKEN +
|
|
136
|
+
totalOutputTokens * HAIKU_4_5_PRICE_OUTPUT_PER_TOKEN;
|
|
137
|
+
const callsMade = report.outcomes.filter((o) => !/short-circuited/.test(o.decision.reason)).length;
|
|
138
|
+
const costPerCall = callsMade === 0 ? 0 : totalCost / callsMade;
|
|
139
|
+
process.stdout.write(`Tokens: input=${totalInputTokens} · output=${totalOutputTokens}\n`);
|
|
140
|
+
process.stdout.write(`Cost: total=$${totalCost.toFixed(4)} · per-call=$${costPerCall.toFixed(4)}\n`);
|
|
141
|
+
process.stdout.write(` G4 cost ≤ $0.002/call → ${costPerCall <= 0.002 ? 'PASS' : 'FAIL'} ($${costPerCall.toFixed(4)})\n`);
|
|
142
|
+
}
|
|
143
|
+
main().catch((err) => {
|
|
144
|
+
process.stderr.write(`probe-rerank failed: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
145
|
+
process.exit(1);
|
|
146
|
+
});
|