@urbicon-ui/blocks 6.40.3 → 6.43.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/components/Calendar/calendar.variants.d.ts +63 -63
- package/dist/components/Chat/A2UIView/A2UINode.svelte +20 -39
- package/dist/components/Chat/A2UIView/A2UIView.svelte +47 -50
- package/dist/components/Chat/A2UIView/a2ui-basic-catalog.d.ts +17 -0
- package/dist/components/Chat/A2UIView/a2ui-basic-catalog.js +69 -0
- package/dist/components/Chat/A2UIView/a2ui-catalog.d.ts +95 -0
- package/dist/components/Chat/A2UIView/a2ui-catalog.js +87 -0
- package/dist/components/Chat/A2UIView/a2ui-node-common.d.ts +40 -0
- package/dist/components/Chat/A2UIView/a2ui-node-common.js +72 -0
- package/dist/components/Chat/A2UIView/a2ui-prompt.d.ts +21 -10
- package/dist/components/Chat/A2UIView/a2ui-prompt.js +170 -24
- package/dist/components/Chat/A2UIView/a2ui-registry.d.ts +1 -1
- package/dist/components/Chat/A2UIView/a2ui-registry.js +2 -1
- package/dist/components/Chat/A2UIView/a2ui-render.d.ts +30 -0
- package/dist/components/Chat/A2UIView/a2ui-render.js +61 -23
- package/dist/components/Chat/A2UIView/a2ui-router.d.ts +136 -0
- package/dist/components/Chat/A2UIView/a2ui-router.js +264 -0
- package/dist/components/Chat/A2UIView/a2ui-schema.d.ts +45 -0
- package/dist/components/Chat/A2UIView/a2ui-schema.js +133 -0
- package/dist/components/Chat/A2UIView/a2ui-stream.d.ts +120 -0
- package/dist/components/Chat/A2UIView/a2ui-stream.js +406 -0
- package/dist/components/Chat/A2UIView/a2ui-transcript.d.ts +65 -0
- package/dist/components/Chat/A2UIView/a2ui-transcript.js +101 -0
- package/dist/components/Chat/A2UIView/a2ui-validate.d.ts +33 -1
- package/dist/components/Chat/A2UIView/a2ui-validate.js +167 -63
- package/dist/components/Chat/A2UIView/a2ui.types.d.ts +50 -0
- package/dist/components/Chat/A2UIView/a2ui.types.js +38 -1
- package/dist/components/Chat/A2UIView/index.d.ts +35 -2
- package/dist/components/Chat/A2UIView/index.js +13 -0
- package/dist/components/Chat/A2UIView/urbicon/UrbiconA2UINode.svelte +831 -0
- package/dist/components/Chat/A2UIView/urbicon/UrbiconA2UINode.svelte.d.ts +4 -0
- package/dist/components/Chat/A2UIView/urbicon/a2ui-urbicon-catalog.d.ts +14 -0
- package/dist/components/Chat/A2UIView/urbicon/a2ui-urbicon-catalog.js +87 -0
- package/dist/components/Chat/A2UIView/urbicon/a2ui-urbicon-registry.d.ts +78 -0
- package/dist/components/Chat/A2UIView/urbicon/a2ui-urbicon-registry.js +783 -0
- package/dist/components/Chat/A2UIView/urbicon/a2ui-urbicon.variants.d.ts +43 -0
- package/dist/components/Chat/A2UIView/urbicon/a2ui-urbicon.variants.js +33 -0
- package/dist/components/Chat/A2UIView/urbicon/urbicon-axes.gen.d.ts +7 -0
- package/dist/components/Chat/A2UIView/urbicon/urbicon-axes.gen.js +86 -0
- package/dist/components/Chat/ChatMessage/chat-message.variants.d.ts +19 -19
- package/dist/components/CopyButton/copy-button.variants.d.ts +4 -4
- package/dist/components/FileUpload/FileUpload.svelte +8 -5
- package/dist/components/FileUpload/fileUpload.variants.js +15 -4
- package/dist/components/PinInput/PinInput.svelte +1 -0
- package/dist/components/PinInput/pin-input.variants.js +14 -1
- package/dist/components/TimeInput/time-input.variants.js +16 -1
- package/dist/i18n/index.d.ts +2 -398
- package/dist/internal/field-chrome.d.ts +18 -1
- package/dist/internal/field-chrome.js +18 -1
- package/dist/primitives/Alert/alert.variants.d.ts +8 -8
- package/dist/primitives/Avatar/avatar.variants.js +4 -1
- package/dist/primitives/Badge/badge.variants.js +11 -2
- package/dist/primitives/Button/button.variants.js +4 -1
- package/dist/primitives/Card/card.variants.js +4 -1
- package/dist/primitives/Checkbox/checkbox.variants.js +7 -1
- package/dist/primitives/Combobox/Combobox.svelte +9 -1
- package/dist/primitives/Combobox/combobox.variants.d.ts +25 -0
- package/dist/primitives/Combobox/combobox.variants.js +32 -3
- package/dist/primitives/Combobox/index.d.ts +8 -2
- package/dist/primitives/Dialog/dialog.variants.js +4 -1
- package/dist/primitives/Drawer/drawer.variants.js +4 -1
- package/dist/primitives/Input/input.variants.js +17 -1
- package/dist/primitives/JourneyTimeline/journey-timeline.variants.d.ts +22 -22
- package/dist/primitives/Menu/menu.variants.js +5 -1
- package/dist/primitives/Progress/progress.variants.js +5 -2
- package/dist/primitives/RadioGroup/radioGroup.variants.js +68 -9
- package/dist/primitives/Select/select.variants.js +13 -4
- package/dist/primitives/Slider/Slider.svelte +4 -1
- package/dist/primitives/Slider/slider.variants.js +9 -2
- package/dist/primitives/Spinner/spinner.variants.d.ts +16 -16
- package/dist/primitives/Stepper/stepper.variants.d.ts +11 -11
- package/dist/primitives/Textarea/textarea.variants.js +15 -1
- package/dist/primitives/Toast/Toaster.svelte +6 -9
- package/dist/primitives/Toast/toast.variants.d.ts +12 -12
- package/dist/primitives/Toast/toast.variants.js +5 -1
- package/dist/primitives/Toggle/toggle.variants.js +92 -18
- package/dist/primitives/Tooltip/tooltip.variants.d.ts +3 -3
- package/dist/primitives/Tooltip/tooltip.variants.js +5 -1
- package/dist/style/themes/index.css +8 -2
- package/dist/utils/guide.svelte.js +16 -4
- package/dist/utils/persistent-state.svelte.d.ts +25 -1
- package/dist/utils/persistent-state.svelte.js +98 -10
- package/docs/MIGRATION-v5.md +29 -0
- package/package.json +3 -3
|
@@ -21,8 +21,10 @@
|
|
|
21
21
|
* because "dangling" is a warning mid-stream and an error once settled.
|
|
22
22
|
*/
|
|
23
23
|
import { A2UI_ISSUE_CODES } from './a2ui.types.js';
|
|
24
|
+
import { basicA2uiCatalogSpec, resolveCatalog } from './a2ui-catalog.js';
|
|
24
25
|
import { cloneData, deleteAtPointer, getAtPointer, setAtPointer } from './a2ui-data.js';
|
|
25
|
-
import {
|
|
26
|
+
import { A2UI_SUPPORTED_VERSIONS, A2UI_SVG_PATH_RE } from './a2ui-registry.js';
|
|
27
|
+
import { validateSchemaWrite } from './a2ui-schema.js';
|
|
26
28
|
const PROTO_KEYS = new Set(['__proto__', 'constructor', 'prototype']);
|
|
27
29
|
// DoS caps. The per-surface render walk is already bounded (depth 32, nodes
|
|
28
30
|
// 512), but that leaves the *number* of surfaces and the per-message component
|
|
@@ -96,7 +98,7 @@ function dynamicRefIssues(value, path, surfaceId) {
|
|
|
96
98
|
}
|
|
97
99
|
return [];
|
|
98
100
|
}
|
|
99
|
-
function validateProp(componentName, key, spec, value, path, surfaceId) {
|
|
101
|
+
function validateProp(componentName, key, spec, value, path, surfaceId, iconNames) {
|
|
100
102
|
const issues = [];
|
|
101
103
|
const mismatch = (detail) => {
|
|
102
104
|
issues.push(issue('error', A2UI_ISSUE_CODES.TYPE_MISMATCH, detail, { surfaceId, path }));
|
|
@@ -130,12 +132,20 @@ function validateProp(componentName, key, spec, value, path, surfaceId) {
|
|
|
130
132
|
return mismatch(`"${key}" on ${componentName} must be a component id (string)`);
|
|
131
133
|
case 'childList':
|
|
132
134
|
return validateChildList(componentName, key, value, path, surfaceId);
|
|
135
|
+
case 'labeledChildren':
|
|
136
|
+
return validateLabeledChildren(componentName, key, value, path, surfaceId);
|
|
133
137
|
case 'action':
|
|
134
138
|
return validateAction(componentName, key, value, path, surfaceId);
|
|
135
139
|
case 'options':
|
|
136
|
-
|
|
140
|
+
// A dynamic options prop may be a { path } binding to a list the agent
|
|
141
|
+
// fetched — the shape is checked when it resolves (see collectGraphIssues),
|
|
142
|
+
// because at envelope time the data model may not carry it yet.
|
|
143
|
+
if (spec.dynamic && isDynamicRef(value)) {
|
|
144
|
+
return { store: true, issues: dynamicRefIssues(value, path, surfaceId) };
|
|
145
|
+
}
|
|
146
|
+
return validateOptions(componentName, key, value, path, surfaceId, spec.dynamic);
|
|
137
147
|
case 'icon':
|
|
138
|
-
return validateIcon(value, path, surfaceId);
|
|
148
|
+
return validateIcon(value, path, surfaceId, iconNames);
|
|
139
149
|
case 'accessibility':
|
|
140
150
|
if (isPlainObject(value))
|
|
141
151
|
return { store: true, issues };
|
|
@@ -168,6 +178,33 @@ function validateChildList(componentName, key, value, path, surfaceId) {
|
|
|
168
178
|
]
|
|
169
179
|
};
|
|
170
180
|
}
|
|
181
|
+
/**
|
|
182
|
+
* A `labeledChildren` value is an array of `{ label, child }` items: `label` is
|
|
183
|
+
* a (dynamic) string, `child` a component id referenced by the labelled slot
|
|
184
|
+
* (Accordion items, Tabs later). The whole prop is rejected if ANY item is
|
|
185
|
+
* malformed, so the render/graph layers may assume every stored item is a valid
|
|
186
|
+
* `{ label, child: string }` — this keeps the item→child index alignment the
|
|
187
|
+
* dispatcher relies on when zipping labels with resolved child nodes.
|
|
188
|
+
*/
|
|
189
|
+
function validateLabeledChildren(componentName, key, value, path, surfaceId) {
|
|
190
|
+
const bad = (detail) => ({
|
|
191
|
+
store: false,
|
|
192
|
+
issues: [issue('error', A2UI_ISSUE_CODES.TYPE_MISMATCH, detail, { surfaceId, path })]
|
|
193
|
+
});
|
|
194
|
+
if (!Array.isArray(value))
|
|
195
|
+
return bad(`"${key}" on ${componentName} must be an array of { label, child } items`);
|
|
196
|
+
const issues = [];
|
|
197
|
+
for (let i = 0; i < value.length; i++) {
|
|
198
|
+
const item = value[i];
|
|
199
|
+
if (!isPlainObject(item) || typeof item.child !== 'string' || !isDynamicString(item.label)) {
|
|
200
|
+
return bad(`item ${i} on ${componentName} must be { label, child: string }`);
|
|
201
|
+
}
|
|
202
|
+
for (const labelIssue of dynamicRefIssues(item.label, `${path}/${i}/label`, surfaceId)) {
|
|
203
|
+
issues.push(labelIssue);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
return { store: true, issues };
|
|
207
|
+
}
|
|
171
208
|
function validateAction(componentName, key, value, path, surfaceId) {
|
|
172
209
|
const issues = [];
|
|
173
210
|
if (!isPlainObject(value)) {
|
|
@@ -219,13 +256,13 @@ function validateAction(componentName, key, value, path, surfaceId) {
|
|
|
219
256
|
}));
|
|
220
257
|
return { store: false, issues };
|
|
221
258
|
}
|
|
222
|
-
function validateOptions(componentName, key, value, path, surfaceId) {
|
|
259
|
+
function validateOptions(componentName, key, value, path, surfaceId, dynamic) {
|
|
223
260
|
const bad = (detail) => ({
|
|
224
261
|
store: false,
|
|
225
262
|
issues: [issue('error', A2UI_ISSUE_CODES.TYPE_MISMATCH, detail, { surfaceId, path })]
|
|
226
263
|
});
|
|
227
264
|
if (!Array.isArray(value))
|
|
228
|
-
return bad(`"${key}" on ${componentName} must be an array of { label, value } options`);
|
|
265
|
+
return bad(`"${key}" on ${componentName} must be an array of { label, value } options${dynamic ? ' or a { path } binding to one' : ''}`);
|
|
229
266
|
const issues = [];
|
|
230
267
|
const seenValues = new Set();
|
|
231
268
|
for (let i = 0; i < value.length; i++) {
|
|
@@ -248,9 +285,9 @@ function validateOptions(componentName, key, value, path, surfaceId) {
|
|
|
248
285
|
}
|
|
249
286
|
return { store: true, issues };
|
|
250
287
|
}
|
|
251
|
-
function validateIcon(value, path, surfaceId) {
|
|
288
|
+
function validateIcon(value, path, surfaceId, iconNames) {
|
|
252
289
|
if (typeof value === 'string') {
|
|
253
|
-
if (
|
|
290
|
+
if (iconNames.includes(value))
|
|
254
291
|
return { store: true, issues: [] };
|
|
255
292
|
return {
|
|
256
293
|
store: true,
|
|
@@ -326,9 +363,10 @@ function validateComponent(surface, raw, envelopeIndex, compIndex, idsSeen) {
|
|
|
326
363
|
surface.components.set(id, { id, component: '', props: new Map(), sourceIndex: envelopeIndex });
|
|
327
364
|
return;
|
|
328
365
|
}
|
|
329
|
-
const
|
|
366
|
+
const catalog = surface.catalog;
|
|
367
|
+
const spec = catalog.registry[componentName];
|
|
330
368
|
if (!spec) {
|
|
331
|
-
if (
|
|
369
|
+
if (catalog.unsupportedComponents.has(componentName)) {
|
|
332
370
|
surface.issues.push(issue('error', A2UI_ISSUE_CODES.UNSUPPORTED_COMPONENT, `Component "${componentName}" is not part of the rendered subset`, {
|
|
333
371
|
surfaceId,
|
|
334
372
|
path: `${base}/component`
|
|
@@ -356,7 +394,7 @@ function validateComponent(surface, raw, envelopeIndex, compIndex, idsSeen) {
|
|
|
356
394
|
surface.issues.push(issue('error', A2UI_ISSUE_CODES.PROTOTYPE_POLLUTION, `Prohibited property "${key}" on "${id}"`, { surfaceId, path: `${base}/${key}` }));
|
|
357
395
|
continue;
|
|
358
396
|
}
|
|
359
|
-
if (
|
|
397
|
+
if (catalog.ignoredProps.has(key)) {
|
|
360
398
|
surface.issues.push(issue('warning', A2UI_ISSUE_CODES.IGNORED_PROP, `Property "${key}" on ${componentName} is not supported and is ignored`, {
|
|
361
399
|
surfaceId,
|
|
362
400
|
path: `${base}/${key}`
|
|
@@ -368,7 +406,7 @@ function validateComponent(surface, raw, envelopeIndex, compIndex, idsSeen) {
|
|
|
368
406
|
surface.issues.push(issue('error', A2UI_ISSUE_CODES.UNKNOWN_PROP, `Unknown property "${key}" on ${componentName}`, { surfaceId, path: `${base}/${key}` }));
|
|
369
407
|
continue;
|
|
370
408
|
}
|
|
371
|
-
const result = validateProp(componentName, key, propSpec, comp[key], `${base}/${key}`, surfaceId);
|
|
409
|
+
const result = validateProp(componentName, key, propSpec, comp[key], `${base}/${key}`, surfaceId, catalog.iconNames);
|
|
372
410
|
for (const propIssue of result.issues)
|
|
373
411
|
surface.issues.push(propIssue);
|
|
374
412
|
if (result.store)
|
|
@@ -382,24 +420,14 @@ function validateComponent(surface, raw, envelopeIndex, compIndex, idsSeen) {
|
|
|
382
420
|
}));
|
|
383
421
|
}
|
|
384
422
|
}
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
if (componentName === 'DateTimeInput') {
|
|
394
|
-
// Both flags default to false in the spec — a DateTimeInput without either
|
|
395
|
-
// would have no input UI at all. We read tolerantly (render a date input)
|
|
396
|
-
// and report loudly so the agent fixes the payload.
|
|
397
|
-
if (props.get('enableDate') !== true && props.get('enableTime') !== true) {
|
|
398
|
-
surface.issues.push(issue('warning', A2UI_ISSUE_CODES.DATETIME_NO_MODE, `DateTimeInput "${id}" sets neither enableDate nor enableTime; rendering a date input`, {
|
|
399
|
-
surfaceId,
|
|
400
|
-
path: base
|
|
401
|
-
}));
|
|
402
|
-
}
|
|
423
|
+
// Per-component post-validation checks are catalog DATA (the Basic catalog
|
|
424
|
+
// owns ChoicePicker chips-fallback and DateTimeInput missing-mode); the engine
|
|
425
|
+
// stays free of catalog-specific branches. Message strings and issue paths are
|
|
426
|
+
// byte-identical to the pre-refactor hardcoded blocks.
|
|
427
|
+
const check = catalog.componentChecks?.[componentName];
|
|
428
|
+
if (check) {
|
|
429
|
+
for (const checkIssue of check({ id, props, surfaceId, base }))
|
|
430
|
+
surface.issues.push(checkIssue);
|
|
403
431
|
}
|
|
404
432
|
surface.components.set(id, { id, component: componentName, props, sourceIndex: envelopeIndex });
|
|
405
433
|
}
|
|
@@ -426,9 +454,10 @@ const CREATE_SURFACE_KEYS = new Set([
|
|
|
426
454
|
const UPDATE_COMPONENTS_KEYS = new Set(['surfaceId', 'components']);
|
|
427
455
|
const UPDATE_DATA_MODEL_KEYS = new Set(['surfaceId', 'path', 'value']);
|
|
428
456
|
const DELETE_SURFACE_KEYS = new Set(['surfaceId']);
|
|
429
|
-
function createProcessor() {
|
|
457
|
+
function createProcessor(catalogs, dataSchema) {
|
|
430
458
|
const surfaces = new Map();
|
|
431
459
|
const globalIssues = [];
|
|
460
|
+
const defaultCatalog = catalogs[0];
|
|
432
461
|
function handleCreateSurface(env, base) {
|
|
433
462
|
const cs = env.createSurface;
|
|
434
463
|
if (!isPlainObject(cs)) {
|
|
@@ -460,7 +489,9 @@ function createProcessor() {
|
|
|
460
489
|
surfaceId,
|
|
461
490
|
components: new Map(),
|
|
462
491
|
dataModel: undefined,
|
|
463
|
-
issues: []
|
|
492
|
+
issues: [],
|
|
493
|
+
catalog: defaultCatalog,
|
|
494
|
+
sendDataModel: false
|
|
464
495
|
};
|
|
465
496
|
surfaces.set(surfaceId, surface);
|
|
466
497
|
if (typeof cs.catalogId !== 'string') {
|
|
@@ -469,6 +500,17 @@ function createProcessor() {
|
|
|
469
500
|
path: `${base}/createSurface/catalogId`
|
|
470
501
|
}));
|
|
471
502
|
}
|
|
503
|
+
else {
|
|
504
|
+
const resolved = resolveCatalog(catalogs, cs.catalogId);
|
|
505
|
+
if (resolved) {
|
|
506
|
+
surface.catalog = resolved;
|
|
507
|
+
}
|
|
508
|
+
else if (catalogs.length >= 2) {
|
|
509
|
+
// Only a multi-catalog processor can meaningfully reject an id; a single
|
|
510
|
+
// catalog accepts any string (back-compat) and uses the default silently.
|
|
511
|
+
surface.issues.push(issue('warning', A2UI_ISSUE_CODES.UNKNOWN_CATALOG, `Unknown catalogId "${cs.catalogId}"; falling back to "${defaultCatalog.catalogId}"`, { surfaceId, path: `${base}/createSurface/catalogId` }));
|
|
512
|
+
}
|
|
513
|
+
}
|
|
472
514
|
if ('theme' in cs) {
|
|
473
515
|
surface.issues.push(issue('warning', A2UI_ISSUE_CODES.SURFACE_PROP_IGNORED, 'theme is ignored', {
|
|
474
516
|
surfaceId,
|
|
@@ -476,10 +518,15 @@ function createProcessor() {
|
|
|
476
518
|
}));
|
|
477
519
|
}
|
|
478
520
|
if ('sendDataModel' in cs) {
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
521
|
+
if (typeof cs.sendDataModel === 'boolean') {
|
|
522
|
+
surface.sendDataModel = cs.sendDataModel;
|
|
523
|
+
}
|
|
524
|
+
else {
|
|
525
|
+
surface.issues.push(issue('warning', A2UI_ISSUE_CODES.TYPE_MISMATCH, 'sendDataModel must be a boolean', {
|
|
526
|
+
surfaceId,
|
|
527
|
+
path: `${base}/createSurface/sendDataModel`
|
|
528
|
+
}));
|
|
529
|
+
}
|
|
483
530
|
}
|
|
484
531
|
flagExtraKeys(cs, CREATE_SURFACE_KEYS, surface.issues, surfaceId, `${base}/createSurface`, 'createSurface');
|
|
485
532
|
}
|
|
@@ -558,6 +605,14 @@ function createProcessor() {
|
|
|
558
605
|
return;
|
|
559
606
|
}
|
|
560
607
|
const hasValue = 'value' in udm;
|
|
608
|
+
// Schema validation (opt-in): a type mismatch on a declared pointer is an
|
|
609
|
+
// error, a write to an undeclared top-level branch a warning — both relayed
|
|
610
|
+
// to the agent. Runs on the raw written value before it enters the model.
|
|
611
|
+
if (dataSchema) {
|
|
612
|
+
const schemaIssues = validateSchemaWrite(dataSchema, pathValue, hasValue ? udm.value : undefined, surfaceId);
|
|
613
|
+
for (const schemaIssue of schemaIssues)
|
|
614
|
+
surface.issues.push(schemaIssue);
|
|
615
|
+
}
|
|
561
616
|
const whole = pathValue === undefined || pathValue === '' || pathValue === '/';
|
|
562
617
|
if (whole) {
|
|
563
618
|
surface.dataModel = hasValue ? cloneData(udm.value) : undefined;
|
|
@@ -638,8 +693,9 @@ function createProcessor() {
|
|
|
638
693
|
}
|
|
639
694
|
return { surfaces, globalIssues, apply };
|
|
640
695
|
}
|
|
641
|
-
export function createA2uiProcessor() {
|
|
642
|
-
|
|
696
|
+
export function createA2uiProcessor(options) {
|
|
697
|
+
const catalogs = options?.catalogs?.length ? options.catalogs : [basicA2uiCatalogSpec];
|
|
698
|
+
return createProcessor(catalogs, options?.dataSchema);
|
|
643
699
|
}
|
|
644
700
|
/**
|
|
645
701
|
* Normalize a render payload into an envelope list. Accepts an envelope array,
|
|
@@ -690,37 +746,65 @@ export function collectGraphIssues(surface, options) {
|
|
|
690
746
|
let nodeCount = 0;
|
|
691
747
|
let overflowReported = false;
|
|
692
748
|
let aborted = false;
|
|
749
|
+
// Child references are discovered by prop KIND (childId / childList) from the
|
|
750
|
+
// surface catalog's registry, not by fixed `child`/`children` names — so a
|
|
751
|
+
// catalog may name its child slots freely. Behaviour is unchanged for Basic,
|
|
752
|
+
// whose only child props ARE `child`/`children`.
|
|
753
|
+
const registry = surface.catalog.registry;
|
|
693
754
|
const childTargets = (comp, scopePrefix) => {
|
|
694
755
|
const out = [];
|
|
695
|
-
const
|
|
696
|
-
if (
|
|
697
|
-
out
|
|
698
|
-
const
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
if (typeof
|
|
702
|
-
out.push({ id:
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
out.push({ id: template.componentId, scope: `${absPath}/${i}` });
|
|
756
|
+
const spec = registry[comp.component];
|
|
757
|
+
if (!spec)
|
|
758
|
+
return out;
|
|
759
|
+
for (const [key, propSpec] of Object.entries(spec.props)) {
|
|
760
|
+
if (propSpec.kind === 'childId') {
|
|
761
|
+
const single = comp.props.get(key);
|
|
762
|
+
if (typeof single === 'string')
|
|
763
|
+
out.push({ id: single, scope: scopePrefix });
|
|
764
|
+
}
|
|
765
|
+
else if (propSpec.kind === 'labeledChildren') {
|
|
766
|
+
const items = comp.props.get(key);
|
|
767
|
+
if (Array.isArray(items)) {
|
|
768
|
+
for (const item of items) {
|
|
769
|
+
if (item && typeof item === 'object') {
|
|
770
|
+
const child = item.child;
|
|
771
|
+
if (typeof child === 'string')
|
|
772
|
+
out.push({ id: child, scope: scopePrefix });
|
|
773
|
+
}
|
|
714
774
|
if (out.length > maxNodes)
|
|
715
775
|
break; // bound expansion
|
|
716
776
|
}
|
|
717
777
|
}
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
778
|
+
}
|
|
779
|
+
else if (propSpec.kind === 'childList') {
|
|
780
|
+
const children = comp.props.get(key);
|
|
781
|
+
if (Array.isArray(children)) {
|
|
782
|
+
for (const childId of children)
|
|
783
|
+
if (typeof childId === 'string')
|
|
784
|
+
out.push({ id: childId, scope: scopePrefix });
|
|
785
|
+
}
|
|
786
|
+
else if (children && typeof children === 'object') {
|
|
787
|
+
const template = children;
|
|
788
|
+
if (typeof template.componentId === 'string' && typeof template.path === 'string') {
|
|
789
|
+
const absPath = template.path.startsWith('/')
|
|
790
|
+
? template.path
|
|
791
|
+
: `${scopePrefix ?? ''}/${template.path}`;
|
|
792
|
+
const list = getAtPointer(surface.dataModel, absPath);
|
|
793
|
+
if (Array.isArray(list)) {
|
|
794
|
+
for (let i = 0; i < list.length; i++) {
|
|
795
|
+
out.push({ id: template.componentId, scope: `${absPath}/${i}` });
|
|
796
|
+
if (out.length > maxNodes)
|
|
797
|
+
break; // bound expansion
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
else if (list !== undefined) {
|
|
801
|
+
issues.push(issue('warning', A2UI_ISSUE_CODES.TEMPLATE_PATH_NOT_ARRAY, `Template path "${absPath}" did not resolve to an array`, {
|
|
802
|
+
surfaceId
|
|
803
|
+
}));
|
|
804
|
+
}
|
|
805
|
+
// list === undefined → data not present yet; render nothing (graceful).
|
|
806
|
+
}
|
|
722
807
|
}
|
|
723
|
-
// list === undefined → data not present yet; render nothing (graceful).
|
|
724
808
|
}
|
|
725
809
|
}
|
|
726
810
|
return out;
|
|
@@ -749,7 +833,27 @@ export function collectGraphIssues(surface, options) {
|
|
|
749
833
|
}
|
|
750
834
|
return;
|
|
751
835
|
}
|
|
752
|
-
|
|
836
|
+
// A bound `options` list is only checkable once it resolves — the envelope
|
|
837
|
+
// validator saw a { path }, not a list. Silent while the path is still
|
|
838
|
+
// undefined (the agent fills it in with a later updateDataModel); a warning
|
|
839
|
+
// once it holds something that is not an option list, because the control
|
|
840
|
+
// then renders empty and the user is stuck with no way to choose.
|
|
841
|
+
for (const [key, propSpec] of Object.entries(registry[comp.component]?.props ?? {})) {
|
|
842
|
+
if (propSpec.kind !== 'options' || !propSpec.dynamic)
|
|
843
|
+
continue;
|
|
844
|
+
const bound = comp.props.get(key);
|
|
845
|
+
if (!isPlainObject(bound) || typeof bound.path !== 'string')
|
|
846
|
+
continue;
|
|
847
|
+
// Same absolute/relative rule as a childList template path.
|
|
848
|
+
const pointer = bound.path.startsWith('/')
|
|
849
|
+
? bound.path
|
|
850
|
+
: `${scopePrefix ?? ''}/${bound.path}`;
|
|
851
|
+
const resolvedList = getAtPointer(surface.dataModel, pointer);
|
|
852
|
+
if (resolvedList === undefined || Array.isArray(resolvedList))
|
|
853
|
+
continue;
|
|
854
|
+
issues.push(issue('warning', A2UI_ISSUE_CODES.OPTIONS_NOT_A_LIST, `"${key}" on "${id}" is bound to "${pointer}", which is not a list of options`, { surfaceId }));
|
|
855
|
+
}
|
|
856
|
+
if (comp.props.has('weight') && !surface.catalog.flexContainers.has(parentComponent ?? '')) {
|
|
753
857
|
issues.push(issue('warning', A2UI_ISSUE_CODES.WEIGHT_CONTEXT, `"weight" on "${id}" is only honored as a direct child of Row or Column`, {
|
|
754
858
|
surfaceId
|
|
755
859
|
}));
|
|
@@ -30,6 +30,19 @@ export interface A2uiActionEvent {
|
|
|
30
30
|
/** ISO 8601 timestamp (`new Date().toISOString()`). */
|
|
31
31
|
timestamp: string;
|
|
32
32
|
context: Record<string, unknown>;
|
|
33
|
+
/**
|
|
34
|
+
* The surface's complete data model — present only when the surface was
|
|
35
|
+
* created with `sendDataModel: true`.
|
|
36
|
+
*
|
|
37
|
+
* The spec calls this the client data model and has the client append it to
|
|
38
|
+
* the metadata of every message sent to the agent, but leaves WHERE metadata
|
|
39
|
+
* travels to the transport binding (A2A `metadata`, HTTP headers, …). This
|
|
40
|
+
* field is that payload; put it wherever your transport carries metadata.
|
|
41
|
+
*
|
|
42
|
+
* It is the antidote to a half-filled `context`: the agent sees everything the
|
|
43
|
+
* user entered, including fields it forgot to list on the action.
|
|
44
|
+
*/
|
|
45
|
+
dataModel?: unknown;
|
|
33
46
|
}
|
|
34
47
|
/** Severity of a validation issue. `error` renders a fault chip; `warning` degrades. */
|
|
35
48
|
export type A2uiIssueSeverity = 'error' | 'warning';
|
|
@@ -115,5 +128,42 @@ export declare const A2UI_ISSUE_CODES: {
|
|
|
115
128
|
readonly CHOICEPICKER_FALLBACK: "CHOICEPICKER_FALLBACK";
|
|
116
129
|
/** A `createSurface`-only prop (`theme`, `sendDataModel`) that the engine ignores. */
|
|
117
130
|
readonly SURFACE_PROP_IGNORED: "SURFACE_PROP_IGNORED";
|
|
131
|
+
/**
|
|
132
|
+
* `createSurface.catalogId` names no configured catalog — the surface falls
|
|
133
|
+
* back to the first (default) catalog. Only emitted in a multi-catalog setup;
|
|
134
|
+
* a single-catalog processor accepts any id string silently (back-compat).
|
|
135
|
+
*/
|
|
136
|
+
readonly UNKNOWN_CATALOG: "UNKNOWN_CATALOG";
|
|
137
|
+
/**
|
|
138
|
+
* A `Text` value looks like it carries Markdown, but `Text` renders PLAIN.
|
|
139
|
+
* A heuristic warning steering the agent to `RichText` (Urbicon catalog).
|
|
140
|
+
*/
|
|
141
|
+
readonly MARKDOWN_IN_TEXT: "MARKDOWN_IN_TEXT";
|
|
142
|
+
/**
|
|
143
|
+
* An `updateDataModel` write's value type contradicts the surface data
|
|
144
|
+
* schema's declared type at that pointer (opt-in `dataSchema`).
|
|
145
|
+
*/
|
|
146
|
+
readonly SCHEMA_TYPE_MISMATCH: "SCHEMA_TYPE_MISMATCH";
|
|
147
|
+
/**
|
|
148
|
+
* An `updateDataModel` write targets a top-level path the surface data schema
|
|
149
|
+
* does not declare (opt-in `dataSchema`; warning).
|
|
150
|
+
*/
|
|
151
|
+
readonly SCHEMA_UNDECLARED_PATH: "SCHEMA_UNDECLARED_PATH";
|
|
152
|
+
/**
|
|
153
|
+
* `createSurface` re-used a surfaceId that another source (an earlier chat
|
|
154
|
+
* message) already owns. The spec requires a surfaceId to be unique for the
|
|
155
|
+
* renderer's lifetime, so this is a protocol violation the agent should hear
|
|
156
|
+
* about; {@link A2uiSurfaceRouter} still transfers ownership to the newest
|
|
157
|
+
* source so the fresh surface renders (last writer wins). Router-only —
|
|
158
|
+
* a single processor reports the same case as `DUPLICATE_SURFACE`.
|
|
159
|
+
*/
|
|
160
|
+
readonly SURFACE_RECREATED: "SURFACE_RECREATED";
|
|
161
|
+
/**
|
|
162
|
+
* An `options` `{ path }` binding resolved to a value that is not a list of
|
|
163
|
+
* `{ label, value }` options — the control renders empty. Not emitted while
|
|
164
|
+
* the path is still `undefined`: the agent is expected to fill it in with a
|
|
165
|
+
* later `updateDataModel`, and an empty chooser mid-flow is normal.
|
|
166
|
+
*/
|
|
167
|
+
readonly OPTIONS_NOT_A_LIST: "OPTIONS_NOT_A_LIST";
|
|
118
168
|
};
|
|
119
169
|
export type A2uiIssueCode = (typeof A2UI_ISSUE_CODES)[keyof typeof A2UI_ISSUE_CODES];
|
|
@@ -81,5 +81,42 @@ export const A2UI_ISSUE_CODES = {
|
|
|
81
81
|
/** `ChoicePicker` `displayStyle: 'chips'` / `filterable` — rendered with a fallback. */
|
|
82
82
|
CHOICEPICKER_FALLBACK: 'CHOICEPICKER_FALLBACK',
|
|
83
83
|
/** A `createSurface`-only prop (`theme`, `sendDataModel`) that the engine ignores. */
|
|
84
|
-
SURFACE_PROP_IGNORED: 'SURFACE_PROP_IGNORED'
|
|
84
|
+
SURFACE_PROP_IGNORED: 'SURFACE_PROP_IGNORED',
|
|
85
|
+
/**
|
|
86
|
+
* `createSurface.catalogId` names no configured catalog — the surface falls
|
|
87
|
+
* back to the first (default) catalog. Only emitted in a multi-catalog setup;
|
|
88
|
+
* a single-catalog processor accepts any id string silently (back-compat).
|
|
89
|
+
*/
|
|
90
|
+
UNKNOWN_CATALOG: 'UNKNOWN_CATALOG',
|
|
91
|
+
/**
|
|
92
|
+
* A `Text` value looks like it carries Markdown, but `Text` renders PLAIN.
|
|
93
|
+
* A heuristic warning steering the agent to `RichText` (Urbicon catalog).
|
|
94
|
+
*/
|
|
95
|
+
MARKDOWN_IN_TEXT: 'MARKDOWN_IN_TEXT',
|
|
96
|
+
/**
|
|
97
|
+
* An `updateDataModel` write's value type contradicts the surface data
|
|
98
|
+
* schema's declared type at that pointer (opt-in `dataSchema`).
|
|
99
|
+
*/
|
|
100
|
+
SCHEMA_TYPE_MISMATCH: 'SCHEMA_TYPE_MISMATCH',
|
|
101
|
+
/**
|
|
102
|
+
* An `updateDataModel` write targets a top-level path the surface data schema
|
|
103
|
+
* does not declare (opt-in `dataSchema`; warning).
|
|
104
|
+
*/
|
|
105
|
+
SCHEMA_UNDECLARED_PATH: 'SCHEMA_UNDECLARED_PATH',
|
|
106
|
+
/**
|
|
107
|
+
* `createSurface` re-used a surfaceId that another source (an earlier chat
|
|
108
|
+
* message) already owns. The spec requires a surfaceId to be unique for the
|
|
109
|
+
* renderer's lifetime, so this is a protocol violation the agent should hear
|
|
110
|
+
* about; {@link A2uiSurfaceRouter} still transfers ownership to the newest
|
|
111
|
+
* source so the fresh surface renders (last writer wins). Router-only —
|
|
112
|
+
* a single processor reports the same case as `DUPLICATE_SURFACE`.
|
|
113
|
+
*/
|
|
114
|
+
SURFACE_RECREATED: 'SURFACE_RECREATED',
|
|
115
|
+
/**
|
|
116
|
+
* An `options` `{ path }` binding resolved to a value that is not a list of
|
|
117
|
+
* `{ label, value }` options — the control renders empty. Not emitted while
|
|
118
|
+
* the path is still `undefined`: the agent is expected to fill it in with a
|
|
119
|
+
* later `updateDataModel`, and an empty chooser mid-flow is normal.
|
|
120
|
+
*/
|
|
121
|
+
OPTIONS_NOT_A_LIST: 'OPTIONS_NOT_A_LIST'
|
|
85
122
|
};
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { HTMLAttributes } from 'svelte/elements';
|
|
2
2
|
import type { MarkdownUrlPolicy } from '../markdown/types.js';
|
|
3
3
|
import type { A2uiActionEvent, A2uiValidationIssue } from './a2ui.types.js';
|
|
4
|
+
import type { A2uiCatalog } from './a2ui-catalog.js';
|
|
5
|
+
import type { A2uiDataSchema } from './a2ui-schema.js';
|
|
4
6
|
import type { A2UIViewSlots } from './a2ui-view.variants.js';
|
|
5
7
|
/**
|
|
6
8
|
* @description Renders a trusted-catalog A2UI (Agent-to-UI, v0.9.1 `basic`
|
|
@@ -16,7 +18,13 @@ import type { A2UIViewSlots } from './a2ui-view.variants.js';
|
|
|
16
18
|
* renderer — wire it in per surface via `partRenderers.a2ui` to keep it out of
|
|
17
19
|
* the base bundle. Generate the agent-side prompt with the shipped
|
|
18
20
|
* `a2uiSystemPrompt()`; validate a payload without a DOM with
|
|
19
|
-
* `createA2uiProcessor()` — never hand-roll either.
|
|
21
|
+
* `createA2uiProcessor()` — never hand-roll either. Opt into the richer
|
|
22
|
+
* Urbicon-native catalog (real intents/variants, Section, RichText, Accordion)
|
|
23
|
+
* by passing `catalogs={[urbiconA2uiCatalog]}` (tree-shaken out otherwise), and
|
|
24
|
+
* type-check the data model with an optional `dataSchema`. One view owns the
|
|
25
|
+
* surfaces of ONE payload; to let an agent patch a surface it sent in an earlier
|
|
26
|
+
* chat turn (multi-step forms), route the later envelopes into that payload with
|
|
27
|
+
* `A2uiSurfaceRouter` — never give a second view the same surfaceId.
|
|
20
28
|
* @tag ai
|
|
21
29
|
* @related ChatMessage
|
|
22
30
|
* @stability experimental
|
|
@@ -77,6 +85,23 @@ export interface A2UIViewProps extends Omit<HTMLAttributes<HTMLDivElement>, 'cla
|
|
|
77
85
|
blockedImageLabel?: string;
|
|
78
86
|
/** Screen-reader label of the streaming placeholder. @default 'Loading UI' */
|
|
79
87
|
pendingLabel?: string;
|
|
88
|
+
/**
|
|
89
|
+
* Additional A2UI catalogs this view can render, beyond the always-present
|
|
90
|
+
* Basic catalog (which is prepended automatically as the default/fallback). A
|
|
91
|
+
* surface renders through the catalog whose id its `createSurface.catalogId`
|
|
92
|
+
* names. Pass the shipped `urbiconA2uiCatalog` to enable the Urbicon-native
|
|
93
|
+
* catalog. Resolved once at init (icon setup reads context) — keep it
|
|
94
|
+
* referentially stable.
|
|
95
|
+
*/
|
|
96
|
+
catalogs?: readonly A2uiCatalog[];
|
|
97
|
+
/**
|
|
98
|
+
* Optional surface data schema. When set, every `updateDataModel` write is
|
|
99
|
+
* validated against it (type mismatch on a declared pointer → error;
|
|
100
|
+
* undeclared top-level branch → warning), reported via `onValidationError`.
|
|
101
|
+
* Document the same schema to the agent with `a2uiDataSchemaSection`. Keep it
|
|
102
|
+
* referentially stable.
|
|
103
|
+
*/
|
|
104
|
+
dataSchema?: A2uiDataSchema;
|
|
80
105
|
/** Extra classes merged onto the root element. */
|
|
81
106
|
class?: string;
|
|
82
107
|
/** Strip the component's default tv() classes. */
|
|
@@ -96,7 +121,15 @@ export interface A2UIViewProps extends Omit<HTMLAttributes<HTMLDivElement>, 'cla
|
|
|
96
121
|
}
|
|
97
122
|
export { default as A2UIView } from './A2UIView.svelte';
|
|
98
123
|
export { A2UI_ISSUE_CODES, type A2uiActionEvent, type A2uiEnvelope, type A2uiIssueCode, type A2uiIssueSeverity, type A2uiValidationIssue } from './a2ui.types.js';
|
|
124
|
+
export { basicA2uiCatalog } from './a2ui-basic-catalog.js';
|
|
125
|
+
export { type A2uiCatalog, type A2uiCatalogSpec, type A2uiComponentCheck, type A2uiComponentCheckContext, basicA2uiCatalogSpec, resolveCatalog } from './a2ui-catalog.js';
|
|
99
126
|
export { a2uiSystemPrompt } from './a2ui-prompt.js';
|
|
100
127
|
export { A2UI_CATALOG_ID, A2UI_ICON_NAMES, A2UI_REGISTRY, A2UI_SUPPORTED_VERSIONS, type A2uiComponentSpec, type A2uiPropKind, type A2uiPropSpec, UNSUPPORTED_A2UI_COMPONENTS } from './a2ui-registry.js';
|
|
101
|
-
export { type
|
|
128
|
+
export { type A2uiRoutePatch, type A2uiRouteResult, A2uiSurfaceRouter } from './a2ui-router.js';
|
|
129
|
+
export { type A2uiDataSchema, type A2uiSchemaField, type A2uiSchemaType, a2uiDataSchemaSection, validateSchemaWrite } from './a2ui-schema.js';
|
|
130
|
+
export { A2UI_FENCE_TAG, type A2uiStreamIssue, type A2uiStreamPart, A2uiStreamSplitter, type A2uiStreamTextPart, type A2uiStreamUiPart, type A2uiTransportSectionOptions, a2uiFencedTransportSection } from './a2ui-stream.js';
|
|
131
|
+
export { editA2uiPayload, type PatchedSurface, type RouteMessageResult, revokeMessage, routeMessageParts, sourceKey } from './a2ui-transcript.js';
|
|
132
|
+
export { type A2uiComponentInstance, type A2uiProcessor, type A2uiProcessorOptions, type A2uiSurfaceState, collectGraphIssues, createA2uiProcessor, normalizeA2uiPayload } from './a2ui-validate.js';
|
|
102
133
|
export { type A2UIViewSlots, type A2UIViewVariants, a2uiViewVariants } from './a2ui-view.variants.js';
|
|
134
|
+
export { urbiconA2uiCatalog } from './urbicon/a2ui-urbicon-catalog.js';
|
|
135
|
+
export { SHARED_AXES, UNSUPPORTED_URBICON_A2UI_COMPONENTS, URBICON_A2UI_CATALOG_ID, URBICON_A2UI_ICON_NAMES, URBICON_A2UI_REGISTRY, type UrbiconComponentSpec, type UrbiconPropSpec, urbiconA2uiCatalogSpec } from './urbicon/a2ui-urbicon-registry.js';
|
|
@@ -1,7 +1,20 @@
|
|
|
1
1
|
export { default as A2UIView } from './A2UIView.svelte';
|
|
2
2
|
// ── Engine surface (Svelte-free; a server building the prompt has no DOM) ────
|
|
3
3
|
export { A2UI_ISSUE_CODES } from './a2ui.types.js';
|
|
4
|
+
export { basicA2uiCatalog } from './a2ui-basic-catalog.js';
|
|
5
|
+
// ── Catalog abstraction (the seam for a second, custom catalog) ──────────────
|
|
6
|
+
export { basicA2uiCatalogSpec, resolveCatalog } from './a2ui-catalog.js';
|
|
4
7
|
export { a2uiSystemPrompt } from './a2ui-prompt.js';
|
|
5
8
|
export { A2UI_CATALOG_ID, A2UI_ICON_NAMES, A2UI_REGISTRY, A2UI_SUPPORTED_VERSIONS, UNSUPPORTED_A2UI_COMPONENTS } from './a2ui-registry.js';
|
|
9
|
+
// ── Cross-message surface routing (keeps a surface patchable after its turn) ──
|
|
10
|
+
export { A2uiSurfaceRouter } from './a2ui-router.js';
|
|
11
|
+
export { a2uiDataSchemaSection, validateSchemaWrite } from './a2ui-schema.js';
|
|
12
|
+
// ── Fenced-JSONL transport: the token-stream parser and the prompt that feeds it ──
|
|
13
|
+
export { A2UI_FENCE_TAG, A2uiStreamSplitter, a2uiFencedTransportSection } from './a2ui-stream.js';
|
|
14
|
+
// ── Transcript wiring: deliver routed envelopes into the messages that own them ─
|
|
15
|
+
export { editA2uiPayload, revokeMessage, routeMessageParts, sourceKey } from './a2ui-transcript.js';
|
|
6
16
|
export { collectGraphIssues, createA2uiProcessor, normalizeA2uiPayload } from './a2ui-validate.js';
|
|
7
17
|
export { a2uiViewVariants } from './a2ui-view.variants.js';
|
|
18
|
+
// ── Urbicon-native catalog (opt-in; tree-shaken out unless imported) ─────────
|
|
19
|
+
export { urbiconA2uiCatalog } from './urbicon/a2ui-urbicon-catalog.js';
|
|
20
|
+
export { SHARED_AXES, UNSUPPORTED_URBICON_A2UI_COMPONENTS, URBICON_A2UI_CATALOG_ID, URBICON_A2UI_ICON_NAMES, URBICON_A2UI_REGISTRY, urbiconA2uiCatalogSpec } from './urbicon/a2ui-urbicon-registry.js';
|