Skip to content
Trilha

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

the tool that asks instead of doing
// 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.

Read the recipe: An AI agent