Your own UI
Every agent already has a working browser page: a voice client for a voice agent, and a form per declared workflow for a workflow app. Come here when you want to show something of your own beside it — a cart, an order, a live form — or replace the page entirely.
You do that by adding a client.tsx. Add the file and you get the same shell
with your own panel in it:
import { sessionSlot } from "@alexkroman1/aai";import { mountClient, useAgentState } from "@alexkroman1/aai-ui";import "@alexkroman1/aai-ui/styles.css";
// In your project this is one line — `import { cartSlot } from "./shared.ts"`.// The slot is declared once, beside the agent, and both ends read the same// object.type Cart = { items: { sku: string; qty: number }[] };const cartSlot = sessionSlot("cart", (): Cart => ({ items: [] }), { view: (cart) => ({ count: cart.items.length }),});
function CartPanel() { const cart = useAgentState(cartSlot.projected); return <p>{cart.count} items</p>;}
mountClient({ sidebar: CartPanel });aai dev builds it and aai publish ships it, with no extra step.
A slot is a named piece of session state. useAgentState reads whatever the
agent projects from one declared sync: true, so declare a slot first or there
is nothing to receive — see Remembering things.