Custom Scopes
You can extend the scope system by creating custom scope plugins in your own modules.
Creating a custom scope plugin
- Create a class that extends
AiContextScopeBase - Place it in
src/Plugin/AiContextScope/within your module - Add the
#[AiContextScope]attribute with plugin metadata - Implement
getValues()to return available scope values
Example
namespace Drupal\my_module\Plugin\AiContextScope;
use Drupal\ai_context\Attribute\AiContextScope;
use Drupal\ai_context\Plugin\AiContextScope\AiContextScopeBase;
use Drupal\Core\StringTranslation\TranslatableMarkup;
#[AiContextScope(
id: 'department',
label: new TranslatableMarkup('Department'),
description: new TranslatableMarkup('Department this context applies to.'),
weight: 0,
)]
class AiContextScopeDepartment extends AiContextScopeBase {
public function getValues(): array {
return [
'marketing' => $this->t('Marketing'),
'engineering' => $this->t('Engineering'),
'sales' => $this->t('Sales'),
];
}
}
The plugin is automatically discovered by the AiContextScopeManager.
Clear caches after adding a new plugin.
Automatic routes and settings tabs
When a scope plugin is discovered, the module automatically generates:
- A settings route named
ai_context.settings.scope.{plugin_id}at the URL path/admin/config/ai/context/settings/scope/{plugin-id}. - A local task tab under the Scope settings page, using the plugin's
labelas the tab title.
Custom scopes always appear after the built-in scopes from the
ai_context module in context item forms, the Details panel, and scope
settings tabs. Within each group (core or custom), weight controls order
(lower appears first). You do not need to define routes or local tasks
manually.
Plugin ID vs URL path
The plugin ID and the URL path use slightly different conventions:
- Route name keeps the plugin ID verbatim, including underscores. For
example, the
target_entityscope produces the route nameai_context.settings.scope.target_entity. - URL path converts underscores to dashes for readability, so the same
scope is served at
/admin/config/ai/context/settings/scope/target-entity.
When linking to a scope settings page from your own code (for example, from
getManageRoute()), always use the route name with underscores -- never the
URL path:
return ['route_name' => 'ai_context.settings.scope.target_entity'];
When the route has placeholders, also include route_parameters (see the
getManageRoute() examples below).
If a scope plugin is removed (e.g., by uninstalling a module or via
hook_ai_context_scope_info_alter()),
its route and tab are removed
automatically. The scope plugin manager invalidates the local_task cache
tag whenever its definitions are cleared, so derived tabs stay in sync
without a full cache rebuild.
Attribute parameters
| Parameter | Type | Description |
|---|---|---|
id |
string |
Unique plugin ID |
label |
TranslatableMarkup |
Human-readable label |
description |
TranslatableMarkup\|null |
Description shown on context item forms |
weight |
int |
Matching/scoring priority among scopes in the same group (core vs custom). Lower = processed first during selection. UI order within each group comes from getScopePluginDisplayWeights(), not this value alone. |
deriver |
string\|null |
Optional deriver class |
Optional overrides
The base class provides sensible defaults. Override these methods to customize behavior:
supportsSubscriptions()
Return FALSE to hide this scope from agent configuration forms. Useful for
scopes that apply automatically (like Global or Target Entity).
public function supportsSubscriptions(): bool {
return FALSE;
}
allowsMultiple()
Return FALSE to render radio buttons instead of checkboxes (single
selection).
isDynamic()
Return TRUE if values come from an external source (database, config, API)
rather than being hardcoded. Dynamic scopes may change at runtime.
getCurrentValue()
Return the currently active value for contextual detection. For example, the Language scope returns the current language, and the Site Section scope returns the matching section for the current URL.
matchesCurrentContext()
Implement custom matching logic for how this scope determines whether a context item matches the current request context.
getManageRoute() and getManageLabel()
Provide a link to an admin page where this scope's values can be managed.
Return a route info array from getManageRoute(), and the link text from
getManageLabel().
Most scope settings routes need only route_name:
public function getManageRoute(): ?array {
return ['route_name' => 'ai_context.settings.scope.target_entity'];
}
When the route has placeholders, include route_parameters as well (as the
Tag scope does for its vocabulary overview page):
public function getManageRoute(): ?array {
return [
'route_name' => 'entity.taxonomy_vocabulary.overview_form',
'route_parameters' => ['taxonomy_vocabulary' => 'ai_context_tags'],
];
}
buildSettingsForm(), validateSettingsForm(), submitSettingsForm()
Add custom settings beyond the default enabled checkbox.
For full API details, see the Scope API reference.
Altering scope values
Use hook_ai_context_scope_values_alter() to add, modify, or remove values
from any scope plugin without writing a full plugin. See
Hooks.
function my_module_ai_context_scope_values_alter(
array &$values,
string $scope_id,
): void {
if ($scope_id === 'use_case') {
$values['custom_workflow'] = t('Custom Workflow');
}
}
Parameters:
$values-- associative array ofvalue_id => labelpairs (passed by reference)$scope_id-- the plugin ID of the scope being altered (e.g.,use_case,language,site_section)