Interrupt and resume
Lesson 4 of 5 in Human-in-the-Loop: Designing the Human Back In.
In a demo, the approval gate is easy: the human is sitting at the terminal, the agent loop blocks on stdin, thirty seconds pass, work continues. In production, the approver is in a meeting, the approval arrives four hours later over Slack, and the process that was running the loop has been redeployed twice since. An approve-before gate is a promise to pause a run mid-loop and resume it later, intact — and keeping that promise is an engineering problem, not a prompt.
Pausing means the run’s full state gets written somewhere durable before the process lets go: the conversation so far, the pending tool call (the exact one shown to the approver), and an approval token that ties the eventual decision back to this run. Resuming means a fresh process can pick that state up hours later and continue as if nothing happened — this is durable execution, and it is the same plumbing that survives crashes and timeouts. The agentops reliability module builds it out; here you need the shape.
The life of a gated tool call
- Agent proposes tool call
- Action gated?
- Execute tool
- Persist run state + pending call
Conversation, the literal pending call, and an approval token — written durably before the request goes out, so a process restart loses nothing.
- Deliver approval request
Slack, email, a review queue — with the exact parameters rendered by the runtime.
- Decision before TTL?
- Execute exactly the approved call
- Inject denial as tool result
The denial (ideally with the approver’s reason) returns to the model as information, so the loop can re-plan instead of dying.
- Expire: cancel or escalate
Silence is not consent. An unanswered request cancels the action or escalates the task — it never auto-approves.
- Resume the loop
What if the process crashes while waiting for the approval?
Nothing is lost, if you persisted before notifying. That ordering is the whole trick: state first, request second. A fresh worker rehydrates the run from the store when the decision arrives. If you notify first and crash before persisting, the approver’s click references a run that no longer exists.
What should a denial do to the run?
Return to the model as a tool result — { status: 'denied', reason: 'wrong customer segment' } — not as an exception that kills the run. A denial is high-value information: the agent can re-plan, propose an alternative, or escalate. Runs that crash on “no” teach teams to stop saying no.
Why can’t an unanswered approval just auto-approve after a while?
Because that converts every reviewer vacation into an autonomy upgrade. Silence cancels or escalates — never consents. If an action is safe enough to fire without an answer, it didn’t need an approve-before gate; move it to notify-after honestly.
What stops a resumed run from re-firing a call that already executed?
Idempotency keys: the runtime records each executed call’s ID durably, and resume-time replay checks the record before firing. Approve-then-crash-then-resume must not become approve-then-execute-twice — one wire transfer approved is one wire transfer sent.
Interactive checkpoint quiz (2 questions) — open this page in a browser to take it.