timbal serve (the /stream SSE endpoint). Two phases: pause (server → client) and resume (client → server). The example uses ask_user; an approval gate is identical except the pause event is an APPROVAL event and you resume with true/false.
1. Start the run
POST /stream with the runnable’s params:
text/event-stream), one data: line per event. When the agent calls ask_user, the client receives an INTERACTION event:
tool_call_id (when present) is the LLM tool_use id, so you can pin the prompt next to the matching message in the transcript. response_schema (when the tool declared one) is the JSON Schema the answer must satisfy; validate the user’s input against it before resuming. An APPROVAL event additionally carries input_schema (the handler’s params schema, for rendering a typed form).
Immediately followed by the final OUTPUT event for the run, which marks it as paused:
- Render UI from the
INTERACTIONevent’skind+payload(here: a question with three option buttons). For anAPPROVALevent, renderprompt+inputand offer Approve/Deny. - Stash
run_idandinteraction_id(orapproval_id). - A run is paused (not finished) whenever the terminal
OUTPUThasstatus.reasonofinput_requiredorapproval_required.
2. Resume with the answer
POST /stream again, echoing the original params plus two keys: parent_id (the paused run_id) and resume (a map of id → value):
ask_user returns "postgres", and the stream ends with a normal success OUTPUT:
resume map: { "<id1>": ..., "<id2>": true }. The id you send back is always the one you received: approval ids resume with true/false, interaction ids with the value the handler asked for.
Cancelling over HTTP
To abort instead of answering (user closed the dialog, navigated away), resume the id with the tagged cancel object, the JSON equivalent ofCancel:
OUTPUT of status.reason == "cancelled" (not input_required/approval_denied), and nothing is sent back to the model. An edit-on-approve over HTTP is the same idea on an approval id: { "<approval_id>": { "approved": true, "override_input": { "to": "fixed@example.com" } } }.
See also
- Resuming a paused run — the in-process and durable-provider story
- Suspend & interaction tools —
InteractionEventand response schemas - Approval gates — the
APPROVALevent and its fields