Skip to main content
Use this when a step needs a yes, a choice or some text before it goes on: approve a deploy, pick an option, confirm a risky tool call. Prerequisites: a server on http://localhost:9858. Add -H "X-API-Key: $YUKTA_API_KEY" if your server has keys; answering needs the OPERATOR role, reading a VIEWER key. Who may answer which risk is explained in Who decides. An input request is a typed question a node asks: a prompt, the answers on offer, a risk and a time to live. The run waits (a wait uses no tokens and no run slot beyond its own), the request appears on the event feed, and the server checks every answer against who may give it.

Steps

1

Ask from a workflow with ASK_INPUT

The kinds are APPROVAL (approve or reject, or your own options), CHOICE, TEXT and STRUCTURED. The node adds input.decision, input.text, input.data, input.responder and input.confidence to the message metadata, so a BRANCH can route on it. Save as session.json:
session.json
risk is LOW, MEDIUM (the default) or HIGH; a HIGH request is answered by people only. onTimeout is FAIL (default), CONTINUE (carries on with input.decision set to timeout) or USE_DEFAULT (answers with defaultDecision). audience limits who may answer, and route picks a route.
2

Find the open request

Each item has an id (the request id), executionId, kind, risk, prompt, options, tier, deadline and a version. The prompt and context are written by the asking step, often by a model, so treat them as untrusted text.
3

Answer it

Optional fields: text, data, expectedVersion (the version you read, so a stale answer is refused).
Anyone allowed can escalate instead: hand the request up to the next tier with a reason and advice. To be told rather than to look, follow GET /api/events/stream?type=InputRequested.
4

Ask from an AI agent

Set "allowAskInput": true on the LLM_CALL node, which offers the model the tool ask_for_input {prompt, options?, kind?, risk?}, and on the MCP_TOOL_CALL node that runs its actions. The model chooses the question, but never a risk below inputRiskFloor (default MEDIUM). Who may answer (inputAudience), how long (inputTtlSeconds, default 3600), the route (inputRoute) and how many questions one node run may ask (inputMaxAsks, default 3) come from the node, never from the model. The answer returns to the model as a tool result, and no answer in time is a tool error, or fails the node with inputOnTimeout: FAIL. See Use tools and MCP servers.
5

Or hold a message until a named approval

WAIT_FOR_SIGNAL asks a request of kind APPROVAL and risk HIGH, so only a person can answer. It holds each message, then lets it go on, drops it or fails:
The message carries signal.name, signal.decision and signal.data. onTimeout: CONTINUE goes on with decision timeout; onReject: CONTINUE drops the message. Answer it exactly as above. MCP_TOOL_CALL’s requireApproval uses the same mechanism.

Verify it worked

Before the answer, the run is RUNNING with the confirm node waiting and the request OPEN. After approve, the request is ANSWERED and the result comes from the deployed terminal; with reject it comes from declined. The log records who answered and why. If the answer is refused, the status says why: 403 names the rule that failed (audience, tier, risk, scope or separation) and leaves the request open, 409 means it was already answered, expired, cancelled or changed since expectedVersion, 422 means the answer does not fit the request (for a CHOICE, the decision must be an option id).

Variations

  • Let a supervisor answer low-risk questions. A rules supervisor can approve LOW requests by policy: Write a rules supervisor.
  • Escalation tiers and webhooks. Supervisors first, then a person, or a chat bot with a one-time token: Route input requests.
  • Pull instead of push. A script can poll GET /api/inputs with an OPERATOR key and answer; example 15 does it with curl.
  • After a restart. Requests are held in memory by default: a restart cancels waiting runs and loses their open requests. With the Plus edition and PostgreSQL they survive: Persist sessions.