Skip to main content

Module streaming

Module streaming 

Source
Expand description

Incremental parsing of a model’s A2UI output as it streams.

crate::toolkit::parser waits for the whole generation before it can hand back a surface. That is the wrong shape for A2UI, whose entire component model exists so a renderer can start painting as soon as root arrives. StreamParser closes that gap: feed it token chunks and it emits renderable A2UI as soon as enough of the tree has arrived to draw something.

use ag_ui_a2ui::catalog::Catalog;
use ag_ui_a2ui::toolkit::streaming::StreamParser;

let catalog = Catalog::basic();
let mut parser = StreamParser::new(catalog);

// Conversational text comes out immediately.
let parts = parser.process_chunk("Here you go. <a2ui-json>[").unwrap();
assert_eq!(parts[0].text, "Here you go. ");

// A message is emitted the moment it closes, mid-array.
let parts = parser
    .process_chunk(r#"{"version":"v0.9","createSurface":{"surfaceId":"s","catalogId":"c"}},"#)
    .unwrap();
assert_eq!(parts[0].a2ui.as_ref().unwrap().len(), 1);

§What “as soon as possible” actually means

Four mechanisms do the work, and they are the reason this is not simply a JSON parser fed one byte at a time:

Healing cut tokens. A chunk boundary can land anywhere, including inside a string. The parser closes open braces and brackets to make the fragment parseable, but it will only close an open string for a key on the cuttable list — text, label, hint and friends. Cutting "id" or "path" would invent an identifier or a binding that the model never wrote, so those fragments are held back until the next chunk instead.

Placeholder synthesis. A parent usually arrives before its children. Its child references are rewritten to loading_<id> and a stand-in component is emitted alongside, so the renderer can lay out the tree immediately and swap in the real component when it lands.

Reachability filtering. Only components reachable from root are emitted. A component that arrives before its parent is cached, not sent — it would have nowhere to attach — and is re-sent as part of the tree once the path from the root exists.

Validation as a filter, not a failure. Partial fragments are validated and silently dropped if they do not hold up. A placeholder of a type the catalog does not define, or a component still missing a required property, is simply not emitted yet. Structural failures that no further input can fix — a reference loop, a message that matches no envelope — are errors.

§State is per-stream

A parser instance carries the surface state for one generation: which surfaces exist, which components have been seen and emitted, and the data model so far. Create a new one per generation.

Structs§

StreamParser
Parses a model’s A2UI output incrementally, one chunk at a time.

Constants§

DEFAULT_CUTTABLE_KEYS
Keys whose string values may be closed early when a chunk cuts them.