@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
@@ -1,7 +1,18 @@
1
1
  /**
2
2
  * Provider adapter contract — the narrow surface every concrete LLM
3
- * provider client (Anthropic, Google, OpenAI, OpenRouter) implements
4
- * before the generator wires them in.
3
+ * provider client (Anthropic, Google, OpenAI, OpenRouter, Bedrock)
4
+ * implements.
5
+ *
6
+ * **Real role:** a provider-agnostic one-shot LLM caller for
7
+ * lightweight callers that need a single `complete()` round-trip — NOT
8
+ * a generation harness. The primary consumer is the negotiator's LLM
9
+ * seam (`@ggui-ai/mcp-server`'s `llm-backed-negotiator.ts`, via
10
+ * {@link selectAdapter} from `./providers/index.js`); other lightweight
11
+ * one-shot callers use it the same way. It is explicitly NOT part of
12
+ * the generation dispatch path: `createUiGenerator()` accepts no
13
+ * adapter option, and generation-call 429 retry/backoff lives entirely
14
+ * in `harness/llm-router.ts`'s `apiCall()` — a separate retry story for
15
+ * a separate call shape (an agentic SDK loop, not a single completion).
5
16
  *
6
17
  * The contract is deliberately defined independently of concrete
7
18
  * adapters so:
@@ -9,10 +20,9 @@
9
20
  * - Adapter implementations can be written against a stable surface —
10
21
  * every concrete adapter MUST pass
11
22
  * {@link providerAdapterContract} or it isn't a `ProviderAdapter`.
12
- * - Downstream callers (`createUiGenerator`, render handlers, retry /
13
- * backoff plumbing) build against ONE structured failure shape
14
- * ({@link ProviderError}) instead of inventing per-provider error
15
- * UX.
23
+ * - Downstream one-shot callers build against ONE structured failure
24
+ * shape ({@link ProviderError}) instead of inventing per-provider
25
+ * error UX.
16
26
  * - The negotiator + cache layers can branch on
17
27
  * `error.kind === 'rate-limited'` etc. without parsing strings.
18
28
  *
@@ -7,8 +7,8 @@
7
7
  *
8
8
  * ## Why this adapter exists
9
9
  *
10
- * Anyone running the generator on an AWS-credentialed host (EC2, ECS,
11
- * Lambda, EKS) can target Bedrock without managing API keys: IAM is
10
+ * Anyone running a one-shot LLM caller on an AWS-credentialed host
11
+ * (EC2, ECS, Lambda, EKS) can target Bedrock without managing API keys: IAM is
12
12
  * the auth boundary, AWS rotates host credentials automatically, and
13
13
  * a misconfigured IAM role surfaces as a clear `AccessDeniedException`
14
14
  * the SDK funnels through `mapError`. The alternative — parking a
@@ -50,19 +50,29 @@
50
50
  * discriminator if a third auth mode (e.g. cross-account assume-role)
51
51
  * lands.
52
52
  *
53
- * ## Model IDs — pass-through
53
+ * ## Model IDs — pass-through, endpoint chosen by ID shape
54
54
  *
55
- * Bedrock and the direct Anthropic API use OVERLAPPING but DISTINCT
56
- * model id namespaces:
55
+ * Bedrock serves Anthropic models through TWO endpoints with DISJOINT
56
+ * model-id namespaces (live-probed against us-east-1, 2026-08-13):
57
57
  *
58
- * - Direct API: `claude-haiku-4-5`, `claude-opus-4-7`, etc.
59
- * - Bedrock foundation models: `anthropic.claude-sonnet-4-6`
60
- * - Bedrock cross-region inference profiles: `us.anthropic.claude-haiku-4-5-20251001-v1:0`
58
+ * - **bedrock-runtime** (`AnthropicBedrock`): serves ONLY
59
+ * cross-region inference-profile ids —
60
+ * `us.anthropic.claude-haiku-4-5-20251001-v1:0` etc. Bare
61
+ * `anthropic.*` foundation ids are rejected with 400
62
+ * "on-demand throughput isn't supported".
63
+ * - **Messages-API endpoint / Mantle** (`AnthropicBedrockMantle`):
64
+ * serves ONLY region-less `anthropic.*` ids —
65
+ * `anthropic.claude-opus-5`, `anthropic.claude-haiku-4-5`. The
66
+ * Claude 5 family and Opus 4.8 exist ONLY here. Profile ids are
67
+ * rejected with 404. Requires the account to have enabled Claude
68
+ * in Amazon Bedrock (otherwise every id 403s "not available for
69
+ * this account").
61
70
  *
62
- * The adapter passes whatever `request.model` contains straight to
63
- * Bedrock — translation lives in the caller (model picker / deployment
64
- * config). Supply a Bedrock foundation-model or inference-profile id,
65
- * not a direct-API model name.
71
+ * Because the namespaces never overlap, the adapter routes each
72
+ * request by shape: ids starting `anthropic.` go to Mantle, region-
73
+ * prefixed ids (`us.` / `eu.` / `apac.` / `global.`) go to
74
+ * bedrock-runtime. The id itself passes through untranslated —
75
+ * supply a Bedrock id, not a direct-API model name.
66
76
  *
67
77
  * ## Failure mapping
68
78
  *
@@ -87,7 +97,7 @@
87
97
  * subclasses in the SDK, distinguished by `.status` (403 / 429 / 400
88
98
  * respectively).
89
99
  */
90
- import { AnthropicBedrock } from '@anthropic-ai/bedrock-sdk';
100
+ import { AnthropicBedrock, AnthropicBedrockMantle } from '@anthropic-ai/bedrock-sdk';
91
101
  import type { LlmProvider } from '@ggui-ai/mcp-server-core';
92
102
  import {
93
103
  makeProviderError,
@@ -110,6 +120,47 @@ import { classifyFetchError } from './http.js';
110
120
  const PROVIDER: LlmProvider = 'bedrock';
111
121
  const DEFAULT_MAX_TOKENS = 4096;
112
122
 
123
+ /**
124
+ * Which Bedrock endpoint a model id resolves to. The namespaces are
125
+ * disjoint (see the docstring above), so the shape of the id fully
126
+ * determines the endpoint — no configuration knob needed.
127
+ */
128
+ export type BedrockEndpoint = 'runtime' | 'mantle';
129
+
130
+ /**
131
+ * Structural slice of the two SDK clients the adapter actually drives —
132
+ * the seam that lets tests inject a stub without standing up a real
133
+ * AWS client. Both `AnthropicBedrock` and `AnthropicBedrockMantle`
134
+ * satisfy it (the adapter's single-completion contract only ever calls
135
+ * non-streaming `messages.create`; the response is parsed from
136
+ * `unknown` by `parseAnthropicMessagesResponse`, so the SDK's
137
+ * version-volatile `Message` type is deliberately not part of the
138
+ * seam).
139
+ */
140
+ export interface BedrockMessagesClient {
141
+ readonly messages: {
142
+ create(
143
+ body: {
144
+ model: string;
145
+ max_tokens: number;
146
+ system?: string;
147
+ messages: Array<{ role: 'user'; content: string }>;
148
+ },
149
+ options?: { signal?: AbortSignal },
150
+ ): Promise<unknown>;
151
+ };
152
+ }
153
+
154
+ /**
155
+ * Route a Bedrock model id to its serving endpoint. Region-less
156
+ * `anthropic.*` ids exist only on the Messages-API (Mantle) endpoint;
157
+ * everything else (region-prefixed inference profiles, ARNs) belongs
158
+ * to bedrock-runtime.
159
+ */
160
+ export function bedrockEndpointFor(model: string): BedrockEndpoint {
161
+ return model.startsWith('anthropic.') ? 'mantle' : 'runtime';
162
+ }
163
+
113
164
  /**
114
165
  * Constructor options for the Bedrock adapter.
115
166
  *
@@ -130,11 +181,16 @@ export interface BedrockAdapterOptions {
130
181
  readonly region?: string;
131
182
  /**
132
183
  * Optional client factory override — used by tests to inject a
133
- * mock or stub `AnthropicBedrock` client without actually hitting
134
- * AWS. Production callers leave this unset; the adapter constructs
135
- * the real client lazily on first `complete(...)` call.
184
+ * mock or stub client without actually hitting AWS. Called with the
185
+ * endpoint the request's model id routed to (`'runtime'` →
186
+ * `AnthropicBedrock`, `'mantle'` → `AnthropicBedrockMantle`).
187
+ * Production callers leave this unset; the adapter constructs the
188
+ * real client lazily on first `complete(...)` call per endpoint.
136
189
  */
137
- readonly clientFactory?: (region: string) => AnthropicBedrock;
190
+ readonly clientFactory?: (
191
+ region: string,
192
+ endpoint: BedrockEndpoint,
193
+ ) => BedrockMessagesClient;
138
194
  }
139
195
 
140
196
  /**
@@ -142,21 +198,28 @@ export interface BedrockAdapterOptions {
142
198
  *
143
199
  * No API key — IAM is the auth boundary. The returned `ProviderAdapter`
144
200
  * satisfies the same contract as `createAnthropicAdapter`, so it
145
- * slots into `createUiGenerator({ adapter })` interchangeably (modulo
146
- * the per-provider model-id namespace differences).
201
+ * slots into any one-shot `ProviderAdapter` caller (e.g. `selectAdapter`)
202
+ * interchangeably (modulo the per-provider model-id namespace
203
+ * differences).
147
204
  */
148
205
  export function createBedrockAdapter(
149
206
  options: BedrockAdapterOptions = {},
150
207
  ): ProviderAdapter {
151
208
  const region = options.region ?? process.env['AWS_REGION'] ?? 'us-east-1';
152
209
  const clientFactory =
153
- options.clientFactory ?? ((r: string) => new AnthropicBedrock({ awsRegion: r }));
210
+ options.clientFactory ??
211
+ ((r: string, endpoint: BedrockEndpoint): BedrockMessagesClient =>
212
+ endpoint === 'mantle'
213
+ ? new AnthropicBedrockMantle({ awsRegion: r })
214
+ : new AnthropicBedrock({ awsRegion: r }));
154
215
 
155
- let cachedClient: AnthropicBedrock | null = null;
156
- function getClient(): AnthropicBedrock {
157
- if (cachedClient) return cachedClient;
158
- cachedClient = clientFactory(region);
159
- return cachedClient;
216
+ const cachedClients: Partial<Record<BedrockEndpoint, BedrockMessagesClient>> = {};
217
+ function getClient(endpoint: BedrockEndpoint): BedrockMessagesClient {
218
+ const cached = cachedClients[endpoint];
219
+ if (cached) return cached;
220
+ const created = clientFactory(region, endpoint);
221
+ cachedClients[endpoint] = created;
222
+ return created;
160
223
  }
161
224
 
162
225
  function mapError(raw: unknown): ProviderError {
@@ -218,7 +281,7 @@ export function createBedrockAdapter(
218
281
  };
219
282
  }
220
283
 
221
- const client = getClient();
284
+ const client = getClient(bedrockEndpointFor(request.route.model));
222
285
  // The SDK's `Message` return type drifts between
223
286
  // `@anthropic-ai/sdk` versions (pnpm hoists multiple copies in
224
287
  // this workspace today). We type the captured value as
@@ -5,6 +5,15 @@
5
5
  * providers ggui supports today: Anthropic (direct API), Google,
6
6
  * OpenAI, OpenRouter, and AWS Bedrock (Anthropic models via IAM).
7
7
  *
8
+ * **Real role:** a provider-agnostic one-shot LLM caller for
9
+ * lightweight callers that need a single `complete()` round-trip — NOT
10
+ * the generation dispatch path. `createUiGenerator()` accepts no
11
+ * adapter option; generation-call retry/backoff lives entirely in
12
+ * `harness/llm-router.ts`'s `apiCall()`. The primary consumer is the
13
+ * negotiator's LLM seam (`@ggui-ai/mcp-server`'s
14
+ * `llm-backed-negotiator.ts`, via {@link selectAdapter}); other
15
+ * lightweight one-shot callers use it the same way.
16
+ *
8
17
  * Every adapter satisfies the structural
9
18
  * {@link import('../provider-adapter.js').ProviderAdapter} contract.
10
19
  * The four direct-API adapters compose
@@ -15,15 +24,18 @@
15
24
  * because rolling our own AWS SigV4 signer for one provider isn't a
16
25
  * reasonable trade.
17
26
  *
18
- * Typical usage from the CLI:
27
+ * Typical usage — a one-shot completion:
19
28
  *
20
29
  * ```ts
21
30
  * import { createAnthropicAdapter } from '@ggui-ai/ui-gen/providers';
22
- * import { createUiGenerator } from '@ggui-ai/ui-gen';
23
31
  *
24
32
  * const adapter = createAnthropicAdapter();
25
- * const generator = createUiGenerator({ adapter });
26
- * const result = await generator.generate({ request, llm, providerKey, blueprints });
33
+ * const result = await adapter.complete({
34
+ * apiKey,
35
+ * route: { provider: 'anthropic', model: 'claude-haiku-4-5-20251001' },
36
+ * systemPrompt,
37
+ * userPrompt,
38
+ * });
27
39
  * ```
28
40
  *
29
41
  * Bedrock pool path (no API key — IAM at process boot):
@@ -28,7 +28,12 @@ import { existsSync } from 'node:fs';
28
28
  import { createRequire } from 'node:module';
29
29
  import { pathToFileURL, fileURLToPath } from 'node:url';
30
30
  import { runSandboxed } from '@ggui-ai/sandbox';
31
- import type { PropsSpec, JsonObject, JsonValue } from '@ggui-ai/protocol';
31
+ import type {
32
+ JsonObject,
33
+ JsonSchema,
34
+ JsonValue,
35
+ PropsSpec,
36
+ } from '@ggui-ai/protocol';
32
37
 
33
38
  /**
34
39
  * Generate sample props from a PropsSpec contract.
@@ -58,21 +63,28 @@ export function generateSampleProps(spec: PropsSpec): JsonObject {
58
63
  return props;
59
64
  }
60
65
 
61
- function synthesizeFromSchema(schema: { type?: string; items?: unknown; properties?: JsonObject; required?: string[] }): JsonValue | undefined {
62
- switch (schema.type) {
66
+ function synthesizeFromSchema(schema: JsonSchema): JsonValue | undefined {
67
+ // Draft-07 type arrays (`['string','null']`) synthesize from the
68
+ // first non-null member — the canonical nullability form the
69
+ // enforced-props-schema emission produces.
70
+ const declared = Array.isArray(schema.type)
71
+ ? schema.type.find((t) => t !== 'null')
72
+ : schema.type;
73
+ switch (declared) {
63
74
  case 'string': return 'sample';
64
- case 'number': return 0;
75
+ case 'number':
76
+ case 'integer': return 0;
65
77
  case 'boolean': return false;
78
+ case 'null': return null;
66
79
  case 'array': {
67
- const itemSchema = schema.items as { type?: string } | undefined;
68
- if (itemSchema) return [synthesizeFromSchema(itemSchema) ?? null];
80
+ if (schema.items) return [synthesizeFromSchema(schema.items) ?? null];
69
81
  return [];
70
82
  }
71
83
  case 'object': {
72
84
  const obj: JsonObject = {};
73
85
  if (schema.properties) {
74
86
  for (const [k, v] of Object.entries(schema.properties)) {
75
- obj[k] = synthesizeFromSchema(v as { type?: string });
87
+ obj[k] = synthesizeFromSchema(v);
76
88
  }
77
89
  }
78
90
  return obj;
@@ -64,8 +64,8 @@ const SANDBOX_EXTERNALS = [
64
64
  '@ggui-ai/design/*',
65
65
  '@ggui-ai/wire',
66
66
  '@ggui-ai/wire/*',
67
- '@ggui-ai/react',
68
- '@ggui-ai/react/*',
67
+ '@ggui-ai/mcp-apps-react',
68
+ '@ggui-ai/mcp-apps-react/*',
69
69
  ];
70
70
 
71
71
  /** Max compiled bundle size (2MB). Prevents accidentally bundling huge deps. */