What This Demonstrates
- Attribute-based rules: each rule applies only when the request’s jurisdiction matches.
- Two ways to author the same policy:
- One control per attribute value, here one per country.
- One composite control with a branch for each value.
- Baseline controls that apply to every country, next to the country controls.
- Two ways to send the jurisdiction with each check:
- In
step.context, withevaluate_controls()or the HTTP API. - As a function argument, with the
@control()decorator.
- In
Quick Start
Prerequisites
- Start the Agent Control server:
make server-runfrom the repo root.
Run the Demo
Send the Jurisdiction
The caller must send the jurisdiction with each check. Use an ISO 3166-1 alpha-2 code, such asDE or US.
If the country code arrives in a request header, such as x-ai-jurisdiction: DE, the caller copies it into step.context.jurisdiction. Agent Control does not map request headers into the step.
In step.context (recommended)
context holds request metadata, separate from the data that the controls check. Controls select the value with the path context.jurisdiction.
POST /api/v1/evaluation:
As a decorator argument
@control() builds the step from the function’s arguments, and it cannot set step.context. To use the decorator, pass the jurisdiction as a function argument and select it with input.jurisdiction.
This works only for
tool steps and custom step types, where input is the dict of all arguments. For an llm step, input is a single string, so the path input.jurisdiction does not resolve.Author the Controls
Each country rule is anand of two conditions:
- The jurisdiction is in a list, checked with the
listevaluator. - The rule matches, here a
regexon the output.
Option 1: One control per country
US with a Social Security number pattern.
Option 2: One composite control
Put each country’sand branch inside one or:
jurisdiction_in() and output_matches() are small helpers in the example scripts. They return the leaf conditions shown in Option 1.
Which option to use
Baseline and Country Controls
Most policies combine two kinds of rules:- Baseline controls apply to every country. They have no jurisdiction condition.
- Country controls apply only to some countries. They include the jurisdiction condition.
Agent Control evaluates the controls in parallel and stops the remaining evaluations after the first
deny match. If a baseline control and a country control both match, result.matches usually names only one of them.tags, for example ["baseline"] and ["country", "DE"].
Scenarios
Both authoring options give the same decisions. The example runs them side by side, with the baseline control on both:Missing Jurisdiction
If you need a strict default, add a control that matches when the jurisdiction is missing or not covered:- The
notlist must name every country that has a rule. - The
ormust repeat every country rule.
FR control but do not add its rule to the or, a request with no jurisdiction that matches the FR rule is allowed.
Files
attribute_controls_context.py- Sends the jurisdiction instep.contextwithevaluate_controls()attribute_controls_decorator.py- Sends the jurisdiction as a@control()function argument
Source Code
View the complete example with all scripts and setup instructions:Attribute-Based Controls Example