prefab: a TypeScript agent-side emitter for A2UI v1.0 #2406
quotentiroler
started this conversation in
Show and tell
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
The ecosystem page lists a lot of excellent renderers. This is the other side of
the wire:
agent_sdks/currently holds Python only, so here is a TypeScript wayto produce A2UI.
@maxhealth.tech/prefabis aserver-side component library for agent UIs. You describe the interface once
with a typed API and it emits A2UI v1.0:
Try it without installing anything: the
playground has an A2UI tab. Pick an
example, switch to it, and you get the translated payload plus a list of
everything the translation cost.
What maps
deterministically so the same tree always emits identical output.
{{ user.name }}becomes{ path: '/user/name' }, and mixed text such asScore: {{ score }}goes throughformatStringasScore: ${/score}.currencytoformatCurrency,numberandroundtoformatNumber, the date pipes toformatDate,pluralizetopluralize.catalogs/basic/examples/18_track-list.json. Data tables use the same shape,so a table stays one template rather than N inlined rows.
before sending and A2UI then needs no concept for it.
checks, so a required field stays required.application/a2ui+json, as ana2ui://resource or anembedded resource in a tool result, per the
A2UI over MCP guide.
What does not
prefab has 115+ components and the Basic catalog has 18, so parts of a tree
change shape. Every change is reported rather than happening quietly:
Most of those are gaps in the catalog. Conditionals are a genuine difference
between the two protocols. A2UI has no declarative
if: the rendererdraws what the adjacency list says and the agent sends a fresh
updateComponentswhen the shape should change. prefab runs a reactive clientthat re-shapes itself without a round trip. A one-item list template would look
like a conditional and behave like one only by accident, so the emitter reports
the loss instead of faking it.
Conformance
Payloads are validated in CI against the official v1.0 JSON Schemas, with the
Basic catalog bound into the
catalog.jsonslot, plus the two structural rulesthe schemas cannot express: every child reference resolves, and every component
is reachable from
root. Every shipped example runs through that gate, which iswhat caught a case where a component that failed to map left its children
stranded.
I read
conformance/*.yamlfirst and concluded it targets SDK internals(streaming parser, catalog pruning, validator behaviour) that a pure producer
does not implement. If that is wrong and there is a producer-facing subset I
should be running, I would like to know.
Corrections welcome on anything I have mapped wrong. Two I am least sure about:
the date pipes pick a fixed TR35 pattern because prefab renders in the reader's
locale and there is no locale-following option, and
{{ $item }}on a list ofplain strings has no relative path to bind to.
All reactions