metadata
preserves the agent’s full prompt payload so a future native renderer (approval buttons, choice
pickers, multi-question forms) can pick it up without protocol changes.
Prompt kinds
The underlying agent SDKs emit three kinds. The worker preserves the kind inmetadata.prompt.kind.
kind | When emitted |
|---|---|
text | Free-text question. Answer is a single string. |
approval | Yes/no approval (typically before a destructive or sensitive tool call). |
ask_user_question | Structured question(s) with options (single- or multi-select). May carry multiple questions. |
kind: approval prompt is the user-facing side of the agent’s permissions: approval setting: when an
agent runs under approval, each sensitive action is routed here for a human decision before it proceeds.
If no human answers — for example, the worker shuts down with the prompt still open — the action is denied.
Under permissions: autonomous there is no approval gate, so the agent does not raise these prompts. See
the permissions setting for how it is resolved.
pending_prompt (worker → thread)
Posted when the agent’s turn pauses for input. The user is expected to reply by posting one or more
thread items.
pending_prompt_resolved (worker → thread, audit)
Posted once the prompt has been answered, cancelled, or failed. Audit-only — the worker has already
delivered the answer to the agent before this item lands.
Answer correlation
The worker correlates the user’s reply to the active prompt in two ways:- Positional (MVP, works with the standard thread widget). While a thread has an active
pending_prompt, the next inbound user item is the answer. Its text is mapped per kind (below). - Forward-compat structured (free). If an inbound user item carries
metadata.prompt.prompt_idmatching the active prompt and a structuredanswersarray, the worker uses it verbatim. A future native widget posts this shape — no backend changes needed.
Text → answer mapping (per kind)
| kind | mapping |
|---|---|
text | answer = [<raw user text>]. |
approval | Affirmative tokens (approve, approved, yes, y, ok, allow, 1) → ["Approve"]. Negative tokens (deny, denied, no, n, reject, 2) → ["Deny"]. Unrecognized input → ["Deny"] (defensive deny-on-uncertainty). |
ask_user_question (single question) | A bare number N → the Nth option’s label. A case-insensitive match to an option label → that label. Otherwise the raw text (the “Other” / free-text path). With multiSelect: true, comma- or space-separated numbers select multiple options. |
ask_user_question (multi-question) | Best-effort line-prefixed parse (1) … 2) …, matching the format the prompt’s content.text shows). Unparseable replies fall back to each question receiving the raw text as free text — best-effort until the native widget ships. |
ask_user_question preserves the user’s typed text as the free-text answer
for that question.
Lifecycle and audit
- Answered — the user provided a valid answer; agent receives it and continues. Audit item
prompt_state: answered. - Cancelled — the prompt was abandoned (worker shutdown, worker restart, agent turn cancelled).
Audit item
prompt_state: cancelledwithreason. - Failed — the prompt couldn’t be resolved due to an internal error. Audit item
prompt_state: failedwithreason.
Worker restart
An unresolved prompt does not survive a worker restart. On recovery the worker posts apending_prompt_resolved audit item with prompt_state: cancelled, reason: worker_restart. When
the agent resumes, it re-asks if it still needs the input.
This is conservative — a future iteration may persist enough context to honor an answer posted
while the worker was down.

