Canvas AI: Add the set_page_value AI tool (+ kernel test)
## Summary
Add a new AI tool `canvas_ai:set_page_value` (class `SetPageValue`) to `canvas_ai`, ported from the POC (MR !1214). A single key-based tool that sets the page `title` or meta `description`. It lands **inert** — no agent lists it yet. Add a kernel test.
## Why (this sprint)
`set_page_value` consolidates three separate page-field tools into one. In the flat-agent architecture the orchestrator sets page fields directly, so the old `create_field_content`, `edit_field_content`, and `add_metadata` tools (and the title/metadata sub-agents that drove them) collapse into a single tool keyed by the field being set. It is trivial deterministic PHP — no services, no layout — so it can land now, tested, in parallel. Additive and inert on landing; the old tools remain until graduation.
- Roadmap: https://git.drupalcode.org/project/canvas/-/work_items/3591777
- Reference implementation (POC, no test in the MR): https://git.drupalcode.org/project/canvas/-/merge_requests/1214
## What to build
Port `SetPageValue` from the POC to `canvas_ai` under the final ID `canvas_ai:set_page_value`. It is the simplest tool: no injected services and no validation — just a switch on `key`.
- **Arguments.** `key` (required, string; allowed values `title` or `description`) and `value` (required, string).
- **Interfaces.** `final class SetPageValue extends FunctionCallBase implements ExecutableFunctionCallInterface, AiAgentContextInterface, BuilderResponseFunctionCallInterface`. `module_dependencies: ['canvas']`, `group: 'modification_tools'`.
### Change vs the POC: emit `canvas_page_data` directly
The POC tool emits intermediate keys (`created_content`, `metadata.metatag_description`) that the controller then rewrites into the UI shape via `CanvasAiPageBuilderHelper::processCanvasPageFields()`. Have the tool emit the final shape itself, so it is self-contained and no controller post-processing is needed:
- `key = title` → `setStructuredOutput(['canvas_page_data' => ['title[0][value]' => $value]])`, readable output `Page title set successfully.`
- `key = description` → `setStructuredOutput(['canvas_page_data' => ['description[0][value]' => $value]])`, readable output `Page description set successfully.`
- unknown `key` → no structured output; readable output `Unknown page value key "<key>". Allowed keys are: title, description.`
`title[0][value]` / `description[0][value]` is exactly the shape `processCanvasPageFields()` produced under `canvas_page_data`, which the UI already consumes.
**Do not remove `processCanvasPageFields()` in this issue.** The live `create_field_content` / `edit_field_content` / `add_metadata` tools still depend on it (`CanvasBuilder.php:276`). Making `set_page_value` self-contained is what lets that method — and those tools — be deleted at graduation; the deletion itself is a graduation step.
### Inert on landing
Do **not** add `set_page_value` to any agent's tool list. It ships as an available plugin only; wiring it to the dev agent is a later issue.
## Tests
New kernel test `modules/canvas_ai/tests/src/Kernel/Plugin/AiFunctionCall/SetPageValueTest.php` extending `CanvasKernelTestBase`. Cover the three branches:
- **Title.** `key=title`, `value=…` → `getStructuredOutput()` equals `['canvas_page_data' => ['title[0][value]' => …]]`; readable output `Page title set successfully.`
- **Description.** `key=description` → `['canvas_page_data' => ['description[0][value]' => …]]`; readable output `Page description set successfully.`
- **Unknown key.** `key=body` → empty structured output; readable output contains `Unknown page value key "body"`.
## Explicitly NOT doing
- Not removing `processCanvasPageFields()` or the old `create_field_content` / `edit_field_content` / `add_metadata` tools (graduation).
- Not wiring `set_page_value` to any agent.
- Not building `get_component_details` — separate issue.
---
_Issue generated with AI assistance._
issue