@ggui-ai/ui-gen 0.15.0 → 0.17.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/dist/adapters/generation-dispatch.d.ts +24 -4
- package/dist/adapters/generation-dispatch.js +5188 -3920
- package/dist/adapters/generation-dispatch.js.map +1 -1
- package/dist/adapters/index.js +33 -26
- package/dist/adapters/index.js.map +1 -1
- package/dist/advanced/index.d.ts +22 -13
- package/dist/advanced/index.js +4889 -3561
- package/dist/advanced/index.js.map +1 -1
- package/dist/blueprint-validator.js +8 -12
- package/dist/blueprint-validator.js.map +1 -1
- package/dist/boilerplate.d.ts +19 -1
- package/dist/boilerplate.js +671 -254
- package/dist/boilerplate.js.map +1 -1
- package/dist/check/index.d.ts +17 -3
- package/dist/check/index.js +34 -25
- package/dist/check/index.js.map +1 -1
- package/dist/compose.js +1 -1
- package/dist/compose.js.map +1 -1
- package/dist/create-ui-generator-C8Ki9Wz1.d.ts +189 -0
- package/dist/design-mode-DLufhrNp.d.ts +61 -0
- package/dist/{dispatch-BuZfTh9r.d.ts → dispatch-D2htzi9h.d.ts} +4 -1
- package/dist/evaluation/axis-checks/index.d.ts +4 -3
- package/dist/evaluation/axis-checks/index.js +300 -14
- package/dist/evaluation/axis-checks/index.js.map +1 -1
- package/dist/evaluation/axis-checks/registry.d.ts +2 -1
- package/dist/evaluation/axis-checks/registry.js +253 -1
- package/dist/evaluation/axis-checks/registry.js.map +1 -1
- package/dist/evaluation/index.d.ts +297 -5
- package/dist/evaluation/index.js +4515 -120
- package/dist/evaluation/index.js.map +1 -1
- package/dist/fragments/index.js +1 -1
- package/dist/fragments/index.js.map +1 -1
- package/dist/{generate-BTfvELgl.d.ts → generate-9IeNT4ZY.d.ts} +10 -1
- package/dist/harness/check/runtime-render/index.d.ts +3 -1
- package/dist/harness/check/runtime-render/index.js +8 -12
- package/dist/harness/check/runtime-render/index.js.map +1 -1
- package/dist/harness/index.d.ts +3 -1
- package/dist/harness/index.js +913 -441
- package/dist/harness/index.js.map +1 -1
- package/dist/harness/llm-trace-sink.d.ts +3 -3
- package/dist/harness/llm-trace-sink.js.map +1 -1
- package/dist/harness/prompts.d.ts +2 -1
- package/dist/harness/prompts.js +6 -3
- package/dist/harness/prompts.js.map +1 -1
- package/dist/harness/result-types.d.ts +17 -5
- package/dist/harness/result-types.js.map +1 -1
- package/dist/harness/runtime.d.ts +28 -3
- package/dist/harness/runtime.js +702 -274
- package/dist/harness/runtime.js.map +1 -1
- package/dist/harness/types-public.d.ts +39 -1
- package/dist/harness/types-public.js +913 -441
- package/dist/harness/types-public.js.map +1 -1
- package/dist/harness/validator-trace-sink.d.ts +2 -1
- package/dist/index.d.ts +32 -6
- package/dist/index.js +4899 -3560
- package/dist/index.js.map +1 -1
- package/dist/patch.d.ts +3 -1
- package/dist/{prompts-BVhtH3M1.d.ts → prompts-YU9piOgs.d.ts} +21 -45
- package/dist/providers/index.d.ts +2 -2
- package/dist/providers/index.js.map +1 -1
- package/dist/styling-profile-CxfvV48g.d.ts +35 -0
- package/dist/tools/get-primitives-ts.d.ts +1 -1
- package/dist/tools/get-primitives-ts.js +1 -1
- package/dist/tools/get-primitives-ts.js.map +1 -1
- package/dist/{types-public-CkNWEov9.d.ts → types-public-DVSssdc-.d.ts} +85 -5
- package/dist/validation/index.d.ts +1 -1
- package/dist/validation/index.js +4 -4
- package/dist/validation/index.js.map +1 -1
- package/dist/workflows.d.ts +3 -1
- package/package.json +12 -12
- package/src/adapters/generation-dispatch.ts +62 -4
- package/src/adapters/provider-router.ts +7 -6
- package/src/adapters/tools.ts +5 -5
- package/src/advanced/generator.ts +11 -10
- package/src/advanced/index.ts +5 -4
- package/src/boilerplate/free-design-prompt.ts +336 -0
- package/src/boilerplate/generate.ts +10 -1
- package/src/boilerplate/hard-sections.ts +257 -0
- package/src/boilerplate/render.ts +32 -8
- package/src/boilerplate/styling-profile.ts +166 -0
- package/src/boilerplate/system-prompt.ts +101 -237
- package/src/boilerplate/templates/base-free.tsx.tmpl +24 -0
- package/src/check/run-tier0.ts +82 -20
- package/src/coding-agent/tools.ts +8 -2
- package/src/contract-context.ts +43 -14
- package/src/create-harness.ts +15 -0
- package/src/create-ui-generator.ts +112 -27
- package/src/design-mode.ts +192 -0
- package/src/design-system-docs.ts +24 -17
- package/src/effort.ts +48 -0
- package/src/evaluation/axis-checks/checks/grid.ts +148 -0
- package/src/evaluation/axis-checks/checks/universal.ts +244 -0
- package/src/evaluation/axis-checks/dispatch.ts +82 -13
- package/src/evaluation/axis-checks/extras.ts +5 -0
- package/src/evaluation/axis-checks/helpers.ts +12 -0
- package/src/evaluation/axis-checks/registry.ts +2 -0
- package/src/evaluation/cost-tracker.ts +2 -3
- package/src/evaluation/design-identity.ts +96 -0
- package/src/evaluation/index.ts +63 -2
- package/src/evaluation/llm-evaluator.ts +89 -21
- package/src/evaluation/theme-css.ts +14 -0
- package/src/evaluation/types-public.ts +137 -8
- package/src/evaluation/visual-evaluator.ts +759 -54
- package/src/fragments/render.ts +1 -1
- package/src/harness/check/runtime-render/prepare-mockup.ts +18 -11
- package/src/harness/coding/dupe-break.ts +0 -0
- package/src/harness/coding/init-session.ts +2 -0
- package/src/harness/coding/run-coding-turn.ts +9 -14
- package/src/harness/coding/run-eval-round.ts +46 -5
- package/src/harness/llm-trace-sink.ts +3 -3
- package/src/harness/result-types.ts +15 -3
- package/src/harness/runtime.ts +28 -0
- package/src/harness/types-public.ts +38 -0
- package/src/index.ts +28 -0
- package/src/internal/extract-call-signatures.ts +2 -2
- package/src/pin-fixtures.ts +98 -0
- package/src/providers/bedrock.ts +4 -4
- package/src/run-check.ts +11 -10
- package/src/tools/get-primitives-ts.ts +1 -1
- package/src/tools.ts +2 -1
- package/src/validation/allowed-imports.ts +8 -2
- package/src/validation/primitives.ts +1 -1
- package/dist/create-ui-generator-D6TKuv9V.d.ts +0 -106
|
@@ -1,11 +1,16 @@
|
|
|
1
|
-
|
|
1
|
+
import { C as CanvasJudgeRecord, E as EvalIssue, V as VisualEvalSummary } from '../types-public-DVSssdc-.js';
|
|
2
|
+
export { A as AxisCheck, a as AxisCheckInput, d as CRITERIA, e as CanvasVisualSummary, f as CriterionCoverage, g as CriterionRunStatus, D as DEFAULT_QUALITY_CONFIG, h as EvalCategory, i as EvalCriterion, j as EvalOutcome, b as EvalResult, c as EvalTier, L as LLM_EVAL_STATIC_CRITERIA, P as Priority, Q as QualityConfig, k as QualityMode, l as buildCodingCriteriaSummary, n as criteriaFor, o as getActionableIssues, p as getCriteriaByPriority, q as getCriterionById, r as getLLMCriteria, s as isBlocked, m as matches, t as notApplicableCoverage, u as priorityForIssue } from '../types-public-DVSssdc-.js';
|
|
2
3
|
import * as _anthropic_ai_claude_agent_sdk from '@anthropic-ai/claude-agent-sdk';
|
|
3
4
|
import { McpServerConfig } from '@anthropic-ai/claude-agent-sdk';
|
|
4
5
|
import { EvaluationContext, EvaluationConfig, QualityMetadata, EvaluationResult, EvaluationIssue } from './types.js';
|
|
5
6
|
export { DEFAULT_EVAL_MAX_ROUNDS, DimensionScores, MAX_EVAL_ROUNDS_HARD_LIMIT } from './types.js';
|
|
6
|
-
export { R as RunAxisChecksInput, r as runAxisChecks } from '../dispatch-
|
|
7
|
+
export { R as RunAxisChecksInput, r as runAxisChecks } from '../dispatch-D2htzi9h.js';
|
|
7
8
|
import { A as AgentConfig, L as LLMResponse } from '../llm-router-D7fjBhtr.js';
|
|
8
|
-
import '
|
|
9
|
+
import { G as GenerationProfileInput } from '../styling-profile-CxfvV48g.js';
|
|
10
|
+
import { LaunchOptions } from 'puppeteer-core';
|
|
11
|
+
import { C as CanvasClass, g as CanvasViewport } from '../design-mode-DLufhrNp.js';
|
|
12
|
+
export { a as CANVAS_BREAKPOINTS, b as CANVAS_CLASSES, c as CANVAS_DESCRIPTORS, d as CANVAS_VIEWPORTS, e as CanvasDescriptor, f as CanvasDisplayMode, j as canvasDisplayModeForShell, k as canvasForRendering, l as canvasForViewportWidth, m as describeCanvas } from '../design-mode-DLufhrNp.js';
|
|
13
|
+
import { AppTheme } from '@ggui-ai/protocol';
|
|
9
14
|
import '../axes-CzLEMDeB.js';
|
|
10
15
|
import '../types-BOvHNG7K.js';
|
|
11
16
|
import '../llm.js';
|
|
@@ -180,6 +185,30 @@ declare function extractCompiledCode(messages: SdkMessage[]): string | undefined
|
|
|
180
185
|
*/
|
|
181
186
|
declare function extractSourceCode(messages: SdkMessage[]): string | undefined;
|
|
182
187
|
|
|
188
|
+
interface JudgeDesignIdentity {
|
|
189
|
+
/** Absolute path of the design `src` tree the judge bundled against. */
|
|
190
|
+
readonly src: string;
|
|
191
|
+
/** sha256 over every rendering input under `src` (see {@link isDesignRenderingInput}) — sorted relative path, then contents. */
|
|
192
|
+
readonly srcSha256: string;
|
|
193
|
+
}
|
|
194
|
+
/** sha256 over every rendering input under `root` (sorted relative path + contents) — the identity of a design tree as it paints. */
|
|
195
|
+
declare function designTreeSha256(root: string): string;
|
|
196
|
+
/**
|
|
197
|
+
* The identity of the tree at `src`, computed once per process per path (a
|
|
198
|
+
* judge run paints hundreds of frames from one tree).
|
|
199
|
+
*
|
|
200
|
+
* `null` when the tree cannot be READ (ggui#1110): a deployed image ships the
|
|
201
|
+
* design package as built output with no `src/`, and an identity is a receipt
|
|
202
|
+
* about a judgement — never a precondition for making one. Before this,
|
|
203
|
+
* `scandir` threw ENOENT inside the evaluation round wherever the package ships
|
|
204
|
+
* built output only, the round returned no evaluation at all, and a bar refused
|
|
205
|
+
* a card that had cleared it. A row without the receipt says so; a round that cannot
|
|
206
|
+
* stamp one still runs.
|
|
207
|
+
*/
|
|
208
|
+
declare function judgeDesignIdentity(src: string): JudgeDesignIdentity | null;
|
|
209
|
+
/** Test seam: forget cached identities (a test that rewrites a tree between runs). */
|
|
210
|
+
declare function resetJudgeDesignIdentityCache(): void;
|
|
211
|
+
|
|
183
212
|
interface VisualEvalConfig {
|
|
184
213
|
/** LLM provider for multimodal evaluation */
|
|
185
214
|
provider: 'claude' | 'google';
|
|
@@ -194,12 +223,41 @@ interface VisualEvalConfig {
|
|
|
194
223
|
width: number;
|
|
195
224
|
height: number;
|
|
196
225
|
};
|
|
226
|
+
/**
|
|
227
|
+
* Per-canvas judging — ARM-NEUTRAL (the same judge, prompt and
|
|
228
|
+
* threshold in every design mode). When set, the SAME rendered HTML
|
|
229
|
+
* shell is screenshotted once per class at `CANVAS_VIEWPORTS[class]`
|
|
230
|
+
* and judged once per class; the result carries one entry per class
|
|
231
|
+
* in `canvases`, and the single-shot fields aggregate: `finalScore` =
|
|
232
|
+
* mean of the canvas scores (rounded), `passed` = every canvas passed,
|
|
233
|
+
* `dimensions` = per-dimension means, `issues` = every canvas's issues
|
|
234
|
+
* (description prefixed `[<canvas>]`). Unset (or empty) = today's
|
|
235
|
+
* single screenshot at `viewport`; no `canvases` field on the result.
|
|
236
|
+
*/
|
|
237
|
+
canvases?: readonly CanvasClass[];
|
|
197
238
|
/**
|
|
198
239
|
* Optional provider-routing override — see
|
|
199
240
|
* `AgentConfig.routeOverride`. Threaded onto the agent this
|
|
200
241
|
* evaluator constructs so its multimodal call never falls back to
|
|
201
242
|
* `process.env` for credentials or model routing.
|
|
202
243
|
*/
|
|
244
|
+
/**
|
|
245
|
+
* Vision calls per judged canvas on the SAME captured frame, aggregated by
|
|
246
|
+
* the median (ggui#1072). Default 1 — a single judgement, byte-identical to
|
|
247
|
+
* the instrument before this option existed. K is an instrument dial: a
|
|
248
|
+
* run mixes K at its own peril.
|
|
249
|
+
*/
|
|
250
|
+
judgeK?: number;
|
|
251
|
+
/** The canvases sampled `judgeK` times; default = every judged canvas when `judgeK > 1`. */
|
|
252
|
+
judgeKCanvases?: readonly CanvasClass[];
|
|
253
|
+
/**
|
|
254
|
+
* The design `src` tree the judge bundles the component against
|
|
255
|
+
* (ggui#1042): an explicit input, so a judge-only re-judge names the tree
|
|
256
|
+
* it painted with. Default: the design package beside this one.
|
|
257
|
+
*/
|
|
258
|
+
designSrcDir?: string;
|
|
259
|
+
/** 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). */
|
|
260
|
+
themeMode?: 'light' | 'dark';
|
|
203
261
|
routeOverride?: AgentConfig['routeOverride'];
|
|
204
262
|
/**
|
|
205
263
|
* Provider-429-retry observer — see `AgentConfig.onRetry`.
|
|
@@ -209,6 +267,170 @@ interface VisualEvalConfig {
|
|
|
209
267
|
*/
|
|
210
268
|
onRetry?: AgentConfig['onRetry'];
|
|
211
269
|
}
|
|
270
|
+
/** One canvas's verdict — screenshot + judge score at that class's viewport. */
|
|
271
|
+
interface CanvasVisualResult {
|
|
272
|
+
canvas: CanvasClass;
|
|
273
|
+
viewport: CanvasViewport;
|
|
274
|
+
/** The judge's weighted score for this canvas (0-100). */
|
|
275
|
+
score: number;
|
|
276
|
+
/** `score >= passThreshold`. */
|
|
277
|
+
passed: boolean;
|
|
278
|
+
/** The PNG the judge saw — kept for artefact persistence + the human look. */
|
|
279
|
+
screenshotPng: Buffer;
|
|
280
|
+
/**
|
|
281
|
+
* The document's scroll height at this canvas's viewport, CSS px — what
|
|
282
|
+
* the box would have to be for nothing to be hidden (ggui#1027). `null`
|
|
283
|
+
* when the page could not be measured.
|
|
284
|
+
*/
|
|
285
|
+
contentHeight: number | null;
|
|
286
|
+
/** `contentHeight > viewport.height` — a measurement; what it MEANS is {@link canvasFitPolicy}'s. */
|
|
287
|
+
overflow: boolean;
|
|
288
|
+
/** How `score` was reached — always present (ggui#1072). */
|
|
289
|
+
judge: CanvasJudgeRecord;
|
|
290
|
+
/** How the judge composed the mount (ggui#1100): `'fill'` on every fullscreen canvas, absent on the inline card. */
|
|
291
|
+
fit?: 'fill';
|
|
292
|
+
}
|
|
293
|
+
/** How a canvas is captured for the judge and what an overflow means there (ggui#1027). */
|
|
294
|
+
type CaptureMode = 'viewport' | 'full-page';
|
|
295
|
+
interface CanvasFitPolicy {
|
|
296
|
+
/** `viewport` = the judge sees the box the user sees; `full-page` = the whole scrolled document. */
|
|
297
|
+
readonly capture: CaptureMode;
|
|
298
|
+
/** The verdict an overflow earns on this canvas. */
|
|
299
|
+
readonly overflow: 'fail' | 'warn' | 'none';
|
|
300
|
+
}
|
|
301
|
+
/**
|
|
302
|
+
* The inline chat card is a BOX — the bubble bounds the component and it
|
|
303
|
+
* does not scroll — so the judge captures the viewport (a 1289 px hello on
|
|
304
|
+
* a 640 px card was scored 86 from a full-page capture that showed the
|
|
305
|
+
* judge what no user sees) and an overflow is a critical layout issue that
|
|
306
|
+
* fails the canvas. A phone's first screen may scroll, so the overflow is
|
|
307
|
+
* reported as a major issue and the score stands. Pages (`md`/`lg`/`xl`)
|
|
308
|
+
* scroll by design: measured, never judged.
|
|
309
|
+
*/
|
|
310
|
+
declare function canvasFitPolicy(canvas: CanvasClass): CanvasFitPolicy;
|
|
311
|
+
/** The deterministic fit issue — one per overflowing canvas, in the judge's issue shape so it rides the same channel. */
|
|
312
|
+
declare function canvasOverflowIssue(canvas: CanvasClass, viewport: CanvasViewport, contentHeight: number, verdict: 'fail' | 'warn'): EvaluationIssue;
|
|
313
|
+
/**
|
|
314
|
+
* `runVisualEvaluation`'s result. Identical to `EvaluationResult` when
|
|
315
|
+
* `config.canvases` is unset; with canvases set, `canvases` holds the
|
|
316
|
+
* per-class verdicts and the base fields aggregate them (see
|
|
317
|
+
* `VisualEvalConfig.canvases`).
|
|
318
|
+
*/
|
|
319
|
+
interface VisualEvaluationResult extends EvaluationResult {
|
|
320
|
+
canvases?: CanvasVisualResult[];
|
|
321
|
+
/** The design tree the judge painted with (ggui#1042) — present on every per-canvas judgement. */
|
|
322
|
+
design?: JudgeDesignIdentity;
|
|
323
|
+
/** The mode `cssTokens` were composed in, when the caller said (ggui#1076). */
|
|
324
|
+
themeMode?: 'light' | 'dark';
|
|
325
|
+
}
|
|
326
|
+
/** Injection points for `runVisualEvaluation` — screenshot deps plus the judge call (tests). */
|
|
327
|
+
interface VisualEvalDeps extends ScreenshotDeps {
|
|
328
|
+
/** The multimodal judge call (default: `callMultimodalLLM`). */
|
|
329
|
+
judge?: typeof callMultimodalLLM;
|
|
330
|
+
}
|
|
331
|
+
interface VisualEvalContext {
|
|
332
|
+
/** Compiled JavaScript code (ESM with imports) */
|
|
333
|
+
compiledCode: string;
|
|
334
|
+
/** Original user prompt */
|
|
335
|
+
originalPrompt: string;
|
|
336
|
+
/** Design system CSS tokens */
|
|
337
|
+
cssTokens?: string;
|
|
338
|
+
/** The app's generation profile (#991) — judged relative to, never against. */
|
|
339
|
+
profile?: GenerationProfileInput;
|
|
340
|
+
}
|
|
341
|
+
/**
|
|
342
|
+
* The `@ggui-ai/design` package root — resolved by MODULE ID, never by counting
|
|
343
|
+
* directories (ggui#1110).
|
|
344
|
+
*
|
|
345
|
+
* The arithmetic this replaced (`…/'..','..','..','design'`) was correct only
|
|
346
|
+
* for the layout it was written against — `node_modules/@ggui-ai/ui-gen/dist/
|
|
347
|
+
* evaluation` → `node_modules/@ggui-ai/` + `design`. Under a deploy-flattened
|
|
348
|
+
* layout it landed one level too high, at `node_modules/design`, a path that is
|
|
349
|
+
* not the design package at all: the judge then walked a directory that does not
|
|
350
|
+
* exist, threw ENOENT inside every evaluation round on that deployment, and a
|
|
351
|
+
* bar refused cards no one could judge. `@ggui-ai/design` exports `./package.json`,
|
|
352
|
+
* so the module resolver answers correctly in every layout — scoped, flattened,
|
|
353
|
+
* hoisted — and the receipt keeps working inside the image.
|
|
354
|
+
*/
|
|
355
|
+
declare function resolveDesignPackageDir(): string;
|
|
356
|
+
/** The page surface the capture uses — a structural subset of puppeteer's `Page`. */
|
|
357
|
+
interface ScreenshotPage {
|
|
358
|
+
setContent(html: string, options: {
|
|
359
|
+
waitUntil: 'load';
|
|
360
|
+
timeout: number;
|
|
361
|
+
}): Promise<void>;
|
|
362
|
+
waitForNetworkIdle(options: {
|
|
363
|
+
idleTime: number;
|
|
364
|
+
timeout: number;
|
|
365
|
+
}): Promise<void>;
|
|
366
|
+
waitForSelector(selector: string, options: {
|
|
367
|
+
timeout: number;
|
|
368
|
+
}): Promise<unknown>;
|
|
369
|
+
/** Evaluates a JS expression in the page and returns its serialised value — the fit measurement (ggui#1027). */
|
|
370
|
+
evaluate(expression: string): Promise<unknown>;
|
|
371
|
+
screenshot(options: {
|
|
372
|
+
type: 'png';
|
|
373
|
+
fullPage: boolean;
|
|
374
|
+
}): Promise<Uint8Array>;
|
|
375
|
+
}
|
|
376
|
+
/** The browser surface the capture uses — a structural subset of puppeteer's `Browser`. */
|
|
377
|
+
interface ScreenshotBrowser {
|
|
378
|
+
newPage(): Promise<ScreenshotPage>;
|
|
379
|
+
close(): Promise<void>;
|
|
380
|
+
}
|
|
381
|
+
type ScreenshotLauncher = (options: LaunchOptions) => Promise<ScreenshotBrowser>;
|
|
382
|
+
/** The two members of `@sparticuz/chromium` the fallback launch path reads. */
|
|
383
|
+
interface ChromiumProvider {
|
|
384
|
+
readonly args: string[];
|
|
385
|
+
executablePath(): Promise<string>;
|
|
386
|
+
}
|
|
387
|
+
/**
|
|
388
|
+
* Injection points for the capture — every default is the production
|
|
389
|
+
* path; tests replace them to pin branch selection without launching a
|
|
390
|
+
* browser.
|
|
391
|
+
*/
|
|
392
|
+
interface ScreenshotDeps {
|
|
393
|
+
/** Launches the browser (default: `puppeteer-core`'s `launch`). */
|
|
394
|
+
launch?: ScreenshotLauncher;
|
|
395
|
+
/** Environment the executable-path override is read from (default: `process.env`). */
|
|
396
|
+
env?: NodeJS.ProcessEnv;
|
|
397
|
+
/** Loads `@sparticuz/chromium` (default: dynamic import) — only consulted when no override is set. */
|
|
398
|
+
loadChromium?: () => Promise<ChromiumProvider>;
|
|
399
|
+
/** Post-load settle time before the screenshot, ms (default 1000). */
|
|
400
|
+
settleMs?: number;
|
|
401
|
+
}
|
|
402
|
+
/**
|
|
403
|
+
* Pick the browser binary. `PUPPETEER_EXECUTABLE_PATH` (a system
|
|
404
|
+
* Chromium — the bench runner image, a dev box) wins and skips the
|
|
405
|
+
* `@sparticuz/chromium` load entirely; otherwise the bundled Lambda
|
|
406
|
+
* Chromium supplies both binary and flags, as before.
|
|
407
|
+
*/
|
|
408
|
+
declare function resolveLaunchOptions(viewport: {
|
|
409
|
+
width: number;
|
|
410
|
+
height: number;
|
|
411
|
+
}, deps?: Pick<ScreenshotDeps, 'env' | 'loadChromium'>): Promise<LaunchOptions>;
|
|
412
|
+
/**
|
|
413
|
+
* Take a screenshot of the rendered component.
|
|
414
|
+
* Returns the PNG bytes, or null if no browser could be launched.
|
|
415
|
+
*/
|
|
416
|
+
/** Screenshot plus the reason when none could be taken — the judge's `unavailableReason`. */
|
|
417
|
+
interface ScreenshotAttempt {
|
|
418
|
+
readonly png: Buffer | null;
|
|
419
|
+
readonly reason?: string;
|
|
420
|
+
/** The document's scroll height at the viewport (ggui#1027); `null` when unmeasurable. */
|
|
421
|
+
readonly contentHeight: number | null;
|
|
422
|
+
}
|
|
423
|
+
/** The expression the fit measurement evaluates in the page — the taller of the two scroll heights. */
|
|
424
|
+
declare const CONTENT_HEIGHT_EXPRESSION = "Math.max(document.documentElement.scrollHeight, document.body ? document.body.scrollHeight : 0)";
|
|
425
|
+
declare function captureScreenshotDetailed(html: string, viewport?: {
|
|
426
|
+
width: number;
|
|
427
|
+
height: number;
|
|
428
|
+
}, deps?: ScreenshotDeps, capture?: CaptureMode): Promise<ScreenshotAttempt>;
|
|
429
|
+
declare function captureScreenshot(html: string, viewport?: {
|
|
430
|
+
width: number;
|
|
431
|
+
height: number;
|
|
432
|
+
}, deps?: ScreenshotDeps): Promise<Buffer | null>;
|
|
433
|
+
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}";
|
|
212
434
|
/**
|
|
213
435
|
* Send the screenshot to the configured multimodal provider through
|
|
214
436
|
* the shared `LLMAgent` machinery. Routing through `createVisionAgent`
|
|
@@ -219,6 +441,76 @@ interface VisualEvalConfig {
|
|
|
219
441
|
* governs credentials and model routing (including the Anthropic
|
|
220
442
|
* Bedrock path) instead of `process.env`.
|
|
221
443
|
*/
|
|
222
|
-
|
|
444
|
+
/**
|
|
445
|
+
* Output budget for the judge's answer. 1500 cut a board's issue list
|
|
446
|
+
* mid-array (`Expected ',' or ']' after array element`, six kanban cells
|
|
447
|
+
* on 2026-09-11) — deterministic on the content, so a same-prompt retry
|
|
448
|
+
* could never clear it. 4096 fits the bounded list the prompt now asks for
|
|
449
|
+
* with room; the salvage path covers the remainder.
|
|
450
|
+
*/
|
|
451
|
+
declare const VISUAL_JUDGE_MAX_OUTPUT_TOKENS = 4096;
|
|
452
|
+
/**
|
|
453
|
+
* The judge instrument's name and content digest, for the record a run
|
|
454
|
+
* stamps beside every visual score. The NAME is for readers; the DIGEST
|
|
455
|
+
* is computed from the prompt text at module load, so a stamped row can
|
|
456
|
+
* never claim a prompt version it did not run — change the prompt and the
|
|
457
|
+
* digest moves with it (the pin ties the name to the bounded-list text).
|
|
458
|
+
*/
|
|
459
|
+
declare const VISUAL_JUDGE_PROMPT_VERSION = "v2-bounded-issues";
|
|
460
|
+
declare const VISUAL_JUDGE_PROMPT_DIGEST: string;
|
|
461
|
+
declare function callMultimodalLLM(config: VisualEvalConfig, model: string, prompt: string, screenshot: Buffer, originalPrompt: string, profileBlock?: string): Promise<LLMResponse>;
|
|
462
|
+
/**
|
|
463
|
+
* Run visual evaluation on a compiled component.
|
|
464
|
+
*
|
|
465
|
+
* 1. Builds an HTML page with the component + sample props
|
|
466
|
+
* 2. Takes a screenshot via puppeteer (if available)
|
|
467
|
+
* 3. Sends screenshot to multimodal LLM for visual scoring
|
|
468
|
+
*
|
|
469
|
+
* Returns null if puppeteer is not available (graceful fallback).
|
|
470
|
+
*/
|
|
471
|
+
/**
|
|
472
|
+
* The judge's answer WITH the reason when it could not judge: `result` is
|
|
473
|
+
* null exactly when no screenshot could be taken (no browser, a launch or
|
|
474
|
+
* in-page failure) or the component could not be bundled; `unavailableReason`
|
|
475
|
+
* names why in words and `canvas` the canvas it happened at. A production
|
|
476
|
+
* caller records the reason in its receipt — a `judge_unavailable` that only
|
|
477
|
+
* says "null" cost a log dive on 2026-09-10 (puppeteer-core missing in the
|
|
478
|
+
* deploy image).
|
|
479
|
+
*/
|
|
480
|
+
interface VisualEvalDetailed {
|
|
481
|
+
readonly result: VisualEvaluationResult | null;
|
|
482
|
+
readonly unavailableReason?: string;
|
|
483
|
+
readonly canvas?: CanvasClass;
|
|
484
|
+
}
|
|
485
|
+
declare function runVisualEvaluation(context: VisualEvalContext, config: VisualEvalConfig, deps?: VisualEvalDeps): Promise<VisualEvaluationResult | null>;
|
|
486
|
+
declare function runVisualEvaluationDetailed(context: VisualEvalContext, config: VisualEvalConfig, deps?: VisualEvalDeps): Promise<VisualEvalDetailed>;
|
|
487
|
+
/** The per-canvas verdicts without the PNGs — what the harness stamps on `EvalResult.visual`. */
|
|
488
|
+
declare function summarizeVisualResult(result: VisualEvaluationResult): VisualEvalSummary | undefined;
|
|
489
|
+
|
|
490
|
+
/** What the harness's eval round consumes from the visual leg. */
|
|
491
|
+
interface VisualEvalOutcome {
|
|
492
|
+
/** Tier-2 issues (empty when no browser is available). */
|
|
493
|
+
issues: EvalIssue[];
|
|
494
|
+
/**
|
|
495
|
+
* Per-canvas summary — present ONLY when `config.canvases` was set and
|
|
496
|
+
* the leg ran; the harness stamps it on `EvalResult.visual`. Absent on
|
|
497
|
+
* the single-shot path (byte-identical to the pre-canvas result).
|
|
498
|
+
*/
|
|
499
|
+
summary?: VisualEvalSummary;
|
|
500
|
+
}
|
|
501
|
+
/**
|
|
502
|
+
* Run visual evaluation and return tier 2 EvalIssues (+ the per-canvas
|
|
503
|
+
* summary when canvases were requested).
|
|
504
|
+
*/
|
|
505
|
+
declare function runVisualEval(context: VisualEvalContext, config: VisualEvalConfig): Promise<VisualEvalOutcome>;
|
|
506
|
+
|
|
507
|
+
/**
|
|
508
|
+
* The stylesheet a visual judge renders under for an app: the app's theme
|
|
509
|
+
* composed the way the runtime composes it (`composeThemeCss`, layer `page`
|
|
510
|
+
* — one composition, never a second), so a judged canvas paints the tokens a
|
|
511
|
+
* visitor's page paints. Absent theme ⇒ the design's default tokens,
|
|
512
|
+
* byte-for-byte what the judge used before.
|
|
513
|
+
*/
|
|
514
|
+
declare function cssTokensForAppTheme(theme: AppTheme | undefined, mode?: 'light' | 'dark'): string;
|
|
223
515
|
|
|
224
|
-
export { type EvaluateScoreInput, EvaluationConfig, EvaluationContext, EvaluationIssue, type EvaluationLoopOptions, type EvaluationLoopResult, EvaluationResult, QualityMetadata, type SdkMessage, type VisualEvalConfig, buildFixPrompt, callMultimodalLLM, computeEvaluationScore, createEvaluationToolsServer, extractCompiledCode, extractCompiledCodeFromMessage, extractEvalResult, extractSourceCode, extractSourceCodeFromMessage, extractToolResultTexts, getEvaluatorSystemPrompt, runEvaluation, runEvaluationLoop };
|
|
516
|
+
export { CONTENT_HEIGHT_EXPRESSION, CanvasClass, type CanvasFitPolicy, CanvasJudgeRecord, CanvasViewport, type CanvasVisualResult, type CaptureMode, type ChromiumProvider, EvalIssue, type EvaluateScoreInput, EvaluationConfig, EvaluationContext, EvaluationIssue, type EvaluationLoopOptions, type EvaluationLoopResult, EvaluationResult, type JudgeDesignIdentity, QualityMetadata, type ScreenshotAttempt, type ScreenshotBrowser, type ScreenshotDeps, type ScreenshotLauncher, type ScreenshotPage, type SdkMessage, VISUAL_EVAL_PROMPT, VISUAL_JUDGE_MAX_OUTPUT_TOKENS, VISUAL_JUDGE_PROMPT_DIGEST, VISUAL_JUDGE_PROMPT_VERSION, type VisualEvalConfig, type VisualEvalContext, type VisualEvalDeps, type VisualEvalDetailed, type VisualEvalOutcome, VisualEvalSummary, type VisualEvaluationResult, buildFixPrompt, callMultimodalLLM, canvasFitPolicy, canvasOverflowIssue, captureScreenshot, captureScreenshotDetailed, computeEvaluationScore, createEvaluationToolsServer, cssTokensForAppTheme, designTreeSha256, extractCompiledCode, extractCompiledCodeFromMessage, extractEvalResult, extractSourceCode, extractSourceCodeFromMessage, extractToolResultTexts, getEvaluatorSystemPrompt, judgeDesignIdentity, resetJudgeDesignIdentityCache, resolveDesignPackageDir, resolveLaunchOptions, runEvaluation, runEvaluationLoop, runVisualEval, runVisualEvaluation, runVisualEvaluationDetailed, summarizeVisualResult };
|