Quick Start
Parse an A2UI stream, build its data model, and resolve a dynamic value โ end to end, in a few minutes.
@threadplane/a2ui is the protocol layer. It parses the JSONL message stream, gives you typed envelopes, and resolves dynamic values against a data model. It does not render anything. Rendering is @threadplane/chat's <a2ui-surface>. This library is what sits underneath it.
#Goals
By the end of this page you'll be able to:
- Install
@threadplane/a2ui. - Parse a newline-delimited A2UI stream into typed messages.
- Build a plain data-model object with
setByPointer. - Resolve a dynamic value with
resolveDynamic.
#Install
The package has no peer dependencies.
#Parse a stream
Let's start with a real stream. An agent emits A2UI as newline-delimited JSON โ one envelope per line. Here's a booking form, in emission order: data first, then the component tree, then the signal to render.
Feed each chunk to a parser. push returns the A2uiMessage[] it could complete from everything buffered so far.
The parser is line-oriented. A line is only parsed once a newline arrives, so partial JSON buffers until it's complete:
That buffering is deliberate. Agent output streams in fragments, and a half-finished line shouldn't throw mid-render.
#Build the data model
A dataModelUpdate carries contents โ an array of typed entries, each with a key and one of valueString / valueNumber / valueBoolean / valueMap. The parser hands you those entries verbatim. Turning them into a plain object the resolver can read is your code.
For the booking stream that's three entries: origin, dest, passengers. setByPointer builds the object immutably โ each call returns a new object, the input is untouched.
To be clear: assembling the model from contents (reading valueString vs valueNumber, honoring the entry's optional path, recursing into valueMap) is the caller's job. This library gives you the pointer helpers; it doesn't ship a contents -> object reducer. The data model guide covers the helpers in depth.
#Resolve a value
A component's props can be literals or path references. resolveDynamic collapses both against the model.
A literal wrapper unwraps to its value. A { path } reads from the model by JSON-Pointer. A missing path resolves to undefined rather than throwing โ same conservative posture as the parser.
#Conclusion
That's the full loop: stream in, model built, value resolved. From here, the three guides go deeper:
- The A2UI message protocol โ surfaces, components, dynamic values, and the four envelopes.
- Working with the data model โ the pointer helpers, immutability, and scopes.
- Validating and adapting an A2UI stream โ guards, test payloads, and custom renderers.