ProfanityFilter

org.llm4s.agent.guardrails.builtin.ProfanityFilter
See theProfanityFilter companion object
class ProfanityFilter(customBadWords: Set[String], caseSensitive: Boolean) extends InputGuardrail, OutputGuardrail

Rejects text that contains a word from a fixed word list.

Works as both an InputGuardrail and an OutputGuardrail: the same instance can be passed to either side of an agent run. The check is rule-based, fast and deterministic, and makes no network call.

The built-in list is deliberately minimal (two placeholder words, badword and inappropriate), so a real deployment supplies its own words through customBadWords, or uses a moderation service or a model-based guardrail for context-aware filtering.

Matching rules, which decide what the filter does and does not catch:

  • Text and word-list entries are first normalised the same way: Unicode NFKD (fullwidth letters become ASCII, compatibility spaces such as a non-breaking space become an ASCII space), then every combining mark and every format character (zero-width space and joiners, byte-order mark, soft hyphen) is removed. So bädword, badword and bad<U+200B>word match badword. Look-alike letters from other scripts (such as Cyrillic а for Latin a) are not mapped, so are not caught. Because marks are removed on both sides, entries that differ only in accents or other marks match the same tokens.
  • The normalised text is split on ASCII whitespace (the regex class \s: space, tab, \n, \r, form feed and vertical tab) and each token is compared with the word list as a whole. badwords does not match badword, and a token with punctuation attached (badword!, "badword") does not match either. Any other character is part of a token, including the line and paragraph separators U+2028 and U+2029, so badword joined to a neighbouring word by one is not caught.
  • Entries are single words. An entry that contains whitespace (a phrase) can never match, because tokens never contain it.
  • By default the comparison ignores case, for the built-in words and for customBadWords alike: after normalisation both sides are lower-cased with Locale.ROOT (so the JVM's default locale has no effect) and the Turkish dotless ı is read as i, so BADWORD, İNAPPROPRIATE and ınappropriate all match. With caseSensitive = true the normalised text and entries are compared without case folding, so the lower-case built-in words no longer match BADWORD.

On a match validate returns a org.llm4s.error.ValidationError for the field input (whichever side the filter is used on) whose detail is Input contains inappropriate content. The detail never names the word that matched.

Value parameters

caseSensitive

false (the default) compares without regard to case; true compares the normalised text without case folding.

customBadWords

Words to reject in addition to the built-in list; empty by default. Single words only (see the matching rules above).

Attributes

Example
import org.llm4s.agent.guardrails.builtin.ProfanityFilter
// built-in list only
val filter = ProfanityFilter()
// your own words, in addition to the built-in ones
val strict = ProfanityFilter.withCustomWords(Set("heck", "darn"))
strict.validate("well, heck")  // Left(ValidationError): the token "heck" is in the list
strict.validate("well, heck!") // Right("well, heck!"): "heck!" is a different token
agent.run(query, tools, inputGuardrails = Seq(strict), outputGuardrails = Seq(strict))
Companion
object
Graph
Supertypes
trait Guardrail[String]
class Object
trait Matchable
class Any
Show all

Members list

Value members

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]

Check value against the word list.

Check value against the word list.

Value parameters

value

the text to check; empty text is valid

Attributes

Returns

Right(value) unchanged when no whitespace-separated token is in the word list, otherwise Left with a org.llm4s.error.ValidationError for the field input that does not name the matching word

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

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