@ggui-ai/ui-gen 0.27.0 → 0.28.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.
@@ -3,7 +3,7 @@ import * as esbuild2 from 'esbuild';
3
3
  import { build } from 'esbuild';
4
4
  import Anthropic from '@anthropic-ai/sdk';
5
5
  import { EXPANDED_FRAME, getCssTokens, expandedFrameScrimDecls, fillFitRule, expandedFramePanelRule, FORBIDDEN_IMPORT_SPECIFIERS } from '@ggui-ai/design/rendering';
6
- import { listContractGadgets, HOOK_NAME_RE, classifyUi, MODEL_REGISTRY, DANGEROUS_PATTERNS as DANGEROUS_PATTERNS$1, modelRefOfRoute, isGeneratorId, APP_GENERATION_PROFILE_BOUNDS, STDLIB_GADGETS_PACKAGE, resolveAppGadgets, anthropicRejectsForcedToolChoice, normalizeAnthropicModelId, anthropicRejectsSamplingParams, isRecord } from '@ggui-ai/protocol';
6
+ import { listContractGadgets, HOOK_NAME_RE, classifyUi, MODEL_REGISTRY, DANGEROUS_PATTERNS as DANGEROUS_PATTERNS$1, modelRefOfRoute, isGeneratorId, DEFAULT_MODEL as DEFAULT_MODEL$1, APP_GENERATION_PROFILE_BOUNDS, STDLIB_GADGETS_PACKAGE, resolveAppGadgets, anthropicRejectsForcedToolChoice, normalizeAnthropicModelId, anthropicRejectsSamplingParams, isRecord } from '@ggui-ai/protocol';
7
7
  import fs, { existsSync, mkdtempSync, writeFileSync, rmSync, readFileSync, readdirSync, statSync } from 'fs';
8
8
  import { contentHash } from '@ggui-ai/protocol/content-hash';
9
9
  import ts4 from 'typescript';
@@ -4527,6 +4527,8 @@ var init_policy = __esm({
4527
4527
  function getBedrockModelId(model) {
4528
4528
  const BEDROCK_MAP = {
4529
4529
  "anthropic/claude-haiku-4-5": "us.anthropic.claude-haiku-4-5-20251001-v1:0",
4530
+ "anthropic/claude-haiku-5-5": "us.anthropic.claude-haiku-5-5",
4531
+ // listed ACTIVE in us-east-1 (ggui#1743)
4530
4532
  "anthropic/claude-sonnet-4-6": "us.anthropic.claude-sonnet-4-6",
4531
4533
  "anthropic/claude-opus-4-6": "us.anthropic.claude-opus-4-6-v1:0",
4532
4534
  // Claude 5-family (ggui#706, strings verified 2026-09-02 against
@@ -7043,10 +7045,16 @@ var dupe_break_exports = {};
7043
7045
  __export(dupe_break_exports, {
7044
7046
  SAME_EXCHANGE_BREAK_AT: () => SAME_EXCHANGE_BREAK_AT,
7045
7047
  SAME_EXCHANGE_NUDGE: () => SAME_EXCHANGE_NUDGE,
7048
+ SAME_FAILURE_BREAK_AT: () => SAME_FAILURE_BREAK_AT,
7049
+ SAME_FAILURE_NUDGE: () => SAME_FAILURE_NUDGE,
7050
+ SAME_FAILURE_NUDGE_AT: () => SAME_FAILURE_NUDGE_AT,
7051
+ clearWriteFailures: () => clearWriteFailures,
7046
7052
  computePatchFingerprint: () => computePatchFingerprint,
7047
7053
  createDupeBreakState: () => createDupeBreakState,
7048
7054
  errorClassBucket: () => errorClassBucket,
7049
- recordToolExchange: () => recordToolExchange
7055
+ failureSignatures: () => failureSignatures,
7056
+ recordToolExchange: () => recordToolExchange,
7057
+ recordWriteFailure: () => recordWriteFailure
7050
7058
  });
7051
7059
  function recordToolExchange(state, name, input, resultText) {
7052
7060
  const key = createHash("sha256").update(name).update("\0").update(JSON.stringify(input) ?? "undefined").update("\0").update(resultText).digest("hex");
@@ -7058,6 +7066,25 @@ function recordToolExchange(state, name, input, resultText) {
7058
7066
  }
7059
7067
  return state.consecutiveIdenticalExchanges;
7060
7068
  }
7069
+ function failureSignatures(resultText) {
7070
+ const norm = (text) => text.replace(/[0-9]+/g, "#").replace(/\s+/g, " ").trim();
7071
+ const violations = [...resultText.matchAll(/^\[[^\]\n]+\] [^\n]+/gm)].map((m) => norm(m[0]));
7072
+ if (violations.length > 0) return [...new Set(violations)];
7073
+ const rest = norm(resultText.replace(/^Committed [^\n]*\n/, ""));
7074
+ return rest.length > 0 ? [rest] : [];
7075
+ }
7076
+ function recordWriteFailure(state, resultText) {
7077
+ let top;
7078
+ for (const signature of failureSignatures(resultText)) {
7079
+ const repeats = (state.failureCounts.get(signature) ?? 0) + 1;
7080
+ state.failureCounts.set(signature, repeats);
7081
+ if (top === void 0 || repeats > top.repeats) top = { signature, repeats };
7082
+ }
7083
+ return top;
7084
+ }
7085
+ function clearWriteFailures(state) {
7086
+ state.failureCounts.clear();
7087
+ }
7061
7088
  function createDupeBreakState() {
7062
7089
  return {
7063
7090
  lastFailedPatchFingerprint: null,
@@ -7074,7 +7101,8 @@ function createDupeBreakState() {
7074
7101
  consecutiveBrokenApplies: 0,
7075
7102
  consecutiveNoToolCalls: 0,
7076
7103
  lastExchangeKey: null,
7077
- consecutiveIdenticalExchanges: 0
7104
+ consecutiveIdenticalExchanges: 0,
7105
+ failureCounts: /* @__PURE__ */ new Map()
7078
7106
  };
7079
7107
  }
7080
7108
  function errorClassBucket(errText) {
@@ -7099,11 +7127,14 @@ function computePatchFingerprint(changes, errText) {
7099
7127
  h.update(errBucket);
7100
7128
  return h.digest("hex");
7101
7129
  }
7102
- var SAME_EXCHANGE_BREAK_AT, SAME_EXCHANGE_NUDGE;
7130
+ var SAME_EXCHANGE_BREAK_AT, SAME_EXCHANGE_NUDGE, SAME_FAILURE_NUDGE_AT, SAME_FAILURE_BREAK_AT, SAME_FAILURE_NUDGE;
7103
7131
  var init_dupe_break = __esm({
7104
7132
  "src/harness/coding/dupe-break.ts"() {
7105
7133
  SAME_EXCHANGE_BREAK_AT = 3;
7106
7134
  SAME_EXCHANGE_NUDGE = "\n\n[harness] This is the SAME tool call with the SAME result as your previous turn \u2014 repeating it cannot produce new information. Use what you already have and emit an apply_changes (or scoped) call now; one more identical repeat terminates the run.";
7135
+ SAME_FAILURE_NUDGE_AT = 3;
7136
+ SAME_FAILURE_BREAK_AT = 5;
7137
+ SAME_FAILURE_NUDGE = "\n\n[harness] This same failure has now been reported for three of your patches. Changing other code does not clear it: re-read that check above and change exactly what it names. Two more reports of it end the run.";
7107
7138
  }
7108
7139
  });
7109
7140
 
@@ -7495,13 +7526,13 @@ Return your evaluation using the evaluate_${criterion} tool.`;
7495
7526
  function getDefaultEvalModel(provider) {
7496
7527
  switch (provider) {
7497
7528
  case "claude":
7498
- return "claude-haiku-4-5-20251001";
7529
+ return "claude-haiku-5-5";
7499
7530
  case "openai":
7500
7531
  return "gpt-5.6-luna";
7501
7532
  case "google":
7502
7533
  return "gemini-3.5-flash-lite";
7503
7534
  default:
7504
- return "claude-haiku-4-5-20251001";
7535
+ return "claude-haiku-5-5";
7505
7536
  }
7506
7537
  }
7507
7538
  function callTokens(response) {
@@ -9579,7 +9610,7 @@ function parseCriteriaAnswers(raw) {
9579
9610
  function getDefaultVisualModel(provider) {
9580
9611
  switch (provider) {
9581
9612
  case "claude":
9582
- return "claude-haiku-4-5-20251001";
9613
+ return "claude-haiku-5-5";
9583
9614
  case "google":
9584
9615
  return "gemini-3-flash-preview";
9585
9616
  }
@@ -11823,10 +11854,96 @@ function getInitialValuePropNames(contract) {
11823
11854
  }
11824
11855
  return names;
11825
11856
  }
11857
+ function objectLiteralKeysAt(src, open) {
11858
+ if (src[open] !== "{") return void 0;
11859
+ const keys = [];
11860
+ let depth = 0;
11861
+ let expectKey = true;
11862
+ for (let i = open; i < src.length; i++) {
11863
+ const c = src[i];
11864
+ if (c === '"' || c === "'" || c === "`") {
11865
+ let j = i + 1;
11866
+ while (j < src.length && src[j] !== c) j += src[j] === "\\" ? 2 : 1;
11867
+ if (depth === 1 && expectKey && /^\s*:/.test(src.slice(j + 1))) keys.push(src.slice(i + 1, j));
11868
+ i = j;
11869
+ expectKey = false;
11870
+ continue;
11871
+ }
11872
+ if (c === "{" || c === "[" || c === "(") {
11873
+ depth++;
11874
+ if (depth === 1) expectKey = true;
11875
+ continue;
11876
+ }
11877
+ if (c === "}" || c === "]" || c === ")") {
11878
+ depth--;
11879
+ if (depth === 0) return keys;
11880
+ continue;
11881
+ }
11882
+ if (depth !== 1) continue;
11883
+ if (c === ",") {
11884
+ expectKey = true;
11885
+ continue;
11886
+ }
11887
+ if (expectKey && /[A-Za-z_$]/.test(c ?? "")) {
11888
+ const m = /^([A-Za-z_$][\w$]*)\s*(:|,|\})/.exec(src.slice(i));
11889
+ if (m !== null && m[1] !== void 0) keys.push(m[1]);
11890
+ expectKey = false;
11891
+ }
11892
+ }
11893
+ return keys;
11894
+ }
11895
+ function callArgsAt(src, open) {
11896
+ const args = [];
11897
+ let depth = 0;
11898
+ let start = open + 1;
11899
+ for (let i = open; i < src.length; i++) {
11900
+ const c = src[i];
11901
+ if (c === '"' || c === "'" || c === "`") {
11902
+ let j = i + 1;
11903
+ while (j < src.length && src[j] !== c) j += src[j] === "\\" ? 2 : 1;
11904
+ i = j;
11905
+ continue;
11906
+ }
11907
+ if (c === "(" || c === "{" || c === "[") depth++;
11908
+ else if (c === ")" || c === "}" || c === "]") {
11909
+ depth--;
11910
+ if (depth === 0) {
11911
+ args.push(src.slice(start, i));
11912
+ return args;
11913
+ }
11914
+ } else if (c === "," && depth === 1) {
11915
+ args.push(src.slice(start, i));
11916
+ start = i + 1;
11917
+ }
11918
+ }
11919
+ return args;
11920
+ }
11921
+ function initialStateKeys(src, argStart, argText) {
11922
+ const lead = argText.length - argText.trimStart().length;
11923
+ let at = argStart + lead;
11924
+ let text = argText.trim();
11925
+ const lazy = /^\(\s*\)\s*=>\s*\(?\s*/.exec(text);
11926
+ if (lazy !== null) {
11927
+ at += lazy[0].length;
11928
+ text = text.slice(lazy[0].length);
11929
+ }
11930
+ if (text.startsWith("{")) return objectLiteralKeysAt(src, at) ?? [];
11931
+ const ident = /^([A-Za-z_$][\w$]*)\s*\)?\s*$/.exec(text);
11932
+ if (ident === null || ident[1] === void 0) return [];
11933
+ const decls = [...src.matchAll(new RegExp(`(?:const|let|var)\\s+${ident[1]}\\s*(?::[^=]{1,200})?=\\s*`, "g"))];
11934
+ const decl = decls.length === 1 ? decls[0] : void 0;
11935
+ if (decl === void 0) return [];
11936
+ return objectLiteralKeysAt(src, (decl.index ?? 0) + decl[0].length) ?? [];
11937
+ }
11826
11938
  function collectStateKeys(src) {
11827
11939
  const keys = /* @__PURE__ */ new Set();
11828
11940
  const varRe = /const\s*\[\s*(\w+)\s*,\s*(\w+)\s*\]\s*=\s*useState/g;
11829
11941
  for (const m of src.matchAll(varRe)) keys.add(m[1]);
11942
+ const contextRe = /const\s*\[\s*(\w+)\s*,\s*\w+\s*\]\s*=\s*useGguiContext\s*(?:<[^>]*>)?\s*\(\s*['"`](\w+)['"`]/g;
11943
+ for (const m of src.matchAll(contextRe)) {
11944
+ keys.add(m[1]);
11945
+ keys.add(m[2]);
11946
+ }
11830
11947
  const objRe = /useState(?:<[^>]*>)?\s*\(\s*\{([\s\S]*?)\}\s*\)/g;
11831
11948
  for (const m of src.matchAll(objRe)) {
11832
11949
  const keyRe = /(?:^|,)\s*(\w+)\s*:/g;
@@ -11837,6 +11954,16 @@ function collectStateKeys(src) {
11837
11954
  const keyRe = /(?:^|,)\s*(\w+)\s*:/g;
11838
11955
  for (const km of m[1].matchAll(keyRe)) keys.add(km[1]);
11839
11956
  }
11957
+ for (const m of src.matchAll(/\b(useState|useReducer)\s*(?:<[^>]*>)?\s*\(/g)) {
11958
+ const open = (m.index ?? 0) + m[0].length - 1;
11959
+ const args = callArgsAt(src, open);
11960
+ const which = m[1] === "useReducer" ? 1 : 0;
11961
+ const arg = args[which];
11962
+ if (arg === void 0) continue;
11963
+ let argStart = open + 1;
11964
+ for (let k = 0; k < which; k++) argStart += (args[k]?.length ?? 0) + 1;
11965
+ for (const key of initialStateKeys(src, argStart, arg)) keys.add(key);
11966
+ }
11840
11967
  return keys;
11841
11968
  }
11842
11969
  function mkIssue(subcategory, description, fix, result = "fail") {
@@ -12449,7 +12576,7 @@ function runNoHardcodedEntities(input) {
12449
12576
  mkIssue(
12450
12577
  "state.merge.no_hardcoded_entities",
12451
12578
  `Hardcoded entity array literal (multiple objects with "${idField}") in the component \u2014 entity data should come from state/props.`,
12452
- `Remove the literal array. Seed state from props.{entityProp} and merge updates via stream.`
12579
+ `Remove the literal array: this data comes from ${all.filter((e) => e.idField === idField).map((e) => `props.${e.name}`).join(" / ") || "props"}. Read it there (\`?? []\` for an absent value, never a literal default), seed state from it, and merge updates via stream.`
12453
12580
  )
12454
12581
  );
12455
12582
  }
@@ -18335,6 +18462,7 @@ async function assembleGenerationResult(input) {
18335
18462
  evalResult: telemetry.evalResult !== void 0 && telemetry.contractFeedback !== void 0 ? { ...telemetry.evalResult, contractFeedback: telemetry.contractFeedback } : telemetry.evalResult,
18336
18463
  // ggui#404 — present only when the same-exchange guard ended the run.
18337
18464
  ...telemetry.sameExchangeBreak !== void 0 ? { sameExchangeBreak: telemetry.sameExchangeBreak } : {},
18465
+ ...telemetry.sameFailureBreak !== void 0 ? { sameFailureBreak: telemetry.sameFailureBreak } : {},
18338
18466
  needsBackgroundImprovement,
18339
18467
  selfCheckPassed: telemetry.selfCheckPassed,
18340
18468
  timing,
@@ -19274,6 +19402,18 @@ Repeated error: ${errText}
19274
19402
  augmentedResultText += SAME_EXCHANGE_NUDGE;
19275
19403
  }
19276
19404
  }
19405
+ const isWrite = call.name === "apply_changes" || call.name === "rewrite";
19406
+ let repeatedFailure;
19407
+ if (ctx.dupeBreak && isWrite) {
19408
+ if (result.done) {
19409
+ clearWriteFailures(ctx.dupeBreak);
19410
+ } else {
19411
+ repeatedFailure = recordWriteFailure(ctx.dupeBreak, result.result);
19412
+ if (repeatedFailure?.repeats === SAME_FAILURE_NUDGE_AT) {
19413
+ augmentedResultText += SAME_FAILURE_NUDGE;
19414
+ }
19415
+ }
19416
+ }
19277
19417
  await codingAgent.sendToolResult([{
19278
19418
  callId: call.id,
19279
19419
  name: call.name,
@@ -19302,6 +19442,29 @@ Repeated error: ${errText}
19302
19442
  sameExchangeBreak: { tool: call.name, repeats: sameExchangeRepeats }
19303
19443
  };
19304
19444
  }
19445
+ if (repeatedFailure !== void 0 && repeatedFailure.repeats >= SAME_FAILURE_BREAK_AT) {
19446
+ const signature = repeatedFailure.signature.slice(0, 160);
19447
+ console.log(
19448
+ `[coding-agent] SAME_FAILURE_BREAK | tool=${call.name} | repeats=${repeatedFailure.repeats} | failure=${JSON.stringify(signature.slice(0, 80))} \u2014 terminating run (ggui#1791)`
19449
+ );
19450
+ return {
19451
+ control: "break",
19452
+ compiledCode: "",
19453
+ selfCheckPassed: false,
19454
+ outcome: void 0,
19455
+ phase: void 0,
19456
+ tokens,
19457
+ ...cacheTokens,
19458
+ llmMs,
19459
+ toolMs,
19460
+ lastResultText: augmentedResultText,
19461
+ lastDiffFailed: false,
19462
+ isEvalFeedback: false,
19463
+ iconNamesCache,
19464
+ preWarmedContext,
19465
+ sameFailureBreak: { signature, repeats: repeatedFailure.repeats }
19466
+ };
19467
+ }
19305
19468
  const turnDiffFailed = !!result.error && result.result.includes("DIFF");
19306
19469
  const isDiffFail = turnDiffFailed && !isPatchInvalid;
19307
19470
  const outcome = result.done ? "PASS" : isPatchInvalid ? "PATCH_INVALID" : isDiffFail ? "DIFF_FAIL" : "SELF_CHECK_FAIL";
@@ -20289,6 +20452,7 @@ function createTelemetry() {
20289
20452
  probeRepairTrigger: void 0,
20290
20453
  contractFeedback: void 0,
20291
20454
  sameExchangeBreak: void 0,
20455
+ sameFailureBreak: void 0,
20292
20456
  compiledCode: "",
20293
20457
  pairedSource: "",
20294
20458
  selfCheckPassed: false,
@@ -20344,6 +20508,7 @@ function absorbTurn(telemetry, turn) {
20344
20508
  else telemetry.counters.outcomes.selfCheckFail++;
20345
20509
  }
20346
20510
  if (turn.sameExchangeBreak !== void 0) telemetry.sameExchangeBreak = turn.sameExchangeBreak;
20511
+ if (turn.sameFailureBreak !== void 0) telemetry.sameFailureBreak = turn.sameFailureBreak;
20347
20512
  }
20348
20513
  function createGenerateTaskRunner(input) {
20349
20514
  const { session, params, classification, telemetry } = input;
@@ -21498,7 +21663,7 @@ function injectVariance(userPrompt, variance, options) {
21498
21663
  init_design_mode();
21499
21664
  init_provider_router();
21500
21665
  var DEFAULT_TIER = "default";
21501
- var DEFAULT_MODEL = "anthropic/claude-haiku-4-5";
21666
+ var DEFAULT_MODEL = DEFAULT_MODEL$1;
21502
21667
  function createUiGenerator(options = {}) {
21503
21668
  const {
21504
21669
  enableRuntimeRender = false,