Skip to content

Services

The AI Context module registers the following services in ai_context.services.yml.

Each core service below is marked Status: Public or Status: Internal. Public services are safe to depend on; internal services are implementation details that may change without deprecation. Services without an explicit label are internal; see Support services. See API stability for the full policy and the public API surface.

Core services

ai_context.request_factory

Status: Public

Class: Drupal\ai_context\Service\AiContextRequestFactory

Builds AiContextRequest value objects from agent config or raw parameters, and provides convenience methods for non-agent modules that just need rendered context.

Request-building methods:

  • fromAgent(string $agentId, string $task, ...) -- builds a request from a saved agent config entry.
  • fromParameters(AiContextRequestParamsData $params) -- builds a request from a strongly-typed DTO (used by function call plugins and advanced consumers).

Convenience methods (build + select in one call):

// One-liner: returns the rendered context string (empty if nothing matches).
public function getRenderedContext(
  array $scopes = [],
  ?int $maxTokens = NULL,
  ?EntityInterface $targetEntity = NULL,
  ?string $consumerId = NULL,
): string

// Full result with cache metadata, selected IDs, token usage.
public function getResult(
  array $scopes = [],
  ?int $maxTokens = NULL,
  ?EntityInterface $targetEntity = NULL,
  ?string $consumerId = NULL,
): AiContextResult

Usage examples:

/** @var \Drupal\ai_context\Service\AiContextRequestFactory $factory */
$factory = \Drupal::service('ai_context.request_factory');

// Get rendered context text (returns empty string if nothing matches).
$text = $factory->getRenderedContext(
  scopes: ['use_case' => ['working_with_text']],
  maxTokens: 2000,
  targetEntity: $node,
  consumerId: 'my_module',
);

// Or get the full result object with cache metadata and selected item IDs.
$result = $factory->getResult(
  scopes: ['use_case' => ['working_with_text']],
  maxTokens: 2000,
  targetEntity: $node,
  consumerId: 'my_module',
);
$text = $result->getRenderedText();
$cacheMetadata = $result->getCacheableMetadata();
$selectedIds = $result->getSelectedItemIds();

Parameters:

  • scopes: Scope subscriptions keyed by scope plugin ID. Pass an empty array to match all published context (subject to token/item limits).
  • maxTokens: Maximum tokens for rendered text. NULL defers to module settings.
  • targetEntity: An entity object for target-entity scope matching.
  • consumerId: Identifier for logging/debugging (e.g., your module name).

These methods use match_all selection mode by default, so all published candidates that pass context filters are considered.

Agent config lookup:

  • findAgentConfig(string $agentId): array — canonical reader for per-agent context config from ai_context.agents. Other services should use this rather than reading config directly.
  • isLoopAware(string $agentId): bool — whether the agent has loop-aware context injection enabled.

See AiContextRequest and selection modes and AiContextResult below.

ai_context.scope_subscription_form

Status: Public

Class: Drupal\ai_context\Service\AiContextScopeSubscriptionFormBuilder

Interface: Drupal\ai_context\Service\AiContextScopeSubscriptionFormBuilderInterface

Builds and processes scope subscription form widgets for consumers that need the same subscription UI as the agent configuration form without depending on the internal scope plugin manager.

Methods:

  • hasSubscribableScopes(): bool — whether any enabled scope supports subscriptions.
  • getNonSubscribableScopeLabels(): string[] — human-readable labels for scopes that do not support subscriptions (for example Global).
  • buildWidgets(array &$form, FormStateInterface $form_state, array $defaults = [], bool $for_subscription = TRUE): array — per-scope subscription widgets keyed by scope plugin ID.
  • extractValues(array $submitted): array — normalizes raw submitted values into a scope map (scope_id => [value_ids]).
  • buildSummary(array $scope_subscriptions): array — summary render array for selected subscriptions.

Usage example (custom entity form with scope subscriptions):

/** @var \Drupal\ai_context\Service\AiContextScopeSubscriptionFormBuilderInterface $builder */
$builder = \Drupal::service('ai_context.scope_subscription_form');

if (!$builder->hasSubscribableScopes()) {
  return;
}

$form['my_module']['scope_subscriptions'] = [
  '#type' => 'container',
  '#tree' => TRUE,
];

foreach ($builder->buildWidgets($form, $form_state, $current_scopes) as $scope_id => $element) {
  $form['my_module']['scope_subscriptions'][$scope_id] = $element;
}

// In submit/entity builder:
$submitted = $form_state->getValue(['my_module', 'scope_subscriptions']) ?? [];
$scope_map = $builder->extractValues(is_array($submitted) ? $submitted : []);

ai_context.selector

Status: Internal

Class: Drupal\ai_context\Service\AiContextSelector

Interface: Drupal\ai_context\Service\AiContextSelectorInterface

Orchestrates context selection: filtering, scope scoring, subcontext resolution, rendering, and dispatching stable selector pipeline events. It has zero knowledge of agents or consumer-specific configuration.

Extension model: Contrib modules extend selection via documented selector pipeline events — not by decorating this service. Decorating or replacing ai_context.selector is unsupported; the selector and its internal pipeline may change without deprecation. See Supported extension model in Events.

Key method:

public function select(AiContextRequest $request): AiContextResult

The AiContextResult contains the rendered text, selected item metadata, token usage, and CacheableMetadata. See AiContextResult for the full API. Pipeline event names and subscriber contracts are documented in Events.

ai_context.scope_index

Status: Internal

Class: Drupal\ai_context\Service\AiContextScopeIndexService

Maintains the denormalized ai_context_item_scope_index table — one row per (item_id, scope_id, value) triple mirroring each item's scope map field. This lets the selector prefilter candidates with SQL instead of loading every published item when scope subscriptions are present.

Key methods:

  • indexItem(AiContextItem $item) — rebuild index rows for one item (called on save)
  • deindexItem(int $item_id) — remove all rows for an item
  • getItemIdsByScopeValues(string $scopeId, array $values): int[] — items matching any of the given values for one scope
  • getItemIdsByScope(array $scope_subscriptions, array $candidate_ids = []): int[] — candidate IDs for PHP-level scoring (superset; false positives OK, false negatives not)

Target entity scope uses a separate DER field and is not indexed here.

ai_context.scope_cleanup

Status: Internal

Class: Drupal\ai_context\Service\AiContextScopeCleanupService

Removes stale scope values from context items and agent subscriptions when dynamic scope options are deleted (for example a site section removed from configuration).

Key methods:

  • removeScopeValues(string $scopeId, array $values) — strip values from item scope maps, agent subscriptions, and the scope index
  • removeTargetEntityReference(string $entityTypeId, int|string $entityId) — clear DER target references when a referenced entity is deleted

Triggered automatically when site section config changes via AiContextScopeConfigSubscriber (see Event subscribers below). Custom scope plugins can invoke the same service when their option lists change.

ai_context.scope_resolver

Status: Internal

Class: Drupal\ai_context\Service\AiContextScopeResolver

Scores context items against scope subscriptions and applies hard context filters (e.g., language, site section). Replaces the former AiContextScopeMatcher.

ai_context.renderer

Status: Internal

Class: Drupal\ai_context\Service\AiContextRenderer

Renders selected context items into a token-limited text block for prompt injection. When a model is configured in provider_config, uses that model's tokenizer locally for token-aware truncation; otherwise falls back to approximate token counting (~4 characters per token). Receives pre-translated entities from the selector.

ai_context.token_estimator

Status: Internal

Class: Drupal\ai_context\Service\AiContextTokenEstimator

Estimates token counts and classifies weight tiers for context text (~4 characters per token). Used by the renderer for token budgeting and by the listing UI for weight badges. The selector uses this after TEXT_RENDERED to recalculate AiContextResult::getTokensUsed() from the final rendered text.

ai_context.subcontext_resolver

Status: Internal

Class: Drupal\ai_context\Service\AiContextSubcontextResolver

Resolves child (subcontext) items for selected parent items. When conditional AI decisions are enabled, filters conditional children via the configured provider/model; without a provider or on failure, conditional children for that parent are skipped. When conditional AI decisions are disabled, all conditional children are included without an AI call. Skipped entirely when subcontext_enabled is FALSE in module settings. This service assumes saved parent-child relationships already satisfy the entity integrity rules.

See Subcontext for when to use parent/child items.

ai_context.entity_target_resolver

Status: Internal

Class: Drupal\ai_context\Service\AiContextEntityTargetResolver

Resolves the current entity from the route or request context. Used to match context items that target specific entities.

ai_context.usage_tracker

Status: Internal

Class: Drupal\ai_context\Service\AiContextUsageTracker

Records usage data when context items are selected. Tracks which items were used, by which agent, on which route, and which entities were involved.

Performance notes:

  • recordUsage() batches the existing-record lookup with a single entity query using context_item_id IN (...).
  • attachEntity() batches duplicate checks for entity-specific records.
  • recordToolUsed() buffers tool IDs in memory; call flushToolsUsed() once per agent run (handled automatically by AiContextAgentFinishedSubscriber on AgentFinishedExecutionEvent).
  • Lookup indexes on runner_id, changed, and (target_entity_type, target_entity_id) are managed by _ai_context_ensure_usage_indexes() in ai_context.install.

Tracking is controlled by the usage_tracking_enabled setting (disabled by default). When disabled, all tracker methods return immediately without database access.

ai_context.children

Status: Internal

Class: Drupal\ai_context\Service\AiContextChildrenService

Provides parent/child hierarchy queries for context items and supports cleanup of child references when a parent item is deleted. Revision view pages use loadChildrenForParentAtTime() so Nav panel siblings match the child list at the viewed revision timestamp.

ai_context.item_view_builder

Class: Drupal\ai_context\Service\AiContextItemViewBuilder

Builds template variables for the ai_context_item theme hook. AiContextThemeHooks::preprocessAiContextItem() delegates to preprocess() on this service. Only the full view mode (canonical and revision routes) receives sidebar and header variables; other view modes get content field render arrays only.

Key methods:

  • preprocess(array &$variables) -- for full view mode, populates title, parent link, subcontext row, status badge, scope rows, author, nav items, and content field render arrays; bubbles cache metadata onto $variables (the top-level preprocess array ThemeManager reads). Non-full view modes only expose content.
  • buildStatus(AiContextItem $entity) -- published/moderation status label and CSS modifier, including "Published (Draft available)" when Content Moderation is enabled.
  • buildScopeRows(AiContextItem $entity) -- sidebar scope rows. Global items show only the global row (Enabled). When at least one non-global scope has values, every enabled scope row is included (global first as Disabled, empty scopes show None); otherwise returns an empty array.
  • buildScopeSection(AiContextItem $entity) -- empty-state SCOPE heading and message when global is disabled and no non-global scopes are in use. View-specific label formatting (custom site section paths, collapsed entity bundle labels) is applied in buildScopeRows().
  • addScopeViewCacheMetadata(CacheableMetadata $cacheability, AiContextItem $entity) -- adds each scope plugin's config tag (including disabled plugins, since enabled is stored in ai_context.scope_settings.*) plus taxonomy and entity cache tags for selected values on enabled plugins.

ai_context.item_validator

Status: Internal

Class: Drupal\ai_context\Service\AiContextItemValidator

Validates persistence-level invariants for context items. For subcontexts, it prevents self-parenting, nested subcontexts, and converting an item with children into a subcontext. It also requires subcontext_type when a parent is selected.

Request and result value objects

AiContextRequestParamsData

Status: Public

Class: Drupal\ai_context\Model\AiContextRequestParamsData

Immutable DTO passed to AiContextRequestFactory::fromParameters(). Centralizes validation and normalization of raw selection parameters before an AiContextRequest is built. Use AiContextRequestParamsData::fromArray() when constructing from plugin context, form values, or other untyped input.

See AiContextRequest for the fields carried into the resulting request.

AiContextRequest and selection modes

Status: Public

Class: Drupal\ai_context\Model\AiContextRequest

Immutable value object passed to AiContextSelector::select(). Built by AiContextRequestFactory::fromAgent() or fromParameters().

Constructor fields:

Field Description
task Task description or user prompt (used for conditional subcontext)
scopeSubscriptions Scope values keyed by scope plugin ID
alwaysInclude / neverInclude Item IDs to force in or out
consumerId Agent or module ID for logging only
entityType / entityId Optional target for entity/bundle matching
maxItems / maxTokens Per-request limits; NULL falls back to module settings
selectionMode minimal or match_all

Selection modes (constant SELECTION_MODE_* on the class):

  • minimal (default for fromAgent() and fromParameters()): when scope subscriptions are empty, only global items, context-auto inclusions (entity target/bundle), and always/never overrides are considered.
  • match_all: when scope subscriptions are empty, all published candidates that pass hard context filters are considered. Used by getRenderedContext() / getResult() and available to any caller that passes selection_mode: match_all explicitly.

Function call plugins expose selection_mode explicitly on get_relevant_ai_context_items.

AiContextResult

Status: Public

Class: Drupal\ai_context\Model\AiContextResult

Immutable result from AiContextSelector::select(). Implements CacheableDependencyInterface.

Methods:

Method Returns
getRenderedText(): string Token-limited context block for prompt injection
getSelectedItemIds(): string[] IDs of selected items
getSelectedItems(bool $fullData = FALSE): array Item metadata keyed by ID; $fullData includes scope, tags, subcontext fields, content snippet
getTokensUsed(): int Approximate tokens consumed by the final rendered text (recalculated after selector pipeline events)
getMaxTokens(): int Max token cap applied during rendering
getTruncatedItems(): string[] IDs of items omitted or trimmed because the token budget was insufficient
getCacheableMetadata(): CacheableMetadata Full cache metadata object
getCacheTags() / getCacheContexts() / getCacheMaxAge() CacheableDependencyInterface delegates

Example:

$result = \Drupal::service('ai_context.request_factory')->getResult(
  scopes: ['language' => ['en']],
  maxTokens: 1200,
);

$text = $result->getRenderedText();
$ids = $result->getSelectedItemIds();
$metadata = $result->getCacheableMetadata();

Plugin managers

plugin.manager.ai_context_scope

Status: Internal

Class: Drupal\ai_context\AiContextScopeManager

Plugin manager for scope plugins. Handles discovery, instantiation, and ordering of AiContextScope plugins. getScopePlugins() returns core scopes first (by plugin weight), then contrib scopes. Use getScopePluginDisplayWeights() wherever UI ordering relies on #weight (forms, local tasks). Plugin weight still controls matching/scoring priority only.

Support services

Status: Internal — All services in this section and the sections below (event subscribers, route subscribers, access checks, and other support services) are internal. They are not labeled individually; see API stability.

ai_context.markdown_renderer

Class: Drupal\ai_context\Markdown\MarkdownRenderer

Converts GitHub Flavored Markdown content to HTML for display (including tables).

logger.channel.ai_context

Standard Drupal logger channel for ai_context log messages.

Event subscribers (registered as services)

ai_context.system_prompt_subscriber

Class: Drupal\ai_context\EventSubscriber\AiContextSystemPromptSubscriber

Listens for BuildSystemPromptEvent and AgentStartedExecutionEvent. See Events.

ai_context.agent_tool_subscriber

Class: Drupal\ai_context\EventSubscriber\AiContextAgentToolSubscriber

Listens for AgentToolFinishedExecutionEvent. See Events.

ai_context.scope_config_subscriber

Class: Drupal\ai_context\EventSubscriber\AiContextScopeConfigSubscriber

Cleans stale site section scope values when site section configuration changes. See ai_context.scope_cleanup.

Route subscribers

ai_context.route_subscriber

Class: Drupal\ai_context\Routing\AiContextRouteSubscriber

Alters routes for the module.

ai_context.scope_route_subscriber

Class: Drupal\ai_context\Routing\AiContextScopeRouteSubscriber

Dynamically generates routes for per-scope settings forms based on discovered scope plugins.

Access checks

ai_context.access_check.overview_page

Class: Drupal\ai_context\Access\AiContextOverviewAccessCheck

Controls access to the overview page based on the show_overview_page setting.

ai_context.access_check.usage_page

Class: Drupal\ai_context\Access\AiContextUsageAccessCheck

Controls access to the usage tracking page based on whether tracking is enabled.

Other services

ai_context.uninstall_validator

Class: Drupal\ai_context\AiContextUninstallValidator

Runs during module uninstall validation with higher priority than core's content validator. Two responsibilities:

  1. Schema repair — installs missing content entity schemas provided by this module before core queries entity tables. Prevents fatal errors on sites where entity tables were never created (for example config-sync installs without entity updates).
  2. Blocking check — prevents uninstall while the AI Context Tags vocabulary (ai_context_tags) still has taxonomy terms. Remove terms at /admin/structure/taxonomy/manage/ai_context_tags/overview before uninstalling.

Context items themselves do not block uninstall through this validator.

Drupal\ai_context\Hook\DiffHooks

Class: Drupal\ai_context\Hook\DiffHooks

Autowired service for Diff module integration hooks.

Drupal\ai_context\Hook\DynamicEntityReferenceHooks

Class: Drupal\ai_context\Hook\DynamicEntityReferenceHooks

Autowired service for Dynamic Entity Reference module integration hooks.