@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/index.js CHANGED
@@ -21,6 +21,7 @@ import { pipeline } from 'stream/promises';
21
21
  import { createBrotliDecompress, createUnzip } from 'zlib';
22
22
  import { parseGeneratorSlug, formatGeneratorSlug, isValidGeneratorSlug } from '@ggui-ai/mcp-server-core';
23
23
  import { LUCIDE_ICON_NAMES, maxWidth } from '@ggui-ai/design';
24
+ import { primeInputs } from '@ggui-ai/ui-visual-tester/prime-inputs';
24
25
  import git from 'isomorphic-git';
25
26
  import { Volume, createFsFromVolume } from 'memfs';
26
27
  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
- tokens: {
811
- input: totalInputTokens,
812
- output: totalOutputTokens,
813
- total: totalInputTokens + totalOutputTokens
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
- tokens: {
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
  };
@@ -13373,6 +13399,46 @@ function runRootWidthCap(input) {
13373
13399
  )
13374
13400
  ];
13375
13401
  }
13402
+ var LABEL_SPECIAL_CHAR = /[^a-z0-9\s]/i;
13403
+ var normText = (s) => s.toLowerCase().replace(/\s+/g, " ").trim();
13404
+ var alnumText = (s) => s.toLowerCase().replace(/[^a-z0-9]/g, "");
13405
+ function visibleText(sourceCode) {
13406
+ const jsx = (sourceCode.match(/>([^<>]*)</g) ?? []).map((m2) => m2.slice(1, -1).replace(/\{[^}]*\}/g, " ")).join(" ");
13407
+ let attrs = "";
13408
+ const attrRx = /\b(?:aria-label|placeholder|title|alt)\s*=\s*(?:"([^"]*)"|'([^']*)')/gi;
13409
+ let m;
13410
+ while ((m = attrRx.exec(sourceCode)) !== null) attrs += " " + (m[1] ?? m[2] ?? "");
13411
+ return jsx + " " + attrs;
13412
+ }
13413
+ function findDroppedActionLabels(sourceCode, contract) {
13414
+ const actionSpec = contract?.actionSpec;
13415
+ if (actionSpec === void 0) return [];
13416
+ if (/\.label\b/.test(sourceCode)) return [];
13417
+ const vis = visibleText(sourceCode);
13418
+ const normVis = normText(vis);
13419
+ const alnumVis = alnumText(vis);
13420
+ const out = [];
13421
+ for (const [name, entry] of Object.entries(actionSpec)) {
13422
+ const label = entry.label;
13423
+ if (typeof label !== "string" || label.length === 0 || label === name) continue;
13424
+ if (!LABEL_SPECIAL_CHAR.test(label)) continue;
13425
+ if (alnumText(label).length < 3) continue;
13426
+ if (normVis.includes(normText(label))) continue;
13427
+ if (alnumVis.includes(alnumText(label))) out.push({ name, label });
13428
+ }
13429
+ return out;
13430
+ }
13431
+ function runActionLabelDropped(input) {
13432
+ if (input.compiledCode === null) return [];
13433
+ return findDroppedActionLabels(input.sourceCode, input.contract).map(
13434
+ ({ name, label }) => mkIssue(
13435
+ "universal.action_label_dropped",
13436
+ `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).`,
13437
+ `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.`,
13438
+ "warn"
13439
+ )
13440
+ );
13441
+ }
13376
13442
  var UNIVERSAL_CHECKS = [
13377
13443
  {
13378
13444
  id: "universal.icon_name_known",
@@ -13398,6 +13464,12 @@ var UNIVERSAL_CHECKS = [
13398
13464
  values: ALL_RENDER_VALUES,
13399
13465
  run: runRootWidthCap
13400
13466
  },
13467
+ {
13468
+ id: "universal.action_label_dropped",
13469
+ axis: "render",
13470
+ values: ALL_RENDER_VALUES,
13471
+ run: runActionLabelDropped
13472
+ },
13401
13473
  {
13402
13474
  id: "universal.terminal_action_unguarded",
13403
13475
  axis: "render",
@@ -17627,8 +17699,6 @@ function editableSurface(el) {
17627
17699
  function parentLink(node) {
17628
17700
  return node;
17629
17701
  }
17630
-
17631
- // src/harness/check/runtime-render/render-check.ts
17632
17702
  async function runRenderCheck(input) {
17633
17703
  const g = hostGlobals();
17634
17704
  if ("window" in g && "document" in g) {
@@ -17807,6 +17877,10 @@ async function runRenderCheckInProcess(input) {
17807
17877
  let actionsChecked = 0;
17808
17878
  let streamsChecked = 0;
17809
17879
  try {
17880
+ try {
17881
+ primeInputs(renderResult.container);
17882
+ } catch {
17883
+ }
17810
17884
  if (input.contract?.actionSpec) {
17811
17885
  const actionSpec = input.contract.actionSpec;
17812
17886
  for (const [name, entry] of Object.entries(actionSpec)) {