Approval External Execution
Approval + external execution HITL: @approval + @tool(external_execution=True).
1"""2Approval External Execution3=============================45Approval + external execution HITL: @approval + @tool(external_execution=True).6"""78import os9import time1011from 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@approval21@tool(external_execution=True)22def deploy_to_production(service_name: str, version: str) -> str:23 """Deploy a service to production.2425 Args:26 service_name (str): The name of the service to deploy.27 version (str): The version to deploy.2829 Returns:30 str: Confirmation of the deployment.31 """32 return f"Deployed {service_name} v{version}"333435# ---------------------------------------------------------------------------36# Create Agent37# ---------------------------------------------------------------------------38db = SqliteDb(39 db_file=DB_FILE, session_table="agent_sessions", approvals_table="approvals"40)41agent = Agent(42 model=OpenAIResponses(id="gpt-5-mini"),43 tools=[deploy_to_production],44 markdown=True,45 db=db,46)4748# ---------------------------------------------------------------------------49# Run Agent50# ---------------------------------------------------------------------------51if __name__ == "__main__":52 # Clean up from previous runs53 if os.path.exists(DB_FILE):54 os.remove(DB_FILE)55 os.makedirs("tmp", exist_ok=True)5657 # Re-create after cleanup58 db = SqliteDb(59 db_file=DB_FILE, session_table="agent_sessions", approvals_table="approvals"60 )61 agent = Agent(62 model=OpenAIResponses(id="gpt-5-mini"),63 tools=[deploy_to_production],64 markdown=True,65 db=db,66 )6768 # Step 1: Run - agent will pause69 print("--- Step 1: Running agent (expects pause) ---")70 run_response = agent.run("Deploy the auth-service version 2.1.0 to production.")71 print(f"Run status: {run_response.status}")72 assert run_response.is_paused, f"Expected paused, got {run_response.status}"73 print("Agent paused as expected.")7475 # Step 2: Check that an approval record was created in the DB76 print("\n--- Step 2: Checking approval record in DB ---")77 approvals_list, total = db.get_approvals(status="pending", approval_type="required")78 print(f"Pending approvals: {total}")79 assert total >= 1, f"Expected at least 1 pending approval, got {total}"80 approval_record = approvals_list[0]81 print(f" Approval ID: {approval_record['id']}")82 print(f" Run ID: {approval_record['run_id']}")83 print(f" Status: {approval_record['status']}")84 print(f" Source: {approval_record['source_type']}")85 print(f" Context: {approval_record.get('context')}")8687 # Step 3: Set external execution result and continue88 print("\n--- Step 3: Setting external result and continuing ---")89 for requirement in run_response.active_requirements:90 if requirement.needs_external_execution:91 print(f" Setting result for tool: {requirement.tool_execution.tool_name}")92 requirement.set_external_execution_result("Deployed auth-service v2.1.0")9394 run_response = agent.continue_run(95 run_id=run_response.run_id,96 requirements=run_response.requirements,97 )98 print(f"Run status after continue: {run_response.status}")99 assert not run_response.is_paused, "Expected run to complete, but it's still paused"100101 # Step 4: Resolve the approval record in the DB102 print("\n--- Step 4: Resolving approval in DB ---")103 resolved = db.update_approval(104 approval_record["id"],105 expected_status="pending",106 status="approved",107 resolved_by="test_user",108 resolved_at=int(time.time()),109 )110 assert resolved is not None, "Approval resolution failed (possible race condition)"111 print(f" Resolved status: {resolved['status']}")112 print(f" Resolved by: {resolved['resolved_by']}")113114 # Step 5: Verify no more pending approvals115 print("\n--- Step 5: Verifying no pending approvals ---")116 count = db.get_pending_approval_count()117 print(f"Remaining pending approvals: {count}")118 assert count == 0, f"Expected 0 pending approvals, got {count}"119120 print("\n--- All checks passed! ---")121 print(f"\nAgent output (truncated): {str(run_response.content)[:200]}...")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 approval_external_execution.py