Agent action patterns: who has the turn?
An agent that only answers needs one screen. An agent that sends emails, edits records and drives a browser needs a clear answer, at every moment, to one question: who is acting right now?
- Author
- Published
- Reading time
- 12 min
- Every moment in a session has exactly one owner: the agent, the person, or nobody.
- We design every hand-off as one of five patterns: Ask, Approve, Watch, Take over, Background. Each has its own states, and each state looks the same everywhere the session appears.
- A waiting agent must never look busy, and a busy agent must never look done.
The question
Chat interfaces were built for a simple rhythm: you write, the model writes back, repeat. The person always knows whose move it is, because the only move is typing.
Agents broke that rhythm. A single request like “clean up the Q3 pipeline” can turn into fifty tool calls, a clarifying question, an email that needs sign-off, a browser session on a CRM, and a long-running job that finishes after you have closed the tab. In between, people kept asking us the same thing in different words: is it doing something, or is it waiting for me?
We stopped treating this as a loading-state problem and started treating it as an ownership problem. At any moment, exactly one party holds the turn: the agent is acting, a person is expected to act, or nobody is, because the work moved to the background. Figure 1 shows one ordinary session through that lens.
Five patterns
We went through every hand-off in the product and grouped them by two properties: who holds the turn, and what returns it. Five patterns covered everything. Step through them below. The left side is a simplified version of the real component; the right side is the state machine behind it.
| Pattern | Turn owner | What returns the turn | Typical wait |
|---|---|---|---|
| Ask | Person | An answer | seconds to hours |
| Approve | Person | Approve, edit or decline | minutes to days |
| Watch | Agent | The agent finishes, or the person interrupts | seconds to minutes |
| Take over | Person | Hand back | minutes |
| Background | Nobody | A result, delivered as a new message | minutes to hours |
Ask and approve
Ask and Approve look alike: the agent stops and a card appears. The difference is what the person is deciding. With Ask, the agent lacks information (“which field means at risk?”). With Approve, it has everything and needs permission for an effect it cannot take back: sending an email, writing to a system of record, spending money.
Our first approval card looked like any other assistant message, so people scrolled past it and assumed the agent had stalled. The fix was not a louder colour. We made the card the only place where the session can move forward, and made every other surface say so: the composer, the sidebar entry and the tab title all switch to the same “Waiting for you” state.
Two details mattered more than we expected. First, the answer to a question is the tool result, not a new chat message. The agent continues the same turn with the answer in hand, instead of starting over and re-deriving its plan. Second, an approval can wait a long time. People approve on their phone the next morning, or after the weekend. The card has to look exactly the same on day three as it did in the first minute, which turned out to be a backend problem as much as a design one.
Watch and take over
Computer use adds a new kind of hand-off. The agent operates a real desktop with a shared browser, and anyone with access to the thread can open a live view of it. Watching is the default; taking over is one click away.
In Watch, the agent holds the turn and the person is an observer. The hard part is motion. An agent acts in bursts: three clicks in 200 ms, then nothing for two seconds while it reads the page. Rendering each action literally looks like flicker. We animate an agent cursor instead: each action glides for 80 to 150 ms depending on distance, clicks get a ripple, and actions without a position get a short label. The cursor is never allowed to trail the real action by more than 150 ms. If a burst arrives faster than we can glide, the in-between clicks ripple in place and the cursor jumps to the newest position.
Take over is the reverse. Sometimes the agent asks for it (“enter the SSO code”), sometimes the person simply grabs the mouse. In both cases one arbiter in the sandbox decides who may send input, and the person always wins. While a person holds the control lease, the agent’s input is refused and its script waits. When they hand back, the script continues in the same turn.
Background
Some work is simply long: re-running a model over every campaign, a workflow that polls an external system, a sub-agent researching a market. Holding the turn for forty minutes would block the chat for no reason.
In the Background pattern, nobody holds the turn. The agent commits a placeholder (“Running in the background”), finishes its turn, and the chat is free. When the result arrives, it shows up as a new message in its own turn. Two rules keep this predictable:
- A background call belongs to the session, not the turn. Stopping or steering the current turn does not cancel it. Each background call has its own stop control.
- Sending to background works at any time. A call that started synchronously can be moved to the background while it is still running, or while it is waiting at an approval.
The agent does not decide which mode a call runs in, and neither does the tool. The runtime does. That keeps the interface simple: the same tool can appear as a waiting card or as a background card, and the person can move it from one to the other.
What we learned
- Name the owner, not the activity. “Waiting for you” is more useful than any spinner, because it tells people what to do.
- One state, every surface. If the card says waiting and the sidebar says running, people believe the sidebar.
- Design the long wait first. The card that has been open for three days is the one that breaks. Treat time as a design input.
- Share vocabulary with the engine. Turns, hand-offs and background calls exist in our backend with the same names. Design reviews and design docs now read the same way.
The five patterns are not finished. Approvals reviewed by another model, and agents that ask other agents, will add new hand-offs. But the question stays the same, and so does the answer we design for: at every moment, someone has the turn, and the interface says who.
Want to work on problems like this? We’re hiring