@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.
Files changed (93) hide show
  1. package/dist/adapters/base.d.ts +7 -0
  2. package/dist/adapters/base.js +1 -0
  3. package/dist/adapters/base.js.map +1 -1
  4. package/dist/adapters/generation-dispatch.d.ts +17 -3
  5. package/dist/adapters/generation-dispatch.js +1078 -3464
  6. package/dist/adapters/generation-dispatch.js.map +1 -1
  7. package/dist/adapters/index.js +60 -3
  8. package/dist/adapters/index.js.map +1 -1
  9. package/dist/advanced/index.d.ts +4 -4
  10. package/dist/advanced/index.js +1346 -3557
  11. package/dist/advanced/index.js.map +1 -1
  12. package/dist/blueprint-validator.js +10 -3
  13. package/dist/blueprint-validator.js.map +1 -1
  14. package/dist/boilerplate.js +2 -2
  15. package/dist/boilerplate.js.map +1 -1
  16. package/dist/check/index.d.ts +1 -1
  17. package/dist/check/index.js.map +1 -1
  18. package/dist/{create-ui-generator-CxPvudbs.d.ts → create-ui-generator-BEkzEtNz.d.ts} +2 -2
  19. package/dist/{dispatch-N8wdNOX-.d.ts → dispatch-DJNpQ7DI.d.ts} +1 -1
  20. package/dist/evaluation/axis-checks/index.d.ts +3 -3
  21. package/dist/evaluation/axis-checks/index.js.map +1 -1
  22. package/dist/evaluation/axis-checks/registry.d.ts +1 -1
  23. package/dist/evaluation/index.d.ts +38 -6
  24. package/dist/evaluation/index.js +670 -3374
  25. package/dist/evaluation/index.js.map +1 -1
  26. package/dist/harness/check/runtime-render/index.d.ts +2 -2
  27. package/dist/harness/check/runtime-render/index.js +10 -3
  28. package/dist/harness/check/runtime-render/index.js.map +1 -1
  29. package/dist/harness/check/runtime-render/render-check-worker.js +5 -3
  30. package/dist/harness/check/runtime-render/render-check-worker.js.map +1 -1
  31. package/dist/harness/index.d.ts +2 -2
  32. package/dist/harness/index.js +587 -30
  33. package/dist/harness/index.js.map +1 -1
  34. package/dist/harness/llm-trace-sink.d.ts +7 -1
  35. package/dist/harness/llm-trace-sink.js.map +1 -1
  36. package/dist/harness/prompts.js +1 -1
  37. package/dist/harness/prompts.js.map +1 -1
  38. package/dist/harness/result-types.d.ts +15 -2
  39. package/dist/harness/result-types.js.map +1 -1
  40. package/dist/harness/runtime.d.ts +11 -2
  41. package/dist/harness/runtime.js +3 -3
  42. package/dist/harness/runtime.js.map +1 -1
  43. package/dist/harness/types-public.d.ts +1 -1
  44. package/dist/harness/types-public.js +2 -2
  45. package/dist/harness/types-public.js.map +1 -1
  46. package/dist/harness/validator-trace-sink.d.ts +1 -1
  47. package/dist/index.d.ts +23 -7
  48. package/dist/index.js +1346 -3557
  49. package/dist/index.js.map +1 -1
  50. package/dist/{llm-router-D7fjBhtr.d.ts → llm-router-DwwUK1bz.d.ts} +16 -3
  51. package/dist/patch.d.ts +1 -1
  52. package/dist/providers/index.js +5 -4
  53. package/dist/providers/index.js.map +1 -1
  54. package/dist/{render-check-WfOVO9kU.d.ts → render-check-C0CqVceF.d.ts} +17 -0
  55. package/dist/{types-public-DKR_h70H.d.ts → types-public-mM_-1Yk3.d.ts} +59 -1
  56. package/dist/validation/index.d.ts +1 -1
  57. package/dist/validation/index.js +1 -1
  58. package/dist/validation/index.js.map +1 -1
  59. package/dist/workflows.d.ts +1 -1
  60. package/package.json +16 -12
  61. package/src/adapters/base.ts +8 -0
  62. package/src/adapters/claude/claude-code-login.ts +128 -0
  63. package/src/adapters/claude/sdk.ts +9 -1
  64. package/src/adapters/generation-dispatch.ts +19 -2
  65. package/src/adapters/openai/tokens.ts +18 -0
  66. package/src/adapters/provider-router.ts +28 -0
  67. package/src/boilerplate/generate.ts +19 -4
  68. package/src/boilerplate/hard-sections.ts +1 -1
  69. package/src/boilerplate/templates/layouts/chat-mobile.tsx.tmpl +7 -3
  70. package/src/boilerplate/templates/layouts/chat-universal.tsx.tmpl +7 -3
  71. package/src/contract-context.ts +1 -1
  72. package/src/create-ui-generator.ts +49 -10
  73. package/src/evaluation/design-identity.ts +16 -5
  74. package/src/evaluation/index.ts +1 -0
  75. package/src/evaluation/llm-evaluator.ts +40 -13
  76. package/src/evaluation/types-public.ts +58 -0
  77. package/src/evaluation/visual-evaluator.ts +240 -30
  78. package/src/generator-build.ts +158 -0
  79. package/src/harness/check/runtime-render/adapter.ts +9 -0
  80. package/src/harness/check/runtime-render/render-check.ts +26 -5
  81. package/src/harness/claude-code-login-query.ts +529 -0
  82. package/src/harness/coding/assemble-result.ts +18 -2
  83. package/src/harness/coding/generate-task-runner.ts +75 -36
  84. package/src/harness/coding/run-coding-turn.ts +9 -0
  85. package/src/harness/coding/run-eval-round.ts +338 -38
  86. package/src/harness/enforced-coding.ts +20 -0
  87. package/src/harness/llm-router.ts +390 -55
  88. package/src/harness/llm-trace-sink.ts +7 -1
  89. package/src/harness/result-types.ts +14 -0
  90. package/src/harness/runtime.ts +6 -0
  91. package/src/index.ts +2 -1
  92. package/src/providers/openai.ts +31 -19
  93. package/src/validation/primitives.ts +1 -1
@@ -12,7 +12,7 @@
12
12
 
13
13
  import type { Classification } from "../../classifier/index.js";
14
14
  import type { JsonValue } from "@ggui-ai/protocol";
15
- import type { EvalResult } from "../../evaluation/types-public.js";
15
+ import type { ContractFeedbackRecord, EvalResult } from "../../evaluation/types-public.js";
16
16
  import type { Harness, Task, TaskContext } from "../types-public.js";
17
17
  import type { SingleComponentParams } from "../runtime.js";
18
18
  import type { TaskRunner } from "../index.js";
@@ -20,8 +20,11 @@ import type { CodingSession } from "./init-session.js";
20
20
  import {
21
21
  runCodingTurn,
22
22
  type A1Phase,
23
+ type CodingTurnResult,
23
24
  } from "./run-coding-turn.js";
24
25
  import { runEvalRound } from "./run-eval-round.js";
26
+ import type { TokenUsage } from "./run-eval-round.js";
27
+ import type { SameExchangeBreak } from "../result-types.js";
25
28
 
26
29
  type PreWarmedEvalContext =
27
30
  import("../../evaluation/llm-evaluator.js").PreWarmedEvalContext;
@@ -64,15 +67,27 @@ export interface GenerateTelemetry {
64
67
  /** Total output tokens billed across coding + eval. */
65
68
  totalOut: number;
66
69
  /**
67
- * Prompt-cache tokens accumulated across coding turns, when the
68
- * provider reports them. Optional: stays `undefined` for providers
69
- * that don't expose cache accounting (never defaulted to 0 here, so
70
- * the boundary can distinguish "no cache reads" from "unreported").
70
+ * Prompt-cache tokens accumulated across coding turns AND eval rounds
71
+ * (ggui#1281), when the provider reports them. Optional: stays
72
+ * `undefined` for providers that don't expose cache accounting (never
73
+ * defaulted to 0 here, so the boundary can distinguish "no cache reads"
74
+ * from "unreported").
71
75
  */
72
76
  cacheReadTokens?: number;
73
77
  cacheCreationTokens?: number;
74
78
  /** Latest evalResult — undefined when eval was disabled or never ran. */
75
79
  evalResult: EvalResult | undefined;
80
+ /**
81
+ * ggui#1261 — the contract-feedback round, once one fired: kept across the
82
+ * rounds after it (each rebuilds `evalResult`) so the assembled result can
83
+ * carry the round's before beside the source the generation ends with.
84
+ */
85
+ contractFeedback: ContractFeedbackRecord | undefined;
86
+ /**
87
+ * The same-exchange guard's record (ggui#404), set by the turn it ended —
88
+ * undefined unless that guard is what stopped the loop.
89
+ */
90
+ sameExchangeBreak: SameExchangeBreak | undefined;
76
91
  /** Latest compiled code — empty string until the first self-check pass. */
77
92
  compiledCode: string;
78
93
  /**
@@ -111,6 +126,8 @@ export function createTelemetry(): GenerateTelemetry {
111
126
  totalIn: 0,
112
127
  totalOut: 0,
113
128
  evalResult: undefined,
129
+ contractFeedback: undefined,
130
+ sameExchangeBreak: undefined,
114
131
  compiledCode: "",
115
132
  pairedSource: "",
116
133
  selfCheckPassed: false,
@@ -120,6 +137,56 @@ export function createTelemetry(): GenerateTelemetry {
120
137
  };
121
138
  }
122
139
 
140
+ /**
141
+ * Fold one call's (or one eval round's) tokens into the run's totals — the ONE
142
+ * rule for coding turns and eval rounds alike (ggui#1281: the eval path used to
143
+ * add input/output only, so `tokens.total` dropped every eval call's cached
144
+ * prefix). A cache counter is seeded on its first report and stays `undefined`
145
+ * while nothing has reported one: unreported, never zero.
146
+ */
147
+ export function absorbTokens(telemetry: GenerateTelemetry, usage: TokenUsage): void {
148
+ telemetry.totalIn += usage.input;
149
+ telemetry.totalOut += usage.output;
150
+ if (usage.cacheRead !== undefined) {
151
+ telemetry.cacheReadTokens = (telemetry.cacheReadTokens ?? 0) + usage.cacheRead;
152
+ }
153
+ if (usage.cacheCreation !== undefined) {
154
+ telemetry.cacheCreationTokens = (telemetry.cacheCreationTokens ?? 0) + usage.cacheCreation;
155
+ }
156
+ }
157
+
158
+ /**
159
+ * Fold one coding turn's measurements into the run's telemetry — tokens (via
160
+ * {@link absorbTokens}), timings, the phase/outcome counters, and the
161
+ * same-exchange guard's record when that guard ended the turn (ggui#404). One
162
+ * function so every per-turn fact the result is assembled from lands in one
163
+ * place.
164
+ */
165
+ export function absorbTurn(telemetry: GenerateTelemetry, turn: CodingTurnResult): void {
166
+ absorbTokens(telemetry, {
167
+ input: turn.tokens.input,
168
+ output: turn.tokens.output,
169
+ ...(turn.cacheReadTokens !== undefined ? { cacheRead: turn.cacheReadTokens } : {}),
170
+ ...(turn.cacheCreationTokens !== undefined ? { cacheCreation: turn.cacheCreationTokens } : {}),
171
+ });
172
+ telemetry.cumulativeLlmMs += turn.llmMs;
173
+ telemetry.cumulativeToolMs += turn.toolMs;
174
+ if (turn.phase) {
175
+ if (turn.phase === "scaffold") telemetry.counters.phases.scaffold++;
176
+ else if (turn.phase === "fill") telemetry.counters.phases.fill++;
177
+ else if (turn.phase === "impl") telemetry.counters.phases.impl++;
178
+ else if (turn.phase === "eval-fix") telemetry.counters.phases.evalFix++;
179
+ else telemetry.counters.phases.patch++;
180
+ }
181
+ if (turn.outcome) {
182
+ if (turn.outcome === "PASS") telemetry.counters.outcomes.pass++;
183
+ else if (turn.outcome === "PATCH_INVALID") telemetry.counters.outcomes.patchInvalid++;
184
+ else if (turn.outcome === "DIFF_FAIL") telemetry.counters.outcomes.diffFail++;
185
+ else telemetry.counters.outcomes.selfCheckFail++;
186
+ }
187
+ if (turn.sameExchangeBreak !== undefined) telemetry.sameExchangeBreak = turn.sameExchangeBreak;
188
+ }
189
+
123
190
  export interface CreateGenerateRunnerInput {
124
191
  readonly session: CodingSession;
125
192
  readonly params: SingleComponentParams;
@@ -203,38 +270,10 @@ export function createGenerateTaskRunner(input: CreateGenerateRunnerInput): Task
203
270
  },
204
271
  );
205
272
 
206
- telemetry.totalIn += turn.tokens.input;
207
- telemetry.totalOut += turn.tokens.output;
208
- // Accumulate prompt-cache counters only when the provider reported
209
- // them this turn. Seeding from `undefined` on first report keeps the
210
- // "unreported" providers' totals absent rather than 0.
211
- if (turn.cacheReadTokens !== undefined) {
212
- telemetry.cacheReadTokens =
213
- (telemetry.cacheReadTokens ?? 0) + turn.cacheReadTokens;
214
- }
215
- if (turn.cacheCreationTokens !== undefined) {
216
- telemetry.cacheCreationTokens =
217
- (telemetry.cacheCreationTokens ?? 0) + turn.cacheCreationTokens;
218
- }
219
- telemetry.cumulativeLlmMs += turn.llmMs;
220
- telemetry.cumulativeToolMs += turn.toolMs;
273
+ absorbTurn(telemetry, turn);
221
274
  iconNamesCache = turn.iconNamesCache;
222
275
  preWarmedContext = turn.preWarmedContext;
223
276
 
224
- if (turn.phase) {
225
- if (turn.phase === "scaffold") telemetry.counters.phases.scaffold++;
226
- else if (turn.phase === "fill") telemetry.counters.phases.fill++;
227
- else if (turn.phase === "impl") telemetry.counters.phases.impl++;
228
- else if (turn.phase === "eval-fix") telemetry.counters.phases.evalFix++;
229
- else telemetry.counters.phases.patch++;
230
- }
231
- if (turn.outcome) {
232
- if (turn.outcome === "PASS") telemetry.counters.outcomes.pass++;
233
- else if (turn.outcome === "PATCH_INVALID") telemetry.counters.outcomes.patchInvalid++;
234
- else if (turn.outcome === "DIFF_FAIL") telemetry.counters.outcomes.diffFail++;
235
- else telemetry.counters.outcomes.selfCheckFail++;
236
- }
237
-
238
277
  if (turn.control === "break") break;
239
278
  if (turn.control === "continue") {
240
279
  lastResultText = turn.lastResultText;
@@ -334,9 +373,9 @@ export function createGenerateTaskRunner(input: CreateGenerateRunnerInput): Task
334
373
  prevFailFingerprints = round.prevFailFingerprints;
335
374
  preWarmedContext = round.preWarmedContext;
336
375
  if (round.evalResult) telemetry.evalResult = round.evalResult;
376
+ if (round.contractFeedback) telemetry.contractFeedback = round.contractFeedback;
337
377
  evalDone = round.evalDone;
338
- telemetry.totalIn += round.evalTokens.input;
339
- telemetry.totalOut += round.evalTokens.output;
378
+ absorbTokens(telemetry, round.evalTokens);
340
379
 
341
380
  if (round.control === "break") break;
342
381
  // round.control === "feedback" — set next coding turn input.
@@ -21,6 +21,7 @@ import { executeTool } from "../../coding-agent/tools.js";
21
21
  import type { CostTracker } from "../../evaluation/cost-tracker.js";
22
22
  import type { LLMAgent } from "../llm-router.js";
23
23
  import type { Harness } from "../types-public.js";
24
+ import type { SameExchangeBreak } from "../result-types.js";
24
25
  import {
25
26
  APPLY_CHANGES_HASHLINE_TOOL,
26
27
  APPLY_CHANGES_HASHLINE_TOOL_FLAT,
@@ -244,6 +245,12 @@ export interface CodingTurnResult {
244
245
  readonly isEvalFeedback: boolean;
245
246
  readonly iconNamesCache: string | null;
246
247
  readonly preWarmedContext: PreWarmedEvalContext | null | undefined;
248
+ /**
249
+ * Set only on the `break` the same-exchange guard returns (ggui#404) — the
250
+ * one way a caller can tell this guard ended the run, since `break` is a
251
+ * control value many exits share. No key on any other turn.
252
+ */
253
+ readonly sameExchangeBreak?: SameExchangeBreak;
247
254
  }
248
255
 
249
256
  /**
@@ -637,6 +644,7 @@ ${closingInstruction}`;
637
644
  isEvalFeedback: false,
638
645
  iconNamesCache,
639
646
  preWarmedContext,
647
+ sameExchangeBreak: { tool: call.name, repeats: iconRepeats },
640
648
  };
641
649
  }
642
650
  return {
@@ -964,6 +972,7 @@ ${closingInstruction}`;
964
972
  isEvalFeedback: false,
965
973
  iconNamesCache,
966
974
  preWarmedContext,
975
+ sameExchangeBreak: { tool: call.name, repeats: sameExchangeRepeats },
967
976
  };
968
977
  }
969
978