An agent that acts on the app's data
The same chat, with the agent's steps on the screen. Every tool call it makes is a line you can read, and the one tool that changes something does not change it: it opens a request in the queue below, where a person decides. Only the model is scripted, in the browser — this page needs no API key.
Order #1043
Ada Lovelace
- Customer
- Ada Lovelace
- Status
- Shipped
- Total
- $32.90
- Placed
- September 1, 2026
Ask where order 1043 is — or ask to cancel it, and watch what the agent does instead.
Try: “where is my order?”, “how much was it?”, “cancel order 1043”.
What is waiting for a person
The write tool opens a request here and answers the model that it asked. Approve it and the order changes — that is the only path from the conversation to the data.
| Subject | Kind | State | Due | |
|---|---|---|---|---|
| Cancel order 1043 | order.cancel | Pending | no deadline |
// The tool that does not do what it says: cancelling is not the
// model's to do. It opens a request and tells the model so.
func AIAgentCancelTool(c *trilha.Ctx) *ai.Tool {
return ai.NewTool("cancel_order",
"Ask a person to cancel an order. This does not cancel anything.",
ai.Schema(`{"type":"object","properties":{"order_id":{"type":"string"},"reason":{"type":"string"}},"required":["order_id","reason"]}`),
ai.Typed(func(ctx context.Context, in struct {
OrderID string `json:"order_id"`
Reason string `json:"reason"`
}) (string, error) {
o, ok := AIAgentOrders.Find(AIAgentWho(c), in.OrderID)
if !ok {
return "there is no order " + in.OrderID + " on this account", nil
}
id, err := trilha.Use[*approval.Approvals](c).Open(c, approval.Request{
Kind: AIAgentCancelKind,
Subject: "Cancel order " + o.ID,
Target: "/orders/" + o.ID,
Assign: approval.Role("support"),
Due: time.Now().Add(AIAgentCancelDue),
Data: map[string]string{"order_id": o.ID, "reason": in.Reason},
})
if err != nil {
return "", err
}
return "request " + id + " is waiting for a person to decide; " +
"the order has not changed", nil
}))
}What is pretending
Only the model. The component, the steps, the queue and the buttons are the real ones; there is no server behind this page, because the documentation site is static. The script answers the same events ai.Serve emits, tool calls included.