Actions and app commands
Handle local actions, control which URLs may open, and let the agent drive the app with opt-in server commands.
Local actions
Kletso.instance.registerAction('open_product', (args, ctx) async {
final sku = args['sku'] as String? ?? '';
Kletso.instance.close();
await Navigator.of(ctx.context).pushNamed('/product/$sku');
});
argsis the action’s declaredargsmerged with whatever the widget passed toexecuteAction.ctxis aKletsoActionContext:context(aBuildContext),origin(surface,server,notification),surfaceandnode(null for server commands),action,client.- After the handler runs, the SDK sends
reportLocalAction(handled: true|false)so the conversation log shows what the app did. Disable withreportLocalActions: false.
Unregistered names are ignored and reported as unhandled; nothing crashes.
Firing actions from your widgets
Inside a component builder, ctx.executeAction('add') looks up the action with that id on the node and dispatches it by kind: local to your handler, agent/submit/confirm/workflow to the runtime, url to onOpenUrl. The “both” pattern (change app state and tell the agent) is simply doing both in the callback.
URLs
Kletso.instance.onOpenUrl = (uri) => launchUrl(uri, mode: LaunchMode.externalApplication);
Without onOpenUrl, links are shown but do nothing. Every URL passes KletsoUrlPolicy first: https only, host must be on the agent’s URL allowlist (delivered in the session as allowedUrlHosts; *.example.com matches subdomains). javascript:, data:, file: and http: are always blocked.
Server commands (app.command)
The agent has a built-in app_command tool. When it calls it, the SDK receives app.command { name, args, closeChat } and runs the local action with origin: server, no tap involved. This is off by default.
KletsoConfig(allowServerCommands: true)
Kletso.instance.ui.contextProvider = () => navigatorKey.currentContext;
Outcomes are published on client.ui.commandResults as ran, disabled, noHandler or noContext. Trigger rules and notification taps use the same registry, so one open_checkout handler serves taps, notifications and commands.
Confirmations
You do not write code for confirmations. When a tool that requires confirmation is called, the runtime renders a confirm block with approve and decline confirm actions; the built-in block handles the tap and the turn resumes. If you replace the confirm block with your own widget, call ctx.executeAction('yes') / ('no') (the ids on the node) or ctx.execute(action).