Skip to main content
Status: Developer preview — contract-stable per @nexislabs/ai-platform v1; not yet serving public traffic.
A run parks pending a human or peer decision whenever the policy engine (design spec §3.3) classifies a proposed action above auto: auto | peer_review | human_approval | deny, each with a TTL and approver requirements attached. deny never reaches an approval — the action is rejected outright. The other two levels emit approval.required. Approval semantics are the same for mode:"turn" and mode:"task": the stream/run pauses, the caller renders the canonical payload, and the caller posts the decision back.

The approval.required event

Repeated here for convenience — see Events for the full envelope.

action_digest

The design spec describes resume_task_after_approval as digest-bound: the digest binds a decision to the exact canonical payload that was proposed, so a decision cannot be replayed against a different action. This mirrors the render == record == gate-match invariant the existing first-party approval domains already hold (design spec §3.3). Neither source in scope for this reference states the digest’s algorithm or where it is carried on the wire response — this reference assumes it travels alongside (or is derivable from) the approval.required event, and flags the gap below rather than inventing a transport.

Endpoint: approve or reject

Request body

Behavior

A valid call invokes resume_task_after_approval, which unparks the run. The caller should continue consuming the run’s event stream (or webhook deliveries) rather than expecting the full result synchronously from this call — the design spec does not describe this endpoint’s success response body beyond “resumes the run.” The design spec separately notes that today’s wakeTaskWorkflow swallows errors when the underlying sendEvent doesn’t land, and states the fabric’s approve wrapper must fail loudly instead — i.e., a 2xx from this endpoint is meant to guarantee the resume was actually delivered to the run, not just accepted for delivery.

Errors

  • approval_timed_out — the approval’s expiresAt passed before a decision was posted.
  • Posting against a run with no pending approval, an already-resolved approval, or a mismatched action_digest is expected to be rejected — most plausibly as conflict, but neither source ties a specific code to this case; treat as inferred, not confirmed.

Inline approvals (mode: turn)

The published AiPlatformChatRequestV1 schema carries a second, differently-shaped approval mechanism: an approvals array on the request itself.
Ambiguity. The design spec states approval semantics are “identical in both modes,” and describes that contract as action_digest + decision. The published chat schema instead threads approvalId + receipt (resubmitted as part of a fresh request, presumably to continue a mode:"turn" stream past an approval.required pause). Whether receipt is an encoded action_digest/decision pair, or a distinct mechanism that predates the fabric’s /v1/runs/:id/approve endpoint, is not stated by either source. Both shapes are documented here rather than merged into one, silently-assumed contract.

Example

TypeScript