@ggui-ai/ui-gen 0.20.0 → 0.22.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/base.d.ts +7 -0
- package/dist/adapters/base.js +1 -0
- package/dist/adapters/base.js.map +1 -1
- package/dist/adapters/generation-dispatch.d.ts +17 -3
- package/dist/adapters/generation-dispatch.js +1078 -3464
- package/dist/adapters/generation-dispatch.js.map +1 -1
- package/dist/adapters/index.js +60 -3
- package/dist/adapters/index.js.map +1 -1
- package/dist/advanced/index.d.ts +4 -4
- package/dist/advanced/index.js +1346 -3557
- package/dist/advanced/index.js.map +1 -1
- package/dist/blueprint-validator.js +10 -3
- package/dist/blueprint-validator.js.map +1 -1
- package/dist/boilerplate.js +2 -2
- package/dist/boilerplate.js.map +1 -1
- package/dist/check/index.d.ts +1 -1
- package/dist/check/index.js.map +1 -1
- package/dist/{create-ui-generator-CxPvudbs.d.ts → create-ui-generator-BEkzEtNz.d.ts} +2 -2
- package/dist/{dispatch-N8wdNOX-.d.ts → dispatch-DJNpQ7DI.d.ts} +1 -1
- package/dist/evaluation/axis-checks/index.d.ts +3 -3
- package/dist/evaluation/axis-checks/index.js.map +1 -1
- package/dist/evaluation/axis-checks/registry.d.ts +1 -1
- package/dist/evaluation/index.d.ts +38 -6
- package/dist/evaluation/index.js +670 -3374
- package/dist/evaluation/index.js.map +1 -1
- package/dist/harness/check/runtime-render/index.d.ts +2 -2
- package/dist/harness/check/runtime-render/index.js +10 -3
- package/dist/harness/check/runtime-render/index.js.map +1 -1
- package/dist/harness/check/runtime-render/render-check-worker.js +5 -3
- package/dist/harness/check/runtime-render/render-check-worker.js.map +1 -1
- package/dist/harness/index.d.ts +2 -2
- package/dist/harness/index.js +587 -30
- package/dist/harness/index.js.map +1 -1
- package/dist/harness/llm-trace-sink.d.ts +7 -1
- package/dist/harness/llm-trace-sink.js.map +1 -1
- package/dist/harness/prompts.js +1 -1
- package/dist/harness/prompts.js.map +1 -1
- package/dist/harness/result-types.d.ts +15 -2
- package/dist/harness/result-types.js.map +1 -1
- package/dist/harness/runtime.d.ts +11 -2
- package/dist/harness/runtime.js +3 -3
- package/dist/harness/runtime.js.map +1 -1
- package/dist/harness/types-public.d.ts +1 -1
- package/dist/harness/types-public.js +2 -2
- package/dist/harness/types-public.js.map +1 -1
- package/dist/harness/validator-trace-sink.d.ts +1 -1
- package/dist/index.d.ts +23 -7
- package/dist/index.js +1346 -3557
- package/dist/index.js.map +1 -1
- package/dist/{llm-router-D7fjBhtr.d.ts → llm-router-DwwUK1bz.d.ts} +16 -3
- package/dist/patch.d.ts +1 -1
- package/dist/providers/index.js +5 -4
- package/dist/providers/index.js.map +1 -1
- package/dist/{render-check-WfOVO9kU.d.ts → render-check-C0CqVceF.d.ts} +17 -0
- package/dist/{types-public-DKR_h70H.d.ts → types-public-mM_-1Yk3.d.ts} +59 -1
- 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/workflows.d.ts +1 -1
- package/package.json +16 -12
- package/src/adapters/base.ts +8 -0
- package/src/adapters/claude/claude-code-login.ts +128 -0
- package/src/adapters/claude/sdk.ts +9 -1
- package/src/adapters/generation-dispatch.ts +19 -2
- package/src/adapters/openai/tokens.ts +18 -0
- package/src/adapters/provider-router.ts +28 -0
- package/src/boilerplate/generate.ts +19 -4
- package/src/boilerplate/hard-sections.ts +1 -1
- package/src/boilerplate/templates/layouts/chat-mobile.tsx.tmpl +7 -3
- package/src/boilerplate/templates/layouts/chat-universal.tsx.tmpl +7 -3
- package/src/contract-context.ts +1 -1
- package/src/create-ui-generator.ts +49 -10
- package/src/evaluation/design-identity.ts +16 -5
- package/src/evaluation/index.ts +1 -0
- package/src/evaluation/llm-evaluator.ts +40 -13
- package/src/evaluation/types-public.ts +58 -0
- package/src/evaluation/visual-evaluator.ts +240 -30
- package/src/generator-build.ts +158 -0
- package/src/harness/check/runtime-render/adapter.ts +9 -0
- package/src/harness/check/runtime-render/render-check.ts +26 -5
- package/src/harness/claude-code-login-query.ts +529 -0
- package/src/harness/coding/assemble-result.ts +18 -2
- package/src/harness/coding/generate-task-runner.ts +75 -36
- package/src/harness/coding/run-coding-turn.ts +9 -0
- package/src/harness/coding/run-eval-round.ts +338 -38
- package/src/harness/enforced-coding.ts +20 -0
- package/src/harness/llm-router.ts +390 -55
- package/src/harness/llm-trace-sink.ts +7 -1
- package/src/harness/result-types.ts +14 -0
- package/src/harness/runtime.ts +6 -0
- package/src/index.ts +2 -1
- package/src/providers/openai.ts +31 -19
- package/src/validation/primitives.ts +1 -1
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The generator's BUILD identity (ggui#1280): values that change when the
|
|
3
|
+
* triad's templates change and never with the request, so generations group
|
|
4
|
+
* by the build that produced them.
|
|
5
|
+
*
|
|
6
|
+
* - `promptTemplateSha256` / `boilerplateTemplateSha256` are sha256 over the
|
|
7
|
+
* production system prompt and the boilerplate rendered on the design-mode
|
|
8
|
+
* pin's FIXED fixtures (`PIN_FIXTURES`), in the live env, so an env-gated
|
|
9
|
+
* block (the pitfalls) counts as it really is. The design-mode pin renders
|
|
10
|
+
* the same functions and asserts these values equal its recorded constants
|
|
11
|
+
* under the default env: the runtime key and the pin cannot drift.
|
|
12
|
+
* - These are BUILD keys, not instance fingerprints. A hash of the prompt one
|
|
13
|
+
* generation actually sent embeds the request and differs every time, so it
|
|
14
|
+
* could never group two generations by build.
|
|
15
|
+
* - `version` is the package's own version, read once from the nearest
|
|
16
|
+
* `package.json` named `@ggui-ai/ui-gen` above this module. It is absent
|
|
17
|
+
* when none is found (e.g. a consumer bundled this package into one file),
|
|
18
|
+
* never guessed.
|
|
19
|
+
*/
|
|
20
|
+
import { createHash } from 'node:crypto';
|
|
21
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
22
|
+
import { dirname, join } from 'node:path';
|
|
23
|
+
import { fileURLToPath } from 'node:url';
|
|
24
|
+
import type { GeneratorBuild } from '@ggui-ai/mcp-server-core';
|
|
25
|
+
import { generateBoilerplate } from './boilerplate/generate.js';
|
|
26
|
+
import type { DesignMode } from './design-mode.js';
|
|
27
|
+
import { buildSystemPrompt } from './harness/runtime.js';
|
|
28
|
+
import { PIN_FIXTURES } from './pin-fixtures.js';
|
|
29
|
+
|
|
30
|
+
/** The separator the rendered fixtures are joined with before hashing. */
|
|
31
|
+
export const TEMPLATE_FIXTURE_BOUNDARY = '\n<<<pin-fixture-boundary>>>\n';
|
|
32
|
+
|
|
33
|
+
/** sha256 hex of a rendered template. */
|
|
34
|
+
export function templateSha256(text: string): string {
|
|
35
|
+
return createHash('sha256').update(text, 'utf8').digest('hex');
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* The production system prompt for every pin fixture, joined. The constrained
|
|
40
|
+
* arm uses the positional default-path signature (no `designMode` argument),
|
|
41
|
+
* which is what the pin has always recorded.
|
|
42
|
+
*/
|
|
43
|
+
export function renderPromptTemplates(designMode: DesignMode): string {
|
|
44
|
+
return PIN_FIXTURES.map((f) => {
|
|
45
|
+
switch (designMode) {
|
|
46
|
+
case 'constrained':
|
|
47
|
+
return buildSystemPrompt(f.userRequest, f.shellType, f.screen);
|
|
48
|
+
case 'free':
|
|
49
|
+
return buildSystemPrompt(f.userRequest, f.shellType, f.screen, undefined, undefined, undefined, 'free');
|
|
50
|
+
}
|
|
51
|
+
}).join(TEMPLATE_FIXTURE_BOUNDARY);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** The boilerplate for every pin fixture, joined — same signature split as the prompt. */
|
|
55
|
+
export function renderBoilerplateTemplates(designMode: DesignMode): string {
|
|
56
|
+
return PIN_FIXTURES.map((f) => {
|
|
57
|
+
switch (designMode) {
|
|
58
|
+
case 'constrained':
|
|
59
|
+
return generateBoilerplate(f.userRequest, f.contract, f.shellType, f.screen);
|
|
60
|
+
case 'free':
|
|
61
|
+
return generateBoilerplate(f.userRequest, f.contract, f.shellType, f.screen, undefined, undefined, 'free');
|
|
62
|
+
}
|
|
63
|
+
}).join(TEMPLATE_FIXTURE_BOUNDARY);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* ui-gen's precise {@link GeneratorBuild}: the core port's generic shape with
|
|
68
|
+
* ui-gen's own keys — `mode` is the design mode, and `digests` names the two
|
|
69
|
+
* template digests (the keys a blueprint's build stamp copies).
|
|
70
|
+
*/
|
|
71
|
+
export interface UiGenBuild extends GeneratorBuild {
|
|
72
|
+
/** This package's version; absent when its `package.json` cannot be found at runtime. */
|
|
73
|
+
readonly version?: string;
|
|
74
|
+
readonly mode: DesignMode;
|
|
75
|
+
readonly digests: {
|
|
76
|
+
readonly promptTemplateSha256: string;
|
|
77
|
+
readonly boilerplateTemplateSha256: string;
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const PACKAGE_NAME = '@ggui-ai/ui-gen';
|
|
82
|
+
/** How far up from this module the package root can sit (`src/`, `dist/`, a nested entry). */
|
|
83
|
+
const MAX_PACKAGE_DEPTH = 6;
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* A `package.json` the walk meets may not be ours, and in a consumer's bundle
|
|
87
|
+
* it may not even parse. A candidate that does not parse is skipped (as if
|
|
88
|
+
* absent), so reading this package's version can never fail a generation —
|
|
89
|
+
* the version is then absent, never guessed. Only a JSON `SyntaxError` is
|
|
90
|
+
* handled here; any other error is a real fault and propagates.
|
|
91
|
+
*/
|
|
92
|
+
function parsePackageJson(text: string): unknown {
|
|
93
|
+
try {
|
|
94
|
+
const parsed: unknown = JSON.parse(text);
|
|
95
|
+
return parsed;
|
|
96
|
+
} catch (err) {
|
|
97
|
+
if (err instanceof SyntaxError) return undefined;
|
|
98
|
+
throw err;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Walk up from `startDir` (this module's own directory by default) to the
|
|
104
|
+
* nearest `package.json` named `@ggui-ai/ui-gen` and return its version;
|
|
105
|
+
* `undefined` when none is found within reach.
|
|
106
|
+
*/
|
|
107
|
+
export function findPackageVersion(startDir: string = dirname(fileURLToPath(import.meta.url))): string | undefined {
|
|
108
|
+
let dir = startDir;
|
|
109
|
+
for (let i = 0; i < MAX_PACKAGE_DEPTH; i++) {
|
|
110
|
+
const candidate = join(dir, 'package.json');
|
|
111
|
+
const pkg = existsSync(candidate) ? parsePackageJson(readFileSync(candidate, 'utf8')) : undefined;
|
|
112
|
+
if (pkg !== undefined) {
|
|
113
|
+
if (
|
|
114
|
+
typeof pkg === 'object' &&
|
|
115
|
+
pkg !== null &&
|
|
116
|
+
'name' in pkg &&
|
|
117
|
+
pkg.name === PACKAGE_NAME &&
|
|
118
|
+
'version' in pkg &&
|
|
119
|
+
typeof pkg.version === 'string'
|
|
120
|
+
) {
|
|
121
|
+
return pkg.version;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
const parent = dirname(dir);
|
|
125
|
+
if (parent === dir) break;
|
|
126
|
+
dir = parent;
|
|
127
|
+
}
|
|
128
|
+
return undefined;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
let versionRead = false;
|
|
132
|
+
let packageVersion: string | undefined;
|
|
133
|
+
const identities = new Map<string, UiGenBuild>();
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* The build identity for `designMode`, computed once per process per design
|
|
137
|
+
* mode and pitfalls env gate (the only env the templates read), so a changed
|
|
138
|
+
* gate is never answered from a stale memo.
|
|
139
|
+
*/
|
|
140
|
+
export function generatorBuild(designMode: DesignMode): UiGenBuild {
|
|
141
|
+
const key = `${designMode}|${process.env.GGUI_PITFALLS ?? ''}|${process.env.GGUI_NEW_PITFALLS ?? ''}`;
|
|
142
|
+
const known = identities.get(key);
|
|
143
|
+
if (known !== undefined) return known;
|
|
144
|
+
if (!versionRead) {
|
|
145
|
+
packageVersion = findPackageVersion();
|
|
146
|
+
versionRead = true;
|
|
147
|
+
}
|
|
148
|
+
const identity: UiGenBuild = {
|
|
149
|
+
...(packageVersion !== undefined ? { version: packageVersion } : {}),
|
|
150
|
+
mode: designMode,
|
|
151
|
+
digests: {
|
|
152
|
+
promptTemplateSha256: templateSha256(renderPromptTemplates(designMode)),
|
|
153
|
+
boilerplateTemplateSha256: templateSha256(renderBoilerplateTemplates(designMode)),
|
|
154
|
+
},
|
|
155
|
+
};
|
|
156
|
+
identities.set(key, identity);
|
|
157
|
+
return identity;
|
|
158
|
+
}
|
|
@@ -203,6 +203,15 @@ function toEvalIssue(issue: RenderCheckIssue): EvalIssue | null {
|
|
|
203
203
|
if (diag?.actionsFiredFromClicks?.length) {
|
|
204
204
|
diagParts.push(`other actions fired from clicks: ${diag.actionsFiredFromClicks.join(", ")}`);
|
|
205
205
|
}
|
|
206
|
+
if (diag?.inputPriming) {
|
|
207
|
+
// ggui#1187: an input-gated action that "did not dispatch" reads
|
|
208
|
+
// differently beside "primed 0" / a priming error than beside "primed 1".
|
|
209
|
+
diagParts.push(
|
|
210
|
+
"primed" in diag.inputPriming
|
|
211
|
+
? `input priming: ${diag.inputPriming.primed} control(s) filled before the click`
|
|
212
|
+
: `input priming failed: ${diag.inputPriming.error}`,
|
|
213
|
+
);
|
|
214
|
+
}
|
|
206
215
|
const diagSuffix = diagParts.length ? ` [observed: ${diagParts.join("; ")}]` : "";
|
|
207
216
|
|
|
208
217
|
switch (issue.check) {
|
|
@@ -99,9 +99,25 @@ export interface RenderCheckIssue {
|
|
|
99
99
|
readonly actionsFiredFromClicks?: readonly string[];
|
|
100
100
|
/** Surfaced to the agent: prop sourceTool hints from the contract (only if present). */
|
|
101
101
|
readonly sourceToolHints?: Readonly<Record<string, string>>;
|
|
102
|
+
/**
|
|
103
|
+
* For action-wiring (ggui#1187): what input priming did before the
|
|
104
|
+
* synthetic dispatch — how many controls it filled, or why it could not
|
|
105
|
+
* run. A "did not dispatch it" on an input-gated action reads differently
|
|
106
|
+
* beside `{ primed: 0 }` or `{ error }` than beside `{ primed: 1 }`.
|
|
107
|
+
*/
|
|
108
|
+
readonly inputPriming?: InputPrimingDiagnostic;
|
|
102
109
|
};
|
|
103
110
|
}
|
|
104
111
|
|
|
112
|
+
/**
|
|
113
|
+
* Outcome of `primeInputs` before the action-wiring probe (ggui#1187). A
|
|
114
|
+
* priming failure never aborts the check — it is recorded here, on every
|
|
115
|
+
* action-wiring issue, so it is visible in the feedback instead of vanishing.
|
|
116
|
+
*/
|
|
117
|
+
export type InputPrimingDiagnostic =
|
|
118
|
+
| { readonly primed: number }
|
|
119
|
+
| { readonly error: string };
|
|
120
|
+
|
|
105
121
|
export interface RenderCheckResult {
|
|
106
122
|
readonly ok: boolean;
|
|
107
123
|
readonly issues: readonly RenderCheckIssue[];
|
|
@@ -513,11 +529,16 @@ export async function runRenderCheckInProcess(
|
|
|
513
529
|
// sets input VALUES (not textContent) and fires input/change before the
|
|
514
530
|
// per-candidate fire-log window is opened, so it neither perturbs the
|
|
515
531
|
// prop-sensitivity text baseline nor false-positives the wiring probe.
|
|
516
|
-
//
|
|
532
|
+
// A priming failure never aborts the check — it is RECORDED on every
|
|
533
|
+
// action-wiring issue as `diagnostics.inputPriming`. (The first cut
|
|
534
|
+
// swallowed it, and a `ReferenceError` in the check worker's realm —
|
|
535
|
+
// no `HTMLInputElement` on `globalThis` — hid behind that catch while
|
|
536
|
+
// every chat cell kept warning.)
|
|
537
|
+
let inputPriming: InputPrimingDiagnostic;
|
|
517
538
|
try {
|
|
518
|
-
primeInputs(renderResult.container);
|
|
519
|
-
} catch {
|
|
520
|
-
|
|
539
|
+
inputPriming = { primed: primeInputs(renderResult.container) };
|
|
540
|
+
} catch (err) {
|
|
541
|
+
inputPriming = { error: err instanceof Error ? err.message : String(err) };
|
|
521
542
|
}
|
|
522
543
|
// ── Check 2: Action wiring (BLOCK / unverified-as-warn) ───────────
|
|
523
544
|
if (input.contract?.actionSpec) {
|
|
@@ -537,7 +558,7 @@ export async function runRenderCheckInProcess(
|
|
|
537
558
|
probe,
|
|
538
559
|
user,
|
|
539
560
|
});
|
|
540
|
-
if (issue) issues.push(issue);
|
|
561
|
+
if (issue) issues.push({ ...issue, diagnostics: { ...issue.diagnostics, inputPriming } });
|
|
541
562
|
}
|
|
542
563
|
}
|
|
543
564
|
|