Skip to main content

Approval Module

The Approval module provides a minimal human-in-the-loop approval system for dangerous tool operations. It extends the existing callback system to require human approval before executing high-risk tools.

Import

from praisonaiagents import require_approval, set_approval_callback
from praisonaiagents.approval import ApprovalDecision, RiskLevel

Quick Example

from praisonaiagents import require_approval

@require_approval(risk_level="high")
def delete_file(path: str):
    """Delete a file - requires human approval."""
    import os
    os.remove(path)
    return f"Deleted {path}"

Risk Levels

LevelDescription
criticalIrreversible actions (delete database, format disk)
highPotentially dangerous (delete files, send emails)
mediumModerate risk (modify configs, write files)
lowLow risk but worth noting

Decorators

@require_approval(risk_level)

Marks a tool as requiring human approval before execution. Parameters:
  • risk_level (str): One of “critical”, “high”, “medium”, “low”
@require_approval(risk_level="critical")
def drop_database(db_name: str):
    """Drop a database - requires critical approval."""
    ...

Functions

set_approval_callback(callback_fn)

Set a custom approval callback function. Parameters:
  • callback_fn: Function that accepts (function_name, arguments, risk_level) and returns ApprovalDecision
def my_approval_handler(func_name, args, risk_level):
    if risk_level == "critical":
        # Always require manual approval for critical
        response = input(f"Approve {func_name}? (y/n): ")
        return ApprovalDecision(approved=response.lower() == 'y')
    return ApprovalDecision(approved=True)

set_approval_callback(my_approval_handler)

get_approval_callback()

Get the current approval callback function. Returns: The current callback or None

mark_approved(tool_name)

Mark a tool as approved in the current context.
mark_approved("delete_file")

is_already_approved(tool_name)

Check if a tool is already approved in the current context. Returns: bool

clear_approval_context()

Clear the approval context (reset all approvals).

ApprovalDecision Class

class ApprovalDecision:
    def __init__(
        self,
        approved: bool,
        modified_args: Optional[Dict[str, Any]] = None,
        reason: str = ""
    ):
        self.approved = approved
        self.modified_args = modified_args or {}
        self.reason = reason

Example: Custom Approval UI

from praisonaiagents import set_approval_callback, require_approval
from praisonaiagents.approval import ApprovalDecision
from rich.console import Console
from rich.prompt import Confirm

console = Console()

def rich_approval_handler(func_name, args, risk_level):
    """Custom approval handler with Rich UI."""
    console.print(f"\n[bold yellow]⚠️ Approval Required[/bold yellow]")
    console.print(f"Function: [cyan]{func_name}[/cyan]")
    console.print(f"Risk Level: [red]{risk_level}[/red]")
    console.print(f"Arguments: {args}")
    
    approved = Confirm.ask("Do you approve this action?")
    return ApprovalDecision(
        approved=approved,
        reason="User approved" if approved else "User denied"
    )

set_approval_callback(rich_approval_handler)

@require_approval(risk_level="high")
def send_email(to: str, subject: str, body: str):
    """Send an email - requires approval."""
    # Email sending logic
    return f"Email sent to {to}"

Example: Automatic Approval for Low Risk

from praisonaiagents import set_approval_callback
from praisonaiagents.approval import ApprovalDecision

def smart_approval(func_name, args, risk_level):
    """Auto-approve low risk, prompt for others."""
    if risk_level == "low":
        return ApprovalDecision(approved=True, reason="Auto-approved (low risk)")
    
    if risk_level == "medium":
        print(f"Medium risk: {func_name}")
        return ApprovalDecision(approved=True, reason="Auto-approved (medium)")
    
    # High and critical require manual approval
    response = input(f"Approve {func_name} ({risk_level})? (y/n): ")
    return ApprovalDecision(approved=response.lower() == 'y')

set_approval_callback(smart_approval)

Global Registries

RegistryTypeDescription
APPROVAL_REQUIRED_TOOLSSet[str]Set of tool names requiring approval
TOOL_RISK_LEVELSDict[str, str]Mapping of tool names to risk levels