Docs

Asking a human

Consumer-facing guide to ask_a_human — the structured human-in-the-loop question an agent raises when it is blocked on human judgment: a preference, a confirmation only a person knows, a pick among options. For the delegation model the escalation path rides on, see Delegating to sub-agents.

What an ask is (and is not)

ask_a_human puts exactly one structured question to the human and pauses only the asking run until it is answered. It is not a free-roaming chat pause: agents are taught to exhaust their tools first — anything a data query, knowledge-base search, or context read answers is never a valid ask.

Two shapes only:

ShapeAgent suppliesHuman answers with
multiple_choicequestion + 2-6 options labels{ "kind": "multiple_choice", "option_id": "...", "other_text": "..." }
free_formquestion only{ "kind": "free_form", "text": "..." }

The Other write-in is guaranteed. On every multiple-choice ask the platform injects exactly one { "id": "other", "label": "Other" } option (deduping any caller-supplied "Other"). Picking other requires a non-empty other_text write-in — an empty or whitespace-only write-in is rejected at resume validation.

When the run resumes, the agent receives the answer as the tool result: { "answer": "<chosen label, write-in, or free text>", "option_id": "<id, multiple_choice only>" }.

Who pauses (escalation semantics)

Only the asking run ever blocks:

  • Direct ask — the asking run transitions to awaiting_input with pending_input_type: "ask_human". Any sub-agents it dispatched keep running to completion.
  • Sub-agent ask — the sub pauses itself and the question is escalated to its caller's event stream as a child_needs_human frame ({ child_run_id, question, timestamp }). Sibling sub-agents keep running; the caller is never paused by the escalation. The answer resumes the waiting sub directly — resume targets the paused child's run id.

Multiple concurrent asks on one conversation are surfaced oldest-first (FIFO); each is answered independently against its own run.

Answering

An ask is answered through the existing resume surface, targeted at the paused run:

bash
curl -X POST https://api.amdahl.com/api/platform/v1/agents/<run_id>/resume \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "input": { "kind": "multiple_choice", "option_id": "other", "other_text": "SMB first, actually" } }'

The body must match the run's persisted pending_input_schema (read it off the paused run row); a payload that violates the contract — unknown option_id, empty Other write-in, empty free text — is rejected with a validation error and the run stays paused for a corrected answer.

Behavior per surface

An ask behaves differently depending on how the run was started, controlled by the run's on_question mode:

Surface / modeWhat happens on an ask
Interactive (console, on_question: "pause", the default)The run pauses; the question renders as a pause widget; answer via resume.
RESTReading the run shows status: "awaiting_input" + the question in pending_input_context; answer via the same resume endpoint.
MCPThe paused state is visible on run reads; the connected model answers via the resume tool or relays the question to its own user.
on_question: "auto" (bare API callers running on judgment)No pause. The tool returns { "skipped": true, "reason": "on_question_auto" } and the agent proceeds on its own judgment, stating the assumption it proceeded on.
Routines / headless (on_question: "none")No pause, no hang. The tool returns { "error": "no_human_in_loop" } immediately — scheduled runs must never depend on human asks.

Limits

  • One pending ask per run; a second ask in the same turn is refused with ask_in_flight.
  • Multiple-choice asks take 2-6 caller options (the write-in is added on top); a question whose only option would be Other is rejected — use free_form.
  • Free-form answers and Other write-ins are capped at 4000 characters.
  • An answer inbox for headless runs (email notification, TTL, on_no_answer policies) is a planned follow-up and not part of v1 — headless asks fail fast by design.