The format
Actions and state
Components never run code. When the reader taps, types or answers, your app gets an action and decides what happens next.
Nothing in an answer runs code. When the reader acts, the SDK hands your app an action, and your app decides what happens: usually the model's next turn.
Actions
| The reader | The action |
|---|---|
Taps a Button with ask, a button outside a form, or a follow-up question |
{ type: "ask", text, node } |
Submits a Form |
{ type: "submit", node, form, button, fields } |
Finishes a Quiz |
{ type: "quiz", node, score, total, answers } |
Votes in a Poll |
{ type: "vote", node, name, choice } |
Ticks a Checklist item, marks a flashcard known |
{ type: "state", node, name, value } |
Taps a Button with href |
nothing: the link opens |
| Switches a tab, opens details, moves a what-if slider | nothing: it all happens on the page |
createAnswer(el, {
core,
onAction: (action) => {
if (action.type === "ask") send(action.text);
if (action.type === "submit") send(`Book ${action.fields.flight} for ${action.fields.guests}`);
},
});With connectAgent, actions become the next user message by themselves (sendActions: false stops that), in words the core writes the same way everywhere:
I finished the quiz: 1 of 2 right.
1. What absorbs light in a leaf? I answered "B. Chlorophyll" (right).
2. Which gas do plants take in? I answered "Oxygen" (wrong).Form fields
fields is keyed by each field's name, or its label as one word when it has none:
| Field | Value |
|---|---|
| Input, TextArea, Select, Radio, Date, Time, Stepper, Combobox, TimeSlots, RatingInput | text |
| Slider | a number |
| Switch | true or false |
| Checkboxes, and a ToggleGroup that allows several | a list of the chosen options |
| Camera, File | a list of Files, the browser's own, for your app to upload |
| Location | { lat, lng, accuracy } in degrees and metres when the reader shared it, or the place they typed |
| Scan | the code, as text; a photo of it, when they took one, as files under <name>-photo |
The SDK checks required before it sends anything. A photo, a file or a location exists only after the reader acted: nothing is captured until they tap.
State
What the reader has done is also kept as plain JSON for each component, so it can be saved, restored, or shared with an agent:
| Component | State |
|---|---|
| Quiz | { "answers": [index or null per question] } |
| Flashcards | { "known": [card index] } |
| Poll | { "vote": option or null } |
| Checklist | { "done": [item index] } |
| WhatIf | { "values": { slider name: number } } |
| Form | { "fields": { name: value } } |
onComponentState(node, state) tells you when it changes, and answer.applyState({ [node]: state }) sets it, say from a saved session. With AG-UI the state rides in the shared state's morphscreen key, so an agent can read what the reader did and set it too (AG-UI agents).