MATIH Platform is in active MVP development. Documentation reflects current implementation status.
12. AI Service
Agent System
Approval Workflows (HITL)

Approval Workflows (HITL)

Production - Human-in-the-loop approval for sensitive agent actions

The Human-in-the-Loop (HITL) approval system requires human review and approval before agents execute sensitive actions. This includes database modifications, external API calls, high-cost LLM operations, and any action flagged by guardrails.


12.2.8.1Approval Architecture

The approval system consists of three components:

ComponentFilePurpose
ApprovalHandlersrc/agents/hitl.pyEvaluates whether a tool call requires approval
ApprovalWorkflowsrc/agents/hitl.pyManages the lifecycle of approval requests
PostgresApprovalStoresrc/agents/approval/postgres_approval_store.pyPersists approval requests to PostgreSQL

Approval Flow

Agent wants to execute tool
    |
    v
ApprovalHandler.check_and_request_approval()
    |
    +-- Is tool in approval-required list? --No--> Execute directly
    |
    Yes
    |
    v
Create ApprovalRequest
    |
    v
Notify reviewer(s) via callback URL
    |
    v
Agent enters WAITING_APPROVAL status
    |
    v
Reviewer approves/rejects via API
    |
    +-- Approved --> Execute tool
    |
    +-- Rejected --> Return rejection to agent

12.2.8.2ApprovalRequest Model

@dataclass
class ApprovalRequest:
    id: str
    session_id: str
    tenant_id: str
    agent_id: str
    tool_call: ToolCall
    status: ApprovalStatus  # PENDING, APPROVED, REJECTED, EXPIRED
    created_at: datetime
    reviewer_id: str | None = None
    reviewed_at: datetime | None = None
    notes: str | None = None
    expires_at: datetime | None = None
 
class ApprovalStatus(str, Enum):
    PENDING = "pending"
    APPROVED = "approved"
    REJECTED = "rejected"
    EXPIRED = "expired"

12.2.8.3API Endpoints

# List pending approvals
curl http://localhost:8000/api/v1/agents/approvals/pending?tenant_id=acme-corp
 
# Approve a request
curl -X POST http://localhost:8000/api/v1/agents/approvals/{request_id}/approve \
  -H "Content-Type: application/json" \
  -H "X-Tenant-ID: acme-corp" \
  -d '{
    "reviewer_id": "user-admin-123",
    "notes": "Approved - query is read-only and within scope"
  }'
 
# Reject a request
curl -X POST http://localhost:8000/api/v1/agents/approvals/{request_id}/reject \
  -H "Content-Type: application/json" \
  -H "X-Tenant-ID: acme-corp" \
  -d '{
    "reviewer_id": "user-admin-123",
    "notes": "Rejected - query accesses restricted schema"
  }'

Approval Response

{
  "id": "approval-uuid-789",
  "status": "approved",
  "tool_call": {
    "name": "execute_sql",
    "arguments": {
      "sql": "SELECT customer_name, email FROM customers WHERE region = 'EMEA'"
    }
  },
  "reviewer_id": "user-admin-123",
  "notes": "Approved - query is read-only and within scope",
  "reviewed_at": "2025-01-15T10:35:00Z"
}