Human-in-the-loop checkpoint for sensitive agent actions
The Approvals page (ApprovalsPage) implements the human-in-the-loop approval workflow for AgenticMail Enterprise. When agents attempt actions that match configured approval policies (based on risk level or side effect type), the action is paused, a request is created, and it appears in the pending queue for human review. The page has two tabs: Pending (requests awaiting decision) and History (past decisions).
The page is organization-aware — when an org is selected via the context switcher, only agents from that org show approval requests.
| Level | Badge | Examples |
|---|---|---|
| Low | low | Reading data, searching, internal queries |
| Medium | medium | Sending messages, modifying files, updating records |
| High | high | Sending external emails, executing code, API calls to third parties |
| Critical | critical | Financial transactions, data deletion, device control |
| Field | Description |
|---|---|
type | The action type (e.g., "send-email", "execute-code", "delete-record") |
description | Human-readable explanation of what the agent wants to do |
context | Additional context data (JSON) about the action parameters |
agentId | Which agent initiated the request |
riskLevel | Assessed risk level of the action |
The Pending tab shows all requests awaiting a decision. Each request is rendered as a card with:
When no pending requests exist, an empty state is displayed: "No pending approvals — When agents need approval for sensitive actions, they'll appear here."
The History tab shows the last 50 resolved requests in a table format:
| Column | Description |
|---|---|
| Type | The action type that was requested |
| Agent | Agent badge with name/avatar |
| Decision | Green "approved" or red "rejected" badge |
| By | Who made the decision (e.g., "admin") |
| Date | When the decision was made |
Approval policies are configured per-agent during creation (Step 4: Permissions in the Create Agent Wizard) or in the agent detail view. Key settings:
// Agent permission configuration
{
"requireApproval": {
"enabled": true,
"forRiskLevels": ["high", "critical"],
"forSideEffects": ["sends-email", "sends-message", "financial"],
"approvers": [],
"timeoutMinutes": 60
}
}
| Setting | Description |
|---|---|
enabled | Master toggle for approval requirements |
forRiskLevels | Which risk levels require approval (array of: low, medium, high, critical) |
forSideEffects | Which side effect types require approval (sends-email, sends-message, sends-sms, posts-social, runs-code, financial) |
timeoutMinutes | How long the agent waits for approval before timing out (default: 60) |
| Endpoint | Method | Description |
|---|---|---|
/api/engine/approvals/pending | GET | List all pending approval requests |
/api/engine/approvals/history | GET | List resolved requests (supports ?limit=) |
/api/engine/approvals/{id}/decide | POST | Approve or reject a request |
POST /api/engine/approvals/{requestId}/decide
Content-Type: application/json
{
"decision": "approved", // or "rejected"
"decidedBy": "admin",
"reason": "Optional explanation for the decision"
}
Check the Pending tab — there may be an unresolved request. If the request has timed out, the agent should have received a rejection notification. Restart the agent if it remains stuck.
Check the agent's permission configuration: (1) Is requireApproval.enabled set to true? (2) Does the action's risk level or side effect type match the configured thresholds? Actions below the configured levels won't trigger approval requests.
Lower the approval sensitivity. Change forRiskLevels from ["medium", "high", "critical"] to ["high", "critical"] to reduce volume while maintaining safety for high-risk actions.
The reject action uses the system's showConfirm utility. Ensure popup blockers or browser extensions aren't interfering with modal dialogs.