Delta Agents logoDelta Agents

Human Oversight

How human reviewers approve, reject, and manage agent actions

Every autonomous system needs a circuit breaker. Delta provides a structured human-in-the-loop layer where the engine pauses, informs, and waits for a human decision before allowing sensitive actions to proceed or recovering from failures the agent cannot resolve alone.

How it works

The engine never assumes perfect autonomy. When an agent reaches a governance boundary it cannot cross alone (an action that requires approval, a budget violation, a persistent API failure), the engine pauses the task, records the reason, and waits. The task stays blocked until a human reviews the situation and decides what to do next.

// Subscribe to approval requests as they happen
delta.events.on("approval-requested", ({ taskId, action, approvalId, reason }) => {
  console.log(`Task ${taskId}: ${action} needs sign-off (${reason})`);
  // Forward to Slack, email, dashboard
});

// List pending approvals for a task
const { pendingApprovals } = await delta.inspect(taskId);

// Approve and resume
await delta.approve(approvalId);
await delta.resume(taskId);

// Reject with optional reason
await delta.reject(approvalId, "Use the standard refund flow instead");

Approval gates

An action that declares requiresApproval: true blocks at the governance gateway until a human approves it. The task stays paused with a persistent ApprovalRequest that the engine re-checks on every resume attempt.

const shipRefund = delta.action({
  name: "issue-refund",
  description: "Issue a refund to a customer",
  requiresApproval: true,
  fn: async (input, ctx) => { /* ... */ },
});

Trust-based waiver

Actions that need human oversight by default can waive it once the agent has earned enough trust. requiresApproval: { untilTrust: 0.7 } means the action requires approval only until the task's trust score reaches 0.7. After that it auto-approves with an auditable record.

const action = delta.action({
  name: "cancel-subscription",
  description: "Cancel a customer subscription",
  requiresApproval: { untilTrust: 0.8 },
  fn: async (input, ctx) => { /* ... */ },
});

A rejection is always final. Even with a trust waiver, a human-rejected action stays blocked. The waiver only governs the initial approval gate, not overrides.

Approval lifecycle

  1. The engine creates an ApprovalRequest in pending status
  2. The task transitions to blocked (persisted as paused)
  3. The engine emits approval-requested. Subscribe via delta.events.on()
  4. A human calls delta.approve() or delta.reject()
  5. The engine emits approval-resolved with the decision
  6. After approval, call delta.resume(taskId) to continue

Escalations

The engine escalates to a human when it hits a boundary it cannot resolve alone. Escalation is not an error. It is a designed recovery path.

When escalation happens, the engine:

  1. Saves an escalation record with the trigger and reason
  2. Pauses the task so no further work runs
  3. Emits escalation-raised for real-time awareness

Escalation triggers

  • Reasoner failure: the model API fails after all retries are exhausted. The problem is likely transient, so the task pauses rather than fails
  • Budget violation: an action would exceed the remaining budget. The engine blocks before executing
  • Risk threshold: the task's assessed risk rises above the configured boundary
  • Bayesian surprise: observed outcomes deviate sharply from expected. This indicates novel or potentially unsafe conditions
  • Supervision policy: a workflow phase declares escalate as its supervision strategy for unrecoverable action failures
// React to escalations in real time
delta.events.on("escalation-raised", ({ taskId, trigger, reason }) => {
  console.log(`Task ${taskId} escalated (${trigger}): ${reason}`);
  notifyOnCallEngineer(taskId, reason);
});

Engine guidance

Before escalating, the engine warns the agent through advisory guidance lines injected into its reasoning context. On each turn, the engine checks governance signals (risk level, trust score, budget consumption, and Bayesian surprise) and computes warning-band text the model sees before it proposes its next action.

Guidance works preventively: the agent sees "Risk rising above threshold" or "Budget at 80 percent" and can change course before the engine blocks the action. This reduces unnecessary escalations without reducing safety.

Guidance is on by default. Set guidance: false in engine configuration to disable it entirely.

Pause and resume

The engine pauses a task automatically on escalations and approval blocks. You can also pause a running task manually:

await delta.pause(taskId);

// Later, resume from the latest checkpoint
const result = await delta.resume(taskId);
if (result.isOk) {
  console.log(`Resumed: ${result.value.status}`);
}

Resume re-enters the governance loop from the last checkpoint. Completed work is never re-executed. If the task is still blocked on a pending approval, it blocks again at the same gate.

Concurrent resume safety

Two callers cannot both resume the same task. The engine uses a compare-and-swap transition so exactly one resume wins. The other gets a clear error. This prevents duplicate execution when multiple reviewers respond to the same escalation.

Rejection routing

When a human rejects an action, the engine feeds the rejection reason back to the model. The agent sees why its proposal was denied and can route around the blocked gate: choose a different approach, complete the task differently, or report what it could not do.

await delta.reject(approvalId, "Use the standard refund flow. The customer is not eligible for manual override");

The model receives this feedback on its next turn (free loop) or the workflow fails with the reason (deterministic path). A rejected action is never re-requested. The engine permanently blocks that specific approval.

Supervision and HITL

Workflow phases declare supervision policies that determine what happens when an action fails. Strategies range from fully automated to human-in-the-loop:

  • Retry: restart from the failed action (automated)
  • Restart: restart the phase from the beginning (automated)
  • Resume: continue from the latest checkpoint after human approval
  • Escalate: hand off to a human when automated recovery is inappropriate
  • Abort subtree: fail the current branch while keeping the workflow alive
  • Abort entire tree: fail the entire task and its descendants

The escalate strategy is the designed HITL path for workflows: when automated recovery is exhausted or inappropriate, the engine pauses and waits for a human to assess the situation.

Events reference

HITL events are always-on. They fire regardless of any diagnostics configuration because a silently dropped human-oversight notification is a safety failure.

EventWhen
approval-requestedAn action requiring human approval needs sign-off
approval-resolveddelta.approve() or delta.reject() resolves it
escalation-raisedReasoner failure, budget violation, or risk threshold exceeded
task-blockedTask is waiting on human action

End-to-end flow

Agent proposes sensitive action

Engine checks requiresApproval gate

No approval on record → creates ApprovalRequest

Task pauses, emits "approval-requested"

─────────────────────────────────────────
  Human reviews (via dashboard, Slack, etc)
─────────────────────────────────────────

Approve → delta.approve(id)  |  Reject → delta.reject(id, reason)
        ↓                              ↓
Engine emits "approval-resolved"        |
        ↓                              ↓
delta.resume(taskId)           Model sees rejection reason
        ↓                              ↓
Agent continues                   Agent routes around block

On this page