@ggui-ai/ui-gen 0.28.0 → 0.29.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/{adapter-h4_V69LI.d.ts → adapter-DLQ-5COm.d.ts} +1 -1
- package/dist/adapters/base.js +2 -27
- package/dist/adapters/base.js.map +1 -1
- package/dist/adapters/generation-dispatch.d.ts +14 -6
- package/dist/adapters/generation-dispatch.js +40 -19260
- package/dist/adapters/generation-dispatch.js.map +1 -1
- package/dist/adapters/index.d.ts +1 -1
- package/dist/adapters/index.js +25 -3561
- package/dist/adapters/index.js.map +1 -1
- package/dist/adapters/types.js +2 -9
- package/dist/adapters/types.js.map +1 -1
- package/dist/advanced/index.d.ts +13 -12
- package/dist/advanced/index.js +63 -21954
- package/dist/advanced/index.js.map +1 -1
- package/dist/{bank-Ctdp3FUA.d.ts → bank-LWaiAtaA.d.ts} +1 -1
- package/dist/blueprint-validator.js +6 -2301
- package/dist/blueprint-validator.js.map +1 -1
- package/dist/boilerplate.d.ts +3 -2
- package/dist/boilerplate.js +6 -1867
- package/dist/boilerplate.js.map +1 -1
- package/dist/check/index.d.ts +3 -2
- package/dist/check/index.js +6 -1923
- package/dist/check/index.js.map +1 -1
- package/dist/chunk-33B3BAWS.js +24 -0
- package/dist/chunk-33B3BAWS.js.map +1 -0
- package/dist/chunk-3HSGA6NI.js +591 -0
- package/dist/chunk-3HSGA6NI.js.map +1 -0
- package/dist/chunk-3NNNGNTO.js +1707 -0
- package/dist/chunk-3NNNGNTO.js.map +1 -0
- package/dist/chunk-3T2HMTON.js +79 -0
- package/dist/chunk-3T2HMTON.js.map +1 -0
- package/dist/chunk-3ZSSDV3L.js +123 -0
- package/dist/chunk-3ZSSDV3L.js.map +1 -0
- package/dist/chunk-4MBR5GA3.js +99 -0
- package/dist/chunk-4MBR5GA3.js.map +1 -0
- package/dist/chunk-56NJFD55.js +337 -0
- package/dist/chunk-56NJFD55.js.map +1 -0
- package/dist/chunk-5AGTY555.js +26 -0
- package/dist/chunk-5AGTY555.js.map +1 -0
- package/dist/chunk-5EJM7EGY.js +115 -0
- package/dist/chunk-5EJM7EGY.js.map +1 -0
- package/dist/chunk-5KXCQLLR.js +529 -0
- package/dist/chunk-5KXCQLLR.js.map +1 -0
- package/dist/chunk-5VBXHVEH.js +171 -0
- package/dist/chunk-5VBXHVEH.js.map +1 -0
- package/dist/chunk-6KDDEING.js +515 -0
- package/dist/chunk-6KDDEING.js.map +1 -0
- package/dist/chunk-6VDRWAP6.js +123 -0
- package/dist/chunk-6VDRWAP6.js.map +1 -0
- package/dist/chunk-732IBFEJ.js +2400 -0
- package/dist/chunk-732IBFEJ.js.map +1 -0
- package/dist/chunk-73AURS3I.js +46 -0
- package/dist/chunk-73AURS3I.js.map +1 -0
- package/dist/chunk-77H5SKLX.js +8 -0
- package/dist/chunk-77H5SKLX.js.map +1 -0
- package/dist/chunk-7QE3AHLE.js +35 -0
- package/dist/chunk-7QE3AHLE.js.map +1 -0
- package/dist/chunk-A375NNWN.js +11 -0
- package/dist/chunk-A375NNWN.js.map +1 -0
- package/dist/chunk-AOU33EFS.js +140 -0
- package/dist/chunk-AOU33EFS.js.map +1 -0
- package/dist/chunk-BA4QYA6E.js +461 -0
- package/dist/chunk-BA4QYA6E.js.map +1 -0
- package/dist/chunk-DBP764GL.js +3 -0
- package/dist/chunk-DBP764GL.js.map +1 -0
- package/dist/chunk-DUU3ZJDQ.js +41 -0
- package/dist/chunk-DUU3ZJDQ.js.map +1 -0
- package/dist/chunk-DXKRBXNU.js +30 -0
- package/dist/chunk-DXKRBXNU.js.map +1 -0
- package/dist/chunk-FB7OEEAH.js +1467 -0
- package/dist/chunk-FB7OEEAH.js.map +1 -0
- package/dist/chunk-FLRNMZV2.js +18 -0
- package/dist/chunk-FLRNMZV2.js.map +1 -0
- package/dist/chunk-FWJIMKFZ.js +2032 -0
- package/dist/chunk-FWJIMKFZ.js.map +1 -0
- package/dist/chunk-FXRHWYIQ.js +163 -0
- package/dist/chunk-FXRHWYIQ.js.map +1 -0
- package/dist/chunk-G3PMV62Z.js +33 -0
- package/dist/chunk-G3PMV62Z.js.map +1 -0
- package/dist/chunk-GAJI7Y3P.js +13 -0
- package/dist/chunk-GAJI7Y3P.js.map +1 -0
- package/dist/chunk-GYINWMPR.js +2052 -0
- package/dist/chunk-GYINWMPR.js.map +1 -0
- package/dist/chunk-HD6ABIK7.js +484 -0
- package/dist/chunk-HD6ABIK7.js.map +1 -0
- package/dist/chunk-HDQVHYO6.js +100 -0
- package/dist/chunk-HDQVHYO6.js.map +1 -0
- package/dist/chunk-IHUT3SIW.js +7 -0
- package/dist/chunk-IHUT3SIW.js.map +1 -0
- package/dist/chunk-JDH5EGNZ.js +126 -0
- package/dist/chunk-JDH5EGNZ.js.map +1 -0
- package/dist/chunk-JMD4RGSV.js +37 -0
- package/dist/chunk-JMD4RGSV.js.map +1 -0
- package/dist/chunk-KJWGZL5B.js +33 -0
- package/dist/chunk-KJWGZL5B.js.map +1 -0
- package/dist/chunk-MKMDQFZ7.js +86 -0
- package/dist/chunk-MKMDQFZ7.js.map +1 -0
- package/dist/chunk-NF6JUZWF.js +85 -0
- package/dist/chunk-NF6JUZWF.js.map +1 -0
- package/dist/chunk-O2YC6XDC.js +1933 -0
- package/dist/chunk-O2YC6XDC.js.map +1 -0
- package/dist/chunk-OVLH5ICV.js +29 -0
- package/dist/chunk-OVLH5ICV.js.map +1 -0
- package/dist/chunk-PBOYHGSD.js +106 -0
- package/dist/chunk-PBOYHGSD.js.map +1 -0
- package/dist/chunk-PJFH7QWA.js +81 -0
- package/dist/chunk-PJFH7QWA.js.map +1 -0
- package/dist/chunk-PUH4CXGZ.js +284 -0
- package/dist/chunk-PUH4CXGZ.js.map +1 -0
- package/dist/chunk-QLXXPGTV.js +18 -0
- package/dist/chunk-QLXXPGTV.js.map +1 -0
- package/dist/chunk-R5GIGPW2.js +2845 -0
- package/dist/chunk-R5GIGPW2.js.map +1 -0
- package/dist/chunk-RH4IUSTO.js +83 -0
- package/dist/chunk-RH4IUSTO.js.map +1 -0
- package/dist/chunk-S2GVXKKY.js +153 -0
- package/dist/chunk-S2GVXKKY.js.map +1 -0
- package/dist/chunk-TVHGKFJS.js +58 -0
- package/dist/chunk-TVHGKFJS.js.map +1 -0
- package/dist/chunk-U7GALWLG.js +66 -0
- package/dist/chunk-U7GALWLG.js.map +1 -0
- package/dist/chunk-VTC263LT.js +256 -0
- package/dist/chunk-VTC263LT.js.map +1 -0
- package/dist/chunk-WEOXFEVE.js +739 -0
- package/dist/chunk-WEOXFEVE.js.map +1 -0
- package/dist/chunk-WYHP46LT.js +28 -0
- package/dist/chunk-WYHP46LT.js.map +1 -0
- package/dist/chunk-XGLO5LGG.js +274 -0
- package/dist/chunk-XGLO5LGG.js.map +1 -0
- package/dist/chunk-XRBCRKA2.js +29 -0
- package/dist/chunk-XRBCRKA2.js.map +1 -0
- package/dist/chunk-XW7ADFFV.js +340 -0
- package/dist/chunk-XW7ADFFV.js.map +1 -0
- package/dist/chunk-YIQ42IUX.js +34 -0
- package/dist/chunk-YIQ42IUX.js.map +1 -0
- package/dist/chunk-YJZTUY7B.js +101 -0
- package/dist/chunk-YJZTUY7B.js.map +1 -0
- package/dist/chunk-Z3CXME3K.js +107 -0
- package/dist/chunk-Z3CXME3K.js.map +1 -0
- package/dist/classifier/index.js +2 -527
- package/dist/classifier/index.js.map +1 -1
- package/dist/client-JBPCXU7W.js +4 -0
- package/dist/client-JBPCXU7W.js.map +1 -0
- package/dist/compose.js +3 -367
- package/dist/compose.js.map +1 -1
- package/dist/cost-tracker-HHGQ4FTW.js +67 -0
- package/dist/cost-tracker-HHGQ4FTW.js.map +1 -0
- package/dist/{create-ui-generator-BrZHF0cf.d.ts → create-ui-generator-BY-WeaPi.d.ts} +3 -3
- package/dist/{design-mode-DGWN_Gkm.d.ts → design-mode-XyOQmzE0.d.ts} +4 -3
- package/dist/{dispatch-B07TI30d.d.ts → dispatch-8LzTddKw.d.ts} +3 -2
- package/dist/dist-UALN6ZVB.js +543 -0
- package/dist/dist-UALN6ZVB.js.map +1 -0
- package/dist/dupe-break-X6K7QFIS.js +4 -0
- package/dist/dupe-break-X6K7QFIS.js.map +1 -0
- package/dist/evaluation/axis-checks/index.d.ts +5 -4
- package/dist/evaluation/axis-checks/index.js +6 -1914
- package/dist/evaluation/axis-checks/index.js.map +1 -1
- package/dist/evaluation/axis-checks/registry.d.ts +3 -2
- package/dist/evaluation/axis-checks/registry.js +3 -1844
- package/dist/evaluation/axis-checks/registry.js.map +1 -1
- package/dist/evaluation/index.d.ts +49 -132
- package/dist/evaluation/index.js +302 -6466
- package/dist/evaluation/index.js.map +1 -1
- package/dist/evaluation/types.d.ts +3 -2
- package/dist/evaluation/types.js +2 -5
- package/dist/evaluation/types.js.map +1 -1
- package/dist/fragments/index.js +2 -338
- package/dist/fragments/index.js.map +1 -1
- package/dist/{generate-tSO_shQ0.d.ts → generate-DQ4ci90s.d.ts} +1 -1
- package/dist/harness/check/runtime-render/index.d.ts +35 -15
- package/dist/harness/check/runtime-render/index.js +6 -2390
- package/dist/harness/check/runtime-render/index.js.map +1 -1
- package/dist/harness/check/runtime-render/render-check-worker.js +4 -1739
- package/dist/harness/check/runtime-render/render-check-worker.js.map +1 -1
- package/dist/harness/index.d.ts +3 -2
- package/dist/harness/index.js +23 -5126
- package/dist/harness/index.js.map +1 -1
- package/dist/harness/llm-trace-sink.js +2 -24
- package/dist/harness/llm-trace-sink.js.map +1 -1
- package/dist/harness/prompts.d.ts +2 -2
- package/dist/harness/prompts.js +8 -324
- package/dist/harness/prompts.js.map +1 -1
- package/dist/harness/result-types.d.ts +6 -5
- package/dist/harness/result-types.js +2 -0
- package/dist/harness/result-types.js.map +1 -1
- package/dist/harness/runtime.d.ts +22 -5
- package/dist/harness/runtime.js +10 -2313
- package/dist/harness/runtime.js.map +1 -1
- package/dist/harness/types-public.d.ts +3 -2
- package/dist/harness/types-public.js +16 -2954
- package/dist/harness/types-public.js.map +1 -1
- package/dist/harness/validator-trace-sink.d.ts +3 -2
- package/dist/harness/validator-trace-sink.js +2 -26
- package/dist/harness/validator-trace-sink.js.map +1 -1
- package/dist/hash.js +2 -39
- package/dist/hash.js.map +1 -1
- package/dist/hashline-5OKREIRM.js +4 -0
- package/dist/hashline-5OKREIRM.js.map +1 -0
- package/dist/index.d.ts +50 -11
- package/dist/index.js +57 -22015
- package/dist/index.js.map +1 -1
- package/dist/llm-evaluator-PN3WFCS4.js +653 -0
- package/dist/llm-evaluator-PN3WFCS4.js.map +1 -0
- package/dist/magic-string.es-2NZTC4GZ.js +1307 -0
- package/dist/magic-string.es-2NZTC4GZ.js.map +1 -0
- package/dist/patch.d.ts +3 -2
- package/dist/patch.js +2 -56
- package/dist/patch.js.map +1 -1
- package/dist/policy-VCYKGSAC.js +5 -0
- package/dist/policy-VCYKGSAC.js.map +1 -0
- package/dist/policy.js +2 -35
- package/dist/policy.js.map +1 -1
- package/dist/primitive-index-2OF6F4TZ.js +131 -0
- package/dist/primitive-index-2OF6F4TZ.js.map +1 -0
- package/dist/primitive-slice-WTMBLYFJ.js +235 -0
- package/dist/primitive-slice-WTMBLYFJ.js.map +1 -0
- package/dist/{prompts-BhNUuRoZ.d.ts → prompts-CLZGywMP.d.ts} +1 -1
- package/dist/provider-adapter-contract.js +10407 -14204
- package/dist/provider-adapter-contract.js.map +1 -1
- package/dist/provider-adapter.js +2 -44
- package/dist/provider-adapter.js.map +1 -1
- package/dist/providers/index.d.ts +89 -1
- package/dist/providers/index.js +115 -44
- package/dist/providers/index.js.map +1 -1
- package/dist/raw-C6KBH5I3.js +141 -0
- package/dist/raw-C6KBH5I3.js.map +1 -0
- package/dist/raw-FXSBXQTZ.js +7 -0
- package/dist/raw-FXSBXQTZ.js.map +1 -0
- package/dist/raw-MURDUPGK.js +8 -0
- package/dist/raw-MURDUPGK.js.map +1 -0
- package/dist/raw-T3GW3UVX.js +8 -0
- package/dist/raw-T3GW3UVX.js.map +1 -0
- package/dist/render-check-host-ZNIS6BJ5.js +5 -0
- package/dist/render-check-host-ZNIS6BJ5.js.map +1 -0
- package/dist/sdk-4JNSDNSR.js +6 -0
- package/dist/sdk-4JNSDNSR.js.map +1 -0
- package/dist/sdk-DIVJMHCX.js +7 -0
- package/dist/sdk-DIVJMHCX.js.map +1 -0
- package/dist/sdk-QRJOCRTS.js +7 -0
- package/dist/sdk-QRJOCRTS.js.map +1 -0
- package/dist/tag-balance-CTHCTRJ7.js +123 -0
- package/dist/tag-balance-CTHCTRJ7.js.map +1 -0
- package/dist/tools/get-primitives-ts.d.ts +1 -1
- package/dist/tools/get-primitives-ts.js +3 -1
- package/dist/tools/get-primitives-ts.js.map +1 -1
- package/dist/tools/render-check-worker.js +3 -40
- package/dist/tools/render-check-worker.js.map +1 -1
- package/dist/{types-public-h8IMnYuh.d.ts → types-public-hYlrerZh.d.ts} +35 -2
- package/dist/validation/index.d.ts +2 -2
- package/dist/validation/index.js +3 -498
- package/dist/validation/index.js.map +1 -1
- package/dist/{visual-evaluator-C2strxqD.d.ts → visual-evaluator-KskajxD5.d.ts} +14 -4
- package/dist/visual-evaluator-TGEXYQTP.js +12 -0
- package/dist/visual-evaluator-TGEXYQTP.js.map +1 -0
- package/dist/workflows.d.ts +3 -2
- package/dist/workflows.js +2 -151
- package/dist/workflows.js.map +1 -1
- package/package.json +20 -16
- package/src/adapters/claude/sdk.ts +4 -2
- package/src/adapters/claude/tool-bridge.ts +2 -1
- package/src/adapters/generation-dispatch.ts +9 -0
- package/src/adapters/openai/raw.ts +4 -0
- package/src/adapters/openai/sdk.ts +6 -1
- package/src/adapters/openai/tokens.ts +21 -7
- package/src/adapters/tool-bridge.ts +1 -1
- package/src/adapters/tools.ts +1 -1
- package/src/advanced/feedback.ts +1 -2
- package/src/advanced/generator.ts +4 -3
- package/src/boilerplate/free-design-prompt.ts +7 -0
- package/src/boilerplate/generate.ts +18 -5
- package/src/boilerplate/hard-sections.ts +8 -3
- package/src/boilerplate/react-hooks.ts +56 -0
- package/src/boilerplate/system-prompt.ts +12 -3
- package/src/check/run-tier0.ts +233 -8
- package/src/check/type-checker.ts +128 -16
- package/src/coding-agent/tools.ts +26 -3
- package/src/design-mode.ts +4 -9
- package/src/evaluation/axis-checks/checks/state-merge.ts +2 -4
- package/src/evaluation/axis-checks/checks/state-payload.ts +1 -28
- package/src/evaluation/axis-checks/checks/tint.ts +197 -0
- package/src/evaluation/axis-checks/helpers.ts +121 -0
- package/src/evaluation/axis-checks/registry.ts +2 -0
- package/src/evaluation/criteria/__fixtures__/edge-v2-draw2.json +4629 -0
- package/src/evaluation/criteria/bank.ts +1 -1
- package/src/evaluation/criteria/edge-instruments.ts +14 -0
- package/src/evaluation/criteria/edge-probe-v2.ts +352 -0
- package/src/evaluation/criteria/edge-v2.ts +242 -0
- package/src/evaluation/criteria/resolve.ts +24 -5
- package/src/evaluation/index.ts +3 -5
- package/src/evaluation/mcp-server.ts +0 -50
- package/src/evaluation/types-public.ts +6 -1
- package/src/evaluation/visual-evaluator.ts +161 -30
- package/src/harness/check/runtime-render/index.ts +28 -4
- package/src/harness/check/runtime-render/render-check.ts +20 -21
- package/src/harness/claude-agent-sdk-loader.ts +93 -0
- package/src/harness/claude-code-login-query.ts +1 -1
- package/src/harness/coding/generate-task-runner.ts +1 -0
- package/src/harness/coding/run-coding-turn.ts +3 -0
- package/src/harness/coding/run-eval-round.ts +9 -0
- package/src/harness/llm-router.ts +50 -2
- package/src/harness/runtime.ts +17 -0
- package/src/index.ts +9 -0
- package/src/providers/anthropic-tool-call.ts +263 -0
- package/src/providers/index.ts +13 -0
- package/src/tools/get-primitives-ts.ts +1 -1
- package/src/tools/render-check.ts +4 -4
- package/src/validation/primitives.ts +2 -1
- package/src/evaluation/loop.ts +0 -218
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
import { propsSpecToTypeScript } from './chunk-FWJIMKFZ.js';
|
|
2
|
+
import { STYLING_PROFILE_PRECEDENCE_NOTE } from './chunk-NF6JUZWF.js';
|
|
3
|
+
import { canvasDisplayModeForShell, canvasForViewportWidth } from './chunk-3T2HMTON.js';
|
|
4
|
+
import { listContractGadgets, HOOK_NAME_RE } from '@ggui-ai/protocol';
|
|
5
|
+
|
|
6
|
+
var SHELL_HINTS = {
|
|
7
|
+
chat: `**Chat Shell \u2014 Inline card in scrolling conversation**
|
|
8
|
+
- Container: width varies (60-80% of viewport), height: auto (natural content height)
|
|
9
|
+
- Chrome: parent provides card border + shadow + rounded corners \u2014 do NOT add your own box-shadow or outer border-radius
|
|
10
|
+
- Sizing: target 300-600px natural height. Do NOT use min-height: 100vh. No full-viewport designs.
|
|
11
|
+
- Padding: use var(--ggui-spacing-2) for inner elements, var(--ggui-spacing-4) for sections. Tight.
|
|
12
|
+
- Scrolling: parent scrolls (chat feed) \u2014 component should NOT have internal scroll
|
|
13
|
+
- Layout: single column, compact. No sidebar. Stack everything vertically.
|
|
14
|
+
- Width: the root is width: 100% (fills the bubble) \u2014 never cap the ROOT. A prose column inside it carries the reading cap (<Container maxWidth="sm">), which is inert at bubble width; the chips or buttons that answer the prose sit in a Container of the same maxWidth, so they share its left edge.`,
|
|
15
|
+
fullscreen: `**Fullscreen Shell \u2014 Takes over entire viewport**
|
|
16
|
+
- Container: the whole viewport, edge to edge \u2014 the frame stretches your root to its full height (you never set a viewport height yourself)
|
|
17
|
+
- Chrome: NONE \u2014 your component IS the entire UI. You own all visual chrome.
|
|
18
|
+
- Sizing: size to content; to fill a parent that has a height use height: 100% or flex: 1. NEVER min-height: 100vh / 100dvh \u2014 the frame already stretches the root, and a viewport height only fights it (tier-0 fail).
|
|
19
|
+
- Padding: component owns ALL padding. Use var(--ggui-spacing-6) or larger for breathing room.
|
|
20
|
+
- Scrolling: component manages its own scroll if content exceeds viewport (overflow-y: auto)
|
|
21
|
+
- Layout: can use multi-column, sidebars, headers/footers. Full creative control.
|
|
22
|
+
- Navigation: swipe left/right between pages is handled by the shell \u2014 don't implement it.
|
|
23
|
+
- DO NOT add outer margins or max-width containers. Fill the space.`,
|
|
24
|
+
partial: `**Partial Shell \u2014 Embedded panel in a larger page**
|
|
25
|
+
- Container: width constrained by parent (could be 400px sidebar or 800px main area)
|
|
26
|
+
- Chrome: parent may or may not have border \u2014 add your own Card/shadow if needed
|
|
27
|
+
- Sizing: width: 100% to fill parent. Use max-width if you want to center content.
|
|
28
|
+
- Padding: use standard spacing (var(--ggui-spacing-4) to var(--ggui-spacing-6))
|
|
29
|
+
- Scrolling: can scroll internally (overflow-y: auto) \u2014 parent does NOT scroll for you
|
|
30
|
+
- Layout: responsive within the container. Flex-wrap for variable parent widths.
|
|
31
|
+
- Context: other UI around you (nav, sidebar) \u2014 don't duplicate page-level chrome.`
|
|
32
|
+
};
|
|
33
|
+
var DEVICE_HINTS = {
|
|
34
|
+
mobile: `**Mobile:** Single column. Touch targets 44px+. Compact padding. Stack all sections vertically.`,
|
|
35
|
+
tablet: `**Tablet:** 1-2 columns adaptive. Medium touch targets. Side-by-side where space allows.`,
|
|
36
|
+
desktop: `**Desktop:** Multi-column. Hover states. Dense layouts. Keyboard shortcuts. Pointer interactions.`,
|
|
37
|
+
spatial: `**Spatial:** Fixed-size floating panel (~600x400). High contrast. Large text. No hover (gaze/hand input).`
|
|
38
|
+
};
|
|
39
|
+
function canvasForRenderingContext(ctx) {
|
|
40
|
+
const mode = canvasDisplayModeForShell(ctx.shell);
|
|
41
|
+
if (mode === "inline") return "xs-chat-card";
|
|
42
|
+
if (ctx.viewport) return canvasForViewportWidth(mode, ctx.viewport.width);
|
|
43
|
+
switch (ctx.device) {
|
|
44
|
+
case "mobile":
|
|
45
|
+
return "mobile-fullscreen-small";
|
|
46
|
+
case "tablet":
|
|
47
|
+
case "spatial":
|
|
48
|
+
return "md";
|
|
49
|
+
case "desktop":
|
|
50
|
+
return ctx.shell === "partial" ? "md" : "lg";
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
function buildRenderingContext(ctx) {
|
|
54
|
+
const parts = [
|
|
55
|
+
"## Rendering Context",
|
|
56
|
+
`- Device: ${ctx.device}`,
|
|
57
|
+
ctx.viewport ? `- Viewport: ${ctx.viewport.width}\xD7${ctx.viewport.height}px` : "",
|
|
58
|
+
`- Shell: ${ctx.shell}`,
|
|
59
|
+
"",
|
|
60
|
+
DEVICE_HINTS[ctx.device] || "",
|
|
61
|
+
SHELL_HINTS[ctx.shell] || ""
|
|
62
|
+
].filter(Boolean);
|
|
63
|
+
return parts.join("\n");
|
|
64
|
+
}
|
|
65
|
+
function injectRenderingContext(userPrompt, rendering) {
|
|
66
|
+
if (!rendering) return userPrompt;
|
|
67
|
+
return userPrompt + "\n\n" + buildRenderingContext(rendering);
|
|
68
|
+
}
|
|
69
|
+
function buildContractsContext(contract, appGadgets) {
|
|
70
|
+
const parts = [];
|
|
71
|
+
if (contract.propsSpec) {
|
|
72
|
+
const propsSpec = contract.propsSpec;
|
|
73
|
+
const requiredFields = Object.entries(propsSpec.properties || {}).filter(([, e]) => e.required).map(([k]) => k);
|
|
74
|
+
const optionalFields = Object.entries(propsSpec.properties || {}).filter(([, e]) => !e.required).map(([k]) => k);
|
|
75
|
+
const tsInterface = propsSpecToTypeScript(propsSpec);
|
|
76
|
+
const fieldInfo = [];
|
|
77
|
+
if (requiredFields.length > 0) fieldInfo.push(`Required: ${requiredFields.join(", ")}`);
|
|
78
|
+
if (optionalFields.length > 0) fieldInfo.push(`Optional: ${optionalFields.join(", ")}`);
|
|
79
|
+
parts.push(
|
|
80
|
+
`## Props Contract (MUST use these exact prop names and types)
|
|
81
|
+
|
|
82
|
+
` + (fieldInfo.length > 0 ? fieldInfo.join("\n") + "\n\n" : "") + `\`\`\`typescript
|
|
83
|
+
interface Props ${tsInterface}
|
|
84
|
+
\`\`\``
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
if (contract.actionSpec && Object.keys(contract.actionSpec).length > 0) {
|
|
88
|
+
const actions = Object.entries(contract.actionSpec).map(([id, entry]) => {
|
|
89
|
+
let line = ` - ${id}: "${entry.label ?? id}"${entry.description ? ` \u2014 ${entry.description}` : ""}`;
|
|
90
|
+
if (entry.example !== void 0) {
|
|
91
|
+
line += `
|
|
92
|
+
Example payload: \`${JSON.stringify(entry.example)}\``;
|
|
93
|
+
}
|
|
94
|
+
if (entry.nextStep) {
|
|
95
|
+
line += `
|
|
96
|
+
Next-step hint: agent intends to call \`${entry.nextStep}\``;
|
|
97
|
+
}
|
|
98
|
+
if (entry.confirm === true) {
|
|
99
|
+
line += `
|
|
100
|
+
Author flag: \`confirm\` \u2014 the author marked this action as one to confirm with the user before it fires.`;
|
|
101
|
+
}
|
|
102
|
+
return line;
|
|
103
|
+
}).join("\n");
|
|
104
|
+
parts.push(`## Action Contract (wire these callbacks)
|
|
105
|
+
${actions}`);
|
|
106
|
+
}
|
|
107
|
+
if (contract.streamSpec && Object.keys(contract.streamSpec).length > 0) {
|
|
108
|
+
const channels = Object.entries(contract.streamSpec).map(([name, entry]) => {
|
|
109
|
+
const bits = [` - ${name}`];
|
|
110
|
+
if (entry.description) bits.push(`\u2014 ${entry.description}`);
|
|
111
|
+
if (entry.source?.tool) {
|
|
112
|
+
bits.push(`(source tool: \`${entry.source.tool}\`)`);
|
|
113
|
+
}
|
|
114
|
+
return bits.join(" ");
|
|
115
|
+
}).join("\n");
|
|
116
|
+
parts.push(
|
|
117
|
+
`## Stream Contract (real-time channels via \`useStream(name)\`)
|
|
118
|
+
${channels}
|
|
119
|
+
|
|
120
|
+
Payload schemas:
|
|
121
|
+
\`\`\`json
|
|
122
|
+
${JSON.stringify(contract.streamSpec, null, 2)}
|
|
123
|
+
\`\`\``
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
const agentTools = contract.agentCapabilities?.tools;
|
|
127
|
+
if (agentTools && Object.keys(agentTools).length > 0) {
|
|
128
|
+
const tools = Object.entries(agentTools).map(([name, entry]) => {
|
|
129
|
+
const bits = [` - **\`${name}\`**`];
|
|
130
|
+
if (entry.toolInfo?.description) bits.push(`\u2014 ${entry.toolInfo.description}`);
|
|
131
|
+
if (entry.usage) bits.push(`(usage: ${entry.usage})`);
|
|
132
|
+
return bits.join(" ");
|
|
133
|
+
}).join("\n");
|
|
134
|
+
parts.push(
|
|
135
|
+
`## AgentTools Catalog (tools the contract references)
|
|
136
|
+
${tools}
|
|
137
|
+
|
|
138
|
+
These are referenced via \`actionSpec[*].nextStep\` (the tool the agent SHOULD call next after the action fires) and \`streamSpec[*].source.tool\` (the tool feeding a channel). The agent OWNS the call \u2014 your component does not invoke these directly.
|
|
139
|
+
|
|
140
|
+
Schemas:
|
|
141
|
+
\`\`\`json
|
|
142
|
+
${JSON.stringify(agentTools, null, 2)}
|
|
143
|
+
\`\`\``
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
const clientCapabilities = contract.clientCapabilities?.gadgets;
|
|
147
|
+
const gadgetUses = listContractGadgets(contract);
|
|
148
|
+
if (gadgetUses.length > 0) {
|
|
149
|
+
const caps = gadgetUses.map((use) => {
|
|
150
|
+
const bits = [` - **\`${use.name}\`**`];
|
|
151
|
+
bits.push(
|
|
152
|
+
HOOK_NAME_RE.test(use.name) ? `via direct-imported hook \`${use.name}\` from \`${use.package}\` (call it)` : `via direct-imported component \`<${use.name} />\` from \`${use.package}\` (render as JSX)`
|
|
153
|
+
);
|
|
154
|
+
if (use.description) bits.push(`\u2014 ${use.description}`);
|
|
155
|
+
return bits.join(" ");
|
|
156
|
+
}).join("\n");
|
|
157
|
+
parts.push(
|
|
158
|
+
`## ClientCapabilities Contract (browser-capability gadgets the UI mounts)
|
|
159
|
+
${caps}
|
|
160
|
+
|
|
161
|
+
Hook entries are imported + called; component entries are imported + rendered as JSX. Capability values reach the agent only when the UI threads them into an actionSpec payload or contextSpec slot.
|
|
162
|
+
|
|
163
|
+
Declarations:
|
|
164
|
+
\`\`\`json
|
|
165
|
+
${JSON.stringify(clientCapabilities, null, 2)}
|
|
166
|
+
\`\`\``
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
const uiRequirements = [];
|
|
170
|
+
if (contract.propsSpec?.properties) {
|
|
171
|
+
for (const [name, entry] of Object.entries(contract.propsSpec.properties)) {
|
|
172
|
+
const required = entry.required === true;
|
|
173
|
+
if (required) {
|
|
174
|
+
uiRequirements.push(
|
|
175
|
+
`- **Required prop \`${name}\`** must appear somewhere in rendered DOM (display the value, or use it to drive a label/aria/key).`
|
|
176
|
+
);
|
|
177
|
+
} else {
|
|
178
|
+
uiRequirements.push(
|
|
179
|
+
`- **Optional prop \`${name}\`** may be ABSENT at runtime \u2014 the component must render without it (guard the access or apply its default) and must display it when it IS provided.`
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
if (contract.actionSpec) {
|
|
185
|
+
for (const [name, entry] of Object.entries(contract.actionSpec)) {
|
|
186
|
+
const label = entry.label ?? name;
|
|
187
|
+
uiRequirements.push(
|
|
188
|
+
`- **Action \`${name}\`** ("${label}") needs an interactive control that fires it (Button click, form submit, key press, etc.).`
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
if (contract.streamSpec) {
|
|
193
|
+
for (const name of Object.keys(contract.streamSpec)) {
|
|
194
|
+
uiRequirements.push(
|
|
195
|
+
`- **Stream \`${name}\`** must mirror into local state via \`useEffect\` and render the resulting state \u2014 \`useStream\` alone never re-renders the DOM.`
|
|
196
|
+
);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
for (const use of gadgetUses) {
|
|
200
|
+
const exportName = use.name;
|
|
201
|
+
const pkg = use.package;
|
|
202
|
+
uiRequirements.push(
|
|
203
|
+
HOOK_NAME_RE.test(exportName) ? `- **ClientCapability \`${exportName}\`** \u2014 the boilerplate has direct-imported \`${exportName}\` from \`${pkg}\` above a \`// DO NOT EDIT\` banner; keep that import, call \`${exportName}\` inside the component, and thread the resulting value into a context slot or action payload if the agent needs to observe it.` : `- **ClientCapability \`${exportName}\`** \u2014 the boilerplate has direct-imported \`${exportName}\` from \`${pkg}\` above a \`// DO NOT EDIT\` banner; keep that import and RENDER \`<${exportName} \u2026 />\` as a JSX element in the tree you return.`
|
|
204
|
+
);
|
|
205
|
+
}
|
|
206
|
+
if (uiRequirements.length > 0) {
|
|
207
|
+
parts.push(
|
|
208
|
+
`## Required UI Surfaces (derived from contract \u2014 every surface below MUST have visible UI, eval will fail if any is missing)
|
|
209
|
+
` + uiRequirements.join("\n")
|
|
210
|
+
);
|
|
211
|
+
}
|
|
212
|
+
return parts.join("\n\n");
|
|
213
|
+
}
|
|
214
|
+
function injectContracts(userPrompt, contract, appGadgets) {
|
|
215
|
+
if (!contract) return userPrompt;
|
|
216
|
+
const ctx = buildContractsContext(contract);
|
|
217
|
+
if (!ctx) return userPrompt;
|
|
218
|
+
return userPrompt + "\n\n" + ctx;
|
|
219
|
+
}
|
|
220
|
+
function buildVarianceContext(variance, options) {
|
|
221
|
+
const lines = [];
|
|
222
|
+
if (typeof variance.persona === "string" && variance.persona.length > 0) {
|
|
223
|
+
lines.push(`- **Persona**: ${variance.persona}`);
|
|
224
|
+
}
|
|
225
|
+
if (typeof variance.aesthetic === "string" && variance.aesthetic.length > 0) {
|
|
226
|
+
lines.push(`- **Aesthetic**: ${variance.aesthetic}`);
|
|
227
|
+
}
|
|
228
|
+
if (typeof variance.seedPrompt === "string" && variance.seedPrompt.length > 0) {
|
|
229
|
+
lines.push(`- **Seed prompt**: ${variance.seedPrompt}`);
|
|
230
|
+
}
|
|
231
|
+
if (variance.context !== void 0 && variance.context !== null && typeof variance.context === "object" && !Array.isArray(variance.context) && Object.keys(variance.context).length > 0) {
|
|
232
|
+
lines.push(`- **Context**: ${JSON.stringify(variance.context)}`);
|
|
233
|
+
}
|
|
234
|
+
if (lines.length === 0) return "";
|
|
235
|
+
return [
|
|
236
|
+
"## Variance (apply to styling, not contract shape)",
|
|
237
|
+
"",
|
|
238
|
+
"The agent (or operator) declared these variant signals. Honor them in",
|
|
239
|
+
"the visual treatment + copy register \u2014 but the contract shape (props,",
|
|
240
|
+
"actions, contexts, streams) remains canonical. Variance changes HOW",
|
|
241
|
+
"the UI looks and reads, not WHAT it does.",
|
|
242
|
+
...options?.profileDeclared === true ? [STYLING_PROFILE_PRECEDENCE_NOTE] : [],
|
|
243
|
+
"",
|
|
244
|
+
...lines
|
|
245
|
+
].join("\n");
|
|
246
|
+
}
|
|
247
|
+
function injectVariance(userPrompt, variance, options) {
|
|
248
|
+
if (!variance) return userPrompt;
|
|
249
|
+
const block = buildVarianceContext(variance, options);
|
|
250
|
+
if (!block) return userPrompt;
|
|
251
|
+
return userPrompt + "\n\n" + block;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
export { buildContractsContext, buildRenderingContext, buildVarianceContext, canvasForRenderingContext, injectContracts, injectRenderingContext, injectVariance };
|
|
255
|
+
//# sourceMappingURL=chunk-VTC263LT.js.map
|
|
256
|
+
//# sourceMappingURL=chunk-VTC263LT.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/contract-context.ts"],"names":[],"mappings":"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","file":"chunk-VTC263LT.js","sourcesContent":["/**\n * Contract + rendering-context prompt rendering.\n *\n * Surfaces every contract dimension explicitly to the LLM. A compact\n * bullet list of action / stream names is not enough — without the\n * Props shape, generation fails tier-0 on most cells with \"Props\n * interface missing required field '<name>'\".\n *\n * Renders:\n *\n * - Props contract — required + optional field lists + a real\n * TypeScript interface (compiled via `propsSpecToTypeScript`)\n * - Action contract — id / label / example / nextStep hint\n * - Stream contract — channel descriptions + payload schemas + source\n * - AgentTools — catalog of tools the contract references (via\n * `actionSpec[*].nextStep` and `streamSpec[*].source.tool`)\n * - ClientCapabilities — browser-capability gadgets the UI mounts:\n * hooks it calls (e.g. `useGeolocation` from `@ggui-ai/gadgets`)\n * and components it renders (e.g. `<LeafletMap />`)\n * - Required UI Surfaces — derived list of \"every contract surface\n * must have visible UI\" so the LLM doesn't drop required props or\n * skip rendering data sources\n *\n * Rendering context (device + shell + viewport) is layered alongside —\n * shells (`chat` / `fullscreen` / `partial`) require very different\n * sizing strategies and including the hint inline cuts a class of\n * \"designed for fullscreen, rendered in a chat bubble\" bugs.\n */\nimport { STYLING_PROFILE_PRECEDENCE_NOTE } from './boilerplate/styling-profile.js';\nimport type { RenderingContext as ProtocolRenderingContext } from '@ggui-ai/protocol';\nimport type {\n ActionEntry,\n BlueprintVariance,\n GadgetDescriptor,\n DataContract,\n StreamChannelEntry,\n} from '@ggui-ai/protocol';\nimport { HOOK_NAME_RE, listContractGadgets } from '@ggui-ai/protocol';\nimport { propsSpecToTypeScript } from './check/index.js';\nimport {\n canvasDisplayModeForShell,\n canvasForViewportWidth,\n type CanvasClass,\n} from './design-mode.js';\n\n/**\n * Rendering context — how and where the component will be displayed.\n * Affects layout strategy, sizing, and interaction patterns. The ONE\n * vocabulary is `@ggui-ai/protocol`'s `renderingContextSchema` (ggui#1000);\n * this is its type, derived — never re-declared here.\n */\nexport type RenderingContext = ProtocolRenderingContext;\n\nconst SHELL_HINTS: Record<string, string> = {\n chat: `**Chat Shell — Inline card in scrolling conversation**\n- Container: width varies (60-80% of viewport), height: auto (natural content height)\n- Chrome: parent provides card border + shadow + rounded corners — do NOT add your own box-shadow or outer border-radius\n- Sizing: target 300-600px natural height. Do NOT use min-height: 100vh. No full-viewport designs.\n- Padding: use var(--ggui-spacing-2) for inner elements, var(--ggui-spacing-4) for sections. Tight.\n- Scrolling: parent scrolls (chat feed) — component should NOT have internal scroll\n- Layout: single column, compact. No sidebar. Stack everything vertically.\n- Width: the root is width: 100% (fills the bubble) — never cap the ROOT. A prose column inside it carries the reading cap (<Container maxWidth=\"sm\">), which is inert at bubble width; the chips or buttons that answer the prose sit in a Container of the same maxWidth, so they share its left edge.`,\n\n fullscreen: `**Fullscreen Shell — Takes over entire viewport**\n- Container: the whole viewport, edge to edge — the frame stretches your root to its full height (you never set a viewport height yourself)\n- Chrome: NONE — your component IS the entire UI. You own all visual chrome.\n- Sizing: size to content; to fill a parent that has a height use height: 100% or flex: 1. NEVER min-height: 100vh / 100dvh — the frame already stretches the root, and a viewport height only fights it (tier-0 fail).\n- Padding: component owns ALL padding. Use var(--ggui-spacing-6) or larger for breathing room.\n- Scrolling: component manages its own scroll if content exceeds viewport (overflow-y: auto)\n- Layout: can use multi-column, sidebars, headers/footers. Full creative control.\n- Navigation: swipe left/right between pages is handled by the shell — don't implement it.\n- DO NOT add outer margins or max-width containers. Fill the space.`,\n\n partial: `**Partial Shell — Embedded panel in a larger page**\n- Container: width constrained by parent (could be 400px sidebar or 800px main area)\n- Chrome: parent may or may not have border — add your own Card/shadow if needed\n- Sizing: width: 100% to fill parent. Use max-width if you want to center content.\n- Padding: use standard spacing (var(--ggui-spacing-4) to var(--ggui-spacing-6))\n- Scrolling: can scroll internally (overflow-y: auto) — parent does NOT scroll for you\n- Layout: responsive within the container. Flex-wrap for variable parent widths.\n- Context: other UI around you (nav, sidebar) — don't duplicate page-level chrome.`,\n};\n\nconst DEVICE_HINTS: Record<string, string> = {\n mobile: `**Mobile:** Single column. Touch targets 44px+. Compact padding. Stack all sections vertically.`,\n tablet: `**Tablet:** 1-2 columns adaptive. Medium touch targets. Side-by-side where space allows.`,\n desktop: `**Desktop:** Multi-column. Hover states. Dense layouts. Keyboard shortcuts. Pointer interactions.`,\n spatial: `**Spatial:** Fixed-size floating panel (~600x400). High contrast. Large text. No hover (gaze/hand input).`,\n};\n\n/**\n * Map a host rendering context onto the canvas class the `free` prompt\n * states and the visual evaluator judges at. The class is derived from\n * DISPLAY MODE + width: a `chat` shell is always the inline card\n * whatever the host viewport is (the bubble, not the window, bounds the\n * component); a known viewport width refines the fullscreen / partial\n * shells; otherwise the device category decides.\n */\nexport function canvasForRenderingContext(ctx: RenderingContext): CanvasClass {\n const mode = canvasDisplayModeForShell(ctx.shell);\n if (mode === 'inline') return 'xs-chat-card';\n if (ctx.viewport) return canvasForViewportWidth(mode, ctx.viewport.width);\n switch (ctx.device) {\n case 'mobile':\n return 'mobile-fullscreen-small';\n case 'tablet':\n case 'spatial':\n return 'md';\n case 'desktop':\n return ctx.shell === 'partial' ? 'md' : 'lg';\n }\n}\n\n/** Build rendering-context block to inject into user prompt. */\nexport function buildRenderingContext(ctx: RenderingContext): string {\n const parts = [\n '## Rendering Context',\n `- Device: ${ctx.device}`,\n ctx.viewport ? `- Viewport: ${ctx.viewport.width}×${ctx.viewport.height}px` : '',\n `- Shell: ${ctx.shell}`,\n '',\n DEVICE_HINTS[ctx.device] || '',\n SHELL_HINTS[ctx.shell] || '',\n ].filter(Boolean);\n return parts.join('\\n');\n}\n\n/** Append rendering context to user prompt if present. */\nexport function injectRenderingContext(\n userPrompt: string,\n rendering?: RenderingContext,\n): string {\n if (!rendering) return userPrompt;\n return userPrompt + '\\n\\n' + buildRenderingContext(rendering);\n}\n\n/**\n * Build the contract-context block. Surfaces every dimension of the\n * contract so the LLM has a complete spec rather than the user-prompt\n * narrative alone — the eval scores against the contract regardless of\n * what prose the prompt carries, so contract-first rendering closes\n * the prompt-vs-contract drift class.\n */\nexport function buildContractsContext(\n contract: DataContract,\n /**\n * Operator-registered gadget catalog. When a\n * `clientCapabilities.gadgets[*]` ref is THIN (just `{hook}` —\n * no per-binding `package`), look the hook up here to surface the\n * correct package in user-prompt lines like `via useLeafletMap from\n * @ggui-samples/gadget-leaflet`. Mirrors the same plumb in\n * `harness/prompts.ts:buildContractsContext` — both surfaces are\n * separate copies used by different call sites (this one is for\n * `createUiGenerator`, the other for the benchmark / dispatch path).\n */\n appGadgets?: readonly GadgetDescriptor[],\n): string {\n const parts: string[] = [];\n\n // The LLM direct-imports each hook from its own package\n // (resolved from the per-entry `package` field). The parameter stays\n // on the signature so the TypeScript sandbox augmentation layer can\n // still consume it.\n void appGadgets;\n\n // `intent` is not a contract field; `userPrompt` already carries\n // the agent's narrative as the prompt body, so the contract-context\n // block focuses on the structural shape (props / actions / streams /\n // contexts). There is no categorical `interaction` mode label: the\n // four-spec surface (props / actions / streams / contexts) describes\n // the wire exhaustively — actions drive turns, contexts observe\n // state, and there is no third category.\n\n if (contract.propsSpec) {\n const propsSpec = contract.propsSpec;\n const requiredFields = Object.entries(propsSpec.properties || {})\n .filter(([, e]) => (e as { required?: boolean }).required)\n .map(([k]) => k);\n const optionalFields = Object.entries(propsSpec.properties || {})\n .filter(([, e]) => !(e as { required?: boolean }).required)\n .map(([k]) => k);\n\n const tsInterface = propsSpecToTypeScript(propsSpec);\n const fieldInfo: string[] = [];\n if (requiredFields.length > 0) fieldInfo.push(`Required: ${requiredFields.join(', ')}`);\n if (optionalFields.length > 0) fieldInfo.push(`Optional: ${optionalFields.join(', ')}`);\n\n parts.push(\n `## Props Contract (MUST use these exact prop names and types)\\n\\n` +\n (fieldInfo.length > 0 ? fieldInfo.join('\\n') + '\\n\\n' : '') +\n `\\`\\`\\`typescript\\ninterface Props ${tsInterface}\\n\\`\\`\\``,\n );\n }\n\n if (contract.actionSpec && Object.keys(contract.actionSpec).length > 0) {\n const actions = Object.entries(contract.actionSpec)\n .map(([id, entry]: [string, ActionEntry]) => {\n let line = ` - ${id}: \"${entry.label ?? id}\"${entry.description ? ` — ${entry.description}` : ''}`;\n if (entry.example !== undefined) {\n line += `\\n Example payload: \\`${JSON.stringify(entry.example)}\\``;\n }\n if (entry.nextStep) {\n line += `\\n Next-step hint: agent intends to call \\`${entry.nextStep}\\``;\n }\n // ggui#1108: `confirm` was the one declared action field the contract\n // renderer dropped — every other author field (label, description,\n // example, nextStep) reaches the model and this one did not. It is\n // rendered as INFORMATION, not as a rule: the terminal-actions section\n // deliberately does NOT cite it, because citing it measured ZERO —\n // two wordings, n=4 each, `save` + `confirm: true` came back armed 0/4\n // and 0/4. The field's own doc says \"whether to show confirmation\n // BEFORE triggering\", which is gravity, not one-shot-ness, and the\n // model reads it that way. Emitted only when true, so an absent flag\n // leaves the prompt bytes identical to before this line existed.\n if (entry.confirm === true) {\n line += `\\n Author flag: \\`confirm\\` — the author marked this action as one to confirm with the user before it fires.`;\n }\n return line;\n })\n .join('\\n');\n parts.push(`## Action Contract (wire these callbacks)\\n${actions}`);\n }\n\n if (contract.streamSpec && Object.keys(contract.streamSpec).length > 0) {\n const channels = Object.entries(contract.streamSpec)\n .map(([name, entry]: [string, StreamChannelEntry]) => {\n const bits = [` - ${name}`];\n if (entry.description) bits.push(`— ${entry.description}`);\n if (entry.source?.tool) {\n bits.push(`(source tool: \\`${entry.source.tool}\\`)`);\n }\n return bits.join(' ');\n })\n .join('\\n');\n parts.push(\n `## Stream Contract (real-time channels via \\`useStream(name)\\`)\\n${channels}\\n\\n` +\n `Payload schemas:\\n\\`\\`\\`json\\n${JSON.stringify(contract.streamSpec, null, 2)}\\n\\`\\`\\``,\n );\n }\n\n const agentTools = contract.agentCapabilities?.tools;\n if (agentTools && Object.keys(agentTools).length > 0) {\n const tools = Object.entries(agentTools)\n .map(([name, entry]) => {\n const bits = [` - **\\`${name}\\`**`];\n if (entry.toolInfo?.description) bits.push(`— ${entry.toolInfo.description}`);\n if (entry.usage) bits.push(`(usage: ${entry.usage})`);\n return bits.join(' ');\n })\n .join('\\n');\n parts.push(\n `## AgentTools Catalog (tools the contract references)\\n${tools}\\n\\n` +\n `These are referenced via \\`actionSpec[*].nextStep\\` (the tool the agent SHOULD call next ` +\n `after the action fires) and \\`streamSpec[*].source.tool\\` (the tool feeding a channel). ` +\n `The agent OWNS the call — your component does not invoke these directly.\\n\\n` +\n `Schemas:\\n\\`\\`\\`json\\n${JSON.stringify(agentTools, null, 2)}\\n\\`\\`\\``,\n );\n }\n\n const clientCapabilities = contract.clientCapabilities?.gadgets;\n const gadgetUses = listContractGadgets(contract);\n if (gadgetUses.length > 0) {\n // The wire `clientCapabilities.gadgets` is a package-keyed\n // two-level map; `listContractGadgets` flattens it to `GadgetUse[]`.\n // Kind is discriminated by the export-name grammar — `use`-prefixed\n // names are hooks (imported + CALLED), PascalCase names are\n // components (imported + RENDERED as JSX). Both are direct-imported.\n const caps = gadgetUses\n .map((use) => {\n const bits = [` - **\\`${use.name}\\`**`];\n bits.push(\n HOOK_NAME_RE.test(use.name)\n ? `via direct-imported hook \\`${use.name}\\` from \\`${use.package}\\` (call it)`\n : `via direct-imported component \\`<${use.name} />\\` from \\`${use.package}\\` (render as JSX)`,\n );\n if (use.description) bits.push(`— ${use.description}`);\n return bits.join(' ');\n })\n .join('\\n');\n parts.push(\n `## ClientCapabilities Contract (browser-capability gadgets the UI mounts)\\n${caps}\\n\\n` +\n `Hook entries are imported + called; component entries are imported + rendered as JSX. ` +\n `Capability values reach the agent only when the UI threads them into an actionSpec ` +\n `payload or contextSpec slot.\\n\\n` +\n `Declarations:\\n\\`\\`\\`json\\n${JSON.stringify(clientCapabilities, null, 2)}\\n\\`\\`\\``,\n );\n }\n\n // Required-UI derivation — the architectural fix at the heart of v15.\n // Every contract surface implies a visible UI element; eval scores\n // against the contract regardless of what the user-prompt narrative\n // says. Emitting the implied UI surfaces explicitly makes the contract\n // the single source of truth for \"what must render\".\n const uiRequirements: string[] = [];\n if (contract.propsSpec?.properties) {\n for (const [name, entry] of Object.entries(contract.propsSpec.properties)) {\n // Opt-in required (`=== true`) — the wire gate's reading, ggui#528.\n // An omitted-`required` prop is OPTIONAL: the agent may leave it\n // out of a legitimate render, so the derived instruction must\n // demand a presence-safe component, not unconditional display.\n const required = (entry as { required?: boolean }).required === true;\n if (required) {\n uiRequirements.push(\n `- **Required prop \\`${name}\\`** must appear somewhere in rendered DOM (display the value, or use it to drive a label/aria/key).`,\n );\n } else {\n uiRequirements.push(\n `- **Optional prop \\`${name}\\`** may be ABSENT at runtime — the component must render without it (guard the access or apply its default) and must display it when it IS provided.`,\n );\n }\n }\n }\n if (contract.actionSpec) {\n for (const [name, entry] of Object.entries(contract.actionSpec)) {\n const label = (entry as ActionEntry).label ?? name;\n uiRequirements.push(\n `- **Action \\`${name}\\`** (\"${label}\") needs an interactive control that fires it (Button click, form submit, key press, etc.).`,\n );\n }\n }\n if (contract.streamSpec) {\n for (const name of Object.keys(contract.streamSpec)) {\n uiRequirements.push(\n `- **Stream \\`${name}\\`** must mirror into local state via \\`useEffect\\` and render the resulting state — \\`useStream\\` alone never re-renders the DOM.`,\n );\n }\n }\n // agentTools entries don't imply UI on their own — they're catalog\n // declarations the agent uses, not hooks the component invokes.\n // The implied UI lives on the referencing actionSpec entries\n // (already enumerated above) and streamSpec channels with `source`\n // declarations. No per-tool UI requirement is emitted here.\n for (const use of gadgetUses) {\n // Hook AND component exports are direct-imported; the\n // implied UI differs — a hook is called + its value threaded,\n // a component is rendered as a JSX element. Kind is discriminated\n // by the export-name grammar.\n const exportName = use.name;\n const pkg = use.package;\n uiRequirements.push(\n HOOK_NAME_RE.test(exportName)\n ? `- **ClientCapability \\`${exportName}\\`** — the boilerplate has direct-imported \\`${exportName}\\` from \\`${pkg}\\` above a \\`// DO NOT EDIT\\` banner; keep that import, call \\`${exportName}\\` inside the component, and thread the resulting value into a context slot or action payload if the agent needs to observe it.`\n : `- **ClientCapability \\`${exportName}\\`** — the boilerplate has direct-imported \\`${exportName}\\` from \\`${pkg}\\` above a \\`// DO NOT EDIT\\` banner; keep that import and RENDER \\`<${exportName} … />\\` as a JSX element in the tree you return.`,\n );\n }\n if (uiRequirements.length > 0) {\n parts.push(\n `## Required UI Surfaces (derived from contract — every surface below MUST have visible UI, eval will fail if any is missing)\\n` +\n uiRequirements.join('\\n'),\n );\n }\n\n return parts.join('\\n\\n');\n}\n\n/**\n * Append the contract-context block to a user prompt if a contract is present.\n *\n * `appGadgets` forwards into `buildContractsContext` so thin contract\n * refs (`{hook}` without per-binding `package`) resolve to the\n * registered descriptor's package in the prompt-emitted \"import X from\n * Y\" lines.\n */\nexport function injectContracts(\n userPrompt: string,\n contract?: DataContract,\n appGadgets?: readonly GadgetDescriptor[],\n): string {\n if (!contract) return userPrompt;\n const ctx = buildContractsContext(contract, appGadgets);\n if (!ctx) return userPrompt;\n return userPrompt + '\\n\\n' + ctx;\n}\n\n/**\n * Build the variance-context block. Surfaces the agent's declared\n * styling signals (persona, aesthetic, context, seedPrompt) so cold-gen\n * aligns the produced component with the requested variant. Each field\n * is optional; the block only renders when at least one is present.\n *\n * - `persona` names the USER mental model (e.g. \"data-analyst\",\n * \"mobile-first reader\") — drives copy register + density choices.\n * - `aesthetic` names the VISUAL treatment (e.g. \"glassmorphic\",\n * \"editorial\", \"brutalist\") — drives surface decoration, typographic\n * weight, color usage.\n * - `context` is structured key-value signal alongside the persona —\n * small JSON-safe shape, serialized verbatim into the prompt.\n * - `seedPrompt` is the operator's original natural-language steer that\n * produced this variant in cache storage — useful as a one-line\n * directive for cold-gen.\n *\n * Returns an empty string when no fields are populated so the inject\n * helper can no-op cleanly.\n */\nexport function buildVarianceContext(\n variance: BlueprintVariance,\n options?: { readonly profileDeclared?: boolean },\n): string {\n const lines: string[] = [];\n if (typeof variance.persona === 'string' && variance.persona.length > 0) {\n lines.push(`- **Persona**: ${variance.persona}`);\n }\n if (typeof variance.aesthetic === 'string' && variance.aesthetic.length > 0) {\n lines.push(`- **Aesthetic**: ${variance.aesthetic}`);\n }\n if (typeof variance.seedPrompt === 'string' && variance.seedPrompt.length > 0) {\n lines.push(`- **Seed prompt**: ${variance.seedPrompt}`);\n }\n if (\n variance.context !== undefined &&\n variance.context !== null &&\n typeof variance.context === 'object' &&\n !Array.isArray(variance.context) &&\n Object.keys(variance.context).length > 0\n ) {\n lines.push(`- **Context**: ${JSON.stringify(variance.context)}`);\n }\n if (lines.length === 0) return '';\n return [\n '## Variance (apply to styling, not contract shape)',\n '',\n 'The agent (or operator) declared these variant signals. Honor them in',\n 'the visual treatment + copy register — but the contract shape (props,',\n 'actions, contexts, streams) remains canonical. Variance changes HOW',\n 'the UI looks and reads, not WHAT it does.',\n ...(options?.profileDeclared === true ? [STYLING_PROFILE_PRECEDENCE_NOTE] : []),\n '',\n ...lines,\n ].join('\\n');\n}\n\n/** Append the variance-context block to a user prompt if variance is present. */\nexport function injectVariance(\n userPrompt: string,\n variance?: BlueprintVariance,\n options?: { readonly profileDeclared?: boolean },\n): string {\n if (!variance) return userPrompt;\n const block = buildVarianceContext(variance, options);\n if (!block) return userPrompt;\n return userPrompt + '\\n\\n' + block;\n}\n"]}
|