Generative UI API¶
ui ¶
Generative UI primitives — agents that design their own surface.
The agent emits a typed :class:UIComponentSpec; the frontend resolves
a renderer by component_type and hot-loads it. Subsequent state
updates flow as :class:UIDeltaEvent records on the same SSE stream.
See :doc:/concepts/generative_ui for the full picture; this module hosts:
- :class:
UIComponentSpec[T]+ :class:UIDeltaEvent+ :data:UIDeltaOp— the protocol primitives. - :class:
ComponentRegistry— per-Workbench schema registry. - :class:
UIEmitter— convenience facade for emitting init/delta/remove events on an :class:EventBus. -
First-party components organised in three layers:
-
Compositional primitives: :class:
PlanComponent, :class:ChartComponent, :class:TableComponent, :class:FormComponent, :class:TakeoverDialogComponent, :class:LayoutComponent, :class:TextComponent, :class:MarkdownComponent, :class:ImageComponent, :class:BadgeComponent, :class:ButtonComponent, :class:InputComponent. - Declarative grammars: :class:
VegaChartComponent, :class:MermaidComponent, :class:LatexComponent, :class:JsonViewerComponent. - Sandboxed escape hatch: :class:
SandboxedHTMLComponent.
UIDeltaOp
module-attribute
¶
Op set for partial component updates.
replace— set value atpathtovalue(RFC 6902 replace).merge— shallow-mergevalue(a dict) into the dict atpath; if value-at-path is not a dict, behaves like replace.append— appendvalueto the list atpath. Required for streaming-append components (chart series, table rows).remove— delete the field/element atpath.valueignored.
BadgeComponentData ¶
icon
class-attribute
instance-attribute
¶
lucide-react icon name. The frontend resolves the symbol; if
the icon is unknown it falls back to label-only.
ButtonComponentData ¶
event_name
class-attribute
instance-attribute
¶
The event_type the frontend POSTs back when the button is clicked. The agent subscribes to this via the SSE bus + event-loop integration.
ChartComponentData ¶
config
class-attribute
instance-attribute
¶
Free-form renderer-specific knobs (axis formatters, colour scheme, etc.). Not load-bearing for the protocol.
ChartSeries ¶
One labelled data series. Points are dicts so the renderer can
pick out the relevant axes (e.g. {"x": ..., "y": ...}).
FormComponentData ¶
submit_event
class-attribute
instance-attribute
¶
The event_type the frontend should emit (back to the agent) on submission. Decoupled from the component_type so multiple forms can share a single rendering path.
FormField ¶
options
class-attribute
instance-attribute
¶
For select / multiselect — the available choices.
InputComponentData ¶
JsonViewerComponentData ¶
LatexComponentData ¶
content
instance-attribute
¶
LaTeX source rendered via KaTeX. Use display=True for block
math, False for inline.
LayoutComponentData ¶
MarkdownComponentData ¶
content
instance-attribute
¶
GFM markdown — tables, code, links, images. Frontend uses react-markdown + remark-gfm + the existing CodeBlock renderer.
MermaidComponentData ¶
diagram
instance-attribute
¶
Mermaid source. flowchart / sequence / classDiagram / erDiagram / gantt / mindmap / etc.
PlanComponentData ¶
Data payload — list of :class:PlanTask records.
SandboxedHTMLComponentData ¶
html
instance-attribute
¶
Raw HTML / SVG / restricted JS. Rendered in an iframe with sandbox="allow-scripts" and a strict CSP. No parent-document access, no network unless allowed via the iframe csp.
height_px
class-attribute
instance-attribute
¶
Fixed height in CSS pixels — iframes don't auto-size.
csp_extra
class-attribute
instance-attribute
¶
Additional CSP directives merged onto the default. Empty by default.
TableColumn ¶
TakeoverDialogData ¶
choices
class-attribute
instance-attribute
¶
For choice kind — the offered options.
VegaChartComponentData ¶
spec
class-attribute
instance-attribute
¶
Full Vega-Lite spec (https://vega.github.io/vega-lite/). The frontend imports vega-embed and renders. The agent emits the JSON directly — Vega-Lite syntax is well-documented and the LLM is typically familiar with it.
UIEmitter ¶
Facade for publishing :class:UIComponentSpec and
:class:UIDeltaEvent events on a :class:EventBus.
Source code in orqest/ui/emitter.py
init
async
¶
Emit ui.<component_type>.init for a fresh component.
Returns the emitted :class:AgentEvent for the caller to log /
record, or None when no bus is configured. Bus failures
log at DEBUG and return None.
Source code in orqest/ui/emitter.py
delta
async
¶
delta(
*,
component_id: str,
component_type: str,
op: UIDeltaOp,
path: str = "",
value: Any = None,
agent_name: str | None = None,
) -> AgentEvent | None
Emit ui.<component_type>.delta with a partial update.
Source code in orqest/ui/emitter.py
remove
async
¶
remove(
*,
component_id: str,
component_type: str,
agent_name: str | None = None,
) -> AgentEvent | None
Emit ui.<component_type>.remove so the frontend
unmounts the component.
Source code in orqest/ui/emitter.py
ComponentRegistry ¶
Maps component_type → :class:UIComponentSpec subclass.
Source code in orqest/ui/registry.py
register ¶
Register a concrete :class:UIComponentSpec subclass.
Reads the component_type Literal default off spec_class;
the discriminator must be set on the class (not the instance).
Re-registering the same component_type is a no-op unless
overwrite=True (the prior class is logged at WARN).
Source code in orqest/ui/registry.py
get ¶
list_types ¶
validate_payload ¶
Hydrate a raw dict against the registered spec.
Returns None on lookup miss or validation failure (logged
at WARN). Best-effort — UI validation should never break agent
execution.
Source code in orqest/ui/registry.py
UIComponentSpec ¶
Generic init payload for a frontend-renderable component.
Subclasses MUST override component_type with a unique
:class:Literal value so the frontend resolver can pick a renderer.
The data field carries the typed payload the renderer reads.
The schema is intentionally minimal: every concrete component
inherits the same envelope (component_type, component_id,
data, metadata, created_at) so the SSE protocol and the
frontend resolver can be component-agnostic.
to_event_data ¶
UIDeltaEvent ¶
Targeted partial update to a previously-emitted :class:UIComponentSpec.
path is a dot-path into data (root = empty string). For list
operations, integer indices may appear in the path (e.g.
"tasks.0.status"). Frontend implementations apply the op
against the previously-rendered component identified by
component_id; an unknown id should be treated as a no-op (the
consumer can re-fetch via the snapshot endpoint to recover).
default_registry ¶
A :class:ComponentRegistry pre-loaded with first-party components.
Three layers of generative-UI primitives ship in core:
- Compositional — :class:
PlanComponent, :class:ChartComponent, :class:TableComponent, :class:FormComponent, :class:TakeoverDialogComponent, :class:LayoutComponent, :class:TextComponent, :class:MarkdownComponent, :class:ImageComponent, :class:BadgeComponent, :class:ButtonComponent, :class:InputComponent. The agent composes these to build arbitrary UI. - Declarative grammars — :class:
VegaChartComponent, :class:MermaidComponent, :class:LatexComponent, :class:JsonViewerComponent. Thin wrappers around external grammars; the agent emits the spec. - Sandboxed escape hatch — :class:
SandboxedHTMLComponent. The agent writes raw HTML/SVG; the frontend confines it in an iframe. The component registers in core unconditionally; consumers gate rendering / emission via their own config flag.