Summary
Add a scope plugin that includes a context item when the AI request carries one of the tags the item is scoped to. Tags here are the strings the ai module records on a provider call — set via AiProviderInterface::setTag() / the $tags argument to chat(), and surfaced on the provider request events as AiProviderRequestBaseEvent::getTags() (e.g. an operation type, ai_ckeditor, or a caller-defined tag like ai_empathy_scenario:5).
Problem / motivation
ai_context today has a tag scope, but it keys on taxonomy term IDs (ai_context_tags vocabulary) matched via agent subscriptions. There is no way to scope a context item to the runtime AI request tags the ai module already tracks. Consumers that are not agents (ai_ckeditor, custom callers, ai_empathy evaluations) tag their provider calls but cannot use those tags to select context.
Related: #3581955 (inject context into ai_ckeditor requests) matches on entity type/ID; request-tag matching is a complementary mechanism that would let CKEditor (and any consumer) also target context by the operation/tags on the call.
The one design constraint
Context is injected into the prompt before the provider request is sent, so a scope cannot wait for ai.pre_generate_response to learn the tags — by then the input (with context) is already built. The request's tags must be made available to context selection up front. This is the only genuinely new integration required; the rest is a standard scope plugin.
Proposed approach
-
New
request_tagscope plugin:- Selectable tags are an admin-defined list on the scope's settings form (mirrors the
entity_bundlescope), rendered as checkboxes on each context item. Values are plain tag strings, not taxonomy term IDs. supportsSubscriptions()stays TRUE, so items are matched by intersecting the request's tags with the item's selected tags through the existing resolver scoring;doGetCurrentValue()returns NULL (no ambient page value).
- Selectable tags are an admin-defined list on the scope's settings form (mirrors the
-
A supported way for callers to declare the request's tags — pick one:
- (a) Recommended: add a
requestTagsfield toAiContextRequest(and a param onAiContextRequestFactory::fromParameters()/getRenderedContext()) that callers populate. Simple and explicit; reuses the existingscopeSubscriptionsmachinery; no changes to theaimodule. - (b) Alternative: a request-scoped "current AI request tags" collector, populated where callers call
$provider->setTag()and, where the flow allows, fromai.pre_generate_response. More automatic but heavier.
- (a) Recommended: add a
Working prototype
A functioning implementation already exists in the ai_empathy_ccc submodule of the ai_empathy project and can be lifted into ai_context:
AiContextScopeRequestTag— the scope plugin (admin-defined tag list + checkboxes; subscription matching;ai_context.scope_settings.request_tagconfig).- The empathy evaluator surfaces its request tags (
ai_empathy,ai_empathy_scenario:<id>,ai_empathy_run:<n>) on its prompt-alter event, and the subscriber passes them viagetRenderedContext(scopes: ['request_tag' => $tags]). - A kernel test proves that with
SELECTION_MODE_MATCH_ALL(asgetRenderedContext()uses), arequest_tagsubscription restricts inclusion to matching items (plus globals) — it does not merely reorder — confirming the resolver already supports this end-to-end.
Moving it upstream mainly requires deciding mechanism (a) vs (b) so any consumer — agents, ai_ckeditor — can declare request tags, not just ai_empathy.
Proposed resolution
- Add
AiContextScopeRequestTagplugin + settings form + config/schema. - Decide (a) vs (b) and expose request tags to selection.
- Kernel test for tag-restricted inclusion; update docs (custom scopes).
Related issues
Issue fork ai_empathy-3610965
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #3
joshua1234511Comment #4
joshua1234511Comment #5
joshua1234511Comment #6
joshua1234511Comment #8
joshua1234511Comment #10
joshua1234511Comment #11
nitinkumar_7 commentedI was checking this issue and writing this comment but not able to submit on time :)
I think this is a clean solution to the problem of making request tags available during context resolution, and the implementation fits well with the existing scope system.
I only have one concern and suggestion before this is marked RTBC. It would be good to add a kernel test covering the case where no request tags are provided. Specifically, verify that a context item scoped only with request_tag is excluded when the request tag list is empty. The current tests cover matching tags and global context, but this boundary case would help ensure the resolver behaves as expected.
Other than that, the implementation look good to me.
Comment #12
joshua1234511Thanks again, @nitinkumar_7. I've opened a follow-up to add the empty request-tag-list boundary test: #3612824.
Since 1.2.0 is already released, I'd like to keep this issue as fixed and handle the additional coverage there. Marking fixed.
Since you spotted the gap, feel free to pick it up if you'd like — I've written up the proposed test method in the summary to make it an easy start. Happy to review a patch/MR whenever it suits you. Otherwise I'll get to it in due course.