Audit Approval Confirmation
Audit approval with confirmation: @approval(type="audit") + @tool(requires_confirmation=True).
Audit approval with confirmation: @approval(type="audit") + @tool(requires_confirmation=True). Demonstrates both approval and rejection paths.
1"""2Audit Approval Confirmation3=============================45Audit approval with confirmation: @approval(type="audit") + @tool(requires_confirmation=True).6Demonstrates both approval and rejection paths.7"""89import os1011from kern.agent import Agent12from kern.approval import approval13from kern.db.sqlite import SqliteDb14from kern.models.openai import OpenAIResponses15from kern.tools import tool1617DB_FILE = "tmp/approvals_test.db"181920@approval(type="audit")21@tool(requires_confirmation=True)22def delete_user_data(user_id: str) -> str:23 """Permanently delete all data for a user.2425 Args:26 user_id (str): The user ID whose data should be deleted.2728 Returns:29 str: Confirmation of the deletion.30 """31 return f"Deleted data for user {user_id}"323334# ---------------------------------------------------------------------------35# Create Agent36# ---------------------------------------------------------------------------37db = SqliteDb(38 db_file=DB_FILE, session_table="agent_sessions", approvals_table="approvals"39)40agent = Agent(41 model=OpenAIResponses(id="gpt-5-mini"),42 tools=[delete_user_data],43 markdown=True,44 db=db,45)4647# ---------------------------------------------------------------------------48# Run Agent49# ---------------------------------------------------------------------------50if __name__ == "__main__":51 # Clean up from previous runs52 if os.path.exists(DB_FILE):53 os.remove(DB_FILE)54 os.makedirs("tmp", exist_ok=True)5556 # Re-create after cleanup57 db = SqliteDb(58 db_file=DB_FILE, session_table="agent_sessions", approvals_table="approvals"59 )60 agent = Agent(61 model=OpenAIResponses(id="gpt-5-mini"),62 tools=[delete_user_data],63 markdown=True,64 db=db,65 )6667 # ========== Part 1: Approval path ==========6869 # Step 1: Run - agent will pause because the tool requires confirmation70 print("--- Step 1: Running agent for approval path (expects pause) ---")71 run_response = agent.run("Delete all data for user U-100.")72 print(f"Run status: {run_response.status}")73 assert run_response.is_paused, f"Expected paused, got {run_response.status}"74 print("Agent paused as expected.")7576 # Step 2: Confirm and continue77 print("\n--- Step 2: Confirming and continuing ---")78 for requirement in run_response.active_requirements:79 if requirement.needs_confirmation:80 print(f" Confirming tool: {requirement.tool_execution.tool_name}")81 requirement.confirm()8283 run_response = agent.continue_run(84 run_id=run_response.run_id,85 requirements=run_response.requirements,86 )87 print(f"Run status after continue: {run_response.status}")88 assert not run_response.is_paused, "Expected run to complete, but it's still paused"8990 # Step 3: Verify logged approval record was created91 print("\n--- Step 3: Verifying logged approval record (approved) ---")92 approvals_list, total = db.get_approvals(approval_type="audit")93 print(f"Logged approvals: {total}")94 assert total >= 1, f"Expected at least 1 logged approval, got {total}"95 approval_record = approvals_list[0]96 print(f" Approval ID: {approval_record['id']}")97 print(f" Status: {approval_record['status']}")98 print(f" Type: {approval_record['approval_type']}")99 assert approval_record["status"] == "approved", (100 f"Expected 'approved', got {approval_record['status']}"101 )102 assert approval_record["approval_type"] == "audit", (103 f"Expected 'audit', got {approval_record['approval_type']}"104 )105 print("Logged approval record verified (approved).")106107 # ========== Part 2: Rejection path ==========108109 # Step 4: Run again - agent will pause for a new confirmation110 print("\n--- Step 4: Running agent for rejection path (expects pause) ---")111 run_response = agent.run("Delete all data for user U-200.")112 print(f"Run status: {run_response.status}")113 assert run_response.is_paused, f"Expected paused, got {run_response.status}"114 print("Agent paused as expected.")115116 # Step 5: Reject and continue117 print("\n--- Step 5: Rejecting and continuing ---")118 for requirement in run_response.active_requirements:119 if requirement.needs_confirmation:120 print(f" Rejecting tool: {requirement.tool_execution.tool_name}")121 requirement.reject("Rejected by admin: not authorized")122123 run_response = agent.continue_run(124 run_id=run_response.run_id,125 requirements=run_response.requirements,126 )127 print(f"Run status after continue: {run_response.status}")128 assert not run_response.is_paused, "Expected run to complete, but it's still paused"129130 # Step 6: Verify logged approval record for rejection131 print("\n--- Step 6: Verifying logged approval record (rejected) ---")132 approvals_list, total = db.get_approvals(approval_type="audit")133 print(f"Total logged approvals: {total}")134 assert total >= 2, f"Expected at least 2 logged approvals, got {total}"135 # Find the rejected one (most recent)136 rejected = [a for a in approvals_list if a["status"] == "rejected"]137 assert len(rejected) >= 1, (138 f"Expected at least 1 rejected approval, got {len(rejected)}"139 )140 rej = rejected[0]141 print(f" Approval ID: {rej['id']}")142 print(f" Status: {rej['status']}")143 print(f" Type: {rej['approval_type']}")144 assert rej["approval_type"] == "audit", (145 f"Expected 'audit', got {rej['approval_type']}"146 )147 print("Logged approval record verified (rejected).")148149 # Final check: total logged approvals150 print("\n--- Final: Checking total logged approvals ---")151 all_logged, all_total = db.get_approvals(approval_type="audit")152 print(f"Total logged approvals: {all_total}")153 assert all_total == 2, f"Expected 2 total logged approvals, got {all_total}"154155 print("\n--- All checks passed! ---")Run the Example
1# Clone and setup repo2git clone https://github.com/kern-ai/kern.git3cd kern/cookbook/02_agents/11_approvals45# Create and activate virtual environment6./scripts/demo_setup.sh7source .venvs/demo/bin/activate89python audit_approval_confirmation.py