Step-level and session-level evaluators — the full evaluation system.
ABS does not have two modes with two syntaxes. A document with no evaluations anywhere is a pure behavioral description. The same document, with evaluations added, becomes executable as an automated test. Nothing about the document's shape changes — evaluations is simply optional annotation.
Step-level evaluations attach to a single Behavior and check that one observed step is correct in isolation.
Session-level (chain) evaluations attach to the Session as a whole and check properties of the entire observed trace: ordering, consistency, invariants.
session: Refund request — approved
behaviors:
- actor: user
action: says
content: "I want to return order #8291, it arrived damaged"
- actor: assistant
action: asks
content: "I'm sorry about that. Can you confirm your name and order date?"
evaluations:
- type: llm_judge
criteria: |
1. Shows empathy for the damaged item
2. References the order number #8291
3. Asks for verification info before taking action
- actor: user
action: says
content: "Franco Vinciarelli, ordered last Tuesday"
capture:
customerName: "Franco Vinciarelli"
- actor: assistant
action: calls
target: Orders API
- actor: tool
action: responds
target: Orders API
- actor: assistant
action: calls
target: Refunds API
- actor: tool
action: responds
target: Refunds API
- actor: assistant
action: informs
content: "Refund of €47.50 processed, Franco. Refund ID: R-5512."
capture:
refundId: "R-5512"
evaluations:
- type: contains
value: "R-5512"
- type: llm_judge
criteria: |
1. States refund amount and timeline
2. Provides refund reference
3. Uses customer's name
4. Reassuring tone, no upsells
evaluations:
- type: sequence
order:
- { actor: assistant, action: asks }
- { actor: assistant, action: calls, target: "Orders API" }
- { actor: assistant, action: calls, target: "Refunds API" }
- { actor: assistant, action: informs }
- type: variable_consistency
variable: refundId
- type: never
match: { actor: assistant, action: hands_off }
exact_matchThe observed content must equal value exactly.
evaluations:
- type: exact_match
value: "12345"
containsThe observed content must contain value as a substring (case-insensitive by default).
evaluations:
- type: contains
value: "on the way"
regexThe observed content must match the given pattern.
evaluations:
- type: regex
pattern: "^Order #\\d+ is (on the way|delivered)$"
schemaThe observed content must validate against a JSON Schema.
evaluations:
- type: schema
schema:
type: object
required: [orderId]
properties:
orderId: { type: string }
tool_callValidates that one or more calls Behaviors were invoked correctly: target matches, parameters match (per with/with_only rules), and optionally that ordering is respected when multiple tools are called. See Tools & MCP for the full rules.
evaluations:
- type: tool_call
target: "Order MCP"
with:
orderId: "{{orderId}}"
ordered: true
llm_judgeDelegates the judgment to an LLM against a natural-language rubric.
evaluations:
- type: llm_judge
criteria: "Response clearly states the order is in transit, in a friendly tone, without inventing a delivery date."
customEscape hatch for evaluators not covered above. Implementations define their own id namespace.
evaluations:
- type: custom
id: my-org.sentiment-positive
All chain evaluators use a selector to identify Behaviors in the trace: an object with any of actor, action, target. A field that's present must match exactly; a field omitted is a wildcard.
match: { actor: assistant, action: calls, target: "Order MCP" }
sequenceEvery selector in order must match some Behavior in the trace, in increasing position (not necessarily adjacent — other Behaviors may fall between them).
- type: sequence
order:
- { actor: assistant, action: calls, target: "Order MCP" }
- { actor: assistant, action: informs }
eventuallyThe selector must match at least one Behavior somewhere in the trace.
- type: eventually
match: { actor: assistant, action: informs }
neverThe selector must match no Behavior anywhere in the trace.
- type: never
match: { actor: assistant, action: hands_off }
countBounds how many Behaviors match the selector.
- type: count
match: { actor: assistant, action: calls }
min: 1
max: 2
withinA match selector must occur within max_steps Behaviors after an after selector.
- type: within
after: { actor: user, action: says }
match: { actor: assistant, action: responds }
max_steps: 3
variable_consistencyEvery value that resolves a given {{variable}} reference anywhere in the Session — plus the value it was originally captured with — must be equal. Catches an agent silently substituting a different order number or ID than the one the user actually gave.
- type: variable_consistency
variable: orderId
all_of / any_of / none_ofAvailable at both levels. Wraps a list of nested evaluations:
- type: any_of
evaluations:
- type: contains
value: "on the way"
- type: contains
value: "in transit"
Listing multiple evaluations directly under evaluations: (without wrapping) is already an implicit all_of. The wrapper types exist specifically for any_of/none_of, which a flat list cannot express.
Default: non-blocking / best-effort. A failing evaluation does not stop other evaluations from being checked. An implementation MUST evaluate every evaluations entry it can and produce a full pass/fail report.
blocking: true. An evaluation MAY set blocking: true as a checkpoint. If a blocking: true evaluation fails, any other evaluation whose Behavior depends — directly or via a captured variable — on the step that failed SHOULD be reported as inconclusive rather than failed, avoiding a wall of misleading downstream failures.
- actor: assistant
action: calls
target: Order MCP
with:
orderId: "{{orderId}}"
evaluations:
- type: tool_call
target: "Order MCP"
blocking: true
The Session's overall result is pass if and only if every evaluation in the report passed.