> ## Documentation Index
> Fetch the complete documentation index at: https://docs.blobhub.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Interactive

> When the agent asks for input: pending_prompt and pending_prompt_resolved items

Claude Code and Codex occasionally pause to ask the user something — for approval before running a
risky command, to pick from a list of options, or for free-text input. The worker surfaces these as
structured thread items and resolves the user's reply back to the agent.

In v1 users answer with **plain text** in the standard thread widget. The structured `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 in `metadata.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. |

A `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](/worker/session-agent-harness/thread-object) 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.

```yaml theme={null}
content:
  - type: text
    text: |
      ❓ Provide input:
      What's the deployment target?
        1. staging — push to staging.example.com
        2. production — push to www.example.com
      Reply with a number, the option text, or free text.
metadata:
  type: pending_prompt
  prompt:
    prompt_id: prm_01J...
    kind: ask_user_question
    prompt_state: pending
    questions:
      - question: "What's the deployment target?"
        multiSelect: false
        options:
          - { label: staging, description: "push to staging.example.com" }
          - { label: production, description: "push to www.example.com" }
```

The agent's turn blocks at the tool call awaiting the answer; no further thread items are emitted
until the prompt resolves.

There is at most **one active prompt per thread** at any time.

## `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.

```yaml theme={null}
content:
  - type: text
    text: "✓ Answered: staging"
metadata:
  type: pending_prompt_resolved
  prompt:
    prompt_id: prm_01J...
    kind: ask_user_question
    prompt_state: answered            # answered | cancelled | failed
    answers:
      - question: "What's the deployment target?"
        answer: [staging]
    reason: null                      # populated when prompt_state is cancelled or failed
```

## Answer correlation

The worker correlates the user's reply to the active prompt in two ways:

1. **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).
2. **Forward-compat structured (free).** If an inbound user item carries
   `metadata.prompt.prompt_id` matching the active prompt and a structured `answers` array, the
   worker uses it verbatim. A future native widget posts this shape — no backend changes needed.

Items posted while no prompt is active are queued for the next agent turn as usual.

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

The "Other" path for `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: cancelled` with `reason`.
* **Failed** — the prompt couldn't be resolved due to an internal error. Audit item
  `prompt_state: failed` with `reason`.

### Worker restart

An unresolved prompt **does not survive** a worker restart. On recovery the worker posts a
`pending_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.

## See also

* [Job Session Object](/worker/session-agent-harness/thread-object)
* [Thread items](/worker/session-agent-harness/thread-items)
* [Recovery](/worker/session-agent-harness/recovery)
* [Reference](/worker/session-agent-harness/reference)
