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.
- The
AiPlatformConfigentity is given a multi-value, orderable field that stores a list of@AiMiddlewareplugin IDs and their individual configurations. - The UI for the
AiPlatformConfigentity allows a site builder to add, remove, reorder, and configure any available middleware plugin. -
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. -
Pros:
- Maximum Extensibility: Developers can create entirely new decorators by simply creating a new
@AiMiddlewareplugin, 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.
- Maximum Extensibility: Developers can create entirely new decorators by simply creating a new
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
AiPlatformConfigentity schema includes an ordered, multi-valuemiddlewaresfield 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
@AiPlatformMiddlewareplugin forTraceablePlatform.