@ggui-ai/ui-gen 0.8.0 → 0.10.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 (100) hide show
  1. package/dist/adapters/generation-dispatch.d.ts +18 -1
  2. package/dist/adapters/generation-dispatch.js +819 -1577
  3. package/dist/adapters/generation-dispatch.js.map +1 -1
  4. package/dist/adapters/index.js +28 -11
  5. package/dist/adapters/index.js.map +1 -1
  6. package/dist/advanced/index.d.ts +5 -3
  7. package/dist/advanced/index.js +838 -1579
  8. package/dist/advanced/index.js.map +1 -1
  9. package/dist/blueprint-validator.js +109 -3
  10. package/dist/blueprint-validator.js.map +1 -1
  11. package/dist/boilerplate.js +17 -4
  12. package/dist/boilerplate.js.map +1 -1
  13. package/dist/check/index.d.ts +1 -1
  14. package/dist/check/index.js +11 -1
  15. package/dist/check/index.js.map +1 -1
  16. package/dist/compose.js +5 -5
  17. package/dist/compose.js.map +1 -1
  18. package/dist/{create-ui-generator-GX7tvbyH.d.ts → create-ui-generator-CF0EL0Li.d.ts} +26 -1
  19. package/dist/{dispatch-Deo9qzrG.d.ts → dispatch-D75M-OfZ.d.ts} +1 -1
  20. package/dist/evaluation/axis-checks/index.d.ts +3 -3
  21. package/dist/evaluation/axis-checks/index.js +133 -1
  22. package/dist/evaluation/axis-checks/index.js.map +1 -1
  23. package/dist/evaluation/axis-checks/registry.d.ts +1 -1
  24. package/dist/evaluation/axis-checks/registry.js +133 -1
  25. package/dist/evaluation/axis-checks/registry.js.map +1 -1
  26. package/dist/evaluation/index.d.ts +46 -3
  27. package/dist/evaluation/index.js +410 -24
  28. package/dist/evaluation/index.js.map +1 -1
  29. package/dist/fragments/index.js +5 -5
  30. package/dist/fragments/index.js.map +1 -1
  31. package/dist/harness/check/runtime-render/index.d.ts +2 -2
  32. package/dist/harness/check/runtime-render/index.js +110 -3
  33. package/dist/harness/check/runtime-render/index.js.map +1 -1
  34. package/dist/harness/index.d.ts +5 -126
  35. package/dist/harness/index.js +292 -32
  36. package/dist/harness/index.js.map +1 -1
  37. package/dist/harness/llm-trace-sink.d.ts +1 -1
  38. package/dist/harness/llm-trace-sink.js.map +1 -1
  39. package/dist/harness/prompts.js +17 -3
  40. package/dist/harness/prompts.js.map +1 -1
  41. package/dist/harness/result-types.d.ts +1 -1
  42. package/dist/harness/runtime.d.ts +17 -1
  43. package/dist/harness/runtime.js +23 -8
  44. package/dist/harness/runtime.js.map +1 -1
  45. package/dist/harness/types-public.d.ts +1 -1
  46. package/dist/harness/types-public.js +22 -9
  47. package/dist/harness/types-public.js.map +1 -1
  48. package/dist/harness/validator-trace-sink.d.ts +1 -1
  49. package/dist/index.d.ts +5 -3
  50. package/dist/index.js +838 -1579
  51. package/dist/index.js.map +1 -1
  52. package/dist/llm-router-BEVtbAb9.d.ts +213 -0
  53. package/dist/patch.d.ts +1 -1
  54. package/dist/provider-adapter.d.ts +16 -6
  55. package/dist/provider-adapter.js.map +1 -1
  56. package/dist/providers/index.d.ts +54 -99
  57. package/dist/providers/index.js +13 -8
  58. package/dist/providers/index.js.map +1 -1
  59. package/dist/{render-check-CNZjHD5g.d.ts → render-check-BNYGVDJd.d.ts} +1 -1
  60. package/dist/{types-public-C36k1q6s.d.ts → types-public-DIpjC-OA.d.ts} +1 -1
  61. package/dist/validation/index.js +2 -2
  62. package/dist/validation/index.js.map +1 -1
  63. package/dist/workflows.d.ts +1 -1
  64. package/package.json +18 -18
  65. package/src/adapters/generation-dispatch.ts +28 -2
  66. package/src/adapters/openrouter/client.ts +2 -2
  67. package/src/adapters/openrouter/types.ts +10 -0
  68. package/src/boilerplate/generate.ts +10 -2
  69. package/src/boilerplate/json-schema-ts.ts +22 -2
  70. package/src/boilerplate/system-prompt.ts +4 -2
  71. package/src/compile.ts +1 -1
  72. package/src/contract-context.ts +10 -2
  73. package/src/create-ui-generator.ts +58 -11
  74. package/src/design-system-docs.ts +6 -4
  75. package/src/evaluation/axis-checks/checks/state-merge.ts +1 -1
  76. package/src/evaluation/axis-checks/checks/state-ui-affordance.ts +162 -0
  77. package/src/evaluation/axis-checks/checks/universal.ts +39 -0
  78. package/src/evaluation/axis-checks/registry.ts +2 -0
  79. package/src/evaluation/index.ts +11 -0
  80. package/src/evaluation/llm-evaluator.ts +26 -3
  81. package/src/evaluation/visual-evaluator.ts +49 -66
  82. package/src/fragments/realtime.ts +3 -3
  83. package/src/fragments/state.ts +2 -2
  84. package/src/harness/check/runtime-render/adapter.ts +18 -0
  85. package/src/harness/check/runtime-render/index.ts +8 -0
  86. package/src/harness/check/runtime-render/prepare-mockup.ts +14 -0
  87. package/src/harness/check/runtime-render/production-act-shim.ts +158 -0
  88. package/src/harness/check/runtime-render/render-check.ts +72 -1
  89. package/src/harness/coding/init-session.ts +4 -1
  90. package/src/harness/coding/run-eval-round.ts +67 -5
  91. package/src/harness/index.ts +1 -1
  92. package/src/harness/llm-router.ts +451 -27
  93. package/src/harness/llm-trace-sink.ts +2 -1
  94. package/src/harness/runtime.ts +15 -0
  95. package/src/index.ts +5 -5
  96. package/src/provider-adapter.ts +16 -6
  97. package/src/providers/bedrock.ts +89 -26
  98. package/src/providers/index.ts +16 -4
  99. package/src/tools/render-check.ts +19 -7
  100. package/src/validation/ui-compiler.ts +2 -2
@@ -72,6 +72,15 @@ function jsonSchemaTypeToTs(schema) {
72
72
  if (schema.enum?.length) {
73
73
  return schema.enum.map((v) => typeof v === "string" ? `'${v}'` : String(v)).join(" | ");
74
74
  }
75
+ if (Array.isArray(schema.type)) {
76
+ const { nullable: _nullable, ...rest } = schema;
77
+ const members = [...new Set(schema.type)].map(
78
+ (member) => jsonSchemaTypeToTs({ ...rest, type: member })
79
+ );
80
+ const unique = [...new Set(members)];
81
+ if (schema.nullable && !unique.includes("null")) unique.push("null");
82
+ return unique.join(" | ");
83
+ }
75
84
  let result;
76
85
  switch (schema.type) {
77
86
  case "string":
@@ -89,7 +98,8 @@ function jsonSchemaTypeToTs(schema) {
89
98
  case "array": {
90
99
  if (schema.items) {
91
100
  const itemType = jsonSchemaTypeToTs(schema.items);
92
- result = schema.items.type === "object" && schema.items.properties ? `Array<${itemType}>` : itemType.includes("|") ? `(${itemType})[]` : `${itemType}[]`;
101
+ const itemsDeclareObject = Array.isArray(schema.items.type) ? schema.items.type.includes("object") : schema.items.type === "object";
102
+ result = itemsDeclareObject && schema.items.properties ? `Array<${itemType}>` : itemType.includes("|") ? `(${itemType})[]` : `${itemType}[]`;
93
103
  } else {
94
104
  result = "unknown[]";
95
105
  }
@@ -222,13 +232,14 @@ function generateBoilerplate(_userPrompt, contract, shellType, screen, composedS
222
232
  const propsFields = [];
223
233
  const propsProperties = contract?.propsSpec?.properties ?? {};
224
234
  for (const [key, entry] of Object.entries(propsProperties)) {
225
- const required = entry.required !== false;
235
+ const required = entry.required === true;
226
236
  const nullable = entry.schema.nullable === true;
227
237
  const tsType = jsonSchemaTypeToTs(entry.schema);
228
238
  const fullType = nullable ? `${tsType} | null` : tsType;
229
239
  const parts = [];
230
240
  if (entry.description) parts.push(entry.description);
231
241
  if (entry.default !== void 0) parts.push(`(default: ${JSON.stringify(entry.default)})`);
242
+ if (!required) parts.push("(optional \u2014 the agent may omit it; guard or fall back)");
232
243
  const desc = parts.length > 0 ? ` // ${parts.join(" ")}` : "";
233
244
  propsFields.push(` ${key}${required ? "" : "?"}: ${fullType};${desc}`);
234
245
  }
@@ -974,13 +985,15 @@ A \`DataContract\` declares everything a GguiSession exchanges with the outside
974
985
 
975
986
  ## Defensive coding for absent / late-arriving data
976
987
 
977
- Props arrive via \`ggui_update\` and may be partial on first render. Stream channels start empty and fill over time. Context slots start at their declared default (often \`null\`). **Never assume a field exists before you read it.**
988
+ Props arrive at mount and may be partial on first render; later prop changes reach the SAME mounted component via \`ggui_amend\` (in-place repaint) on the live channel. Stream channels start empty and fill over time. Context slots start at their declared default (often \`null\`). **Never assume a field exists before you read it.**
978
989
 
990
+ - **Optional contract props**: a \`Props\` field marked \`?\` in the boilerplate may be omitted by the agent ENTIRELY \u2014 the wire gate only enforces \`required: true\` entries, and the harness verifies your component with those props stripped. Guard them (\`?? default\`, \`?.\`, or an empty-state branch) from the FIRST render.
979
991
  - **Array iteration**: always default to \`[]\` before \`.map\`/\`.filter\`/\`.length\`. Use \`(props.items ?? []).map(...)\` not \`props.items.map(...)\`. Same for stream.all, stream.latest, etc.
980
992
  - **Object access**: optional-chain through nested fields. \`props.user?.name ?? 'Anonymous'\` not \`props.user.name\`.
981
993
  - **Number ops**: default before arithmetic. \`(props.count ?? 0) + 1\` not \`props.count + 1\`.
982
994
  - **Stream latest**: \`useStream\` returns \`{latest: T | null, all: T[], isComplete: boolean}\`. The default \`all\` is \`[]\` so it's safe to map; \`latest\` is null until the first frame arrives \u2014 guard before reading \`.foo\`.
983
995
  - **Stream reconciliation**: when a stream event carries an \`action\` discriminant (e.g. \`create | move | edit | delete\`), the channel is a CRUD feed \u2014 your handler MUST branch on EVERY value: append on \`create\`, drop on \`delete\`, replace-by-id on \`move\` / \`edit\`. Merging only the "edit" case silently loses created and deleted items. Reconcile into the SAME state that seeds from \`props\` (e.g. \`useState(() => props.tasks ?? [])\`) so the seed data and the live feed render as one list \u2014 and handle an event whose id is not yet present (a \`create\` for an unknown item) by inserting it, not ignoring it.
996
+ - **Props re-sync on repaint**: props the agent owns are the source of truth for display \u2014 prefer rendering DIRECTLY from \`props\` (controlled, no local copy). When local optimistic state genuinely needs a prop seed (a click bumps a count before the agent confirms), it MUST re-sync on prop change \u2014 \`useEffect(() => setCount(props.count ?? 0), [props.count])\` \u2014 or a \`ggui_amend\` repaint applies the new props while the display keeps the stale local value. BAD: \`const [count, setCount] = useState(props.count ?? 0)\` alone. GOOD: the same seed + the one-line re-sync effect.
984
997
  - **Loading state**: while data is still absent, render \`<Skeleton>\` placeholders \u2014 never a blank screen. \`<Skeleton variant="text" />\` for a text line, \`variant="circle"\` for an avatar slot, default \`rect\` for a block.
985
998
  - **Empty state**: when a list or results array is empty, render \`<EmptyState title="\u2026" description="\u2026" />\` \u2014 a region that renders nothing when empty looks broken to the user.
986
999
 
@@ -1108,7 +1121,7 @@ Every value change is mirrored to the host LLM's context automatically (debounce
1108
1121
 
1109
1122
  **When NOT to use it.** Local UI state the contract did NOT declare \u2014 \`isDropdownOpen\`, hover flags, animation phase, ephemeral toggles. For those, use a plain \`useState\` directly. The runtime ignores undeclared state.
1110
1123
 
1111
- **\`contextSpec\` direction is one-way: client \u2192 agent.** The agent uses \`propsSpec\` (via \`ggui_update\`) and \`streamSpec\` (via the live channel) to push state TO the client. Don't try to write to the agent via \`contextSpec\` \u2014 there is no return path.
1124
+ **\`contextSpec\` direction is one-way: client \u2192 agent.** The agent uses \`propsSpec\` (via \`ggui_amend\` for in-place repaints of this mount, or \`ggui_update\` when it mints a new history card) and \`streamSpec\` (via the live channel) to push state TO the client. Don't try to write to the agent via \`contextSpec\` \u2014 there is no return path.
1112
1125
 
1113
1126
  **Schema mismatches drop silently.** If you set a value that doesn't match the slot's schema (e.g. a string into a \`{type: 'number'}\` slot), the runtime logs a dev \`console.warn\` and skips the post. Make sure your setter calls produce values that match the declared shape.
1114
1127