Writing a rule of your own
Lesson 6 found that the built-in argument checks only know a handful of tool names. Lesson 7 found the second path. This lesson uses that path to write the rule the built-ins do not have: no refund over a hundred pounds.
A custom rule is a small object with a function inside it. The function gets the request and returns True to allow.
from agent_control_plane.agent_kernel import PolicyRule, ActionType
def small_refunds_only(request):
return request.parameters.get("amount", 0) <= 100
rule = PolicyRule(rule_id="refund-cap", name="small_refunds_only",
description="Refunds over 100 need a human",
action_types=[ActionType.API_CALL], validator=small_refunds_only)
print(rule.name, rule.priority)action_types is what decides whether the rule is consulted at all. A rule listing API_CALL never sees a FILE_READ request, so a rule that seems not to run is usually a rule watching the wrong action type.
Registering it
from agent_control_plane import PolicyEngine
policy = PolicyEngine()
policy.add_custom_rule(rule)
for amount in [40, 4000]:
print(amount, policy.validate_request(make_request(amount)))The reason names the rule, which is what makes a refusal readable months later when there are thirty rules and somebody asks why a refund did not go through.
The mistake this lesson exists to prevent
Register the same rule, then ask the gate from lesson 4 instead.
from agent_control_plane import AgentKernel
policy.add_constraint("support", ["issue_refund"])
kernel = AgentKernel(policy_engine=policy)
print(kernel.intercept_tool_execution("support", "issue_refund", {"amount": 4000}))A four thousand pound refund, allowed, by an engine holding a rule that forbids exactly that. The rule is real and registered; it simply is not on this path.
validate_request. Lesson 30 builds a gate that asks both paths so a rule like this cannot be bypassed by the caller choosing the wrong door.Rules are sorted by priority when they are added, highest first, and the first one that returns False ends the check.
- Add a second rule with a higher priority that allows everything, and see whether the cap still fires.
- Change
action_typesto[ActionType.FILE_READ]and watch the rule stop running. - Make the validator raise an exception and find out whether the engine fails open or closed.
Slow is fine. Stopping is the only problem.