How RequireApprovalPolicy Controls Tool Execution in aisuite: A Complete Guide
RequireApprovalPolicy is a built-in safety mechanism that intercepts every LLM tool invocation in aisuite and delegates the execution decision to a custom callback function, enabling human-in-the-loop approval or automated policy enforcement before any Python function runs.
When building AI agents with the andrewyng/aisuite framework, controlling which tools the LLM can execute is critical for security and compliance. The RequireApprovalPolicy class, defined in aisuite/agents/policies.py, provides a programmable gatekeeper that evaluates every tool call against custom business logic before the underlying Python callable is invoked.
What is RequireApprovalPolicy?
RequireApprovalPolicy is one of the built-in tool policies available in aisuite's agent framework. It is designed to execute a user-defined callback for every tool invocation, allowing developers to implement approval workflows, audit logging, or automated risk assessment before the actual tool function executes.
The policy is exposed at the top-level aisuite namespace and is configured when initializing an Agent instance through the tool_policy parameter.
The ToolPolicyContext Object
When a tool is called during agent execution, aisuite constructs a ToolPolicyContext containing the complete invocation details. According to the implementation in aisuite/agents/policies.py, this context includes:
tool_name: The string identifier of the tool being invokedarguments: The JSON-decoded arguments supplied by the modeltool_metadata: OptionalToolMetadataattached to the callable via the@ai.tooldecoratoragent: TheAgentinstance that requested the tool executionclient: TheClientused for the LLM request
This context object is passed as the single argument to your approval callback, giving you full visibility into what the model is attempting to do.
Implementing the Approval Callback
The core of RequireApprovalPolicy is the callback function you provide during instantiation. As implemented in lines 43-61 of aisuite/agents/policies.py, this callback must return one of two types:
- Boolean:
Trueallows execution,Falsedenies it - ToolPolicyDecision: An object specifying both
allowed(bool) andreason(str)
If you return a boolean, aisuite automatically wraps it in a ToolPolicyDecision with the reason set to "approved" or "denied". Returning any other type raises a TypeError.
The callback signature should accept a ToolPolicyContext and return the decision:
def approval_callback(ctx: ai.ToolPolicyContext) -> ai.ToolPolicyDecision:
if ctx.tool_metadata.risk_level == "high":
return ai.ToolPolicyDecision(
allowed=False,
reason="high-risk operations require manual review"
)
return True # Equivalent to ToolPolicyDecision(allowed=True, reason="approved")
Execution Flow and Decision Handling
Once the callback returns a decision, aisuite processes the result as follows:
- If
allowed=False, the tool's Python function is not executed. The denial reason is returned to the agent as the tool result. - If
allowed=True, the tool executes normally with the provided arguments. - The final
ToolPolicyDecisionis stored in the execution trace atstep.data["allowed"]andstep.data["reason"], providing full observability for debugging and audit trails.
This mechanism is tested in tests/agents/test_tool_metadata_policy.py (lines 15-30), where callbacks record invocation details and explicitly deny high-risk operations to verify the policy enforcement chain.
Complete Implementation Example
The following example demonstrates configuring an agent with RequireApprovalPolicy to gate database deletion operations based on risk metadata:
import aisuite as ai
# 1. Define a tool with metadata indicating it requires approval
@ai.tool
def delete_user(user_id: str) -> str:
"""Delete a user from the database."""
return f"User {user_id} deleted"
# Attach metadata to mark as high-risk
delete_user = ai.tool(
delete_user,
metadata=ai.ToolMetadata(
category="admin",
risk_level="high",
requires_approval=True,
),
)
# 2. Define the approval callback with business logic
def approval_callback(ctx: ai.ToolPolicyContext) -> ai.ToolPolicyDecision:
# Automatically deny high-risk tools in this example
if ctx.tool_metadata and ctx.tool_metadata.risk_level == "high":
return ai.ToolPolicyDecision(
allowed=False,
reason="high-risk operation blocked by policy"
)
return True
# 3. Create agent with the RequireApprovalPolicy
agent = ai.Agent(
name="assistant",
model="openai:gpt-4o",
tools=[delete_user],
tool_policy=ai.RequireApprovalPolicy(approval_callback),
)
# 4. Execute - policy is consulted before delete_user runs
result = ai.Runner.run_sync(agent, "Remove user 12345")
print(result.final_output) # "high-risk operation blocked by policy"
print(result.steps[-1].data) # {'allowed': False, 'reason': '...', ...}
In this implementation, the approval_callback receives the full ToolPolicyContext including the ToolMetadata, allowing risk-based decisions. The execution trace preserves the denial reason for observability.
Summary
- RequireApprovalPolicy acts as a programmable gatekeeper for all tool executions in aisuite, defined in
aisuite/agents/policies.py - The policy receives a
ToolPolicyContextcontaining complete invocation details includingtool_name,arguments,tool_metadata,agent, andclient - Approval callbacks return boolean values or
ToolPolicyDecisionobjects; invalid return types raiseTypeError - When denied, the tool function is skipped entirely and the reason is recorded in
step.data["reason"] - The policy integrates with
ToolMetadatadefined inaisuite/utils/tools.pyto enable risk-based access control
Frequently Asked Questions
What happens when the approval callback returns False?
When the callback returns False or a ToolPolicyDecision with allowed=False, aisuite skips the Python function execution entirely. The denial reason is stored in the step's trace data at step.data["allowed"] and step.data["reason"], then returned to the agent as the tool result instead of the actual function output.
Can I access custom tool metadata in the approval callback?
Yes. The ToolPolicyContext passed to your callback includes a tool_metadata field containing the ToolMetadata object attached to the callable via the @ai.tool decorator. This metadata is defined in aisuite/utils/tools.py and can include custom fields like risk_level or category to implement granular policies.
What return types are valid for the approval callback?
The callback must return either a boolean (True to allow, False to deny) or a ToolPolicyDecision object specifying both allowed and reason fields. According to the source in aisuite/agents/policies.py, any other return type raises a TypeError. Boolean returns are automatically wrapped in ToolPolicyDecision with default reasons.
How do I configure an agent to use RequireApprovalPolicy?
Instantiate RequireApprovalPolicy with your callback function and pass it to the tool_policy parameter when creating an Agent. The class is exported at the top-level aisuite namespace, making it accessible as ai.RequireApprovalPolicy. You can combine it with tools that have ToolMetadata attached to create sophisticated approval workflows.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →