Problem/Motivation

The AI ecosystem is gaining first-class support for guardrails and guardrail sets.
In particular, work in the LiteLLM provider adds support for syncing guardrails from
the proxy and attaching an ai_guardrail_set to a request.

However, ai_search_block does not currently provide a UI for selecting
guardrail sets on the block configuration form. That means site builders cannot apply
guardrail policies to AI Search Block requests in a clean, reusable way, even when the
underlying AI provider supports them.

This should be solved directly in ai_search_block so site builders can:

  • attach one or more existing guardrail sets to a block,
  • quickly create a new set if none exists yet, and
  • understand clearly which safety rules are active for that block.

Proposed solution

Add a dedicated Guardrails section to the AI Search Block configuration form.

  • Add a selector for existing ai_guardrail_set entities.
  • Support selecting one or multiple sets.
  • Provide an inline link such as Create guardrail set / Manage guardrail sets.
  • Show a short description/help text so the purpose of the selected sets is obvious.
  • When multiple sets are selected, merge their referenced guardrails in a deterministic way and deduplicate duplicates.
  • Pass the effective guardrail set(s) along with AI Search Block requests through the AI API layer.

For the UI itself, a compact and clean approach would be preferable over a large multi-select.
For example, an entity autocomplete with tagging support, or another equally tight UI pattern.

Acceptance criteria

  • An administrator can configure an AI Search Block and attach one or more guardrail sets.
  • The block form includes a clear link to create/manage guardrail sets.
  • The selected guardrail sets are saved in block configuration and export correctly.
  • Requests made by ai_search_block include the configured guardrail information so compatible providers can apply it.
  • If multiple sets are selected, duplicate guardrails are not applied twice.
  • If no guardrail sets exist yet, the UI provides a clear empty state instead of a confusing field.
  • No WSOD or fatal error occurs if guardrail entities are missing, deleted, or temporarily unavailable.

Possible follow-up work

  • Show a summary of the selected guardrail sets directly in the form.
  • Add per-block overrides later if there is a real use case.
CommentFileSizeAuthor
#7 14-individual-mode-persisted.png60.15 KBabhisekmazumdar
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

nikro created an issue. See original summary.

nikro’s picture

I'm picking this up, as soon as we release 1.2.x as per - https://www.drupal.org/project/ai_search_block/issues/3582387#comment-16...
So that we can start a good prep for 1.3.x and this being a good candidate.

arianraeesi’s picture

nikro’s picture

Assigned: nikro » abhisekmazumdar
Status: Active » Needs review

Added guardrail selection support to the AI Search Block configuration.

This adds a new Guardrails section to the block settings with three modes: no guardrails, use an existing guardrail set, or select individual guardrails. The existing-set mode intentionally follows the AI API Explorer pattern: a single guardrail set can be selected and is applied via the AI module’s AiGuardrailHelper::applyGuardrailSetToChatInput().

For ad-hoc usage, the block also supports selecting individual pre-generation and post-generation guardrails. Since the AI runtime expects a single AiGuardrailSetInterface, those individual selections are wrapped in an unsaved transient guardrail set at request time and attached to the ChatInput. This stays provider-agnostic, so provider passthrough guardrails such as LiteLLM continue to be handled by the AI/provider layer.

The change also bumps the AI dependency to ^1.3, adds config schema for the new block settings, records config dependencies for selected guardrail sets/entities, and adds kernel test coverage for both saved-set mode and ad-hoc individual guardrail mode.

Suggested testing:

  1. Create one or more AI guardrails at /admin/config/ai/guardrails.
  2. Create a guardrail set at /admin/config/ai/guardrails/guardrail-sets.
  3. Edit an AI Search Block and test all three Guardrail modes.
  4. Confirm saved-set mode applies the selected set, and individual mode applies selected pre/post guardrails.
  5. If using LiteLLM passthrough guardrails (i.e. those provided by litellm provider (dev version)), confirm synced LiteLLM guardrail entities can be selected and are enforced by the provider.

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

abhisekmazumdar’s picture

StatusFileSize
new60.15 KB

Tested on branch 3582452-add-guardrail-set, MR !44.

I followed the testing steps from the comment above.

Setup

  1. Created two guardrails at /admin/config/ai/guardrails: a Regexp Guardrail ("Block Profanity") and an Input Length Limit guardrail ("Limit Input Length").
  2. Created a guardrail set ("Content Safety Set") at /admin/config/ai/guardrails/guardrail-sets with "Block Profanity" as a pre-generation guardrail and "Limit Input Length" as a post-generation guardrail.

Block configuration: all three modes

Mode 1 (no guardrails): Three radio options render correctly. No sub-fields shown, no errors.

Mode 2 (existing guardrail set): Selecting the radio shows the "Guardrail set" dropdown via the #states API. "Content Safety Set" appeared in the list. A "Manage guardrail sets" link is present. Saved and reopened the block; selection persisted.

Mode 3 (individual guardrails): Pre-generation and post-generation checkbox groups appeared with both guardrails listed. Selected "Block Profanity" (pre-gen) and "Limit Input Length" (post-gen). Saved and reopened; both selections retained.

Config dependencies

After saving in individual mode, the block config correctly recorded all three entities:

dependencies:
  config:
    - ai.ai_guardrail.block_profanity
    - ai.ai_guardrail.limit_input_length
    - ai.ai_guardrail_set.content_safety_set

calculateDependencies() works correctly for both modes.

Fixes I applied to the branch

I found a few issues in the files this MR touches and pushed fixes directly to the branch:

  1. setGuardrailSet() and getGuardrailSet() are deprecated in ai:1.4.0. Replaced with addGuardrailSet() and getGuardrailSets() in AiSearchBlockHelper.php and the kernel test.
  2. Two uasort() calls in SearchFormBlock.php used anonymous closures. Replaced with arrow functions.
  3. use Drupal\Core\Render\Element\Checkboxes; was out of alphabetical order. Fixed.
  4. The kernel test @covers annotation pointed at a private method. Changed to cover the class.

Re-verified all three modes after applying the fixes; no regressions.

AI disclosure: I used Claude Code to review the MR diff, analyse the tests, summarise the comment thread, and surface gaps. The reasoning and positions are my own. I reviewed everything before posting.

abhisekmazumdar’s picture

Assigned: abhisekmazumdar » Unassigned
Status: Needs review » Reviewed & tested by the community
nikro’s picture

Pushed the dependency fix to the branch (MR !44). The guardrail code uses addGuardrailSet()/getGuardrailSets(), which only exist in ai ≥ 1.4.0, so I bumped ai:ai / ai:ai_search and composer.json from ^1.3 to ^1.4 — this now correctly lands as 1.1.x requiring AI core ≥ 1.4. Retargeted the MR to 1.1.x.

Verified locally against ai 1.4.3: kernel test passes (5 tests, 16 assertions), no guardrail-API deprecations. The red pipeline is unrelated to this feature — pre-existing PHPCS/PHPStan violations in .module/log_tag files plus a CI --verbose bug, all tracked separately in https://www.drupal.org/project/ai_search_block/issues/3609906. This MR is scoped to the guardrail feature only.

Merged into 1.1. Closing.

nikro’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)