RegexValidator

org.llm4s.agent.guardrails.builtin.RegexValidator
See theRegexValidator companion object
class RegexValidator(compiledPattern: Pattern, patternDescription: String, errorMessage: Option[String], fallbackError: Option[String]) extends InputGuardrail, OutputGuardrail

Rejects text in which a regular expression finds no match.

Works as both an InputGuardrail and an OutputGuardrail. Use it to enforce a format (an email address, a phone number, an order id) or to require that some text is present.

The pattern is searched for, not matched against the whole text: [0-9]+ accepts order 66. Anchor the pattern (^[0-9]+$) to require that the whole text fits, with one caveat: by default $ also matches just before a line terminator that ends the text, so ^[0-9]+$ accepts 66 followed by one line break. These are standard java.util.regex semantics, and inline flags such as (?m), (?s) and (?d) change them; see java.util.regex.Pattern for the details.

Patterns are user-supplied, so matching goes through org.llm4s.security.RegexSafetyManager, whichever way the validator was built: text that is null or longer than 100000 characters is rejected before matching, and a match that exceeds its character-access budget (the guard against catastrophic backtracking) is aborted. Only the companion's String factories also pre-screen the pattern itself: there a pattern that is null, empty after trimming, longer than 1000 characters, or matches a known catastrophic-backtracking shape is refused. The shape check is a rough textual heuristic aimed at nested quantifiers and quantified alternation (it refuses (a+)+ and (cat|dog)*): it refuses some harmless patterns and misses some dangerous ones. A pattern passed as a scala.util.matching.Regex or a compiled java.util.regex.Pattern (the constructors, RegexValidator(regex), RegexValidator.email, RegexValidator.phone and RegexValidator.alphanumeric) is used as given, with no pre-screen; its matching is still bounded.

validate reports failures as a org.llm4s.error.ValidationError for the field value. Its detail is errorMessage when one was given, else Value does not match pattern: <pattern>, for a plain mismatch. Other failures use their own detail: Regex security error: <reason> when the text is null or too long, or the match is aborted or otherwise fails, and Invalid or unsafe regex pattern: <reason> for every text when the pattern was given as a String and was refused or did not compile. That last failure replaces any custom message, so a bad pattern shows up on the first validation rather than as a startup error.

The JDK regex engine recurses as it matches some patterns, such as (a|aa)*b, and on long enough text it can overflow the stack before reaching the character-access budget. The safety manager catches that StackOverflowError and aborts the match, so validate returns a Regex security error Left for it too rather than throwing. The String factories' pre-screen refuses some of these shapes (including that one), but not all of them.

Prefer the String factories (RegexValidator("...") and RegexValidator("...", errorMessage)) for patterns that are not fixed in code: they are the only ones that compile through org.llm4s.security.RegexSafetyManager.safeCompile and pre-screen the pattern.

Value parameters

compiledPattern

the pattern to search for, already compiled; used as given, without the safety manager's pre-screen

errorMessage

the detail to report on a plain mismatch; the default message names the pattern

fallbackError

when set, validate fails every text with this detail, ignoring the pattern; the companion's String factories set it when the pattern is refused or does not compile

patternDescription

the pattern's source text, used in the default error and in description

Attributes

Example
import org.llm4s.agent.guardrails.builtin.RegexValidator
val orderId = RegexValidator("^ORD-[0-9]{6}$", "Order ids look like ORD-123456")
orderId.validate("ORD-123456")   // Right("ORD-123456")
orderId.validate("ORD-123456\n") // Right: `$` also accepts one trailing line break
orderId.validate("ORD-12")       // Left(ValidationError): "Order ids look like ORD-123456"
agent.run(query, tools, inputGuardrails = Seq(RegexValidator.email))
Companion
object
Graph
Supertypes
trait Guardrail[String]
class Object
trait Matchable
class Any
Show all

Members list

Value members

Constructors

def this(pattern: Regex, errorMessage: Option[String], fallbackError: Option[String])

Build a validator from a Scala scala.util.matching.Regex.

Build a validator from a Scala scala.util.matching.Regex.

The pattern is used as given, without the safety manager's pre-screen of its shape and length; matching is still bounded.

Value parameters

errorMessage

the detail to report on a plain mismatch

fallbackError

when set, validate fails every text with this detail

pattern

the pattern to search for

Attributes

def this(pattern: Regex, errorMessage: Option[String])

Build a validator from a Scala scala.util.matching.Regex with a custom mismatch message.

Build a validator from a Scala scala.util.matching.Regex with a custom mismatch message.

Value parameters

errorMessage

the detail to report on a plain mismatch

pattern

the pattern to search for

Attributes

def this(pattern: Regex)

Build a validator from a Scala scala.util.matching.Regex with the default mismatch message.

Build a validator from a Scala scala.util.matching.Regex with the default mismatch message.

Value parameters

pattern

the pattern to search for

Attributes

Concrete methods

override def transform(input: String): String

Optional: Transform the output after validation. Default is identity (no transformation).

Optional: Transform the output after validation. Default is identity (no transformation).

Value parameters

output

The validated output

Attributes

Returns

The transformed output

Definition Classes
def validate(value: String): Result[String]

Search value for the pattern.

Search value for the pattern.

Value parameters

value

the text to check

Attributes

Returns

Right(value) unchanged when the pattern is found, otherwise Left with a org.llm4s.error.ValidationError for the field value; see the class documentation for the detail of each failure, including a match aborted because it recursed too deeply

Inherited methods

def andThen(other: Guardrail[String]): Guardrail[String]

Compose this guardrail with another sequentially.

Compose this guardrail with another sequentially.

The second guardrail runs only if this one passes.

Value parameters

other

The guardrail to run after this one

Attributes

Returns

A composite guardrail that runs both in sequence

Inherited from:
Guardrail
def validate(value: String, context: ModelContext): Result[String]

Validates value inside an agent's hook, as validate(value) does, with the hook's context. A guardrail that calls a model overrides this to call through context.accounted, so the call is counted in the thread's usage and on the run's terminal event even when the task fails (design §4.22); one that combines guardrails passes context on to each. GuardrailMiddleware and GuardrailReviewMiddleware call this form.

Validates value inside an agent's hook, as validate(value) does, with the hook's context. A guardrail that calls a model overrides this to call through context.accounted, so the call is counted in the thread's usage and on the run's terminal event even when the task fails (design §4.22); one that combines guardrails passes context on to each. GuardrailMiddleware and GuardrailReviewMiddleware call this form.

Attributes

Inherited from:
Guardrail

Concrete fields

override val description: Option[String]

Optional description of what this guardrail validates.

Optional description of what this guardrail validates.

Attributes

val name: String

Name of this guardrail for logging and error messages.

Name of this guardrail for logging and error messages.

Attributes