Canvas AI - fix deprecated Image import, unsupported package handling, prop/slot name collision, hardcoded error messages, and add slots support
> [!note] Migrated issue
>
> <!--Drupal.org comment-->
>
> <!--Migrated from issue #3584136.-->
>
> Reported by: [subbu94](https://www.drupal.org/user/3513305)
>
> Related to !907
### Overview
The `canvas_component_agent` system prompt in `ai_agents.ai_agent.canvas_component_agent.yml` contains several bugs that cause the agent to generate invalid or broken code components. These problems were surfaced across four related issues: \[#3584114\], \[#3558216\], \[#3564656\], and \[#3551659\]. This issue consolidates them so they can be fixed together in a single pass over the agent configuration.
### Acceptance criteria
When this issue is resolved, the following should all be true when tested against OpenAI GPT-4.1 and Claude Sonnet 4.6. Validation should be done against `drupal/ai_agents` 1.2.4, not 1.3 as the fix in #3590309 targets that version.
- Asking the agent to create a component that includes an image produces code that imports from `drupal-canvas`, not `next-image-standalone`.
- Asking the agent to use a library not available in Canvas (e.g. `dompurify`) results in the agent declining and explaining the limitation, not generating broken code.
- Asking the agent to create a component where a prop and a slot would share the same name results in a valid component with no naming conflict.
- Editing a code component via Canvas AI works. Selecting a component in the editor and asking the agent to change it does not produce an error.
- When the agent cannot fulfill a request due to missing context (no component selected, menu fetching unavailable), it responds with natural-language guidance telling the user what to do, not a hardcoded string.
- Users can ask the agent to create a code component with one or more slots, and the resulting component accepts child components in those slots in the Canvas editor.
### Out of scope of this ticket
The following are related gaps but will be tracked in separate issues once the bugs above are stabilized:
- **Multi-valued props**: Teaching the agent to generate components where a prop holds an array of structured items.
- **Importing other components**: Teaching the agent to import and compose existing Canvas components inside a new code component (see https://project.pages.drupalcode.org/canvas/code-components/imports-and-assets/).
### Bug 1: Deprecated `next-image-standalone` import (from \[#3584114\])
The system prompt currently instructs the agent to import the `Image` component from `next-image-standalone`:
```js
import Image from 'next-image-standalone';
```
The `next-image-standalone` package is deprecated. A prior change introduced the correct import source (`drupal-canvas`), but the agent YAML was never updated. Any component the agent generates that uses an image will import from the wrong package and fail at runtime. See https://project.pages.drupalcode.org/canvas/code-components/responsive-images/ for the current recommended approach to images in Canvas code components.
The system prompt also contains the note "Note that while next-image-standalone can be imported, other Next.js components are not available." This line must be removed entirely because it is both incorrect and misleading.
### Bug 2: Agent uses unsupported external libraries (from \[#3564656\])
Despite the system prompt including a `custom_libraries` context that lists all available libraries, the agent still imports unsupported packages when asked for functionality that seems to match them. For example, asking the agent to "create a component that renders unsafe HTML content safely" results in code that imports `dompurify`, which is not available in the Canvas runtime. The preview then fails to load.
The `custom_libraries` constraint alone is not enforced strongly enough. The system prompt does not explicitly forbid importing any package not present in `custom_libraries`. The current list of supported packages is documented at https://project.pages.drupalcode.org/canvas/code-components/packages/.
### Bug 3: Prop names can reuse slot names, producing invalid components (from \[#3551659\])
The agent can generate a component where a prop ID is identical to a slot name. This produces an invalid `JavaScriptComponent` config entity. The invalid props are not displayed in the Canvas UI, so users have no way to correct the conflict through the editor. The agent's current validation step only checks that every prop ID matches the corresponding function argument. It does not check that prop IDs are distinct from slot names.
Steps to reproduce:
1. Ask the agent to create a component that has both named slots and props, for example: "Create a header component with a navigation slot and a navigation prop for fallback link text."
2. Observe that the generated component has a prop ID identical to a slot name (e.g., both named `navigation`).
3. Save the component and open it in the Canvas editor. The conflicting prop is not shown in the UI.
### Bug 4: Unhelpful error when editing a component without a selected component context (from \[#3558216\])
When a user asks the Canvas AI to edit a code component but the context variable `[canvas_ai:selected_component]` is null (for example, because the user has not opened a code component), the agent returns the exact hardcoded string:
> "The 'edit component' functionality is only available on component edit route."
This message gives the user no actionable guidance. A similar pattern exists for menu fetching: when `menu_fetch_source` is `menu_fetching_functionality_not_available` or `linkset_not_configured`, the agent is instructed to return exact two-line hardcoded responses. These rigid formats are hard to maintain and do not help users understand what to do next.
### Bug 5: Agent cannot add slots to code components
The agent has no knowledge of slots for code components. Slots allow a component to accept child components placed by the Canvas editor. `Drupal\canvas_ai\Plugin\AiFunctionCall\CreateComponent` and `Drupal\canvas_ai\Plugin\AiFunctionCall\EditComponentJs` currently accept no `slots_metadata` context, so even if the system prompt described slots, the agent has no mechanism to pass slot definitions through to the component.
### Steps to reproduce bugs 1 and 2
1. Install Canvas with the `canvas_ai` sub-module enabled.
2. Open the Canvas AI chat interface on any Canvas page.
3. Ask the agent: "Create a component that shows a profile photo with a name."
4. Observe that the generated JS contains `import Image from 'next-image-standalone'` instead of `import Image from 'drupal-canvas'`.
5. Ask the agent: "Create a component that renders unsafe HTML content safely."
6. Observe that the generated JS imports `dompurify` or another unsupported external package. The preview fails to load.
### Proposed resolution
All of these issues require updating the system prompt in `modules/canvas_ai/config/install/ai_agents.ai_agent.canvas_component_agent.yml`. They are grouped in a single issue so the prompt can be revised and tested as a unit.
The easiest way to approach this is to send the current system prompt, the issues identified here, and the reference documentation to a higher-end model such as Claude Opus 4.8 or Gemini 3.5 Pro (available in Google AI Studio). Give it the persona of a prompt engineer and ask it to produce a revised prompt that fixes all of the identified problems. Then refine that prompt by running the testing scenarios from the remaining tasks section and iterating until the acceptance criteria pass.
The revised prompt must also be written with extensibility in mind. New functionality and new tools will be added to the component agent over time. The prompt should be structured so that adding something new, for example a tool that lets users query the Canvas code components documentation directly, does not require a complete prompt restructuring.
Two methods in `Drupal\canvas_ai\Controller\CanvasBuilder` are also directly relevant:
- `Drupal\canvas_ai\Controller\CanvasBuilder::getSupportedLibraries()` builds the `custom_libraries` context the agent already receives. Any library instruction in the prompt must be consistent with what this method returns at runtime.
- `Drupal\canvas_ai\Controller\CanvasBuilder::getMenuFetchSource()` sets the `menu_fetch_source` context. The prompt already branches on this value to decide which menu-fetching approach to use.
The final prompt should be validated against GPT-4.1 and Claude Sonnet 4.6 before the issue is marked fixed.
### Remaining tasks
- Update `ai_agents.ai_agent.canvas_component_agent.yml` to fix all bugs and remove the hardcoded response strings.
- Extend `Drupal\canvas_ai\Plugin\AiFunctionCall\CreateComponent` and `Drupal\canvas_ai\Plugin\AiFunctionCall\EditComponentJs` to accept a `slots_metadata` context, and update the system prompt to teach the agent how to define slots.
- There are currently no automated tests for the code component agent. As part of this issue, build a set of manual testing prompts that cover the scenarios described above and can be run against both GPT-4.1 and Claude Sonnet 4.6 to confirm correct behavior.
_Issue description generated with AI assistance._
issue