xiaohongshu
xiaohongshu
castella-a2ui
Render A2UI JSON as native Castella widgets. Parse A2UI messages, handle actions, progressive rendering, data binding, and connect to A2UI-enabled agents.
Full skill instructions
A2UI (Agent-to-User Interface) enables AI agents to generate rich, interactive UIs by outputting JSON component descriptions. Castella renders these natively across desktop, web, and terminal platforms.
When to use: "render A2UI JSON", "A2UI component", "A2UIRenderer", "A2UI data binding", "A2UI streaming", "connect to A2UI agent", "updateDataModel", "A2UIClient"
Render A2UI JSON to a Castella widget:
from castella import App
from castella.a2ui import A2UIRenderer, A2UIComponent
from castella.frame import Frame
renderer = A2UIRenderer()
widget = renderer.render_json({
"components": [
{"id": "root", "component": "Column", "children": {"explicitList": ["text1"]}},
{"id": "text1", "component": "Text", "text": {"literalString": "Hello A2UI!"}}
],
"rootId": "root"
})
App(Frame("A2UI Demo", 800, 600), widget).run()
The main class for converting A2UI messages to Castella widgets:
from castella.a2ui import A2UIRenderer, UserAction
def on_action(action: UserAction):
print(f"Action: {action.name}")
print(f"Source: {action.source_component_id}")
print(f"Context: {action.context}")
renderer = A2UIRenderer(on_action=on_action)
A2UI uses typed values for properties:
# Literal values (static)
{"text": {"literalString": "Hello"}}
{"value": {"literalNumber": 42}}
{"checked": {"literalBoolean": True}}
# Data binding (dynamic, JSON Pointer RFC 6901)
{"text": {"path": "/user/name"}}
{"value": {"path": "/counter"}}
Helper functions:
from castella.a2ui import literal, binding
literal("Hello") # {"literalString": "Hello"}
literal(42) # {"literalNumber": 42}
literal(True) # {"literalBoolean": True}
binding("/counter") # {"path": "/counter"}
| A2UI Component | Castella Widget | Notes |
|---|---|---|
| Text | Text | usageHint: h1-h5, body, caption |
| Button | Button | action with context |
| TextField | Input/MultilineInput | usageHint: password, multiline |
| CheckBox | CheckBox | Two-way binding |
| Slider | Slider | min/max range |
| DateTimeInput | DateTimeInput | Date/time picker |
| ChoicePicker | RadioButtons/Column | Single/multiple selection |
| Image | NetImage | URL-based images |
| Icon | Text | Material Icons → emoji |
| Divider | Spacer | Horizontal/vertical |
| Row | Row | Horizontal layout |
| Column | Column | Vertical layout |
| Card | Column | Container with styling |
| List | Column | TemplateChildren support |
| Tabs | Tabs | Tabbed navigation |
| Modal | Modal | Overlay dialog |
| Markdown | Markdown | Rich text (Castella extension) |
See references/components.md for detailed component reference.
Bind widget values to a data model using JSON Pointer paths:
a2ui_json = {
"components": [
{"id": "root", "component": "Column", "children": {"explicitList": ["greeting"]}},
{"id": "greeting", "component": "Text", "text": {"path": "/message"}}
],
"rootId": "root"
}
# Provide initial data
initial_data = {"/message": "Hello, World!"}
widget = renderer.render_json(a2ui_json, initial_data=initial_data)
Handle user interactions via actions:
{
"id": "submit_btn",
"component": "Button",
"text": {"literalString": "Submit"},
"action": {"name": "submit", "context": ["/formData"]}
}
Action handler receives UserAction:
def on_action(action: UserAction):
print(action.name) # "submit"
print(action.source_component_id) # "submit_btn"
print(action.context) # ["/formData"]
Update bound values dynamically:
renderer.handle_message({
"updateDataModel": {
"surfaceId": "default",
"data": {"/message": "Updated message!"}
}
})
Wrap surface in A2UIComponent for automatic UI updates:
from castella.a2ui import A2UIComponent
renderer.render_json(a2ui_json, initial_data=initial_data)
surface = renderer.get_surface("default")
component = A2UIComponent(surface) # Auto-updates on data changes
App(Frame("A2UI", 800, 600), component).run()
Render lists from data arrays:
a2ui_json = {
"components": [
{"id": "root", "component": "Column", "children": {"explicitList": ["user_list"]}},
{"id": "user_list", "component": "List", "children": {
"path": "/users", # JSON Pointer to array
"componentId": "user_item" # Template component
}},
{"id": "user_item", "component": "Text", "text": {"path": "name"}} # Relative path
],
"rootId": "root"
}
initial_data = {"/users": [{"name": "Alice"}, {"name": "Bob"}, {"name": "Charlie"}]}
widget = renderer.render_json(a2ui_json, initial_data=initial_data)
Single or multiple selection:
# Single selection (renders as RadioButtons)
{
"id": "color_picker",
"component": "ChoicePicker",
"choices": [
{"literalString": "Red"},
{"literalString": "Green"},
{"literalString": "Blue"}
],
"selected": {"literalString": "Red"},
"allowMultiple": False
}
# Multiple selection (renders as CheckBox list)
{
"id": "toppings",
"component": "ChoicePicker",
"choices": [
{"literalString": "Cheese"},
{"literalString": "Pepperoni"},
{"literalString": "Mushrooms"}
],
"selected": {"path": "/selectedToppings"},
"allowMultiple": True
}
Handle JSONL streams for incremental UI updates:
# From JSONL string
jsonl_content = """
{"beginRendering": {"surfaceId": "main", "root": "root"}}
{"updateComponents": {"surfaceId": "main", "components": [...]}}
"""
surface = renderer.handle_jsonl(jsonl_content)
# From file
with open("ui.jsonl") as f:
surface = renderer.handle_stream(f, on_update=lambda s: app.redraw())
# From async SSE stream
from castella.a2ui.transports import sse_stream
surface = await renderer.handle_stream_async(await sse_stream(url))
Message sequence:
beginRendering - Start progressive renderupdateComponents - Add/update componentsupdateDataModel - Update data valuesSee references/streaming.md for transport details.
Connect to A2A agents with A2UI extension:
from castella.a2ui import A2UIClient, A2UIComponent, UserAction
def on_action(action: UserAction):
print(f"Action: {action.name}")
client = A2UIClient("http://localhost:10002", on_action=on_action)
surface = client.send("Find restaurants in Tokyo")
if surface:
App(Frame("Restaurant Finder", 800, 600), A2UIComponent(surface)).run()
Async usage:
async def main():
client = A2UIClient("http://localhost:10002")
surface = await client.send_async("Hello!")
if surface:
# Send action back to agent
await client.send_action_async(action)
Castella auto-normalizes A2UI 0.9 spec format:
# A2UI 0.9 format (plain values) - accepted
{"text": "Hello", "children": ["a", "b"]}
# Castella internal format (wrapped) - also accepted
{"text": {"literalString": "Hello"}, "children": {"explicitList": ["a", "b"]}}
Key normalizations:
text: "Hello" → text: {literalString: "Hello"}children: ["a", "b"] → children: {explicitList: ["a", "b"]}usageHint: "shortText" → usageHint: "text"usageHint: "obscured" → usageHint: "password"# Password field (masked ●●●●)
{"id": "password", "component": "TextField", "usageHint": "password"}
# Multiline field
{"id": "comments", "component": "TextField", "usageHint": "multiline"}
uv sync --extra agent # A2UI + A2A support
references/components.md - Complete A2UI component referencereferences/messages.md - A2UI message typesreferences/streaming.md - Streaming and transportsscripts/ - Executable examples (basic_a2ui.py, a2ui_form.py, a2ui_list.py)xiaohongshu
technical spec
product ux expert
database patterns
Conduct multi-agent task orchestration and workflow coordination.
Initialize project with Conductor artifacts (product definition,
Expert in web animations, transitions, and motion design using Framer Motion and CSS
Creates Mermaid and ASCII diagrams for flowcharts, architecture, ERDs, state machines, mindmaps, and more. Use when user mentions diagram, flowchart, mermaid, ASCII diagram, text diagram, terminal diagram, visualize, C4, mindmap, architecture diagram, sequence diagram, ERD, or needs visual docume...
PostgreSQL bindings for H3 hexagonal grid system. Use when working with H3 cells in Postgres, including spatial indexing, geometry/geography integration, and raster analysis.
Context-Driven Development skill for projects using Conductor. Use this skill when you detect a `conductor/` directory in the project, when working on tasks defined in a `plan.md` file, or when the user asks about tracks, specs, or plans. Automatically applies TDD workflow, tracks task completion...
Display project status, active tracks, and next actions
Official Stakpak application containerization standard operating procedure, a step-by-step guidline to properly dockerize applications. This is a rule book curated by the Stakpak Team.
Generate, edit, and beat-sync AI video with leading models in one workspace.
The world's fastest calendar for remote work
Transform Your Design with AI Designer by ImgCreator.ai
Revolutionizing Video Production with AI-Powered Creativity
Extend an image past the frame and let AI fill the new aspect ratio.
Discover your celebrity doppelgänger with StarByFace!
ChainClarity explains 700+ crypto whitepapers in plain English, with layered summaries, comparisons, research tools, alerts, and a $4.99 Pro plan.
Opus.ai: Revolutionize Your Web Experience