Problem / Motivation

ai_validations currently ships an AI Image Classification field validation rule that runs an uploaded
image through an AI provider's image-classification operation and validates the field based on whether
a configured tag is returned above a minimum confidence threshold.

There is no equivalent for text. We should add an AI Text Classification validation rule that does the
same for text/string/long-text fields: send the field value to an AI provider's classification
operation and validate based on the returned label and confidence. Useful for rejecting
spam/toxic/off-topic submissions, requiring a field to fall into an allowed category, or flagging
sentiment.

Proposed resolution

Mirror the existing image classification implementation, swapping the image input/operation for a text
classification input/operation. Three new classes, modeled on their image counterparts:

1. src/Plugin/FieldValidationRule/AiTextClassificationConstraintFieldValidationRule.php — model on the
image version. getConstraintName() returns AiTextClassification. Same config form: model selection
(limited to text-classification-capable models), tag, finder method (exact/contains/case-insensitive),
minimum confidence, "model not available" behavior, custom message.
2. src/Plugin/Validation/Constraint/AiTextClassificationConstraint.php — model on the image version.
@Constraint id AiTextClassification, label "AI Text Classification Check", same properties (message,
model, tag, finder, minimum, na).
3. src/Plugin/Validation/Constraint/AiTextClassificationConstraintValidator.php — model on the image
version. Instead of loading a file and calling $provider->imageClassification(...), take the text
value directly and call the AI module's text classification operation, then apply the same finder +
minimum-confidence matching.

Reuse the matching logic, confidence comparison, na exception handling, and DI structure from the
image version so behaviour stays consistent.

Remaining tasks

- [ ] Confirm the AI module exposes a text classification operation/input class (analogous to
imageClassification() / ImageClassificationInput)
- [ ] Add the three plugin classes
- [ ] Restrict the model dropdown to text-classification-capable providers
- [ ] Add test coverage mirroring the image classification tests
- [ ] Update docs/README

User interface changes

A new AI Text Classification option in the field validation rule list, with a config form matching the
image classification rule.

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

marcus_johansson created an issue. See original summary.

marcus_johansson’s picture

abhisekmazumdar made their first commit to this issue’s fork.

abhisekmazumdar’s picture

Steps to test

  1. Enable ai_validations and configure at least one AI provider that supports text_classification.
  2. Go to Structure > Field validation rule set. Create a rule set on a content type with a text field. The Body field on Article is fine.
  3. Add a rule and pick AI text classification constraint from the list.
  4. Fill in the fields:
    • Classification Model: your provider and model.
    • Classification Tag: the label to block, e.g. spam.
    • Finder: Exact, Contains, or Contains (Case-Insensitive).
    • Minimum Confidence: e.g. 0.8.
    • If model is not available: Skip or Fail.
    • Message: error text shown when the rule fires.
  5. Save the rule, then save the rule set.
  6. Open the content form. Enter text into the validated field and submit.
    • Text classified as the configured tag at or above the threshold should fail with your message.
    • Text that does not match (wrong label or lower confidence) should save.
  7. Edit the saved rule and check that all fields reload correctly.
abhisekmazumdar’s picture

Assigned: abhisekmazumdar » Unassigned
Status: Active » Needs review

What was done

I have added the AI text classification constraint as a mirror of the existing image classification constraint. The MR adds three plugin files and a Kernel test suite.

Differences from the original plan

Validator-logic test: Unit test was not viable

The issue summary asked for test coverage mirroring the image classification tests. The image classification feature ships no validator-logic test itself, only a FunctionalJavascript form test.

I tried a Unit test first. AiProviderPluginManager is declared final, so PHPUnit cannot mock it. A Unit test covering the full call chain requires bypass-finals, which the module does not use.

I wrote a Kernel test instead, backed by ai_validations_test. That module registers a ClassifierTestProvider extending EchoProvider whose textClassification() output is controlled via Drupal state. The Kernel test drives every branch through the real provider manager.

EchoProvider cannot trigger a positive match

EchoProvider returns labels only when the input carries them. The validator passes new TextClassificationInput($text) with no labels, so EchoProvider always returns an empty list. ClassifierTestProvider in ai_validations_test was added to work around this.

Plugin id typo not copied

The image classification plugin id has a space: ai_image_classification constraint_rule. The new plugin uses ai_text_classification_constraint_rule with no space. This is intentional.

abhisekmazumdar’s picture

Found and fixed a bug while preping for demo

When a site has no text_classification provider configured and the rule is set to na: skip, the validator was still showing an error message on save instead of silently passing. The na setting was being ignored at the provider lookup stage.

The fix adds a parameter to resolveProviderOption() so callers can tell it not to raise a violation when no provider is found. The text classification validator now passes that flag based on the na setting.

Also updated one kernel test that was affected by the change, and corrected a minor code style issue flagged by the CI pipeline.

Three commits have been pushed to the MR branch.

marcus_johansson’s picture

Status: Needs review » Needs work

Setting to needs work, but really just a NIT. Feel free to merge without fixing.

marcus_johansson’s picture

Assigned: Unassigned » marcus_johansson
marcus_johansson’s picture

Assigned: marcus_johansson » Unassigned
abhisekmazumdar’s picture

Status: Needs work » Reviewed & tested by the community

  • abhisekmazumdar committed 9daecc54 on 1.3.x
    fix #3595515: update testMissingModelRaisesViolation to use na:fail...

  • abhisekmazumdar committed 88fb6f27 on 1.3.x
    fix #3595515: fix PHPCS ParamGroup — remove blank line between @param...

  • abhisekmazumdar committed 24130ece on 1.3.x
    fix #3595515: respect na:skip when no text_classification provider is...

  • abhisekmazumdar committed c0270a88 on 1.3.x
    feat: #3595515 Add AI text classification field validation constraint.
    
abhisekmazumdar’s picture

Status: Reviewed & tested by the community » Fixed

Now that this issue is closed, review the contribution record.

As a contributor, attribute any organization that helped you, or if you volunteered your own time.

Maintainers, credit people who helped resolve this issue.

arianraeesi’s picture

Status: Fixed » Closed (fixed)