Issue #3591882: Add an Agents & Tools settings form.
Adds the Agents & Tools settings form to canvas_dev_ai, populating
drupalSettings.canvas.ai.tools for the dropdown in #3591856.
AI-Generated: Yes (Used Claude Code to help write the form, the two test classes and this description. All of it was reviewed, run and manually verified locally — see Testing instructions below.)
What changed
New in canvas_dev_ai:
src/Form/CanvasDevAiAgentSelectionForm.php—ConfigFormBasewith a requiredmain_agentselect and atoolscheckboxes element, both built from theai_agentconfig entities filtered to the three Canvas chat agents. Validation rejects selecting the main agent as a Tool.canvas_dev_ai.links.task.yml— fourth local task,base_route: canvas_ai.setting, weight 30 (existing tabs are 0/10/20).config/schema/canvas_dev_ai.schema.yml— schema forcanvas_dev_ai.settings.config/install/canvas_dev_ai.settings.yml— defaults.
Edited in canvas_dev_ai:
canvas_dev_ai.routing.yml— addedcanvas_dev_ai.agent_selection.src/Hook/CanvasDevAiHooks.php—jsSettingsAlter()now emitscanvas.ai.toolsalongside the existingaiDevModeflag.
New tests in canvas_ai (where the dev module's coverage lives, per the
issue and the existing CanvasAiDevControllerTest):
tests/src/Kernel/CanvasDevAiAgentSelectionTest.php— 3 tests / 17 assertions: Tools exposed to JS withlabel/descriptionread from theai_agententities, no key emitted when no Tools are selected, and uninstall removing the config object and the JS key.tests/src/Functional/Form/CanvasDevAiAgentSelectionFormTest.php— 3 tests / 27 assertions: the tab is present under the settings route and gone after uninstall; the form saves both values; the main-agent-as-Tool submission is rejected.
Config stores only agent IDs; labels and descriptions are read from the
ai_agent entities at runtime, as the issue specifies.
Note: component_agent → canvas_component_agent
The issue summary lists component_agent, but the shipped entity is
canvas_component_agent. Confirmed with @AkhilBabu that this is a typo in the
summary, so the prefixed ID is used here.
Question: which permission?
I used _permission: 'use Drupal Canvas AI' because it matches the base route
canvas_ai.setting. Note the sibling tabs are inconsistent —
canvas_ai.theme_region_settings uses use Drupal Canvas AI while
canvas_ai.component_description_settings uses administer components. Happy to
switch if administer components is preferred for settings forms.
Note: the local task assertion lives in the functional test
The issue lists local task availability among the kernel test's assertions, but asserting it there means enumerating local task definitions, which runs core's views local-task deriver. In a kernel test views' routes are not built, so the deriver emits:
views/src/Plugin/Derivative/ViewsLocalTask.php:82
Trying to access array offset on nullPHPUnit exits non-zero on any warning, so the kernel job failed despite every
assertion passing. #[WithoutErrorHandler] did not suppress it.
The assertion is therefore in the functional test, where routes are built and no
warning occurs — and where it checks something stronger: that the tab is actually
rendered under canvas_ai.setting, and is gone once canvas_dev_ai is
uninstalled. This needs block in $modules and
drupalPlaceBlock('local_tasks_block'), since the test profile places no blocks
and local tasks would otherwise not render at all.
Happy to move it back if you'd prefer it in the kernel test with the warning handled some other way.
Testing instructions
- Enable
canvas_dev_ai(drush en canvas_dev_ai -y). - Go to
/admin/config/ai/canvas-ai-settings. Confirm a fourth Agents & Tools tab appears after Page Region Descriptions. - On that tab, confirm the dropdown and checkboxes offer exactly three agents
— Orchestrator, Component Agent, Page Builder Agent — and not the other
ai_agententities on the site. - Confirm the shipped defaults are pre-selected: Orchestrator as main agent, Component Agent and Page Builder Agent ticked.
- Set the main agent to Component Agent while leaving it ticked as a Tool and save. Expect: The main agent cannot also be offered as a Tool.
- Set the main agent to Page Builder Agent, tick only Component Agent, save. Expect the saved-configuration message.
-
drush cget canvas_dev_ai.settings— expectmain_agent: canvas_page_builder_agentandtools:containing onlycanvas_component_agent, i.e. IDs with no labels. - Open the Canvas editor and check
drupalSettings.canvas.ai.toolsin the browser console. Expect one entry withid,labelanddescriptionfor Component Agent, and no main agent in the payload. - Untick all Tools, save, reload the editor. Expect no
canvas.ai.toolskey at all. - Uninstall
canvas_dev_ai. Expect the tab, the config object and thecanvas.ai.toolskey all to disappear.
Verification already done
- Both new test classes pass on MariaDB, and the kernel class also exits 0 on SQLite — the configuration the earlier pipeline failed on.
canvas_aikernel suite: 140 tests pass with these changes, includingCanvasAiDevControllerTest, which covers thejsSettingsAlter()method edited here. (10 of those tests needdrupal/ai_agents_test, which is in Canvas'srequire-devand so is not present when Canvas is installed as a site dependency — it had to be added locally to run the full suite.)phpcs --standard=Drupal,DrupalPracticeclean over all changed files.- PHPStan level 8 clean over the changed files apart from
missingType.iterableValue, whichphpstan.neonignores globally, and the two findings from the\assert($admin_user instanceof …)line insetUp()— that line is copied fromCanvasAiComponentDescriptionSettingsFormTest::setUp(), which reports the identical pair. Happy to drop the assert if you'd rather the new file be clean. (Canvas's ownphpstan.neoncould not be run locally: it referencesCanvas\PHPStan\Rules\*classes that are only autoloadable when Canvas is the root composer project.) - All the manual steps above were performed, with one exception: reading
drupalSettings.canvas.ai.toolsin the editor.ui/distis not committed on1.x(built assets are added at release time), so the editor does not boot from a dev checkout. That payload is asserted in the kernel test instead, and was verified by invokinghook_js_settings_alter()directly.
Closes #3591882