Approval-Required Tool Calls

Set policy=approval_required and tool calls pause mid-step until a human reviewer approves. The SDK exposes a single helper that handles the full 202 → poll → resume / throw lifecycle.

Features

Four-eyes enforced

Reviewer must differ from requester. Enforced at three layers: DB CHECK constraint, service-layer guard, and the operator UI disable.

TTL auto-deny

Pending approvals past 1h auto-expire via a worker scheduled sweep. The SDK throws CloudVeraApprovalExpired so your agent can fall back without the tool.

Denial-of-wallet quota

Max 25 pending approvals per agent. Beyond that, the SDK throws CloudVeraQuotaError — protects operators from being drowned in a runaway-agent queue.

Code Examples

recordToolCallAndWait — full lifecycle in one call

import {
  CloudVeraApprovalDenied,
  CloudVeraApprovalExpired,
  CloudVeraQuotaError,
} from '@cloudvera/agent-sdk';

try {
  const call = await sessions.recordToolCallAndWait(
    agent.id,
    session.id,
    {
      toolName: 'deploy_rule',
      inputPreview: JSON.stringify({ ruleId: 'r-42' }),
    },
    { timeoutMs: 5 * 60_000 }, // 5 min reviewer SLA
  );
  // call.status === 'executed' — your real handler now runs
  await deployRuleToProd(call);
} catch (err) {
  if (err instanceof CloudVeraApprovalDenied) {
    // err.reviewNotes carries the human reason
  } else if (err instanceof CloudVeraApprovalExpired) {
    // nobody answered in time — retry later or pick a different action
  } else if (err instanceof CloudVeraQuotaError) {
    // too many pending — backoff
  } else {
    throw err;
  }
}

Reviewer side — /dashboard/agent-approvals

Operators see every pending tool call at:

  https://cloudvera.io/dashboard/agent-approvals

Each row shows: tool name, agent, session, args preview, expiry
countdown, and inline approve / deny buttons. Reviewers must hold
owner / admin / editor role; viewers cannot enumerate the queue.

The decision is audit-logged with reviewer email + free-text notes.