Skip to main content

Synchronous & Asynchronous Execution

Operations that outlast a request — an LLM generation, a document ingestion, an orchestration run — are controlled by one toggle, wait:

An operation runs in the background by default and answers immediately with a handle; wait=true blocks until it settles and answers with the result.

This page is the canonical definition. Module pages describe their own handle and link here.

The toggle​

ValueResponseUse when
Defaultwait omitted or false202 Accepted — or 201 Created when a run is created — plus a handle to poll (see Status codes)The work may take a while and you have somewhere to put the result: a poll loop, a webhook, a UI that refreshes
Blockingwait=true200/201 + the settled resultA script that needs the answer on the next line, or any flow that must observe requires_action

wait is a query parameter on the generation and ingestion endpoints, and a body field on the run endpoints (start-orchestration-run, start-eval-run, create-decision, create-inline-decision, create-workflow-migration); same name, same meaning.

# Background (default): returns a handle immediately
soat create-agent-generation --agent-id agent_01 \
--messages '[{"role":"user","content":"Summarize Q1"}]'

# Blocking: returns the finished generation
soat create-agent-generation --agent-id agent_01 --wait true \
--messages '[{"role":"user","content":"Summarize Q1"}]'

Where it applies​

OperationHandle returned by defaultPoll it with
POST /agents/{agent_id}/generategeneration_id, trace_idGET /generations/{generation_id}
POST /sessions/{session_id}/generatesession_idGET /conversations/{conversation_id}/messages
POST /conversations/{conversation_id}/generateconversation_idGET /conversations/{conversation_id}/messages
POST /documents/ingest and POST /documents/{document_id}/ingestthe document, in status: pendingGET /documents/{document_id}/status
POST /orchestration-runsthe run, in status: queuedGET /orchestration-runs/{orchestration_run_id}
POST /evals/{eval_id}/runsthe run, in status: queuedGET /evals/{eval_id}/runs/{eval_run_id}
POST /deciders/{decider_id}/decisionsthe decision, in status: queuedGET /decisions/{decision_id}
POST /decisionsthe decision, in status: queuedGET /decisions/{decision_id}
POST /playbook-cases/{case_id}/nodes/{node}/runthe execution, in status: runningGET /playbook-cases/{case_id}/executions/{execution_id}
POST /playbook-cases/{case_id}/nodes/{node}/exportsthe exports, in status: runningGET /playbook-cases/{case_id}/exports/{export_id}
POST /workflows/{workflow_id}/migrationsthe migration, in status: queuedGET /workflows/{workflow_id}/migrations/{migration_id}
POST /playbook-cases/{case_id}/inputs, POST /playbook-cases/{case_id}/nodes/{node}/confirmation and POST /playbook-cases/{case_id}/upgrade (cascade)the case, in automation_status: runningGET /playbook-cases/{case_id}

What the default does not change​

Backgrounding defers the slow part, never the checks. Everything that can reject a request still runs before the accepted response:

  • Authentication and permissions — a caller without the IAM action gets 401/403.
  • Input validation — a malformed body is 400 VALIDATION_FAILED.
  • Resource resolution — an unknown agent, session, or conversation is 404.
  • Admission control — a breached quota is 429, and the agent-to-agent call-depth guard still fires.
  • The record write — the generation record exists before the response is written, so the generation_id is immediately readable. It reports running until the run reaches completed or failed.

An accepted response means admitted; the only failures discovered by polling are those of the model call itself.

Status codes​

FamilyBackgroundBlockingWhy
Work on an existing resource — agent, session and conversation generation, document ingestion202 Accepted200 (201 for ingestion)The request is accepting work; no new resource's creation to report
Run creation — orchestration runs, eval runs, decisions, inline decisions, playbook node runs, playbook exports, workflow migrations201 Created201 CreatedA run row is created either way and is immediately readable; the mode shows in its status (queued), not the status code
Writes that start a playbook cascade — inputs, confirmation, upgrade200200The write is done either way; wait only holds the answer for the executions it queued, and the mode shows in the case's automation_status

Branch on wait and on the run's own status field, never on 202 alone. The uniform rule: the response always carries something you can poll, and a caller that omitted wait never receives a settled result.

A trigger firing has no wait: it always starts an eval run in the background, and the firing record names the evrun_… to poll.

Two combinations that are resolved for you​

Streaming implies waiting. stream: true holds the response open, so it is a blocking call whether or not you pass wait. stream: true with ?wait=false is contradictory and returns 400 VALIDATION_FAILED.

A tool call always waits where the result is the point of the call and the work is bounded. That is create-agent-generation, generate-conversation-message, generate-session-response, create-decision, create-inline-decision (requesting a decision, inline questions) and export-playbook-case-node (exports), as builtin tools and as the MCP tools derived from the same specs: a tool call is one request returning one result, and an agent step or an orchestration tool node reading a queued record would find no answer in it. The field is not offered on the tool surface, like stream. See Agent-to-Agent Calls. Runs that can pause or run long keep wait on the tool surface, since polling them is the point: start-orchestration-run, start-eval-run, run-playbook-case-node, write-playbook-case-inputs, confirm-playbook-case-node, upgrade-playbook-case, create-workflow-migration, ingest-document and reingest-document.

Choosing a mode​

wait=true when the result is the next thing you need: a shell script, a smoke test, a tutorial step, or any client-tool flow (requires_action is only observable in a blocking response).

The default when the work is detached: a UI that renders a pending state, a batch ingestion, a run inspected later.