A policy in a file
Everything in part 2 was policy written in Python. That means a rule change is a code change, a deployment and a review by somebody who reads Python. This part moves the rules into files.
The declarative layer lives in agent_os.policies, in the same core distribution you already installed. A policy is a YAML document with a name and a list of rules.
version: "1.0"
name: refunds
description: What the support agent may do with money
rules:
- name: block_big_refunds
condition:
field: amount
operator: gt
value: 100
action: deny
message: Refunds over 100 need a human
defaults:
action: allowOne rule. It has a condition, an action and a message, and the document has a default for when nothing matches. Save it as refunds.yaml.
Loading it
from agent_os.policies.schema import PolicyDocument
policy = PolicyDocument.from_yaml("refunds.yaml")
print(policy.name, "|", len(policy.rules), "rule")
print(policy.rules[0].name, policy.rules[0].condition.operator.value,
policy.rules[0].condition.value)The document is validated as it loads. Fields become typed objects, so operator comes back as an enum rather than the string you wrote.
Asking it about a call
An evaluator holds one or more documents and answers questions about a context. The context is a flat dictionary describing the call.
from agent_os.policies.evaluator import PolicyEvaluator
evaluator = PolicyEvaluator(policies=[policy])
for amount in [40, 4000]:
decision = evaluator.evaluate({"amount": amount})
print(amount, decision.allowed, decision.matched_rule, "|", decision.reason)The decision carries more than a yes or no. It names the rule that fired and repeats the message from the file, so a refusal explains itself in words a human wrote.
The forty pound refund matched nothing, so the document's default applied, and the reason says exactly that rather than pretending a rule allowed it.
Two engines, one library
This is a different engine from part 2. It does not know about roles, it does not share the allow-list, and nothing connects the two automatically. Lesson 30 wires this evaluator into the gate from lesson 4 by hand, which is the supported way to use both.
- Change
value: 100tovalue: 10and run the same script. - Delete the
messageline and see what the reason says instead. - Add a second rule blocking refunds on order
B22and check both still fire.
Every expert started right here.