Actions & Interactivity

How buttons, sliders, and toggles in a generated UI actually do things.

A2UI isn't just for display β€” generated widgets can act. A button can kill a process, a slider can set the volume, a toggle can flip Wi-Fi. This page explains how an interactive component's action travels from a tap in the shell to a real effect on your machine.

The action round-trip

Every interactive component carries an action:

json
{
 "type": "button",
 "label": "Kill",
 "style": "danger",
 "action": { "payload": { "command": "kill_process", "pid": "1234" } }
}

When tapped, (ActionHandler.handle) reads the endpoint (default /api/action) and the payload, and POSTs it to the agent via StateClient.sendRpc(endpoint, payload). The agent's handle_action routes it.

Built-in commands

handle_action recognizes a set of commands directly:

CommandEffectPayload
kill_processTerminate a process (SIGTERM)pid
set_volumeSet output volume 0–100value
set_brightnessSet screen brightness 0–100value
toggle_wifiTurn Wi-Fi on/offβ€”
open_appLaunch an applicationvalue / app name
close_appQuit an app (pkill -f)app name
run_commandRun a shell commandvalue
refreshAsk the UI to refreshβ€”

These map to the core system layer under the hood, so a generated control panel and a chat command ("set volume to 30") hit the same code.

Anything-is-an-action: tool fallback

If a command isn't one of the built-ins, handle_action treats it as a tool name and dispatches it through the plugin manager (with light legacy mapping, e.g. send_email). This means the LLM can wire a button to any of the 285 tools β€” a "Send" button whose action is SEND_EMAIL, a "Refresh data" button calling a widget endpoint, and so on.

Reactive JIT actions

If the payload carries a jit_session_id, the action is routed to handle_jit_action instead. This powers reactive parameter updates on JIT widgets β€” changing a slider re-substitutes values into the widget's template with zero LLM calls, so it's instant.

json
{ "type": "slider", "min": 0, "max": 100, "value": 50,
 "action": { "payload": { "command": "update_param", "jit_session_id": "abc123", "value": 50 } } }

Standard payload commands (quick reference)

The A2UI schema documents the common command set the LLM may emit:

text
kill_process Β· set_volume Β· set_brightness Β· toggle_wifi Β·
run_command (with "value") Β· open_app Β· refresh

Inter-widget reactions

Some interactivity never leaves the client. Widgets can also fire and listen on the event bus (timer.complete, widget.refresh, …) so one widget can react to another without a backend call.

Tip

When you ask for a control panel β€” "a panel to control my system volume, brightness, and Wi-Fi" β€” the LLM emits sliders/toggles wired to these exact commands, and the shell turns your taps into real OS changes.