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:
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: 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 built-in capabilities. For example, 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. For example, changing a slider re-substitutes values into the widget’s template with zero LLM calls, so it’s instant.

Standard payload commands (quick reference)

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

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.
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.