Skip to content
Merged
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
7 changes: 6 additions & 1 deletion evaluators/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,14 @@ Pattern matching for text (PII, keywords, SQL injection)
```

### List
Match against value lists (blocked users, restricted cities)
Match against value lists (blocked users, restricted cities, allowed prefixes).
Supports `match_mode: "exact"` for full-string membership, `match_mode: "contains"`
for keyword-style matching, `match_mode: "starts_with"` for prefix matching, and
`match_mode: "ends_with"` for suffix matching.
```python
{"name": "list", "config": {"values": ["admin", "root"], "case_sensitive": False}}
{"name": "list", "config": {"values": ["/home/lev/agent-control"], "match_mode": "starts_with"}}
{"name": "list", "config": {"values": [".md"], "match_mode": "ends_with"}}
```

### SQL
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,12 @@ class ListEvaluatorConfig(EvaluatorConfig):
match_on: Literal["match", "no_match"] = Field(
"match", description="Trigger rule on match or no match"
)
match_mode: Literal["exact", "contains"] = Field(
match_mode: Literal["exact", "contains", "starts_with", "ends_with"] = Field(
"exact",
description="'exact' for full string match, 'contains' for keyword/substring match",
description=(
"'exact' for full string match, 'contains' for keyword matching, "
"'starts_with' for prefix matching, and 'ends_with' for suffix matching"
),
)
case_sensitive: bool = Field(False, description="Whether matching is case sensitive")

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class ListEvaluator(Evaluator[ListEvaluatorConfig]):
Checks if data matches values in a list. Supports:
- any/all logic (match any value vs match all values)
- match/no_match trigger (trigger on match or no match)
- exact/contains mode (full match vs substring/keyword)
- exact/contains/starts_with/ends_with mode (full match vs keyword vs prefix/suffix)
- case sensitivity toggle

Example configs:
Expand Down Expand Up @@ -50,6 +50,12 @@ def _build_regex(self) -> Any:
if self.config.match_mode == "contains":
# Word boundary matching for substring/keyword detection
pattern = f"\\b({'|'.join(escaped)})\\b"
elif self.config.match_mode == "starts_with":
# Prefix matching using anchors
pattern = f"^({'|'.join(escaped)})"
elif self.config.match_mode == "ends_with":
# Suffix matching using anchors
pattern = f"({'|'.join(escaped)})$"
else:
# Exact match using anchors
pattern = f"^({'|'.join(escaped)})$"
Expand Down
Loading
Loading