--- ## A2UIView **Stability:** experimental — shipped to be used and judged, but the API may change in any release without notice. Renders a trusted-catalog A2UI (Agent-to-UI, v0.9.1 `basic` subset) payload into live, interactive Urbicon components. Fail-loud and whitelist-only: only the mapped catalog components and their declared props ever reach the DOM. Unknown components/props, prototype-pollution keys and function-call bindings are rejected, never rendered, and reported through `onValidationError` (spec-compatible issues a consumer can relay to the agent as a `VALIDATION_FAILED` error). Inputs are two-way (typing writes into the local data model; bound text updates live); actions dispatch a spec-exact `A2uiActionEvent`. Images and links are gated by the same strict-by-default `urlPolicy` as StreamingMarkdown. It is NOT a default ChatMessage renderer, so wire it in per surface via `partRenderers.a2ui` to keep it out of the base bundle. Generate the agent-side prompt with the shipped `a2uiSystemPrompt()`; validate a payload without a DOM with `createA2uiProcessor()`; never hand-roll either. Opt into the richer Urbicon-native catalog (real intents/variants, Section, RichText, Accordion) by passing `catalogs={[urbiconA2uiCatalog]}` (tree-shaken out otherwise), and type-check the data model with an optional `dataSchema`. One view owns the surfaces of ONE payload; to let an agent patch a surface it sent in an earlier chat turn (multi-step forms), route the later envelopes into that payload with `A2uiSurfaceRouter`; never give a second view the same surfaceId. **Import:** `import { A2UIView } from '@urbicon-ui/blocks';` ### Examples ```svelte {#snippet a2uiPart(part)} sendUserTurn(`[ui-action] ${JSON.stringify(event)}`)} onValidationError={(issues) => reportToAgent(issues)} /> {/snippet} ``` ```svelte console.log(e)} /> ``` ### Api | Prop | Type | Required | Default | Description | | --- | --- | :---: | --- | --- | | payload | `unknown` | yes | | The A2UI payload. Accepts an array of envelopes (the accumulated JSONL sequence — stream by extending it immutably: `[...prev, envelope]`), a single envelope object, or the golden-file `{ messages: [...] }` wrapper. | | ...HTMLAttributes | `HTMLAttributes` | no | | HTML attributes (excluding: 'class') | | blockedImageLabel | `string` | no | 'Image blocked' | Chip label shown in place of a policy-blocked image. | | catalogs | `readonly A2uiCatalog[]` | no | | Additional A2UI catalogs this view can render, beyond the always-present Basic catalog (which is prepended automatically as the default/fallback). A surface renders through the catalog whose id its `createSurface.catalogId` names. Pass the shipped `urbiconA2uiCatalog` to enable the Urbicon-native catalog. Resolved once at init (icon setup reads context) — keep it referentially stable. | | class | `string` | no | | Extra classes merged onto the root element. In the same Tailwind bucket `class` wins over the `slotClasses` entry for the element it lands on. Presets and provider defaults sit below both. | | dataSchema | `A2uiDataSchema` | no | | Optional surface data schema. When set, every `updateDataModel` write is validated against it (type mismatch on a declared pointer → error; undeclared top-level branch → warning), reported via `onValidationError`. Document the same schema to the agent with `a2uiDataSchemaSection`. Keep it referentially stable. | | errorTitle | `string` | no | 'Invalid UI payload' | Title of the top-level error Alert for envelope-level faults. | | onAction | `(event: A2uiActionEvent) => void` | no | | Fired when a Button is activated, with the spec-exact resolved action event. | | onValidationError | `(issues: A2uiValidationIssue[]) => void` | no | | Fired whenever the validation-issue list changes (errors AND warnings, each with a `severity`). Relay error-severity issues to the agent as an A2UI `error` message. | | pendingLabel | `string` | no | 'Loading UI' | Screen-reader label of the streaming placeholder. | | preset | `string` | no | | Apply a named preset registered via ``. Prefer this over `class` overrides for reusable custom looks. | | slotClasses | `Partial>` | no | | Per-slot class overrides. Slots: `root`, `surface`, `errorList`, `errorChip`, `errorIcon`, `pending`, `column`, `row`, `list`, `listItem`, `heading`, `caption`, `inlineText`, `image`, `blockedChip`, `icon`, `svgIcon`, `choiceGroup`, `choiceLabel`. In the same Tailwind bucket `class` wins over the `slotClasses` entry for the element it lands on. Presets and provider defaults sit below both. | | streaming | `boolean` | no | false | While true, a reference to a not-yet-defined component renders a placeholder instead of a fault chip (mid-stream tolerance). Flip to false when the stream settles so dangling references become errors. | | unstyled | `boolean` | no | | Strip the component's default tv() classes, and those of every catalog component the surface renders (Button, Input, Card …). | | unsupportedLabel | `string` | no | 'Unsupported component' | Fault-chip label for an unknown/unsupported/incomplete component. | | urlPolicy | `MarkdownUrlPolicy` | no | | URL policy for `Image` sources (and Text markdown links). Strict by default: every external image is blocked unless its prefix is allowlisted. Keep the object referentially stable. | Inherited from: - Omit, 'class'> (omit-pattern) ### Types ```ts interface MarkdownUrlPolicy { /** * Allowed link protocols (with trailing colon). Relative URLs are always * allowed for links. @default ['http:', 'https:', 'mailto:', 'tel:'] */ allowedLinkProtocols?: string[]; /** * Prefix allowlist for image sources, matched against the normalized * absolute URL. Empty (the default) blocks every external image; relative * sources are allowed. Prefer deep, specific prefixes — broad ones are * open-redirect bait. `data:` images are blocked unless a `data:` prefix * is listed explicitly. * @default [] */ allowedImagePrefixes?: string[]; /** Observability hook — fires once per blocked URL occurrence. */ onBlocked?: (kind: 'link' | 'image', url: string) => void; } ``` ```ts interface A2uiActionEvent { name: string; surfaceId: string; sourceComponentId: string; /** ISO 8601 timestamp (`new Date().toISOString()`). */ timestamp: string; context: Record; /** * The surface's complete data model — present only when the surface was * created with `sendDataModel: true`. * * The spec calls this the client data model and has the client append it to * the metadata of every message sent to the agent, but leaves WHERE metadata * travels to the transport binding (A2A `metadata`, HTTP headers, …). This * field is that payload; put it wherever your transport carries metadata. * * It is the antidote to a half-filled `context`: the agent sees everything the * user entered, including fields it forgot to list on the action. */ dataModel?: unknown; } ``` ```ts interface A2uiValidationIssue { severity: A2uiIssueSeverity; code: string; surfaceId?: string; path?: string; message: string; } ``` ```ts interface A2uiCatalog { Node: Component; createIcons: () => { icons: Readonly>; fallbackIcon: IconComponent; }; // ── inherited from A2uiCatalogSpec ── /** Catalog id advertised in `createSurface` and matched against incoming surfaces. */ catalogId: string; /** Additional ids that resolve to this catalog (version/back-compat aliases). */ catalogIdAliases?: readonly string[]; /** Component name → spec (the single source of truth for validation AND the prompt). */ registry: Readonly>; /** Mapped `Icon.name` values; an unmapped name degrades to a fallback glyph. */ iconNames: readonly string[]; /** Real catalog components deliberately not rendered (error chip, not "unknown"). */ unsupportedComponents: ReadonlySet; /** Props recognised anywhere but dropped before render (validation warning only). */ ignoredProps: ReadonlySet; /** Component names whose DIRECT children may carry a `weight` (flex-grow). */ flexContainers: ReadonlySet; /** Optional per-component post-validation checks, keyed by component name. */ componentChecks?: Readonly>; } ``` ```ts type A2uiDataSchema = Readonly> ``` ```ts type A2uiIssueSeverity = 'error' | 'warning' ``` ```ts type IconComponent = Component ``` ```ts interface A2uiSchemaField { type: A2uiSchemaType; /** Agent-facing description; emitted into the prompt verbatim. */ description?: string; /** Allowed literal values (documented + enforced for string/number fields). */ enum?: readonly (string | number)[]; /** A format hint (e.g. `date`, `time`, `email`) — documented, not enforced in v1. */ format?: string; } ``` ```ts type SlotNames = keyof ReturnType & string ``` ```ts interface A2uiRenderNode { key: string; id: string; instance: A2uiComponentInstance | null; /** Template-item scope for relative-path resolution and two-way write-back. */ scopePrefix: string | undefined; children: A2uiRenderNode[]; /** flex-grow, present only when this node is a direct Row/Column child with a finite `weight`. */ weight?: number; /** * The parent prop this child came from (e.g. Card `header`/`footer`/`child`). * Lets a dispatcher with several named childId slots pick the right child by * name instead of position; single-slot / list components ignore it. */ slot?: string; } ``` - `interface A2uiRenderContext` — 15 members, definition omitted (45 lines; full definition: packages/blocks/src/lib/components/Chat/A2UIView/a2ui-render.ts) ```ts type A2uiSchemaType = 'string' | 'number' | 'integer' | 'boolean' | 'array' | 'object' ```