Skip to content

Pause and resume

Sigil agents can suspend a run pending an external decision and resume later with that decision injected back into the LLM conversation. This is the foundation of:

  • The Reviews queue for human-gated transactions
  • Cross-agent delegation that survives long-running children
  • (Future) Wait-for-signature flows

Two pause flavours, one primitive

StatusTriggerResume
awaiting_reviewA tool calls request_human_reviewOperator approves/blocks in the portal Reviews queue
awaiting_delegatecall_agent spawned a child runChild’s terminal state automatically resumes the parent

Both use the same persistence (paused_messages + pause_tool_call_id) and the same resume path — only the trigger differs.

Lifecycle

running ──┐
│ tool returns PauseForReview │
▼ │
awaiting_review │ status persisted +
│ POST /reviews/{runID}/resume │ paused_messages JSON
▼ │
pending (resumed_at set) │
│ runner trigger │
▼ │
running ──┘ loop continues with synthetic
tool_result injected against
pause_tool_call_id

The run row stores enough state to drop the Cloud Run instance entirely between pause and resume — no idle compute, runs can sit awaiting a human reviewer indefinitely.

Cascading pauses

Orchestrator (awaiting_delegate)
▼ parent_run_id
Compliance Agent (awaiting_review)
▼ paused_messages includes the orchestrator's call_agent context
Reviewer approves
Compliance resumes → finishes → triggers Orchestrator resume
Orchestrator continues with compliance's verdict as the tool_result
of its call_agent.

You write each agent assuming it is the only one running. The platform handles the cascade.

Resuming from the API

External integrations can resume programmatically using the same endpoint the portal uses:

Terminal window
curl -X POST https://api.sigilkeys.com/v1/orgs/$ORG/reviews/$RUN/resume \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $SESSION_COOKIE" \
-d '{ "decision": "allow", "notes": "Cleared after manual KYC review." }'

Decision is a strict enum (allow | block | review). Notes are length-capped at 4 KB. The decision is wrapped with an explicit _kind: "sigil.human_review_decision" marker before being injected as the LLM’s tool_result so prompt-injection from reviewer notes cannot pose as a system directive.

Idempotency

Two reviewers approving the same case concurrently is a real race. The backend returns 409 Conflict with code already_resumed when a second resume call finds the run no longer in an awaiting state. Clients should refresh the Reviews list and re-render — do not retry blindly.

Designing tools that pause

Any tool can suspend by returning tools.PauseForReview(title, payload):

func (RequestHumanReview) Execute(ctx context.Context, in map[string]any) (Result, error) {
return Result{}, PauseForReview(title, map[string]any{
"title": title,
"report_md": report,
"payload": structuredData,
})
}

The payload renders in the Reviews queue detail page. Markdown in report_md is rendered to the reviewer; everything in payload is shown as structured JSON.