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 fromai_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 itemgetItemIdsByScopeValues(string $scopeId, array $values): int[]— items matching any of the given values for one scopegetItemIdsByScope(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 indexremoveTargetEntityReference(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 usingcontext_item_id IN (...).attachEntity()batches duplicate checks for entity-specific records.recordToolUsed()buffers tool IDs in memory; callflushToolsUsed()once per agent run (handled automatically byAiContextAgentFinishedSubscriberonAgentFinishedExecutionEvent).- Lookup indexes on
runner_id,changed, and(target_entity_type, target_entity_id)are managed by_ai_context_ensure_usage_indexes()inai_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, andcontentfield render arrays; bubbles cache metadata onto$variables(the top-level preprocess array ThemeManager reads). Non-full view modes only exposecontent.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 inbuildScopeRows().addScopeViewCacheMetadata(CacheableMetadata $cacheability, AiContextItem $entity)-- adds each scope plugin's config tag (including disabled plugins, sinceenabledis stored inai_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 forfromAgent()andfromParameters()): 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 bygetRenderedContext()/getResult()and available to any caller that passesselection_mode: match_allexplicitly.
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:
- 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).
- 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/overviewbefore 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.