Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 35 additions & 5 deletions components/models.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,14 @@ step = Step(
### Control Models

```python
from agent_control_models import ControlDefinition, ControlScope, ControlAction
from agent_control_models import (
ConditionNode,
ControlAction,
ControlDefinition,
ControlScope,
ControlSelector,
EvaluatorSpec,
)

control = ControlDefinition(
description="Block toxic user messages",
Expand All @@ -62,8 +69,10 @@ control = ControlDefinition(
step_types=["llm"],
stages=["pre"],
),
selector={"path": "input"},
evaluator={"name": "regex", "config": {"pattern": "toxic"}},
condition=ConditionNode(
selector=ControlSelector(path="input"),
evaluator=EvaluatorSpec(name="regex", config={"pattern": "toxic"}),
),
action=ControlAction(decision="deny"),
)
```
Expand Down Expand Up @@ -135,11 +144,32 @@ Complete control specification.
- `enabled` (bool): Whether control is active
- `execution` (str): Execution mode (`server` or `sdk`)
- `scope` (ControlScope): When to apply the control
- `selector` (ControlSelector): What data to evaluate
- `evaluator` (EvaluatorSpec): How to evaluate
- `condition` (ConditionNode): Recursive condition tree; leaf nodes contain `selector` + `evaluator`
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should still explain selector here somewhere, no?

- `action` (ControlAction): What to do on match
- `tags` (List[str]): Tags for categorization

### ConditionNode

Recursive condition tree used by `ControlDefinition.condition`.

- Leaf nodes contain both `selector` and `evaluator`
- Composite nodes contain exactly one of `and`, `or`, or `not`
- Maximum nesting depth is 6

### ControlSelector

Selector used inside a leaf condition.

- `path` (Optional[str]): Dot-path for the value to evaluate; defaults to `"*"`
- Common paths: `input`, `output`, `input.query`, `context.user_id`, `name`, `*`

### EvaluatorSpec

Evaluator used inside a leaf condition.

- `name` (str): Evaluator name, such as `regex`, `list`, `sql`, or `galileo.luna2`
- `config` (Dict[str, Any]): Evaluator-specific configuration payload

### EvaluationRequest

Request for evaluating controls.
Expand Down
140 changes: 104 additions & 36 deletions concepts/controls.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ description: Understand how controls work and how to define them.

A Control is a protection rule that evaluates agent interactions (inputs/outputs) and takes action based on configured criteria. It defines when to check, what to check, how to evaluate it, and what to do with the results.

Control formula: **Control = Scope (When) + Selector (What) + Evaluator (How) + Action (Decision)**
Control formula: **Control = Scope (When) + Condition (What + How) + Action (Decision)**

## 1. Scope (When to Check)

Expand Down Expand Up @@ -75,9 +75,66 @@ Fields:

---

## 2. Selector (What to Check)
## 2. Condition (What and How to Check)

The **Selector** specifies which portion of the step's data to extract and pass to the evaluator for analysis. It uses a path specification to navigate the step object.
The **Condition** is a recursive boolean tree. Leaf conditions pair a `selector` with an `evaluator`, and composite conditions can combine child conditions with `and`, `or`, and `not`.

### Example 1: Leaf condition that checks tool output for PII

```json
{
"condition": {
"selector": {
"path": "output"
},
"evaluator": {
"name": "regex",
"config": {
"pattern": "\\b\\d{3}-\\d{2}-\\d{4}\\b"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should be r "\b\d{3}-\d{2}-\d{4}\b"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is pure JSON so these need to be escaped

}
}
}
}
```

### Example 2: Composite condition with `and` and `not`

```json
{
"condition": {
"and": [
{
"selector": {
"path": "context.risk_level"
},
"evaluator": {
"name": "list",
"config": {
"values": ["high", "critical"]
}
}
},
{
"not": {
"selector": {
"path": "context.user_role"
},
"evaluator": {
"name": "list",
"config": {
"values": ["admin", "security"]
}
}
}
}
]
}
}
```

### 2.1 Selector (What to Check Inside a Leaf)

Inside a leaf condition, the **Selector** specifies which portion of the step's data to extract and pass to the evaluator for analysis. It uses a path specification to navigate the step object.

Field:

Expand Down Expand Up @@ -141,9 +198,9 @@ Common Paths:

---

## 3. Evaluator (How to Check)
### 2.2 Evaluator (How to Check Inside a Leaf)

The **Evaluator** receives the data extracted by the selector and evaluates it against configured rules, returning whether the data matches specified criteria.
Inside a leaf condition, the **Evaluator** receives the data extracted by the selector and evaluates it against configured rules, returning whether the data matches specified criteria.

Components:

Expand Down Expand Up @@ -217,7 +274,7 @@ Agent Control supports custom evaluators for domain-specific requirements. See [

---

## 4. Action (What to Do)
## 3. Action (What to Do)

The **Action** defines what happens when the evaluator matches/detects an issue.

Expand Down Expand Up @@ -313,13 +370,15 @@ Putting it all together - a control that blocks Social Security Numbers in tool
"step_types": ["tool"],
"stages": ["post"]
},
"selector": {
"path": "output"
},
"evaluator": {
"name": "regex",
"config": {
"pattern": "\\b\\d{3}-\\d{2}-\\d{4}\\b"
"condition": {
"selector": {
"path": "output"
},
"evaluator": {
"name": "regex",
"config": {
"pattern": "\\b\\d{3}-\\d{2}-\\d{4}\\b"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

json only example needs escape

}
}
},
"action": {
Expand Down Expand Up @@ -354,10 +413,12 @@ async with AgentControlClient() as client:
"enabled": True,
"execution": "server",
"scope": {"step_names": ["generate_response"], "stages": ["post"]},
"selector": {"path": "output"},
"evaluator": {
"name": "regex",
"config": {"pattern": r"\\b\\d{3}-\\d{2}-\\d{4}\\b"}
"condition": {
"selector": {"path": "output"},
"evaluator": {
"name": "regex",
"config": {"pattern": r"\b\d{3}-\d{2}-\d{4}\b"}
},
},
"action": {"decision": "deny"}
}
Expand All @@ -384,16 +445,20 @@ curl -X PUT "http://localhost:8000/api/v1/controls/$CONTROL_ID/data" \
"enabled": true,
"execution": "server",
"scope": {"step_names": ["generate_response"], "stages": ["post"]},
"selector": {"path": "output"},
"evaluator": {
"name": "regex",
"config": {"pattern": "\\\\b\\\\d{3}-\\\\d{2}-\\\\d{4}\\\\b"}
"condition": {
"selector": {"path": "output"},
"evaluator": {
"name": "regex",
"config": {"pattern": "\\b\\d{3}-\\d{2}-\\d{4}\\b"}
}
},
"action": {"decision": "deny"}
}
}'
```

Regex pattern note: the pattern itself is `\b\d{3}-\d{2}-\d{4}\b`. Python raw strings render that as `r"\b\d{3}-\d{2}-\d{4}\b"`, while JSON payloads must escape backslashes as `"\\b\\d{3}-\\d{2}-\\d{4}\\b"`.

### Example: Block Toxic Input (Luna-2 AI)

To use this evaluator, install the package and restart the server.
Expand All @@ -413,13 +478,15 @@ await controls.create_control(
"enabled": True,
"execution": "server",
"scope": {"step_names": ["process_user_message"], "step_types": ["llm"], "stages": ["pre"]},
"selector": {"path": "input"},
"evaluator": {
"name": "galileo.luna2",
"config": {
"metric": "input_toxicity",
"operator": "gt",
"target_value": 0.5
"condition": {
"selector": {"path": "input"},
"evaluator": {
"name": "galileo.luna2",
"config": {
"metric": "input_toxicity",
"operator": "gt",
"target_value": 0.5
}
}
},
"action": {"decision": "deny"}
Expand All @@ -445,13 +512,15 @@ curl -X PUT "http://localhost:8000/api/v1/controls/$CONTROL_ID/data" \
"enabled": true,
"execution": "server",
"scope": {"step_names": ["process_user_message"], "step_types": ["llm"], "stages": ["pre"]},
"selector": {"path": "input"},
"evaluator": {
"name": "galileo.luna2",
"config": {
"metric": "input_toxicity",
"operator": "gt",
"target_value": 0.5
"condition": {
"selector": {"path": "input"},
"evaluator": {
"name": "galileo.luna2",
"config": {
"metric": "input_toxicity",
"operator": "gt",
"target_value": 0.5
}
}
},
"action": {"decision": "deny"}
Expand All @@ -460,4 +529,3 @@ curl -X PUT "http://localhost:8000/api/v1/controls/$CONTROL_ID/data" \
```

> **Note**: For the Luna-2 evaluator, set the `GALILEO_API_KEY` environment variable. See the [Evaluators](/concepts/evaluators/overview) for all available evaluators.

16 changes: 10 additions & 6 deletions concepts/overview.mdx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
title: Overview
description: Core concepts behind Agent Control — policies, controls, selectors, evaluators, and actions.
description: Core concepts behind Agent Control — policies, controls, conditions, selectors, evaluators, and actions.
---

Understanding these core concepts will help you get the most out of Agent Control. Start with the high-level [architecture](/concepts/architecture) to see how components fit together, then dive into [evaluators](/concepts/evaluators/overview) to understand how checks are implemented.
Expand All @@ -10,7 +10,7 @@ Understanding these core concepts will help you get the most out of Agent Contro
A **[Control](/concepts/controls)** is a single rule that defines what to check and what to do when a condition is met.

```text
Control = Scope + Selector + Evaluator + Action
Control = Scope + Condition + Action
```

Example: "If the output contains an SSN pattern, block the response."
Expand All @@ -20,15 +20,19 @@ Example: "If the output contains an SSN pattern, block the response."
"name": "block-ssn-in-output",
"execution": "server",
"scope": { "step_types": ["llm"], "stages": ["post"] },
"selector": { "path": "output" },
"evaluator": {
"name": "regex",
"config": { "pattern": "\\b\\d{3}-\\d{2}-\\d{4}\\b" }
"condition": {
"selector": { "path": "output" },
"evaluator": {
"name": "regex",
"config": { "pattern": "\\b\\d{3}-\\d{2}-\\d{4}\\b" }
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why the fuck does it keep escaping this shit? it should be \b\d{3}-\d{2}-\d{4}\b and i already fixed it previously: aedbbed

}
},
"action": { "decision": "deny" }
}
```

Leaf conditions pair a `selector` with an `evaluator`. Composite conditions can use `and`, `or`, and `not` to combine multiple leaf checks.

## Scope

**Scope** defines when a control runs by filtering which steps are evaluated.
Expand Down
12 changes: 8 additions & 4 deletions core/quickstart.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -160,10 +160,12 @@ async def setup():
"enabled": True,
"execution": "server",
"scope": {"stages": ["post"]},
"selector": {"path": "output"},
"evaluator": {
"name": "regex",
"config": {"pattern": r"\b\d{3}-\d{2}-\d{4}\b"},
"condition": {
"selector": {"path": "output"},
"evaluator": {
"name": "regex",
"config": {"pattern": r"\b\d{3}-\d{2}-\d{4}\b"},
},
},
"action": {"decision": "deny"},
},
Expand All @@ -182,6 +184,8 @@ async def setup():
asyncio.run(setup())
```

Controls store leaf `selector` and `evaluator` definitions under `condition`, which also enables composite `and`, `or`, and `not` trees.

Now, run your agent code.

**🎉 Done!** Your agent now blocks SSN patterns automatically.
Expand Down
3 changes: 1 addition & 2 deletions core/reference.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ uv run mypy . # Type-check
A **Control** is a single rule that defines what to check and what to do when a condition is met.

```text
Control = Scope + Selector + Evaluator + Action
Control = Scope + Condition + Action
```

**Control associations** are direct links between controls and agents.
Expand Down Expand Up @@ -286,4 +286,3 @@ make alembic-upgrade
- [Models](/components/models)
- [Evaluators](/components/evaluators)
- [UI Dashboard](/components/ui)

13 changes: 7 additions & 6 deletions examples/agent-control-demo.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,7 @@ Key insight: controls are enforced server-side, so you can update rules in real
Controls are defined on the server with:

- Scope: When to check (step types, stages: pre or post)
- Selector: What to check (input, output, specific fields)
- Evaluator: How to check (regex patterns, list matching, AI-based)
- Condition: What and how to check
- Action: What to do (allow, deny, steer, warn, log)

Example from `setup_controls.py`:
Expand All @@ -116,10 +115,12 @@ control_data = ControlDefinition(
enabled=True,
execution="server",
scope=ControlScope(step_types=["tool"], stages=["post"]),
selector=ControlSelector(path="output"),
evaluator=EvaluatorConfig(
name="regex",
config={"pattern": r"\b\d{3}-\d{2}-\d{4}\b"},
condition=ConditionNode(
selector=ControlSelector(path="output"),
evaluator=EvaluatorSpec(
name="regex",
config={"pattern": r"\b\d{3}-\d{2}-\d{4}\b"},
),
),
action=ControlAction(decision="deny"),
)
Expand Down
Loading
Loading