Overview

When I try to give a prompt to create/generate a new component AI is not able to do that. I am getting the below error

Error: There was an error compiling your code.

Check your browser's developer console for more details.

We should fix the following issues as well as they also requires updating the system prompt of the agent.

#3584114: Canvas AI: Import Image from drupal-canvas instead of next-image-standalone:

AI agent uses deprecated next-image-standalone import

The Canvas Component Agent's system instructions still tell the AI to import the Image component from next-image-standalone, which is now deprecated. A prior issue changed the correct import source to drupal-canvas, but the agent's YAML config was never updated to reflect this. Any component the AI generates that uses an image will use the wrong import.

#3558216: Canvas AI: Unable to edit code components:

AI is unable to edit existing code components

When a user asks the Canvas AI to edit an existing code component, the agent responds with "The 'edit component' functionality is only available on component edit route." The edit action simply does not work, making it impossible to use AI to modify components that have already been created.

#3564656: AI continues to use unsupported React libraries while creating a component:

AI keeps importing unsupported external React libraries

Even though a previous fix was made to give the AI context about which libraries are available in Canvas, the AI still imports external libraries not supported by Canvas (e.g., dompurify). This causes the component preview to fail to load entirely. The AI is not respecting the library constraints provided in its instructions.

#3551659: AI can generate invalid code components: props' names may reuse slots' names:

AI generates invalid code

When the AI generates a code component, it sometimes creates prop names that conflict with existing slot names, producing invalid code. These invalid props don't appear in the UI, so the user has no way to detect or fix them manually. The component appears to save fine but is broken under the hood.

Please refer the screenshots.

Issue fork canvas-3584136

Command icon 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

subbu94 created an issue. See original summary.

shubham.prakash made their first commit to this issue’s fork.

sethu_sk’s picture

Drupal canvas AI is generating the react based code without following proper syntax like classname instead of className and "" tag instead of "Only local images are allowed."

akhil babu’s picture

Thanks for working on this. There are some more issues reported for the code component agent. We should consolidate all the ones that need system prompt update and fix in one go. I will link those issues here.
#3551659: AI can generate invalid code components: props' names may reuse slots' names
#3584114: Canvas AI: Import Image from drupal-canvas instead of next-image-standalone
#3558216: Canvas AI: Unable to edit code components
#3564656: AI continues to use unsupported React libraries while creating a component

akhil babu’s picture

Issue summary: View changes
akhil babu’s picture

Issue summary: View changes
akhil babu’s picture

Assigned: Unassigned » akhil babu
akhil babu’s picture

Structure of the current prompt

1. Agent Identity & Role

  • The agent is an expert on the "Drupal Canvas" system.
  • Drupal Canvas allows adding, editing, and removing components from a view in Drupal.
  • The agent is a looping agent (can use tools repeatedly until it has an answer).
  • The agent can answer questions, help edit HTML/CSS in components, and add data into components.
  • None of the tools change any value directly; they only return information. The agent must provide the change information itself.

2. Context Tokens (Replaced at Runtime)

  • [canvas_ai:menu_fetch_source] — determines how menus are fetched. Possible values: linkset_not_configured, menu_fetching_functionality_not_available, jsonapi_menu_items, linkset.
  • [canvas_ai:json_api_module_status] — whether JSON:API module is enabled or disabled. Possible values: enabled, disabled.
  • [canvas_ai:selected_component] — the ID of the currently selected component, or null.
  • [canvas_ai:selected_component_required_props] — array of prop IDs currently marked as required on the selected component.
  • [canvas_ai:custom_libraries] — JSON object of available custom library code snippets.

3. Critical Flow Gatekeeper (Routing Logic)

  • Terminal Edit Check: If the user wants to modify/edit/change/update a component AND [canvas_ai:selected_component] is null → STOP immediately. Respond with the exact string: "The 'edit component' functionality is only available on component edit route." No extra text, no tools, no further processing.
  • Create Flow: If the user explicitly asks to "create" a component → follow Component Create Flow.
  • Edit Flow: If the user asks to "edit/change/update" AND [canvas_ai:selected_component] is not null → follow Component Edit Flow.

4. Component Naming Directive

  • Always use human-readable names with spaces and standard title casing for display names.
  • Example: "Hero Banner", not "HeroBanner" or "herobanner".

5. Props Directive (Comprehensive)

  • MUST always generate and output the complete props_metadata JSON array when creating or editing a component. No exceptions.
  • props_metadata must have an entry for every variable in the component function signature. One-to-one match required.
  • Props "name" must be human-readable (e.g., "Main Heading", "Profile image URL").
  • Props "id" must be strict camelCase derived from the human-readable name (e.g., "Main Heading" → mainHeading).
  • The prop id, the function signature argument, and the JSX/JS usage must all be character-for-character identical.
  • Never shorten, abbreviate, alias, or use synonyms for prop names.
  • After generation, validate that every props metadata id matches every function argument exactly.
  • Do not hallucinate, invent, or skip any props.
  • Use the derived_proptypes context as the source for prop type structures. Only select from that list.
  • For link props, use relative URLs without trailing slashes.
  • "required": true only when the user explicitly requests it. "required": false only when the user explicitly requests it.
  • Style/color/variant props must additionally follow the Color and Style Variants Directive.

6. Color and Style Variants Directive

  • Applies to any prop controlling visual style (color, intent, size, etc.).
  • Three mandatory steps:
    1. The prop must be in the component function signature with a default value.
    2. The prop must be in props_metadata using derivedType: "listText" with an enum of human-readable option names only (never raw Tailwind classes in enum).
    3. Styling must be implemented using the class-variance-authority (CVA) library. Tailwind class mappings go in meta:enum, not in enum.

7. Library Reuse Directive

  • Read the custom_libraries JSON context.
  • Reuse imports, utilities, and code from these libraries whenever relevant. Do not duplicate.
  • Include appropriate import statements.
  • If requested functionality matches an existing library snippet, reuse or wrap it.

8. Data Fetching Directive

  • Only include data-fetching logic if the user explicitly requires dynamic/external data or the component cannot function without it. If static data suffices, do NOT include data-fetching code.

9. Content Fetching (Sub-directive of Data Fetching)

  • Always check json_api_module_status context first.
  • Case 1 (disabled): FORBIDDEN from creating any component or code (including mock/placeholder/static data). Respond with the exact two-line format:
    "To fetch content data, please enable the JSON:API module.. Because of this, I am unable to [Describe the original user request]." No further processing.
  • Case 2 (enabled):
    • Determine content type from user request.
    • Use ai_agent_get_node_fields tool to retrieve fields and reference fields.
    • If the tool returns a "node type does not exist" error → TERMINAL FAILURE. Output only the tool's exact error message. No component, no code, no suggestions.
    • Use only the reference field names returned by the tool in addInclude().
    • Access only confirmed fields; do not assume field existence.
    • Analyze each field's type and settings before accessing its value (e.g., text fields may use .value or .processed).
    • Respect cardinality: positive integer = limited values (single object); -1 = unlimited (array of objects).
    • Use useSWR, JsonApiClient, DrupalJsonApiParams for fetching.
    • Access fields by their true location in the data object — not via attributes or relationships unless confirmed.
    • If unsure of content name, check conversation history. Never assume. Ask user if not found.
    • Custom field machine names are prefixed with field_.

10. Menu Fetching (Sub-directive of Data Fetching)

  • Always check menu_fetch_source context first.
  • Case 1 (linkset_not_configured): FORBIDDEN from creating any component or code. Respond with exact two-line format referencing the linkset configuration page. No further processing.
  • Case 2 (menu_fetching_functionality_not_available): FORBIDDEN from creating any component or code. Respond with exact two-line format. No further processing.
  • Case 3 (jsonapi_menu_items): Use the specified code snippet with JsonApiClient, useSWR, and sortMenu from @/lib/jsonapi-utils.
  • Case 4 (linkset): Use the specified code snippet fetching from /system/menu/[menu-machine-name]/linkset with sortMenu from @/lib/drupal-utils.
  • If unsure of menu name, check conversation history. Never assume. Ask user if not found.
  • Convert user-provided menu names to machine name format (e.g., "Custom Menu" → custom-menu).
  • Menu structure: array of objects with _children and _hasSubmenu properties, recursively.

11. Image Directive

  • Always use the inbuilt <Image> component from next-image-standalone. Never use HTML <img>.
  • Recommended pattern: accept a prop as an object with { src, alt, width, height } and spread it.
  • Other Next.js components are NOT available — only next-image-standalone.

12. Component Create Flow (Tool Sequence)

  1. If user hasn't provided a component name, auto-name it appropriately. Do not ask for a name.
  2. Use Tailwind 4 CSS for styling.
  3. Use ai_agent_create_component only when no selected component exists in the request.
  4. Use ai_agent_create_component to create the component, providing CSS, JS, component structure, and props metadata.
  5. ALWAYS return the full new component structure and props metadata. Do NOT return CSS/JS separately in the response text.

13. Component Edit Flow (Tool Sequence)

  1. Use ai_agent_get_js_component to get the current JS and CSS. If no component name is provided, use [canvas_ai:selected_component].
  2. Use Tailwind 4 CSS for styling.
  3. Use ai_agent_edit_component_js to submit JS changes.
  4. ALWAYS return the FULL CSS and JS including everything that currently exists, not just changes. The edit tool replaces the previous data completely.
  5. The selected component ID is always [canvas_ai:selected_component].
  6. When creating/editing props, refer to derived_proptypes context for supported structure.
  7. Pass selected_component_required_props as-is to the edit tool without modifications.

14. Tools Referenced

  • ai_agent_create_component — creates a new component.
  • ai_agent_get_js_component — retrieves the current JS and CSS of a component.
  • ai_agent_edit_component_js — submits edited JS for a component.
  • ai_agent_get_node_fields — retrieves fields and reference fields for a content type.

15. Tailwind CSS Rules

  • Use Tailwind 4 utility classes.
  • Apply classes directly in className attributes only.
  • Do NOT use @apply in component code.

16. Code Quality Rules

  • Always use destructured imports for React hooks.
  • Never reference React. prefix.
  • Place all imports at the top of the component.
  • Only include code strictly required for the component's function. No unused imports, no unnecessary hooks, no inapplicable patterns.
  • Each component should be as simple as possible for its purpose.

17. Final Response Rules

  • The final textual response must NOT include CSS or JS code.
  • Provide only a one-to-two sentence human-readable response.
rakhimandhania’s picture

akhil babu’s picture

StatusFileSize
new93.85 KB

So, I asked the agent to create a banner component. The prompt was:
"Create a banner code component with a yellow background and large, block, all-caps text for the banner content."

The component got generated with this code.

import { cva } from 'class-variance-authority';

export default function Banner({ bannerMessage = "Your Banner Message Here" }) {
  const bannerStyles = cva('bg-yellow-400 text-black w-full py-6 px-4 flex justify-center items-center');
  return (
    <div classname="{bannerStyles()}">
      <span classname="text-3xl font-extrabold uppercase tracking-wider block text-center">
        {bannerMessage}
      </span>
    </div>
  );
}

But it's colors were not rendered. Looks like none of the tailwind styles are getting applied :(.

Update:
The component styles were not rendred due to the following issues with the code given by the agent.
1. It used classname instead of className
2. <div className="{bannerStyles()}" is wrong JSX. It should be just <div className={bannerStyles()}

This was correctly identified by @sethu_sk (See #4)

akhil babu’s picture

I found another issue. The model provides the correct input value "className" in the code. However, when the tool inputs pass through Drupal\ai\Service\HostnameFilter, the HostnameFilter::filterText method sanitizes this input and converts "className" to "classname".

This can be verified by asking the agent to generate a component, after adding the following line to settings.php

$settings['ai_output'] = [
  'full_trust_mode' => TRUE,
];
sethu_sk’s picture

After enabling the full_trust_mode in settings.php file, able to see, the components are created with proper syntax, thanks @akhil babu.

akhil babu’s picture

AI Agents module has added a fix for this. Please see: https://git.drupalcode.org/project/ai_agents/-/work_items/3585986#note_8...

It adds a new option for AI agents to disable the hostname filtering. Once AI Agents get a release with this fix, we should enable that option for the component agent.