ACAgentic Craft

Intermediate~40 minHazelJS

Add Human Approval Without Breaking the Run

Pause AgentRuntime with durableSuspend, notify approvers, and continue via approveAndResume without losing checkpoints.

Authors
editorial-team
Published
Last reviewed

Before you start

You will leave with

  • Configure durableSuspend + createDurableRunStore on AgentRuntime
  • Resume safely with approveAndResume after PolicyEngine require_approval
  • Avoid blocking HTTP workers and leaking secrets in approval channels
On this page

Goal

Add HITL so high-impact tools suspend the AgentRun durably, survive process restarts, and resume only after an authenticated approval—without turning your API worker into a long poll.

Pattern: /patterns/human-approval-gate. Docs: Agent OS.

Step 1Durable store + durableSuspend

typescript
import {
  AgentRuntime,
  PolicyEngine,
  createDurableRunStore,
  defaultPiiMaskPolicies,
} from '@hazeljs/agent';

const store = createDurableRunStore('./.hazel/runs');
// Production: createSqlDurableRunStore(prisma) where documented

const runtime = new AgentRuntime({
  llmProvider,
  durableSuspend: true,
  runRepository: store.runRepository,
  checkpointService: store.checkpointService,
  humanTaskService: store.humanTaskService,
  policyEngine: new PolicyEngine([
    ...defaultPiiMaskPolicies(),
    {
      id: 'refund-needs-approval',
      tool: 'processRefund',
      effect: 'require_approval',
      priority: 20,
    },
  ]),
});

Step 2Execute and return waiting state

typescript
const waiting = await runtime.execute('order-desk', 'Refund ORD-100');
// waiting status indicates suspension — return executionId to the client/ops UI
// Do not block the HTTP request until a human clicks approve

Notify approvers with redacted args (tool name, amount, order id)—never raw secrets.

Step 3Approve or reject

typescript
const done = await runtime.approveAndResume(waiting.executionId, {
  approved: true,
  approvedBy: 'ops@example.com',
});
// reject → cancel without executing the gated tool

Write tools must be idempotent so a double-click approve cannot double-charge (/patterns/idempotent-tool-execution).

Step 4CLI / ops note

hazel agent runs resume|approve against a file store records HITL intent; app code must still call approveAndResume for the runtime to continue. Lesson: /learn/agentic-development/hazel-cli-agent-ops.

Step 5Verify

  • Kill Node mid-SUSPENDED; restart; approve still works
  • Reject leaves no side effect
  • Approval channel redacts PII
  • Metrics: approval latency, stuck SUSPENDED alert
  • describeAgent / integration test covers gated path

Sources

Continue learning