Skip to content

4. AI Platform Decorators via Middleware

Authors: Dezső Biczó (@mxr576), Wolfgang Ziegler (@fago)

Date: 2026-07-09

Status

Implemented

Context

The Symfony\Component\Ai\Platform\PlatformInterface is designed to be enhanced using the decorator pattern. Symfony itself provides decorators like TraceablePlatform (for logging/tracing) and CacheablePlatform, which wrap a PlatformInterface object to add functionality.

The Drupal AI module needs a way to apply these decorators—and allow developers to add their own—to the AI Platforms configured by site administrators. The solution must be flexible, allowing decorators to be enabled, disabled, re-ordered, and configured on a per-platform basis through the UI.

We considered several approaches for applying these decorators.

Option A: Hardcoded Decorators with Service Swapping

In this model, the module would be aware of a fixed set of decorators. To enable a decorator like tracing, a developer would need to alter the service container definition, for example, by decorating the platform manager service. This is a common Symfony pattern, but it is a developer-only task, applies globally, and is not suitable for per-platform configuration by a site administrator.

  • Pros: Uses standard Symfony service container features.
  • Cons:
    • Inflexible; requires code changes and cache rebuilds to alter behavior.
    • Not configurable through the UI.
    • Cannot be configured on a per-platform basis.

Option B: Simple Checkboxes on the Config Entity

The AiPlatformConfig entity form could include a set of checkboxes for a predefined list of decorators (e.g., "Enable Tracing"). When the platform object is built, the code would check these boolean fields and wrap the platform object accordingly.

  • Pros: Simple to implement for a fixed set of decorators.
  • Cons:
    • Violates Open/Closed Principle: To add a new decorator, a developer would have to modify the core module's entity schema, form, and platform build logic.
    • Not Configurable: Provides no way to pass settings to the decorators (e.g., a specific logger service for TraceablePlatform).
    • Order is Fixed: The order in which decorators are applied is hardcoded.

Option C: A Generic @AiMiddleware Plugin System

This approach introduces a new plugin type, @AiMiddleware. Each middleware plugin is a factory for a specific decorator.

  1. The AiPlatformConfig entity is given a multi-value, orderable field that stores a list of @AiMiddleware plugin IDs and their individual configurations.
  2. The UI for the AiPlatformConfig entity allows a site builder to add, remove, reorder, and configure any available middleware plugin.
  3. During platform construction (inside AiManagedPlatform::create()), after the base platform object is created, the system iterates through the configured middlewares. For each one, it instantiates the middleware plugin and uses it to decorate the platform object.

  4. Pros:

    • Maximum Extensibility: Developers can create entirely new decorators by simply creating a new @AiMiddleware plugin, with no changes needed to the core module.
    • Fully Configurable: Each middleware can have its own configuration schema and sub-form, allowing fine-grained control.
    • Order is Controllable: Site builders can control the exact order of the decorator stack via a drag-and-drop UI.
    • Follows Drupal Best Practices: This "plugin-in-config" approach is a standard and well-understood pattern in the Drupal ecosystem.

Decision

We have chosen Option C: A Generic @AiMiddleware Plugin System.

This pattern provides a clean, powerful, and Drupal-native way to handle the decoration of PlatformInterface objects. It treats cross-cutting concerns like tracing, caching, and logging as distinct, configurable layers that can be applied to any platform backend.

This decision perfectly aligns with our choice of a plugin-based system for the platforms themselves (ADR-001), creating a cohesive and highly extensible architecture. The platform defines the "what" (the connection to AI models), and the middlewares define the "how" (caching, tracing, etc.).

Consequences

  • A new plugin type, Drupal\ai\Plugin\ai\PlatformMiddleware\AiPlatformMiddlewareInterface, and its corresponding manager (plugin.manager.ai.platform_middleware) are created.
  • The AiPlatformConfig entity schema includes an ordered, multi-value middlewares field storing middleware plugin IDs and their per-plugin configurations.
  • The entity form will be updated with a drag-and-drop UI to manage the middleware stack (currently deferred — the field exists in the data model but the UI is not yet built).
  • The logic within AiManagedPlatform::create() applies the configured middleware plugins in sequence when instantiating a platform.
  • The module ships with an initial @AiPlatformMiddleware plugin for TraceablePlatform.