AI scenarios
Generative UI
Bit.BlazorUI.AI Scripted transportThe model chooses a component from a registry and supplies its properties. Anything it names that is not registered renders nothing.
Live demo
Ask about three cities: the answer is three weather cards the model asked for by name.
Components the model chose
How it works
The registry is the boundary. A model can only instantiate a component the application registered, and can
only set the parameters that registration exposed. Event callbacks, render fragments, unmatched-attribute
catch-alls and anything marked [BitAiGenerativeIgnore] are excluded, so a generated payload
cannot wire up handlers or inject attributes. ForecastCard is an ordinary component of this site
with ordinary parameters; nothing about it knows it is generative.
The transport writes its introduction as text, then sends one BitAiGenerativeUiEvent per card -
the registered name, forecast_card, and the properties as JSON - and ends with more text. Each
event becomes a BitAiGenerativeUiPart in the reply, between the text parts. Properties a model
writes as it goes can stream as well: the same event with IsPartial set, sent again as more
arrives, or BitAiGenerativeUiDeltaEvents carrying the raw JSON a piece at a time; the card is
bound again as far as its properties have arrived.
registry.DescribeAll() produces the JSON Schema to put in the prompt, or to use as the schema of a
render tool. Give the model the schema and it stops guessing component names. City is required
here (the last argument of Register, or a [Required] on the parameter), and the
descriptions of the parameters go into the schema.
Binding is BitAiGenerativePropsBinder.Bind(component, props), which the view runs on every
change. Its BitAiGenerativeBindResult holds the Parameters the card renders with,
and what did not bind: each Failures entry is a BitAiGenerativeBindError - its
Kind (BitAiGenerativeBindErrorKind.Missing, a required property left out, or
Unreadable, a value of the wrong shape, with the serializer's Detail and the
ExpectedType), its PropertyName and ComponentName - and
IgnoredProperties lists the names the component does not declare, which never reach it.
IsComplete says whether anything failed. None of it is fatal: the card renders with what did
bind. ShowBindingErrors of the view lists the failures under the card; an app runs the binder
itself to check a payload - to log what a model got wrong while a prompt is developed, as the
Binding a payload tab does.
Registering reads the component's parameters by reflection, so Register is marked as unsafe to
trim. In a trimmed app, register the components from a method of your own that says why it is safe there -
the component type is kept whole by the annotation of Register, so what remains to check is
that its bindable parameters are plain data - as this site does for ForecastCard, whose
parameters are strings and integers.
Components used
BitAiGenerativeUiView- renders the component the model named, with the properties it supplied, and lists what did not bind (ShowBindingErrors).BitAiRendererBoundary- keeps a component that throws on what the model gave it to itself.
Feedback
Found a mistake, a gap, or something that could be clearer? Every page and every component is one click from its source.