@ggui-ai/ui-gen 0.19.0 → 0.20.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.js +51 -2
- package/dist/adapters/generation-dispatch.js.map +1 -1
- package/dist/adapters/index.js +35 -10
- package/dist/adapters/index.js.map +1 -1
- package/dist/adapters/types.d.ts +1 -1
- package/dist/adapters/types.js.map +1 -1
- package/dist/advanced/index.js +86 -12
- package/dist/advanced/index.js.map +1 -1
- package/dist/blueprint-validator.js +5 -2
- package/dist/blueprint-validator.js.map +1 -1
- package/dist/evaluation/axis-checks/index.js +46 -0
- package/dist/evaluation/axis-checks/index.js.map +1 -1
- package/dist/evaluation/axis-checks/registry.js +46 -0
- package/dist/evaluation/axis-checks/registry.js.map +1 -1
- package/dist/evaluation/index.js +46 -0
- package/dist/evaluation/index.js.map +1 -1
- package/dist/harness/check/runtime-render/index.js +5 -2
- package/dist/harness/check/runtime-render/index.js.map +1 -1
- package/dist/harness/check/runtime-render/render-check-worker.js +5 -2
- package/dist/harness/check/runtime-render/render-check-worker.js.map +1 -1
- package/dist/harness/index.js.map +1 -1
- package/dist/harness/types-public.js.map +1 -1
- package/dist/index.js +86 -12
- package/dist/index.js.map +1 -1
- package/package.json +12 -12
- package/src/adapters/openai/raw.ts +11 -5
- package/src/adapters/openai/sdk.ts +8 -5
- package/src/adapters/openai/tokens.ts +49 -0
- package/src/adapters/types.ts +1 -1
- package/src/evaluation/axis-checks/checks/universal.ts +92 -0
- package/src/harness/check/runtime-render/render-check.ts +15 -0
package/dist/adapters/types.d.ts
CHANGED
|
@@ -62,7 +62,7 @@ interface AdapterResult {
|
|
|
62
62
|
subagentsUsed?: string[];
|
|
63
63
|
/** Tokens written to prompt cache (Claude-specific) */
|
|
64
64
|
cacheCreationTokens?: number;
|
|
65
|
-
/** Tokens read from prompt cache (Claude
|
|
65
|
+
/** Tokens read from prompt cache (Claude / OpenRouter / OpenAI). */
|
|
66
66
|
cacheReadTokens?: number;
|
|
67
67
|
/** SDK session ID for evaluation loop resume (Claude SDK-specific) */
|
|
68
68
|
sdkSessionId?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/adapters/types.ts"],"names":[],"mappings":";AAcO,IAAM,sBAAA,GAAuD;AAAA,EAClE,MAAA,EAAQ,kBAAA;AAAA,EACR,MAAA,EAAQ,QAAA;AAAA,EACR,MAAA,EAAQ,eAAA;AAAA,EACR,UAAA,EAAY;AACd","file":"types.js","sourcesContent":["// packages/ui-gen/src/adapters/types.ts\n//\n// Production adapter types — used by both Lambda generation and benchmarks.\n\nimport type { z } from 'zod';\nimport type { JsonObject } from '@ggui-ai/protocol';\n\n// =============================================================================\n// Provider & Mode\n// =============================================================================\n\nexport type ProviderName = 'claude' | 'openai' | 'google' | 'openrouter';\nexport type AdapterMode = 'raw' | 'sdk' | 'multi-agent';\n\nexport const PROVIDER_DISPLAY_NAMES: Record<ProviderName, string> = {\n claude: 'Anthropic Claude',\n openai: 'OpenAI',\n google: 'Google Gemini',\n openrouter: 'OpenRouter',\n};\n\n// =============================================================================\n// Tool Definition (SDK-agnostic)\n// =============================================================================\n\nexport interface ToolResultContent {\n type: 'text';\n text: string;\n}\n\nexport interface ToolResult {\n content: ToolResultContent[];\n isError?: boolean;\n}\n\n/**\n * SDK-agnostic tool definition.\n * Each adapter converts these to its native tool format.\n */\nexport interface ToolDefinition {\n /** Tool name (e.g., 'compile_component') */\n name: string;\n /** Tool description for the LLM */\n description: string;\n /** Zod schema for input parameters (always an object schema — tools take named args) */\n inputSchema: z.ZodObject<z.ZodRawShape>;\n /** Handler function — same signature regardless of SDK */\n handler: (args: JsonObject) => Promise<ToolResult>;\n}\n\n// =============================================================================\n// Adapter Result\n// =============================================================================\n\n/**\n * Result returned by any adapter's generate() method.\n *\n * Core fields are populated by all adapters. Extended fields are\n * populated by adapters that support richer output (e.g., Claude SDK).\n */\nexport interface AdapterResult {\n /** Final compiled JavaScript component code */\n compiledCode: string;\n /** TSX source code (captured from compile_component input) */\n sourceCode?: string;\n /** Token usage breakdown */\n tokens: {\n input: number;\n output: number;\n total: number;\n };\n /** Wall-clock generation time in ms */\n generationTimeMs: number;\n /** Total number of LLM API calls across all phases */\n turnsUsed: number;\n /** Number of harness iterations (Plan→Code→Evaluate→Regen cycles). 1 = single pass. */\n iterations?: number;\n /** Raw cost from SDK if available */\n rawCostUsd?: number;\n\n // ── Extended fields (production use) ───────────────────────────────\n\n /** Data spec for ggui_emit — describes what data the component accepts */\n stream?: JsonObject;\n /** LLM-generated metadata annotation for blueprint indexing */\n generatorMeta?: { category: string; description: string };\n /** Names of subagents invoked during generation */\n subagentsUsed?: string[];\n /** Tokens written to prompt cache (Claude-specific) */\n cacheCreationTokens?: number;\n /** Tokens read from prompt cache (Claude
|
|
1
|
+
{"version":3,"sources":["../../src/adapters/types.ts"],"names":[],"mappings":";AAcO,IAAM,sBAAA,GAAuD;AAAA,EAClE,MAAA,EAAQ,kBAAA;AAAA,EACR,MAAA,EAAQ,QAAA;AAAA,EACR,MAAA,EAAQ,eAAA;AAAA,EACR,UAAA,EAAY;AACd","file":"types.js","sourcesContent":["// packages/ui-gen/src/adapters/types.ts\n//\n// Production adapter types — used by both Lambda generation and benchmarks.\n\nimport type { z } from 'zod';\nimport type { JsonObject } from '@ggui-ai/protocol';\n\n// =============================================================================\n// Provider & Mode\n// =============================================================================\n\nexport type ProviderName = 'claude' | 'openai' | 'google' | 'openrouter';\nexport type AdapterMode = 'raw' | 'sdk' | 'multi-agent';\n\nexport const PROVIDER_DISPLAY_NAMES: Record<ProviderName, string> = {\n claude: 'Anthropic Claude',\n openai: 'OpenAI',\n google: 'Google Gemini',\n openrouter: 'OpenRouter',\n};\n\n// =============================================================================\n// Tool Definition (SDK-agnostic)\n// =============================================================================\n\nexport interface ToolResultContent {\n type: 'text';\n text: string;\n}\n\nexport interface ToolResult {\n content: ToolResultContent[];\n isError?: boolean;\n}\n\n/**\n * SDK-agnostic tool definition.\n * Each adapter converts these to its native tool format.\n */\nexport interface ToolDefinition {\n /** Tool name (e.g., 'compile_component') */\n name: string;\n /** Tool description for the LLM */\n description: string;\n /** Zod schema for input parameters (always an object schema — tools take named args) */\n inputSchema: z.ZodObject<z.ZodRawShape>;\n /** Handler function — same signature regardless of SDK */\n handler: (args: JsonObject) => Promise<ToolResult>;\n}\n\n// =============================================================================\n// Adapter Result\n// =============================================================================\n\n/**\n * Result returned by any adapter's generate() method.\n *\n * Core fields are populated by all adapters. Extended fields are\n * populated by adapters that support richer output (e.g., Claude SDK).\n */\nexport interface AdapterResult {\n /** Final compiled JavaScript component code */\n compiledCode: string;\n /** TSX source code (captured from compile_component input) */\n sourceCode?: string;\n /** Token usage breakdown */\n tokens: {\n input: number;\n output: number;\n total: number;\n };\n /** Wall-clock generation time in ms */\n generationTimeMs: number;\n /** Total number of LLM API calls across all phases */\n turnsUsed: number;\n /** Number of harness iterations (Plan→Code→Evaluate→Regen cycles). 1 = single pass. */\n iterations?: number;\n /** Raw cost from SDK if available */\n rawCostUsd?: number;\n\n // ── Extended fields (production use) ───────────────────────────────\n\n /** Data spec for ggui_emit — describes what data the component accepts */\n stream?: JsonObject;\n /** LLM-generated metadata annotation for blueprint indexing */\n generatorMeta?: { category: string; description: string };\n /** Names of subagents invoked during generation */\n subagentsUsed?: string[];\n /** Tokens written to prompt cache (Claude-specific) */\n cacheCreationTokens?: number;\n /** Tokens read from prompt cache (Claude / OpenRouter / OpenAI). */\n cacheReadTokens?: number;\n /** SDK session ID for evaluation loop resume (Claude SDK-specific) */\n sdkSessionId?: string;\n}\n"]}
|
package/dist/advanced/index.js
CHANGED
|
@@ -22,6 +22,7 @@ import { createBrotliDecompress, createUnzip } from 'zlib';
|
|
|
22
22
|
import { PlaywrightNotAvailableError, validateContractBehavior } from '@ggui-ai/ui-visual-tester';
|
|
23
23
|
import { parseGeneratorSlug, formatGeneratorSlug, isValidGeneratorSlug } from '@ggui-ai/mcp-server-core';
|
|
24
24
|
import { LUCIDE_ICON_NAMES, maxWidth } from '@ggui-ai/design';
|
|
25
|
+
import { primeInputs } from '@ggui-ai/ui-visual-tester/prime-inputs';
|
|
25
26
|
import git from 'isomorphic-git';
|
|
26
27
|
import { Volume, createFsFromVolume } from 'memfs';
|
|
27
28
|
import { createPatch, applyPatch } from 'diff';
|
|
@@ -681,6 +682,27 @@ var init_sdk = __esm({
|
|
|
681
682
|
}
|
|
682
683
|
});
|
|
683
684
|
|
|
685
|
+
// src/adapters/openai/tokens.ts
|
|
686
|
+
function splitOpenAiUsage(inputTokensInclCached, outputTokens, cachedTokens) {
|
|
687
|
+
const cacheRead = Math.min(
|
|
688
|
+
Math.max(cachedTokens, 0),
|
|
689
|
+
Math.max(inputTokensInclCached, 0)
|
|
690
|
+
);
|
|
691
|
+
const nonCachedInput = Math.max(inputTokensInclCached, 0) - cacheRead;
|
|
692
|
+
return {
|
|
693
|
+
tokens: {
|
|
694
|
+
input: nonCachedInput,
|
|
695
|
+
output: outputTokens,
|
|
696
|
+
total: nonCachedInput + cacheRead + outputTokens
|
|
697
|
+
},
|
|
698
|
+
cacheReadTokens: cacheRead
|
|
699
|
+
};
|
|
700
|
+
}
|
|
701
|
+
var init_tokens = __esm({
|
|
702
|
+
"src/adapters/openai/tokens.ts"() {
|
|
703
|
+
}
|
|
704
|
+
});
|
|
705
|
+
|
|
684
706
|
// src/adapters/openai/raw.ts
|
|
685
707
|
var raw_exports2 = {};
|
|
686
708
|
__export(raw_exports2, {
|
|
@@ -703,6 +725,7 @@ var init_raw2 = __esm({
|
|
|
703
725
|
"src/adapters/openai/raw.ts"() {
|
|
704
726
|
init_base();
|
|
705
727
|
init_tool_bridge();
|
|
728
|
+
init_tokens();
|
|
706
729
|
init_extract_code();
|
|
707
730
|
OpenAiRawAdapter = class extends GeneratorAdapter {
|
|
708
731
|
provider = "openai";
|
|
@@ -727,6 +750,7 @@ var init_raw2 = __esm({
|
|
|
727
750
|
const capture = createCapture();
|
|
728
751
|
let totalInputTokens = 0;
|
|
729
752
|
let totalOutputTokens = 0;
|
|
753
|
+
let totalCachedInputTokens = 0;
|
|
730
754
|
let turnsUsed = 0;
|
|
731
755
|
let allTextOutput = "";
|
|
732
756
|
let response = await this.client.responses.create({
|
|
@@ -742,6 +766,7 @@ var init_raw2 = __esm({
|
|
|
742
766
|
if (response.usage) {
|
|
743
767
|
totalInputTokens += response.usage.input_tokens ?? 0;
|
|
744
768
|
totalOutputTokens += response.usage.output_tokens ?? 0;
|
|
769
|
+
totalCachedInputTokens += response.usage.input_tokens_details?.cached_tokens ?? 0;
|
|
745
770
|
}
|
|
746
771
|
const output = response.output ?? [];
|
|
747
772
|
const functionCalls = output.filter(
|
|
@@ -807,11 +832,11 @@ var init_raw2 = __esm({
|
|
|
807
832
|
sourceCode: capture.sourceCode,
|
|
808
833
|
stream: capture.stream,
|
|
809
834
|
generatorMeta: capture.generatorMeta,
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
835
|
+
...splitOpenAiUsage(
|
|
836
|
+
totalInputTokens,
|
|
837
|
+
totalOutputTokens,
|
|
838
|
+
totalCachedInputTokens
|
|
839
|
+
),
|
|
815
840
|
generationTimeMs: Date.now() - startTime,
|
|
816
841
|
turnsUsed
|
|
817
842
|
};
|
|
@@ -832,6 +857,7 @@ var OpenAiSdkAdapter;
|
|
|
832
857
|
var init_sdk2 = __esm({
|
|
833
858
|
"src/adapters/openai/sdk.ts"() {
|
|
834
859
|
init_base();
|
|
860
|
+
init_tokens();
|
|
835
861
|
init_extract_code();
|
|
836
862
|
OpenAiSdkAdapter = class extends GeneratorAdapter {
|
|
837
863
|
provider = "openai";
|
|
@@ -883,16 +909,16 @@ var init_sdk2 = __esm({
|
|
|
883
909
|
const usage = result.state.usage;
|
|
884
910
|
const inputTokens = usage.inputTokens;
|
|
885
911
|
const outputTokens = usage.outputTokens;
|
|
912
|
+
const cachedInputTokens = (usage.inputTokensDetails ?? []).reduce(
|
|
913
|
+
(sum, details) => sum + (details.cached_tokens ?? 0),
|
|
914
|
+
0
|
|
915
|
+
);
|
|
886
916
|
return {
|
|
887
917
|
compiledCode: capture.compiledCode,
|
|
888
918
|
sourceCode: capture.sourceCode,
|
|
889
919
|
stream: capture.stream,
|
|
890
920
|
generatorMeta: capture.generatorMeta,
|
|
891
|
-
|
|
892
|
-
input: inputTokens,
|
|
893
|
-
output: outputTokens,
|
|
894
|
-
total: inputTokens + outputTokens
|
|
895
|
-
},
|
|
921
|
+
...splitOpenAiUsage(inputTokens, outputTokens, cachedInputTokens),
|
|
896
922
|
generationTimeMs: Date.now() - startTime,
|
|
897
923
|
turnsUsed: result.rawResponses?.length ?? 0
|
|
898
924
|
};
|
|
@@ -13365,6 +13391,46 @@ function runRootWidthCap(input) {
|
|
|
13365
13391
|
)
|
|
13366
13392
|
];
|
|
13367
13393
|
}
|
|
13394
|
+
var LABEL_SPECIAL_CHAR = /[^a-z0-9\s]/i;
|
|
13395
|
+
var normText = (s) => s.toLowerCase().replace(/\s+/g, " ").trim();
|
|
13396
|
+
var alnumText = (s) => s.toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
13397
|
+
function visibleText(sourceCode) {
|
|
13398
|
+
const jsx = (sourceCode.match(/>([^<>]*)</g) ?? []).map((m2) => m2.slice(1, -1).replace(/\{[^}]*\}/g, " ")).join(" ");
|
|
13399
|
+
let attrs = "";
|
|
13400
|
+
const attrRx = /\b(?:aria-label|placeholder|title|alt)\s*=\s*(?:"([^"]*)"|'([^']*)')/gi;
|
|
13401
|
+
let m;
|
|
13402
|
+
while ((m = attrRx.exec(sourceCode)) !== null) attrs += " " + (m[1] ?? m[2] ?? "");
|
|
13403
|
+
return jsx + " " + attrs;
|
|
13404
|
+
}
|
|
13405
|
+
function findDroppedActionLabels(sourceCode, contract) {
|
|
13406
|
+
const actionSpec = contract?.actionSpec;
|
|
13407
|
+
if (actionSpec === void 0) return [];
|
|
13408
|
+
if (/\.label\b/.test(sourceCode)) return [];
|
|
13409
|
+
const vis = visibleText(sourceCode);
|
|
13410
|
+
const normVis = normText(vis);
|
|
13411
|
+
const alnumVis = alnumText(vis);
|
|
13412
|
+
const out = [];
|
|
13413
|
+
for (const [name, entry] of Object.entries(actionSpec)) {
|
|
13414
|
+
const label = entry.label;
|
|
13415
|
+
if (typeof label !== "string" || label.length === 0 || label === name) continue;
|
|
13416
|
+
if (!LABEL_SPECIAL_CHAR.test(label)) continue;
|
|
13417
|
+
if (alnumText(label).length < 3) continue;
|
|
13418
|
+
if (normVis.includes(normText(label))) continue;
|
|
13419
|
+
if (alnumVis.includes(alnumText(label))) out.push({ name, label });
|
|
13420
|
+
}
|
|
13421
|
+
return out;
|
|
13422
|
+
}
|
|
13423
|
+
function runActionLabelDropped(input) {
|
|
13424
|
+
if (input.compiledCode === null) return [];
|
|
13425
|
+
return findDroppedActionLabels(input.sourceCode, input.contract).map(
|
|
13426
|
+
({ name, label }) => mkIssue(
|
|
13427
|
+
"universal.action_label_dropped",
|
|
13428
|
+
`The action "${name}" declares label "${label}", but the rendered control appears to drop its "${label.replace(/[a-z0-9\s]/gi, "").trim()}": the label's words are in the generated source, the full label is not \u2014 a transcription drop (ggui#1190).`,
|
|
13429
|
+
`Render the label EXACTLY as the contract states it \u2014 button text should be the verbatim \`actionSpec.${name}.label\`, or render it from data (\`{x.label}\`), never a re-typed copy that drops "&", "/", "+", etc.`,
|
|
13430
|
+
"warn"
|
|
13431
|
+
)
|
|
13432
|
+
);
|
|
13433
|
+
}
|
|
13368
13434
|
var UNIVERSAL_CHECKS = [
|
|
13369
13435
|
{
|
|
13370
13436
|
id: "universal.icon_name_known",
|
|
@@ -13390,6 +13456,12 @@ var UNIVERSAL_CHECKS = [
|
|
|
13390
13456
|
values: ALL_RENDER_VALUES,
|
|
13391
13457
|
run: runRootWidthCap
|
|
13392
13458
|
},
|
|
13459
|
+
{
|
|
13460
|
+
id: "universal.action_label_dropped",
|
|
13461
|
+
axis: "render",
|
|
13462
|
+
values: ALL_RENDER_VALUES,
|
|
13463
|
+
run: runActionLabelDropped
|
|
13464
|
+
},
|
|
13393
13465
|
{
|
|
13394
13466
|
id: "universal.terminal_action_unguarded",
|
|
13395
13467
|
axis: "render",
|
|
@@ -17619,8 +17691,6 @@ function editableSurface(el) {
|
|
|
17619
17691
|
function parentLink(node) {
|
|
17620
17692
|
return node;
|
|
17621
17693
|
}
|
|
17622
|
-
|
|
17623
|
-
// src/harness/check/runtime-render/render-check.ts
|
|
17624
17694
|
async function runRenderCheck(input) {
|
|
17625
17695
|
const g = hostGlobals();
|
|
17626
17696
|
if ("window" in g && "document" in g) {
|
|
@@ -17799,6 +17869,10 @@ async function runRenderCheckInProcess(input) {
|
|
|
17799
17869
|
let actionsChecked = 0;
|
|
17800
17870
|
let streamsChecked = 0;
|
|
17801
17871
|
try {
|
|
17872
|
+
try {
|
|
17873
|
+
primeInputs(renderResult.container);
|
|
17874
|
+
} catch {
|
|
17875
|
+
}
|
|
17802
17876
|
if (input.contract?.actionSpec) {
|
|
17803
17877
|
const actionSpec = input.contract.actionSpec;
|
|
17804
17878
|
for (const [name, entry] of Object.entries(actionSpec)) {
|