Try it
- Browse (read-only): "find a waterproof trail shoe under $170": the agent calls
search_products. It's annotatedreadOnlyHint: true, so the gate auto-approves it (no bubble) and matching cards light up. - Inspect (read-only): "tell me about SHOE-005": the agent calls
view_product; the card flashes and scrolls into view. Still read-only → still no bubble. - Add (mutating): "add SHOE-001 to my cart":
add_to_cartis mutating, so Persona's native approval bubble opens; approve it and the Cart updates. - Parallel (the headline): "add SHOE-001 and SHOE-007 at the same time": the model emits two
add_to_cartcalls in one turn. Each gets its own approval bubble; approve both and the widget batches the two results into a single/resume, keyed by per-call id (runtypelabs/core#3878). Watch the orange batched /resume row in the wire log show both ids at once. - Promo & remove (mutating): "apply code TRAIL10 and drop the socks":
apply_promo+remove_from_cart, both gated. The cart shows the discount line and the item leaves.
The gate policy splits read-only from mutating: the storefront
auto-approves its read-only tools (search_products,
view_product) so they run with no friction, and routes every
mutating call to the approval bubble. The page is the authority on which
of its own tools mutate state.