ApprovalCallback gates a plan before it runs, and its async approve_fn now works even when called from inside a running event loop — such as a FastAPI async route.
Async approval callbacks now work from a running event loop. As of MervinPraison/PraisonAI#4533,
ApprovalCallback(approve_fn=<async fn>) can be reached from inside a running loop — a FastAPI async route, a Textual app, a Jupyter cell — without crashing with RuntimeError: Cannot run the event loop while another loop is running. The callback routes through the package’s shared safe bridge and preserves the caller’s loop.Quick Start
1
Attach an async approval function
Pass an async
approve_fn to ApprovalCallback. It returns True to approve, False to reject.2
Works inside a running loop
The synchronous
__call__ can now be reached from inside a running loop without crashing — the async approve_fn runs on the caller’s loop.How It Works
The sync__call__ detects an async approve_fn and forwards it through the package’s shared safe bridge run_coroutine_from_any_context, which detects a running loop and schedules the coroutine on it instead of spinning up a fresh loop.
FastAPI async route
Embed PraisonAI in a FastAPI async endpoint and the plan-approval prompt no longer raisesRuntimeError when the plan is presented.
What the user experiences
- A user hits a FastAPI endpoint that runs
await agent.astart("..."). - The planning phase produces a plan;
ApprovalCallbackis invoked. - The user-supplied async
approve_fnruns on the caller’s loop (no new-loop crash). - The plan proceeds if approved, or halts if the callback returns
False.
Common Patterns
- Async approval
- Sync approval
- Auto-approve
Route approval through any async check — a database lookup, an HTTP call, a message-queue round-trip.
Best Practices
Prefer an async approve_fn for I/O-bound checks
Prefer an async approve_fn for I/O-bound checks
When your approval decision calls out to Slack, a database, or an HTTP endpoint, use an async
approve_fn so it runs on the caller’s loop without blocking — safe from a FastAPI route as of PR #4533.Return a plain bool from approve_fn
Return a plain bool from approve_fn
approve_fn must return True to approve or False to reject. Keep the decision logic inside the function and let ApprovalCallback handle the plan’s approve() transition.Use auto_approve only for unattended runs
Use auto_approve only for unattended runs
ApprovalCallback(auto_approve=True) skips all checks — reserve it for trusted CI or scripted runs where no human is available to review.Related
Planning Mode
Configure planning with PlanningConfig
Planning Concepts
Core planning architecture and the ApprovalCallback denial snippet

