@ggui-ai/ui-gen 0.25.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 +2 -2
- package/dist/{adapter-Cg_rkpGq.d.ts → adapter-BJwn74rx.d.ts} +49 -1
- package/dist/adapters/generation-dispatch.d.ts +8 -5
- package/dist/adapters/generation-dispatch.js +1118 -193
- package/dist/adapters/generation-dispatch.js.map +1 -1
- package/dist/adapters/index.js +27 -6
- package/dist/adapters/index.js.map +1 -1
- package/dist/advanced/index.d.ts +10 -9
- package/dist/advanced/index.js +1126 -202
- package/dist/advanced/index.js.map +1 -1
- package/dist/blueprint-validator.js +416 -92
- package/dist/blueprint-validator.js.map +1 -1
- package/dist/boilerplate.d.ts +2 -2
- package/dist/boilerplate.js +10 -3
- package/dist/boilerplate.js.map +1 -1
- package/dist/check/index.d.ts +3 -2
- package/dist/check/index.js +9 -2
- package/dist/check/index.js.map +1 -1
- package/dist/{create-ui-generator-DFnnArrv.d.ts → create-ui-generator-N4gRXpcL.d.ts} +3 -4
- package/dist/{design-mode-DLufhrNp.d.ts → design-mode-DGWN_Gkm.d.ts} +1 -1
- package/dist/{dispatch-CStl9eAw.d.ts → dispatch-BUoXRj_r.d.ts} +2 -2
- package/dist/evaluation/axis-checks/index.d.ts +5 -4
- package/dist/evaluation/axis-checks/index.js.map +1 -1
- package/dist/evaluation/axis-checks/registry.d.ts +4 -3
- package/dist/evaluation/index.d.ts +107 -539
- package/dist/evaluation/index.js +552 -55
- package/dist/evaluation/index.js.map +1 -1
- package/dist/evaluation/types.d.ts +17 -0
- package/dist/evaluation/types.js.map +1 -1
- package/dist/{generate-9IeNT4ZY.d.ts → generate-tSO_shQ0.d.ts} +1 -1
- package/dist/harness/check/runtime-render/index.d.ts +5 -5
- package/dist/harness/check/runtime-render/index.js +416 -92
- package/dist/harness/check/runtime-render/index.js.map +1 -1
- package/dist/harness/check/runtime-render/render-check-worker.js +393 -88
- package/dist/harness/check/runtime-render/render-check-worker.js.map +1 -1
- package/dist/harness/index.d.ts +4 -5
- package/dist/harness/index.js +36 -5
- package/dist/harness/index.js.map +1 -1
- package/dist/harness/prompts.d.ts +2 -2
- package/dist/harness/prompts.js +10 -1
- package/dist/harness/prompts.js.map +1 -1
- package/dist/harness/result-types.d.ts +17 -3
- package/dist/harness/result-types.js.map +1 -1
- package/dist/harness/runtime.d.ts +14 -6
- package/dist/harness/runtime.js +11 -4
- package/dist/harness/runtime.js.map +1 -1
- package/dist/harness/types-public.d.ts +4 -2
- package/dist/harness/types-public.js +10 -3
- package/dist/harness/types-public.js.map +1 -1
- package/dist/harness/validator-trace-sink.d.ts +4 -3
- package/dist/index.d.ts +46 -11
- package/dist/index.js +1128 -200
- package/dist/index.js.map +1 -1
- package/dist/patch.d.ts +3 -3
- package/dist/{prompts-YU9piOgs.d.ts → prompts-BhNUuRoZ.d.ts} +1 -1
- package/dist/tools/render-check-worker.js +8 -1
- package/dist/tools/render-check-worker.js.map +1 -1
- package/dist/{types-public-BJTLpzWn.d.ts → types-public-B7wn4ce5.d.ts} +384 -3
- package/dist/validation/index.d.ts +1 -1
- package/dist/validation/index.js +1 -1
- package/dist/validation/index.js.map +1 -1
- package/dist/visual-evaluator-C9L-o6ap.d.ts +639 -0
- package/dist/workflows.d.ts +3 -3
- package/package.json +12 -12
- package/src/adapters/generation-dispatch.ts +2 -0
- package/src/boilerplate/free-design-prompt.ts +3 -3
- package/src/boilerplate/hard-sections.ts +1 -1
- package/src/boilerplate/templates/layouts/chat-mobile.tsx.tmpl +3 -1
- package/src/boilerplate/templates/layouts/chat-universal.tsx.tmpl +3 -1
- package/src/boilerplate/templates/layouts/fullscreen-desktop.tsx.tmpl +3 -1
- package/src/boilerplate/templates/layouts/fullscreen-universal.tsx.tmpl +3 -1
- package/src/check/run-tier0.ts +6 -3
- package/src/contract-context.ts +1 -1
- package/src/evaluation/cost-tracker.ts +54 -6
- package/src/evaluation/criteria/edge-probe.ts +286 -0
- package/src/evaluation/criteria/edge.ts +202 -0
- package/src/evaluation/criteria/resolve.ts +55 -7
- package/src/evaluation/index.ts +5 -1
- package/src/evaluation/judge-spend.ts +48 -0
- package/src/evaluation/types-public.ts +91 -0
- package/src/evaluation/types.ts +10 -0
- package/src/evaluation/visual-evaluator.ts +236 -40
- package/src/harness/check/runtime-render/adapter.ts +18 -0
- package/src/harness/check/runtime-render/probe-pending.ts +111 -0
- package/src/harness/check/runtime-render/render-check-host.ts +10 -6
- package/src/harness/check/runtime-render/render-check-worker.ts +6 -3
- package/src/harness/check/runtime-render/render-check.ts +417 -133
- package/src/harness/check/runtime-render/walk.ts +200 -0
- package/src/harness/coding/assemble-result.ts +2 -0
- package/src/harness/coding/generate-task-runner.ts +27 -0
- package/src/harness/coding/init-session.ts +5 -3
- package/src/harness/coding/run-coding-turn.ts +5 -1
- package/src/harness/coding/run-eval-round.ts +63 -3
- package/src/harness/in-loop-evaluation.ts +39 -0
- package/src/harness/llm-router.ts +58 -1
- package/src/harness/result-types.ts +9 -0
- package/src/harness/runtime.ts +9 -0
- package/src/harness/types-public.ts +10 -1
- package/src/index.ts +5 -0
- package/src/internal/verdict-line.ts +33 -0
- package/src/taught-tokens.ts +32 -0
- package/src/tools/render-check-worker.ts +2 -1
- package/src/tools/render-check.ts +8 -7
- package/src/validation/primitives.ts +1 -1
- package/dist/llm-router-nfO7wPec.d.ts +0 -267
- package/dist/{bank-CT4eEkta.d.ts → bank-Ctdp3FUA.d.ts} +3 -3
|
@@ -0,0 +1,639 @@
|
|
|
1
|
+
import { h as CriteriaContext, i as CriteriaChroma, j as CanvasJudgeRecord, k as CriteriaBlock, l as CanvasPresentationOutcome, n as CanvasHostPresentation, b as AgentConfig, L as LLMResponse, J as JudgeSalvageCounts, E as EvalIssue, o as VisualEvalSummary, p as VisualCoverage } from './types-public-B7wn4ce5.js';
|
|
2
|
+
import { G as GenerationProfileInput } from './styling-profile-CxfvV48g.js';
|
|
3
|
+
import { C as CriteriaBank } from './bank-Ctdp3FUA.js';
|
|
4
|
+
import { DataContract, JsonObject } from '@ggui-ai/protocol';
|
|
5
|
+
import { C as Classification } from './axes-CKVCzR_x.js';
|
|
6
|
+
import { EvaluationIssue, EvaluationResult } from './evaluation/types.js';
|
|
7
|
+
import { LaunchOptions } from 'puppeteer-core';
|
|
8
|
+
import { C as CanvasClass, a as CanvasViewport } from './design-mode-DGWN_Gkm.js';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* The selector's inputs for one card — ggui#1436. Every key here is hashed into `criteriaSetId`
|
|
12
|
+
* and STORED in the block (the CTO's A1), so a stored verdict reproduces its own set from the
|
|
13
|
+
* record alone. `canvas` is added per canvas inside the judge; the rest is the harness's.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
/** Read the theme's chroma off its tokens; `unknown` when no primary is named. */
|
|
17
|
+
declare function chromaOfCssTokens(cssTokens: string | undefined): CriteriaChroma;
|
|
18
|
+
interface CriteriaContextSources {
|
|
19
|
+
readonly classification: Classification;
|
|
20
|
+
readonly contract: DataContract | undefined;
|
|
21
|
+
readonly cssTokens: string | undefined;
|
|
22
|
+
readonly profile: GenerationProfileInput | undefined;
|
|
23
|
+
readonly shell: string;
|
|
24
|
+
readonly kind?: string;
|
|
25
|
+
}
|
|
26
|
+
/** The context minus `canvas` — the judge fills that per canvas. */
|
|
27
|
+
type CriteriaContextInput = Omit<CriteriaContext, 'canvas'>;
|
|
28
|
+
declare function criteriaContextFor(src: CriteriaContextSources): CriteriaContextInput;
|
|
29
|
+
|
|
30
|
+
interface JudgeDesignIdentity {
|
|
31
|
+
/** Absolute path of the design `src` tree the judge bundled against. */
|
|
32
|
+
readonly src: string;
|
|
33
|
+
/** sha256 over every rendering input under `src` (see {@link isDesignRenderingInput}) — sorted relative path, then contents. */
|
|
34
|
+
readonly srcSha256: string;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* sha256 over every rendering input under `root` (sorted relative path +
|
|
38
|
+
* contents) — the identity of a design tree as it paints.
|
|
39
|
+
*
|
|
40
|
+
* A function of the TREE, not of the spelling of `root`: the relative keys
|
|
41
|
+
* are taken against the RESOLVED root, so `…/design/src`, `…/design/src/` and
|
|
42
|
+
* `…/ui-gen/../design/src` hash the same bytes. Before this the key was
|
|
43
|
+
* sliced by the unresolved root's length while each entry had already been
|
|
44
|
+
* resolved, so an un-normalised root produced a different hash for the same
|
|
45
|
+
* tree — a phantom design skew for any caller composing the path.
|
|
46
|
+
*/
|
|
47
|
+
declare function designTreeSha256(root: string): string;
|
|
48
|
+
/**
|
|
49
|
+
* The identity of the tree at `src`, computed once per process per path (a
|
|
50
|
+
* judge run paints hundreds of frames from one tree).
|
|
51
|
+
*
|
|
52
|
+
* `null` when the tree cannot be READ (ggui#1110): a deployed image ships the
|
|
53
|
+
* design package as built output with no `src/`, and an identity is a receipt
|
|
54
|
+
* about a judgement — never a precondition for making one. Before this,
|
|
55
|
+
* `scandir` threw ENOENT inside the evaluation round wherever the package ships
|
|
56
|
+
* built output only, the round returned no evaluation at all, and a bar refused
|
|
57
|
+
* a card that had cleared it. A row without the receipt says so; a round that cannot
|
|
58
|
+
* stamp one still runs.
|
|
59
|
+
*/
|
|
60
|
+
declare function judgeDesignIdentity(src: string): JudgeDesignIdentity | null;
|
|
61
|
+
/** Test seam: forget cached identities (a test that rewrites a tree between runs). */
|
|
62
|
+
declare function resetJudgeDesignIdentityCache(): void;
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* `space.edge` as an instrument (#1663): the alignment rule applied to measured blocks, never to a model's estimate.
|
|
66
|
+
*
|
|
67
|
+
* The rule (docs/design/direction/visual-criteria.md, "The edge rule, measurable"): in each column of a card, the things
|
|
68
|
+
* that stack start on one edge. A block may start in only two other places — inside a box, on the box's inner edge,
|
|
69
|
+
* which everything inside the box then shares; or next to a box or a band, on the box's own outer edge or on the edge
|
|
70
|
+
* of the text inside it. Same edge means within 2 px. A card fails if any captured width fails; this function judges one
|
|
71
|
+
* width.
|
|
72
|
+
*
|
|
73
|
+
* Levels that are allowed: a hanging marker (a block with two edges, the marker's and its text's); a list inside
|
|
74
|
+
* running text (list items share an edge of their own); a table (measured at its rule, its cells not re-checked);
|
|
75
|
+
* columns side by side (each with its own edge); a centred group (one centre axis). A frame that shows only loading
|
|
76
|
+
* placeholders is not evaluated.
|
|
77
|
+
*
|
|
78
|
+
* Input is the measured block list (a DOM probe at capture produces it); output is the verdict plus every offset in
|
|
79
|
+
* px, so a near miss reads apart from a split. This module measures nothing itself. *
|
|
80
|
+
* **Validated instrument (#1663, 2026-10-02):** this file as of `cec465319` (with `7bb4da13e`) passed a fresh sealed
|
|
81
|
+
* blind draw at the registered bar (27/30, κ 0.76), stricter than the design lead's reading on its disagreements. Any
|
|
82
|
+
* later change to what this file measures or decides is a new instrument until another fresh sealed draw.
|
|
83
|
+
*/
|
|
84
|
+
/** The rule's tolerance: two edges within this many px are the same edge. */
|
|
85
|
+
declare const EDGE_TOLERANCE_PX = 2;
|
|
86
|
+
/** One block of a captured card, at one canvas width. All x in CSS px from the card's left. */
|
|
87
|
+
interface EdgeBlock {
|
|
88
|
+
/** A stable label for evidence (a DOM path in production, a name in tests). */
|
|
89
|
+
readonly id: string;
|
|
90
|
+
/** A text block, a control group (measured at its first control), or a surface (a box: border or its own fill). */
|
|
91
|
+
readonly kind: 'text' | 'controls' | 'surface';
|
|
92
|
+
/**
|
|
93
|
+
* The block's edge: a text's first-character origin, a bounded control's or a surface's border box, an unbounded
|
|
94
|
+
* control's text. For a hanging marker, the marker's edge.
|
|
95
|
+
*/
|
|
96
|
+
readonly edge: number;
|
|
97
|
+
/** Horizontal extent, for telling side-by-side columns apart. */
|
|
98
|
+
readonly left: number;
|
|
99
|
+
readonly right: number;
|
|
100
|
+
/** Vertical position, for finding a surface's first text. */
|
|
101
|
+
readonly top: number;
|
|
102
|
+
/** The surface this block sits inside, by id; absent at the card's own level. */
|
|
103
|
+
readonly within?: string;
|
|
104
|
+
/** A hanging marker's text edge: what stacks with the block may line up with this or with `edge`. */
|
|
105
|
+
readonly textEdge?: number;
|
|
106
|
+
/** Structure the DOM names: a list item, a table (measured at its rule), a member of a centred group. */
|
|
107
|
+
readonly role?: 'list-item' | 'table' | 'centred' | 'placeholder';
|
|
108
|
+
}
|
|
109
|
+
interface EdgeOffset {
|
|
110
|
+
/** The container checked: the card, or a surface's id. */
|
|
111
|
+
readonly container: string;
|
|
112
|
+
/** The block that sits off every allowed edge. */
|
|
113
|
+
readonly block: string;
|
|
114
|
+
/** Its edge, and the nearest edge the rule allowed it, in px. */
|
|
115
|
+
readonly at: number;
|
|
116
|
+
readonly nearest: number;
|
|
117
|
+
readonly offPx: number;
|
|
118
|
+
/** Why the block is off when it is not plain distance (a centred block among edge-aligned ones). */
|
|
119
|
+
readonly reason?: string;
|
|
120
|
+
}
|
|
121
|
+
interface EdgeVerdict {
|
|
122
|
+
readonly verdict: 'pass' | 'fail' | 'n/a';
|
|
123
|
+
/** Every block that sits off the allowed edges, with its offset; empty on a pass. */
|
|
124
|
+
readonly offsets: readonly EdgeOffset[];
|
|
125
|
+
readonly evidence: string;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Judge one captured width. `placeholdersOnly`: the frame shows only loading placeholders, so the row is not evaluated.
|
|
129
|
+
*/
|
|
130
|
+
declare function judgeEdges(measured: readonly EdgeBlock[], opts?: {
|
|
131
|
+
readonly placeholdersOnly?: boolean;
|
|
132
|
+
}): EdgeVerdict;
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* An issue as the visual leg CREATES it (ggui#1545 follow-up): its `origin` is required here, so a new producer, an
|
|
136
|
+
* instrument check or a judge-side parse, that forgets to say whose finding it is fails to compile instead of
|
|
137
|
+
* quietly dropping out of `visualEvaluation.actOn`'s treatment. The public `EvaluationIssue` keeps `origin` optional
|
|
138
|
+
* for stored and external data.
|
|
139
|
+
*/
|
|
140
|
+
type VisualIssue = EvaluationIssue & {
|
|
141
|
+
origin: 'judge' | 'instrument';
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
interface VisualEvalConfig {
|
|
145
|
+
/** LLM provider for multimodal evaluation */
|
|
146
|
+
provider: 'claude' | 'google';
|
|
147
|
+
/** Model ID (must support vision/multimodal) */
|
|
148
|
+
model?: string;
|
|
149
|
+
/** Pass threshold for visual score (0-100) */
|
|
150
|
+
passThreshold: number;
|
|
151
|
+
/** Sample props to render the component with */
|
|
152
|
+
sampleProps?: Record<string, unknown>;
|
|
153
|
+
/** Viewport dimensions for screenshot */
|
|
154
|
+
viewport?: {
|
|
155
|
+
width: number;
|
|
156
|
+
height: number;
|
|
157
|
+
};
|
|
158
|
+
/**
|
|
159
|
+
* Per-canvas judging — ARM-NEUTRAL (the same judge, prompt and
|
|
160
|
+
* threshold in every design mode). When set, the SAME rendered HTML
|
|
161
|
+
* shell is screenshotted once per class at `CANVAS_VIEWPORTS[class]`
|
|
162
|
+
* and judged once per class; the result carries one entry per class
|
|
163
|
+
* in `canvases`, and the single-shot fields aggregate: `finalScore` =
|
|
164
|
+
* mean of the canvas scores (rounded), `passed` = every canvas passed,
|
|
165
|
+
* `dimensions` = per-dimension means, `issues` = every canvas's issues
|
|
166
|
+
* (description prefixed `[<canvas>]`). Unset (or empty) = today's
|
|
167
|
+
* single screenshot at `viewport`; no `canvases` field on the result.
|
|
168
|
+
*/
|
|
169
|
+
canvases?: readonly CanvasClass[];
|
|
170
|
+
/**
|
|
171
|
+
* ggui#1195 — the box a canvas is COMPOSED for and CAPTURED at when the
|
|
172
|
+
* order declared one (the chat card at the visitor's real column, not the
|
|
173
|
+
* class's 400×640). Keyed by canvas; a canvas without an entry is judged
|
|
174
|
+
* at `CANVAS_VIEWPORTS[canvas]` as before. The composer's
|
|
175
|
+
* `rendering.viewport` and this entry are ONE value written once (the
|
|
176
|
+
* seam derives it), so the judge never scores a box the mint did not
|
|
177
|
+
* target. Only read in per-canvas mode. Captured at WHOLE CSS px: the
|
|
178
|
+
* browser's device-metrics override takes integers (measured — a 383.5 px
|
|
179
|
+
* width is refused by CDP), so a fractional declared box is rounded once
|
|
180
|
+
* where it enters and the capture, the ceiling and the reported
|
|
181
|
+
* `viewport` all carry that same integer box.
|
|
182
|
+
*/
|
|
183
|
+
canvasViewports?: Partial<Readonly<Record<CanvasClass, CanvasViewport>>>;
|
|
184
|
+
/**
|
|
185
|
+
* ggui#1492 — how a host presents each canvas, as data the caller supplies (a lane that knows its host). Keyed by
|
|
186
|
+
* canvas; a canvas without an entry is judged exactly as before (the generic stand-in round the inline card, the
|
|
187
|
+
* scrim under a panel). The box stays in {@link canvasViewports}. An entry this judge cannot use (a colour that is
|
|
188
|
+
* not `#rrggbb`, a number out of range, a frame on a canvas that is not the inline card) is ignored for its canvas,
|
|
189
|
+
* said once in the log, never partly applied.
|
|
190
|
+
*/
|
|
191
|
+
hostPresentations?: Partial<Readonly<Record<CanvasClass, CanvasHostPresentation>>>;
|
|
192
|
+
/**
|
|
193
|
+
* Optional provider-routing override — see
|
|
194
|
+
* `AgentConfig.routeOverride`. Threaded onto the agent this
|
|
195
|
+
* evaluator constructs so its multimodal call never falls back to
|
|
196
|
+
* `process.env` for credentials or model routing.
|
|
197
|
+
*/
|
|
198
|
+
/**
|
|
199
|
+
* Vision calls per judged canvas on the SAME captured frame, aggregated by
|
|
200
|
+
* the median (ggui#1072). Default 1 — a single judgement, byte-identical to
|
|
201
|
+
* the instrument before this option existed. K is an instrument dial: a
|
|
202
|
+
* run mixes K at its own peril.
|
|
203
|
+
*/
|
|
204
|
+
judgeK?: number;
|
|
205
|
+
/** The canvases sampled `judgeK` times; default = every judged canvas when `judgeK > 1`. */
|
|
206
|
+
judgeKCanvases?: readonly CanvasClass[];
|
|
207
|
+
/**
|
|
208
|
+
* The design `src` tree the judge bundles the component against
|
|
209
|
+
* (ggui#1042): an explicit input, so a judge-only re-judge names the tree
|
|
210
|
+
* it painted with. Default: the design package beside this one.
|
|
211
|
+
*/
|
|
212
|
+
designSrcDir?: string;
|
|
213
|
+
/** The mode the caller composed `cssTokens` in — a receipt on the row, never a switch (ggui#1076: judge and runtime must name the same mode). */
|
|
214
|
+
themeMode?: 'light' | 'dark';
|
|
215
|
+
routeOverride?: AgentConfig['routeOverride'];
|
|
216
|
+
/**
|
|
217
|
+
* Provider-429-retry observer — see `AgentConfig.onRetry`.
|
|
218
|
+
* Without it, a rate-limited retry inside the evaluation call
|
|
219
|
+
* happens (the agent's retry loop is unconditional) but never
|
|
220
|
+
* reaches the caller's structured log.
|
|
221
|
+
*/
|
|
222
|
+
onRetry?: AgentConfig['onRetry'];
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* ggui#1436 — what the report-only criteria call spent. Kept APART from the scoring calls' `inputTokens` /
|
|
226
|
+
* `outputTokens`: those price the judgement a caller may meter, and the criteria call is a measurement beside it.
|
|
227
|
+
*/
|
|
228
|
+
interface CriteriaCallTokens {
|
|
229
|
+
readonly inputTokens: number;
|
|
230
|
+
readonly outputTokens: number;
|
|
231
|
+
}
|
|
232
|
+
/** One canvas's verdict — screenshot + judge score at that class's viewport. */
|
|
233
|
+
interface CanvasVisualResult {
|
|
234
|
+
canvas: CanvasClass;
|
|
235
|
+
viewport: CanvasViewport;
|
|
236
|
+
/** The judge's weighted score for this canvas (0-100). */
|
|
237
|
+
score: number;
|
|
238
|
+
/** `score >= passThreshold`. */
|
|
239
|
+
passed: boolean;
|
|
240
|
+
/** The PNG the judge saw — kept for artefact persistence + the human look. */
|
|
241
|
+
screenshotPng: Buffer;
|
|
242
|
+
/**
|
|
243
|
+
* The document's scroll height at this canvas's viewport, CSS px — what
|
|
244
|
+
* the box would have to be for nothing to be hidden (ggui#1027). `null`
|
|
245
|
+
* when the page could not be measured.
|
|
246
|
+
*/
|
|
247
|
+
contentHeight: number | null;
|
|
248
|
+
/** `contentHeight > viewport.height` — a measurement; what it MEANS is {@link canvasFitPolicy}'s. */
|
|
249
|
+
overflow: boolean;
|
|
250
|
+
/** How `score` was reached — always present (ggui#1072). */
|
|
251
|
+
/**
|
|
252
|
+
* ggui#1120 — how far down the capture anything was painted (the last inked row over the measured
|
|
253
|
+
* region's height, read against the capture's dominant colour, inside a drawn panel's chrome); `0`
|
|
254
|
+
* is the blank the judge fails, `null` an unreadable capture.
|
|
255
|
+
*/
|
|
256
|
+
inkRatio: number | null;
|
|
257
|
+
judge: CanvasJudgeRecord;
|
|
258
|
+
/** How the judge composed the mount (ggui#1100): `'fill'` on every fullscreen canvas, absent on the inline card. */
|
|
259
|
+
fit?: 'fill';
|
|
260
|
+
/** ggui#1195 — `true` when the order DECLARED this canvas's box (`config.canvasViewports` carried an entry), whatever its value. */
|
|
261
|
+
declared?: true;
|
|
262
|
+
/** ggui#1436 — the typed criteria block, when a bank was configured. */
|
|
263
|
+
criteria?: CriteriaBlock;
|
|
264
|
+
/** ggui#1436 — the criteria call's own spend, when one was asked and answered; never inside the canvas's scoring tokens. */
|
|
265
|
+
criteriaTokens?: CriteriaCallTokens;
|
|
266
|
+
/** ggui#1492 — what the judge did with this canvas's host presentation (drawn, or ignored and why), when one was supplied. */
|
|
267
|
+
presentation?: CanvasPresentationOutcome;
|
|
268
|
+
}
|
|
269
|
+
/** How a canvas is captured for the judge and what an overflow means there (ggui#1027). */
|
|
270
|
+
type CaptureMode = 'viewport' | 'full-page' | 'natural';
|
|
271
|
+
interface CanvasFitPolicy {
|
|
272
|
+
/**
|
|
273
|
+
* `viewport` = the whole box; `full-page` = the whole scrolled document; `natural` (ggui#1475) = the
|
|
274
|
+
* card at its OWN height, clipped to its extent and capped at the box — the inline card a host sizes
|
|
275
|
+
* to its content, on the host's ground ({@link JUDGE_GROUND_MARGIN_PX}).
|
|
276
|
+
*/
|
|
277
|
+
readonly capture: CaptureMode;
|
|
278
|
+
/** The verdict an overflow earns on this canvas. */
|
|
279
|
+
readonly overflow: 'fail' | 'warn' | 'none';
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* The inline chat card takes its NATURAL height under a ceiling (ggui#1475):
|
|
283
|
+
* an MCP Apps host sizes the inline frame to the card's content
|
|
284
|
+
* (`ui/notifications/size-changed`, auto-resize) up to its maximum, so the
|
|
285
|
+
* visitor sees the card and nothing under it. The judge captures exactly
|
|
286
|
+
* that — the card's own extent on the host's ground, capped at the box — and
|
|
287
|
+
* never the box's remainder (a fixed 640 px capture scored every hello
|
|
288
|
+
* against a void no visitor sees). The box stays the ceiling: content taller
|
|
289
|
+
* than it is a critical layout issue that fails the canvas (a 1289 px hello
|
|
290
|
+
* on a 640 px card was scored 86 from a full-page capture that showed the
|
|
291
|
+
* judge what no user sees). A phone's first screen may scroll, so the
|
|
292
|
+
* overflow is reported as a major issue and the score stands. Pages
|
|
293
|
+
* (`md`/`lg`/`xl`) scroll by design: measured, never judged.
|
|
294
|
+
*/
|
|
295
|
+
declare function canvasFitPolicy(canvas: CanvasClass): CanvasFitPolicy;
|
|
296
|
+
/**
|
|
297
|
+
* How far in from a panelled page's edges the ink is read (ggui#1120): past the panel's gap, its
|
|
298
|
+
* largest rounded corner (the `round` bucket, 24 px — the scrim shows through the corner) and its
|
|
299
|
+
* 1 px hairline, so the host's chrome never counts as paint. The card's own inset is 16 px, so the
|
|
300
|
+
* band skipped inside the card is 25 px of a canvas — reported ratios are over the region.
|
|
301
|
+
*/
|
|
302
|
+
declare const JUDGE_INK_INSET_PX: number;
|
|
303
|
+
/**
|
|
304
|
+
* The host ground round a naturally-captured inline card (ggui#1475): the card is mounted this far in
|
|
305
|
+
* from the page's edges and captured with this margin, so its edge and radius are read against the
|
|
306
|
+
* host surface — the page's scrim ground, never the card's own. The design's one gap (the panel's).
|
|
307
|
+
*/
|
|
308
|
+
declare const JUDGE_GROUND_MARGIN_PX: 16;
|
|
309
|
+
/**
|
|
310
|
+
* The bounds a host frame must meet to be drawn (ggui#1492), exported so a lane's reader applies exactly the frames
|
|
311
|
+
* this judge draws: an entry the reader accepts and the judge ignores would be echoed as applied while never drawn.
|
|
312
|
+
*/
|
|
313
|
+
declare const HOST_COLOUR_PATTERN: RegExp;
|
|
314
|
+
declare const HOST_FRAME_BOUNDS: {
|
|
315
|
+
readonly ringWidthPx: {
|
|
316
|
+
readonly min: 0;
|
|
317
|
+
readonly max: 8;
|
|
318
|
+
};
|
|
319
|
+
readonly ringAlpha: {
|
|
320
|
+
readonly min: 0;
|
|
321
|
+
readonly max: 1;
|
|
322
|
+
};
|
|
323
|
+
readonly radiusPx: {
|
|
324
|
+
readonly min: 0;
|
|
325
|
+
readonly max: 64;
|
|
326
|
+
};
|
|
327
|
+
readonly minHeightPx: {
|
|
328
|
+
readonly min: 0;
|
|
329
|
+
readonly max: 2560;
|
|
330
|
+
};
|
|
331
|
+
};
|
|
332
|
+
/** The deterministic fit issue — one per overflowing canvas, in the judge's issue shape so it rides the same channel. */
|
|
333
|
+
declare function canvasOverflowIssue(canvas: CanvasClass, viewport: CanvasViewport, contentHeight: number, verdict: 'fail' | 'warn'): VisualIssue;
|
|
334
|
+
/** ggui#1120 — the deterministic blank: the capture is one flat colour, so the component mounted and painted nothing. */
|
|
335
|
+
declare function canvasBlankIssue(canvas: CanvasClass, viewport: CanvasViewport): VisualIssue;
|
|
336
|
+
/**
|
|
337
|
+
* `runVisualEvaluation`'s result. Identical to `EvaluationResult` when
|
|
338
|
+
* `config.canvases` is unset; with canvases set, `canvases` holds the
|
|
339
|
+
* per-class verdicts and the base fields aggregate them (see
|
|
340
|
+
* `VisualEvalConfig.canvases`).
|
|
341
|
+
*/
|
|
342
|
+
interface VisualEvaluationResult extends EvaluationResult {
|
|
343
|
+
canvases?: CanvasVisualResult[];
|
|
344
|
+
/**
|
|
345
|
+
* ggui#1436 — the criteria calls' spend across canvases, when any was asked and answered. `inputTokens` /
|
|
346
|
+
* `outputTokens` stay the SCORING calls' alone, so a cost read off them never includes the report-only block.
|
|
347
|
+
*/
|
|
348
|
+
criteriaTokens?: CriteriaCallTokens;
|
|
349
|
+
/**
|
|
350
|
+
* ggui#1127 — salvaged judge answers across the canvases, per leg, as N of M (scoring answers; criteria calls
|
|
351
|
+
* answered). Present on every canvas run, zeros included, so a reader can tell "none salvaged" from "not counted".
|
|
352
|
+
*/
|
|
353
|
+
judgeSalvage?: JudgeSalvageCounts;
|
|
354
|
+
/** The design tree the judge painted with (ggui#1042) — present on every per-canvas judgement. */
|
|
355
|
+
design?: JudgeDesignIdentity;
|
|
356
|
+
/** The mode `cssTokens` were composed in, when the caller said (ggui#1076). */
|
|
357
|
+
themeMode?: 'light' | 'dark';
|
|
358
|
+
}
|
|
359
|
+
/** Injection points for `runVisualEvaluation` — screenshot deps plus the judge call (tests). */
|
|
360
|
+
interface VisualEvalDeps extends ScreenshotDeps {
|
|
361
|
+
/** The multimodal judge call (default: `callMultimodalLLM`). */
|
|
362
|
+
judge?: typeof callMultimodalLLM;
|
|
363
|
+
}
|
|
364
|
+
interface VisualEvalContext {
|
|
365
|
+
/** Compiled JavaScript code (ESM with imports) */
|
|
366
|
+
compiledCode: string;
|
|
367
|
+
/** Original user prompt */
|
|
368
|
+
originalPrompt: string;
|
|
369
|
+
/** Design system CSS tokens */
|
|
370
|
+
cssTokens?: string;
|
|
371
|
+
/** The app's generation profile (#991) — judged relative to, never against. */
|
|
372
|
+
profile?: GenerationProfileInput;
|
|
373
|
+
/** ggui#1436 — a criteria bank and the card's context; the judge selects per canvas and answers report-only. */
|
|
374
|
+
criteria?: {
|
|
375
|
+
readonly bank: CriteriaBank;
|
|
376
|
+
readonly context: CriteriaContextInput;
|
|
377
|
+
};
|
|
378
|
+
}
|
|
379
|
+
/**
|
|
380
|
+
* The `@ggui-ai/design` package root — resolved by MODULE ID, never by counting
|
|
381
|
+
* directories (ggui#1110).
|
|
382
|
+
*
|
|
383
|
+
* The arithmetic this replaced (`…/'..','..','..','design'`) was correct only
|
|
384
|
+
* for the layout it was written against — `node_modules/@ggui-ai/ui-gen/dist/
|
|
385
|
+
* evaluation` → `node_modules/@ggui-ai/` + `design`. Under a deploy-flattened
|
|
386
|
+
* layout it landed one level too high, at `node_modules/design`, a path that is
|
|
387
|
+
* not the design package at all: the judge then walked a directory that does not
|
|
388
|
+
* exist, threw ENOENT inside every evaluation round on that deployment, and a
|
|
389
|
+
* bar refused cards no one could judge. `@ggui-ai/design` exports `./package.json`,
|
|
390
|
+
* so the module resolver answers correctly in every layout — scoped, flattened,
|
|
391
|
+
* hoisted — and the receipt keeps working inside the image.
|
|
392
|
+
*/
|
|
393
|
+
declare function resolveDesignPackageDir(): string;
|
|
394
|
+
/** A screenshot's region in page px (puppeteer's `clip`). */
|
|
395
|
+
interface ScreenshotClip {
|
|
396
|
+
readonly x: number;
|
|
397
|
+
readonly y: number;
|
|
398
|
+
readonly width: number;
|
|
399
|
+
readonly height: number;
|
|
400
|
+
}
|
|
401
|
+
/** The page surface the capture uses — a structural subset of puppeteer's `Page`. */
|
|
402
|
+
interface ScreenshotPage {
|
|
403
|
+
setContent(html: string, options: {
|
|
404
|
+
waitUntil: 'load';
|
|
405
|
+
timeout: number;
|
|
406
|
+
}): Promise<void>;
|
|
407
|
+
waitForNetworkIdle(options: {
|
|
408
|
+
idleTime: number;
|
|
409
|
+
timeout: number;
|
|
410
|
+
}): Promise<void>;
|
|
411
|
+
waitForSelector(selector: string, options: {
|
|
412
|
+
timeout: number;
|
|
413
|
+
}): Promise<unknown>;
|
|
414
|
+
/** Evaluates a JS expression in the page and returns its serialised value — the fit measurement (ggui#1027). */
|
|
415
|
+
evaluate(expression: string): Promise<unknown>;
|
|
416
|
+
screenshot(options: {
|
|
417
|
+
type: 'png';
|
|
418
|
+
fullPage: boolean;
|
|
419
|
+
clip?: ScreenshotClip;
|
|
420
|
+
}): Promise<Uint8Array>;
|
|
421
|
+
}
|
|
422
|
+
/** The browser surface the capture uses — a structural subset of puppeteer's `Browser`. */
|
|
423
|
+
interface ScreenshotBrowser {
|
|
424
|
+
newPage(): Promise<ScreenshotPage>;
|
|
425
|
+
close(): Promise<void>;
|
|
426
|
+
}
|
|
427
|
+
type ScreenshotLauncher = (options: LaunchOptions) => Promise<ScreenshotBrowser>;
|
|
428
|
+
/** The two members of `@sparticuz/chromium` the fallback launch path reads. */
|
|
429
|
+
interface ChromiumProvider {
|
|
430
|
+
readonly args: string[];
|
|
431
|
+
executablePath(): Promise<string>;
|
|
432
|
+
}
|
|
433
|
+
/**
|
|
434
|
+
* Injection points for the capture — every default is the production
|
|
435
|
+
* path; tests replace them to pin branch selection without launching a
|
|
436
|
+
* browser.
|
|
437
|
+
*/
|
|
438
|
+
interface ScreenshotDeps {
|
|
439
|
+
/** Launches the browser (default: `puppeteer-core`'s `launch`). */
|
|
440
|
+
launch?: ScreenshotLauncher;
|
|
441
|
+
/** Environment the executable-path override is read from (default: `process.env`). */
|
|
442
|
+
env?: NodeJS.ProcessEnv;
|
|
443
|
+
/** Loads `@sparticuz/chromium` (default: dynamic import) — only consulted when no override is set. */
|
|
444
|
+
loadChromium?: () => Promise<ChromiumProvider>;
|
|
445
|
+
/** Post-load settle time before the screenshot, ms (default 1000). */
|
|
446
|
+
settleMs?: number;
|
|
447
|
+
}
|
|
448
|
+
/**
|
|
449
|
+
* Pick the browser binary. `PUPPETEER_EXECUTABLE_PATH` (a system
|
|
450
|
+
* Chromium — the bench runner image, a dev box) wins and skips the
|
|
451
|
+
* `@sparticuz/chromium` load entirely; otherwise the bundled Lambda
|
|
452
|
+
* Chromium supplies both binary and flags, as before.
|
|
453
|
+
*/
|
|
454
|
+
declare function resolveLaunchOptions(viewport: {
|
|
455
|
+
width: number;
|
|
456
|
+
height: number;
|
|
457
|
+
}, deps?: Pick<ScreenshotDeps, 'env' | 'loadChromium'>): Promise<LaunchOptions>;
|
|
458
|
+
/**
|
|
459
|
+
* Take a screenshot of the rendered component.
|
|
460
|
+
* Returns the PNG bytes, or null if no browser could be launched.
|
|
461
|
+
*/
|
|
462
|
+
/** Screenshot plus the reason when none could be taken — the judge's `unavailableReason`. */
|
|
463
|
+
interface ScreenshotAttempt {
|
|
464
|
+
readonly png: Buffer | null;
|
|
465
|
+
readonly reason?: string;
|
|
466
|
+
/** The document's scroll height at the viewport (ggui#1027); `null` when unmeasurable. */
|
|
467
|
+
readonly contentHeight: number | null;
|
|
468
|
+
/** ggui#1475 — a natural capture's horizontal overflow: how many px the card's content runs past its width; absent on every other capture. */
|
|
469
|
+
readonly overflowX?: number | null;
|
|
470
|
+
/**
|
|
471
|
+
* ggui#1663 — the edge rule on this capture's DOM, read just before the screenshot (report-only); `null` when the
|
|
472
|
+
* probe failed. Absent on a failed capture.
|
|
473
|
+
*/
|
|
474
|
+
readonly edge?: EdgeVerdict | null;
|
|
475
|
+
}
|
|
476
|
+
/** The expression the fit measurement evaluates in the page — the taller of the two scroll heights. */
|
|
477
|
+
declare const CONTENT_HEIGHT_EXPRESSION = "Math.max(document.documentElement.scrollHeight, document.body ? document.body.scrollHeight : 0)";
|
|
478
|
+
/** The stand-in page's card height ({@link cardHeightExpression} at the stand-in's pad). */
|
|
479
|
+
declare const CARD_HEIGHT_EXPRESSION: string;
|
|
480
|
+
/** ggui#1492 — a natural capture's geometry: the page's pad per side, and the host's floor when it has one. */
|
|
481
|
+
interface NaturalCaptureOptions {
|
|
482
|
+
readonly padPx: number;
|
|
483
|
+
readonly floorPx?: number;
|
|
484
|
+
}
|
|
485
|
+
declare function captureScreenshotDetailed(html: string, viewport?: {
|
|
486
|
+
width: number;
|
|
487
|
+
height: number;
|
|
488
|
+
}, deps?: ScreenshotDeps, capture?: CaptureMode, natural?: NaturalCaptureOptions): Promise<ScreenshotAttempt>;
|
|
489
|
+
declare function captureScreenshot(html: string, viewport?: {
|
|
490
|
+
width: number;
|
|
491
|
+
height: number;
|
|
492
|
+
}, deps?: ScreenshotDeps): Promise<Buffer | null>;
|
|
493
|
+
declare const VISUAL_EVAL_PROMPT = "You are a visual quality evaluator for ggui \u2014 a platform where AI agents generate React UI components on demand.\n\n## Context\nThe screenshot shows a generated React component built from a design system with CSS variable theming. The component was created by an LLM to fulfill a user's request. Your job is to evaluate whether the generated UI achieves the user's goal AND looks professionally designed.\n\n## Scoring Dimensions (0-100 each)\n\n1. **completeness** (25%): Does the screenshot show ALL features the user requested? Are all sections, controls, data fields, and interactive elements present? Missing features or sections = major deduction. Compare against the original request carefully.\n\n2. **layout** (25%): Is the layout well-composed? Clear sections and grouping? No overlapping elements? Proper spacing between elements? Responsive-looking? Does it look like a professional app UI, not a homework project?\n\n3. **hierarchy** (25%): Clear visual hierarchy? Headings are visually distinct from body text? Primary actions (buttons) are prominent? Information grouped logically with clear section breaks? Color and size used to guide the eye?\n\n4. **aesthetics** (25%): Professional, polished appearance? Consistent color palette? Good use of whitespace \u2014 not too sparse, not too cluttered? Cards, shadows, and borders used effectively? Does it look like something a designer would approve? Would you be comfortable showing this to a client?\n\n## Scoring Guide\n- 90-100: Production-ready. Would ship to real users. Polished layout, clear hierarchy, professional aesthetics.\n- 80-89: Good quality. Minor improvements needed (slightly tight spacing, one section could be better grouped).\n- 70-79: Acceptable but generic. Works correctly but lacks design polish or visual refinement.\n- 60-69: Below standard. Noticeable problems \u2014 cramped layout, poor hierarchy, or missing sections.\n- Below 60: Broken or fundamentally incomplete. Error messages visible, blank areas, or critical features missing.\n\n## Important\n- Check the screenshot against the \"Original Request\" \u2014 does it actually deliver what was asked for?\n- Error messages like \"Render error\" or blank white space = rendering score 0\n- A component that renders but is just a wall of text with no structure should score low on layout and hierarchy\n\nList AT MOST 6 issues, most severe first, one sentence each for \"description\" and \"fix\" \u2014 a longer list is cut off and lost.\n\nRespond with ONLY a JSON object (no markdown, no explanation):\n{\n \"completeness\": <0-100>,\n \"layout\": <0-100>,\n \"hierarchy\": <0-100>,\n \"aesthetics\": <0-100>,\n \"issues\": [\n { \"dimension\": \"<dimension>\", \"severity\": \"<critical|major|minor>\", \"description\": \"<what's wrong>\", \"fix\": \"<specific fix>\" }\n ],\n \"critique\": \"<2-3 sentences: what's good, what needs improvement, does it achieve the user's goal?>\"\n}";
|
|
494
|
+
/**
|
|
495
|
+
* Send the screenshot to the configured multimodal provider through
|
|
496
|
+
* the shared `LLMAgent` machinery. Routing through `createVisionAgent`
|
|
497
|
+
* (rather than constructing provider SDK clients inline) is what puts
|
|
498
|
+
* this call inside the same `apiCall()` choke point as every other
|
|
499
|
+
* completion: provider 429s retry with `Retry-After` honoring, the
|
|
500
|
+
* caller's `onRetry` observer sees each retry, and `routeOverride`
|
|
501
|
+
* governs credentials and model routing (including the Anthropic
|
|
502
|
+
* Bedrock path) instead of `process.env`.
|
|
503
|
+
*/
|
|
504
|
+
/**
|
|
505
|
+
* Output budget for the judge's answer. 1500 cut a board's issue list
|
|
506
|
+
* mid-array (`Expected ',' or ']' after array element`, six kanban cells
|
|
507
|
+
* on 2026-09-11) — deterministic on the content, so a same-prompt retry
|
|
508
|
+
* could never clear it. 4096 fits the bounded list the prompt now asks for
|
|
509
|
+
* with room; the salvage path covers the remainder.
|
|
510
|
+
*/
|
|
511
|
+
declare const VISUAL_JUDGE_MAX_OUTPUT_TOKENS = 4096;
|
|
512
|
+
/**
|
|
513
|
+
* The judge instrument's name and content digest, for the record a run
|
|
514
|
+
* stamps beside every visual score. The NAME is for readers; the DIGEST
|
|
515
|
+
* is computed from the prompt text at module load, so a stamped row can
|
|
516
|
+
* never claim a prompt version it did not run — change the prompt and the
|
|
517
|
+
* digest moves with it (the pin ties the name to the bounded-list text).
|
|
518
|
+
*/
|
|
519
|
+
declare const VISUAL_JUDGE_PROMPT_VERSION = "v2-bounded-issues";
|
|
520
|
+
declare const VISUAL_JUDGE_PROMPT_DIGEST: string;
|
|
521
|
+
declare function callMultimodalLLM(config: VisualEvalConfig, model: string, prompt: string, screenshot: Buffer, originalPrompt: string, profileBlock?: string, criteriaBlock?: string): Promise<LLMResponse>;
|
|
522
|
+
/**
|
|
523
|
+
* Run visual evaluation on a compiled component.
|
|
524
|
+
*
|
|
525
|
+
* 1. Builds an HTML page with the component + sample props
|
|
526
|
+
* 2. Takes a screenshot via puppeteer (if available)
|
|
527
|
+
* 3. Sends screenshot to multimodal LLM for visual scoring
|
|
528
|
+
*
|
|
529
|
+
* Returns null if puppeteer is not available (graceful fallback).
|
|
530
|
+
*/
|
|
531
|
+
/**
|
|
532
|
+
* The judge's answer WITH the reason when it could not judge: `result` is
|
|
533
|
+
* null exactly when no screenshot could be taken (no browser, a launch or
|
|
534
|
+
* in-page failure) or the component could not be bundled; `unavailableReason`
|
|
535
|
+
* names why in words and `canvas` the canvas it happened at. A production
|
|
536
|
+
* caller records the reason in its receipt — a `judge_unavailable` that only
|
|
537
|
+
* says "null" cost a log dive on 2026-09-10 (puppeteer-core missing in the
|
|
538
|
+
* deploy image).
|
|
539
|
+
*/
|
|
540
|
+
interface VisualEvalDetailed {
|
|
541
|
+
readonly result: VisualEvaluationResult | null;
|
|
542
|
+
readonly unavailableReason?: string;
|
|
543
|
+
readonly canvas?: CanvasClass;
|
|
544
|
+
}
|
|
545
|
+
declare function runVisualEvaluation(context: VisualEvalContext, config: VisualEvalConfig, deps?: VisualEvalDeps): Promise<VisualEvaluationResult | null>;
|
|
546
|
+
declare function runVisualEvaluationDetailed(context: VisualEvalContext, config: VisualEvalConfig, deps?: VisualEvalDeps): Promise<VisualEvalDetailed>;
|
|
547
|
+
/** The per-canvas verdicts without the PNGs — what the harness stamps on `EvalResult.visual`. */
|
|
548
|
+
declare function summarizeVisualResult(result: VisualEvaluationResult): VisualEvalSummary | undefined;
|
|
549
|
+
/** One stored capture to judge: the frame the judge saw at capture time, plus what the capture measured. */
|
|
550
|
+
interface StoredCaptureInput {
|
|
551
|
+
readonly canvas: CanvasClass;
|
|
552
|
+
/** The capture as saved (`canvas-<class>.png`). */
|
|
553
|
+
readonly png: Buffer;
|
|
554
|
+
/** The box the capture was taken at — the class box, or the declared one. */
|
|
555
|
+
readonly viewport: CanvasViewport;
|
|
556
|
+
/** The document's scroll height the capture recorded; `null` when it did not. */
|
|
557
|
+
readonly contentHeight: number | null;
|
|
558
|
+
readonly originalPrompt: string;
|
|
559
|
+
readonly profile?: GenerationProfileInput;
|
|
560
|
+
/** ggui#1436 — the bank and the card's context; absent = today's judge, no block. */
|
|
561
|
+
readonly criteria?: {
|
|
562
|
+
readonly bank: CriteriaBank;
|
|
563
|
+
readonly context: CriteriaContextInput;
|
|
564
|
+
};
|
|
565
|
+
/** The props the capture was rendered with — handed to the criteria block for the rows whose evidence names props. */
|
|
566
|
+
readonly sampleProps?: JsonObject;
|
|
567
|
+
}
|
|
568
|
+
interface StoredCaptureVerdict {
|
|
569
|
+
readonly canvas: CanvasClass;
|
|
570
|
+
readonly viewport: CanvasViewport;
|
|
571
|
+
readonly score: number;
|
|
572
|
+
readonly passed: boolean;
|
|
573
|
+
readonly issues: EvaluationIssue[];
|
|
574
|
+
readonly judge: CanvasJudgeRecord;
|
|
575
|
+
readonly contentHeight: number | null;
|
|
576
|
+
readonly overflow: boolean;
|
|
577
|
+
readonly inkRatio: number | null;
|
|
578
|
+
readonly criteria?: CriteriaBlock;
|
|
579
|
+
/** The scoring calls' spend. */
|
|
580
|
+
readonly inputTokens: number;
|
|
581
|
+
readonly outputTokens: number;
|
|
582
|
+
/** ggui#1436 — the report-only criteria call's spend, apart from the scoring calls'; absent when none was asked or answered. */
|
|
583
|
+
readonly criteriaTokens?: CriteriaCallTokens;
|
|
584
|
+
}
|
|
585
|
+
type StoredCaptureOutcome = {
|
|
586
|
+
readonly kind: 'ok';
|
|
587
|
+
readonly verdict: StoredCaptureVerdict;
|
|
588
|
+
} | {
|
|
589
|
+
readonly kind: 'unavailable';
|
|
590
|
+
readonly reason: string;
|
|
591
|
+
};
|
|
592
|
+
/**
|
|
593
|
+
* Judge a STORED capture exactly as the per-canvas leg judges a fresh one — the same K scoring calls on the
|
|
594
|
+
* same frame, the same median, the same fit and blank verdicts, the same report-only criteria call — without
|
|
595
|
+
* rendering.
|
|
596
|
+
* This is the calibration's path (ggui#1438): the frame his eye marks is the frame the judge saw, and a
|
|
597
|
+
* re-judge costs judge tokens only. Fit reads the capture's recorded `contentHeight`; ink is read off the
|
|
598
|
+
* PNG inside the canvas's chrome, as at capture.
|
|
599
|
+
*/
|
|
600
|
+
declare function judgeStoredCapture(input: StoredCaptureInput, config: VisualEvalConfig, deps?: Pick<VisualEvalDeps, 'judge'>): Promise<StoredCaptureOutcome>;
|
|
601
|
+
|
|
602
|
+
/**
|
|
603
|
+
* ggui#1522 — what a visual leg's judge calls spent: the scoring calls, and the report-only criteria calls apart
|
|
604
|
+
* (ggui#1436). Priced at the VISUAL agent's model, never folded into a text evaluator's or a coding turn's tokens.
|
|
605
|
+
*/
|
|
606
|
+
interface VisualLegTokens {
|
|
607
|
+
readonly inputTokens: number;
|
|
608
|
+
readonly outputTokens: number;
|
|
609
|
+
readonly criteria?: CriteriaCallTokens;
|
|
610
|
+
}
|
|
611
|
+
/** What the harness's eval round consumes from the visual leg. */
|
|
612
|
+
interface VisualEvalOutcome {
|
|
613
|
+
/** Tier-2 issues (empty when no browser is available). */
|
|
614
|
+
issues: EvalIssue[];
|
|
615
|
+
/**
|
|
616
|
+
* Per-canvas summary — present ONLY when `config.canvases` was set and
|
|
617
|
+
* the leg ran; the harness stamps it on `EvalResult.visual`. Absent on
|
|
618
|
+
* the single-shot path (byte-identical to the pre-canvas result).
|
|
619
|
+
*/
|
|
620
|
+
summary?: VisualEvalSummary;
|
|
621
|
+
/**
|
|
622
|
+
* ggui#1221 — whether the judge leg ran or was skipped (with the reason
|
|
623
|
+
* `runVisualEvaluationDetailed` names). Always present: the absence of a
|
|
624
|
+
* summary used to be indistinguishable from a clean single-shot run.
|
|
625
|
+
*/
|
|
626
|
+
coverage: VisualCoverage;
|
|
627
|
+
/**
|
|
628
|
+
* ggui#1522 — the leg's own spend, when its judge ran and reported tokens. The round records it in the cost
|
|
629
|
+
* tracker at the visual agent's model and carries it apart; absent on a skipped leg.
|
|
630
|
+
*/
|
|
631
|
+
tokens?: VisualLegTokens;
|
|
632
|
+
}
|
|
633
|
+
/**
|
|
634
|
+
* Run visual evaluation and return tier 2 EvalIssues (+ the per-canvas
|
|
635
|
+
* summary when canvases were requested).
|
|
636
|
+
*/
|
|
637
|
+
declare function runVisualEval(context: VisualEvalContext, config: VisualEvalConfig, deps?: VisualEvalDeps): Promise<VisualEvalOutcome>;
|
|
638
|
+
|
|
639
|
+
export { resolveLaunchOptions as $, type VisualEvalConfig as A, type VisualEvalContext as B, type CriteriaCallTokens as C, type VisualEvalDeps as D, type EdgeVerdict as E, type VisualEvalDetailed as F, type VisualEvalOutcome as G, HOST_COLOUR_PATTERN as H, type VisualEvaluationResult as I, JUDGE_GROUND_MARGIN_PX as J, callMultimodalLLM as K, canvasBlankIssue as L, canvasFitPolicy as M, type NaturalCaptureOptions as N, canvasOverflowIssue as O, captureScreenshot as P, captureScreenshotDetailed as Q, chromaOfCssTokens as R, type ScreenshotAttempt as S, criteriaContextFor as T, designTreeSha256 as U, type VisualLegTokens as V, judgeDesignIdentity as W, judgeEdges as X, judgeStoredCapture as Y, resetJudgeDesignIdentityCache as Z, resolveDesignPackageDir as _, type EdgeBlock as a, runVisualEval as a0, runVisualEvaluation as a1, runVisualEvaluationDetailed as a2, summarizeVisualResult as a3, CARD_HEIGHT_EXPRESSION as b, CONTENT_HEIGHT_EXPRESSION as c, type CanvasFitPolicy as d, type CanvasVisualResult as e, type CaptureMode as f, type ChromiumProvider as g, type CriteriaContextInput as h, type CriteriaContextSources as i, EDGE_TOLERANCE_PX as j, type EdgeOffset as k, HOST_FRAME_BOUNDS as l, JUDGE_INK_INSET_PX as m, type JudgeDesignIdentity as n, type ScreenshotBrowser as o, type ScreenshotClip as p, type ScreenshotDeps as q, type ScreenshotLauncher as r, type ScreenshotPage as s, type StoredCaptureInput as t, type StoredCaptureOutcome as u, type StoredCaptureVerdict as v, VISUAL_EVAL_PROMPT as w, VISUAL_JUDGE_MAX_OUTPUT_TOKENS as x, VISUAL_JUDGE_PROMPT_DIGEST as y, VISUAL_JUDGE_PROMPT_VERSION as z };
|
package/dist/workflows.d.ts
CHANGED
|
@@ -2,11 +2,11 @@ import { C as Classification } from './axes-CKVCzR_x.js';
|
|
|
2
2
|
import { Workflow } from './harness/types-public.js';
|
|
3
3
|
import '@ggui-ai/protocol';
|
|
4
4
|
import './styling-profile-CxfvV48g.js';
|
|
5
|
-
import './types-public-
|
|
5
|
+
import './types-public-B7wn4ce5.js';
|
|
6
|
+
import './llm.js';
|
|
6
7
|
import '@ggui-ai/mcp-server-core';
|
|
7
|
-
import './design-mode-
|
|
8
|
+
import './design-mode-DGWN_Gkm.js';
|
|
8
9
|
import './types-Dh1s4K9j.js';
|
|
9
|
-
import './llm.js';
|
|
10
10
|
import './policy.js';
|
|
11
11
|
|
|
12
12
|
declare const WORKFLOWS: {
|