From 78451cbd146d88d26a73f7a1a36753effa9e6206 Mon Sep 17 00:00:00 2001 From: AKHIL BABU Date: Wed, 10 Jun 2026 21:00:26 +0530 Subject: [PATCH 1/2] Canvas Real time page updates POC- Chicago demo --- composer.json | 9 +- composer.lock | 171 ++++-- custom_recipes/ai_context_setup/recipe.yml | 40 +- ...agents.ai_agent.canvas_ai_orchestrator.yml | 563 +++++++----------- .../findrop/config/canvas_ai.settings.yml | 2 + patches.lock.json | 28 +- 6 files changed, 336 insertions(+), 477 deletions(-) diff --git a/composer.json b/composer.json index 0ed0b7b..f40502d 100644 --- a/composer.json +++ b/composer.json @@ -19,11 +19,12 @@ "composer/composer": "^2.8", "composer/installers": "^2.3", "cweagans/composer-patches": "~2.0", + "drupal/ai": "^1.3", "drupal/ai_agents": "^1.2", - "drupal/ai_context": "1.0.x-dev#cee7d3d", + "drupal/ai_context": "^1.0@beta", "drupal/ai_vdb_provider_milvus": "^1.1@beta", "drupal/byte": "^1", - "drupal/canvas": "1.x-dev#0bff26f", + "drupal/canvas": "1.x-dev#7711076993ee71f00a9e4c022aecfb2e7151bc15", "drupal/core-composer-scaffold": "^11.3", "drupal/core-project-message": "^11.3", "drupal/core-recipe-unpack": "^11.3", @@ -112,9 +113,7 @@ "Navigation fatal error on 404 pages (3565886)": "patches/drupal/navigation.patch" }, "drupal/canvas": { - "issues-3549232-3533079-3545816-3558241-3548718-3551315-3569120-3571988-3541873": "patches/canvas/issues-3549232-3533079-3545816-3558241-3548718-3551315-3569120-3571988-3541873.patch", - "Update AiPanel and AiWizard components": "patches/canvas/canvas-content-performance.patch", - "Unable to publish content with a large JSON in the schema_jsonld field": "patches/canvas/fix-long-json-in-schema_jsonld-field-blocks-page-publishing.patch" + "POC": "https://git.drupalcode.org/project/canvas/-/merge_requests/1214/diffs.patch" }, "drupal/byte_theme": { "Remove default aspect ratio from icon card": "patches/byte_theme/remove-default-aspect-ration-from-icon-card-component.patch" diff --git a/composer.lock b/composer.lock index b4d05bc..6911038 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "02c696a74ab92c32b17eb306495368c5", + "content-hash": "42a93cd09325fb741bcd8ed28e01ebfc", "packages": [ { "name": "asm89/stack-cors", @@ -1817,17 +1817,17 @@ }, { "name": "drupal/ai", - "version": "1.3.0-rc2", + "version": "1.4.1", "source": { "type": "git", "url": "https://git.drupalcode.org/project/ai.git", - "reference": "1.3.0-rc2" + "reference": "1.4.1" }, "dist": { "type": "zip", - "url": "https://ftp.drupal.org/files/projects/ai-1.3.0-rc2.zip", - "reference": "1.3.0-rc2", - "shasum": "cb0efcd34cedecb4a48d901a78bb06aa7eb7ab7c" + "url": "https://ftp.drupal.org/files/projects/ai-1.4.1.zip", + "reference": "1.4.1", + "shasum": "8f7ecf9b75194d306443c72ca686707a55334d46" }, "require": { "drupal/core": "^10.5 || ^11.2", @@ -1857,11 +1857,11 @@ "type": "drupal-module", "extra": { "drupal": { - "version": "1.3.0-rc2", - "datestamp": "1772193193", + "version": "1.4.1", + "datestamp": "1780493201", "security-coverage": { - "status": "not-covered", - "message": "RC releases are not covered by Drupal security advisories." + "status": "covered", + "message": "Covered by Drupal's security advisory policy" } } }, @@ -1918,6 +1918,10 @@ "name": "murz", "homepage": "https://www.drupal.org/user/157092" }, + { + "name": "mxr576", + "homepage": "https://www.drupal.org/user/315522" + }, { "name": "robloach", "homepage": "https://www.drupal.org/user/61114" @@ -1941,6 +1945,10 @@ { "name": "yautja_cetanu", "homepage": "https://www.drupal.org/user/626050" + }, + { + "name": "ahmad khader", + "homepage": "https://www.drupal.org/user/3727855" } ], "description": "AI module for Drupal", @@ -2056,20 +2064,20 @@ }, { "name": "drupal/ai_agents", - "version": "1.2.3", + "version": "1.3.0", "source": { "type": "git", "url": "https://git.drupalcode.org/project/ai_agents.git", - "reference": "1.2.3" + "reference": "1.3.0" }, "dist": { "type": "zip", - "url": "https://ftp.drupal.org/files/projects/ai_agents-1.2.3.zip", - "reference": "1.2.3", - "shasum": "a31a58f3a37048e2706c5bd9bed251d670755989" + "url": "https://ftp.drupal.org/files/projects/ai_agents-1.3.0.zip", + "reference": "1.3.0", + "shasum": "676787dc830587fde80bde4658d1428ed5616333" }, "require": { - "drupal/ai": "^1.2.0", + "drupal/ai": "^1.4.0", "drupal/core": "^10.2 || ^11", "drupal/modeler_api": "^1.0.3" }, @@ -2084,8 +2092,8 @@ "type": "drupal-module", "extra": { "drupal": { - "version": "1.2.3", - "datestamp": "1772092822", + "version": "1.3.0", + "datestamp": "1779962575", "security-coverage": { "status": "covered", "message": "Covered by Drupal's security advisory policy" @@ -2097,6 +2105,10 @@ "GPL-2.0-or-later" ], "authors": [ + { + "name": "a.dmitriiev", + "homepage": "https://www.drupal.org/user/3235287" + }, { "name": "akhil babu", "homepage": "https://www.drupal.org/user/3632866" @@ -2105,6 +2117,10 @@ "name": "andrewbelcher", "homepage": "https://www.drupal.org/user/655282" }, + { + "name": "harivansh", + "homepage": "https://www.drupal.org/user/3678656" + }, { "name": "jurgenhaas", "homepage": "https://www.drupal.org/user/168924" @@ -2133,41 +2149,44 @@ }, { "name": "drupal/ai_context", - "version": "dev-1.0.x", + "version": "1.0.0-beta2", "source": { "type": "git", "url": "https://git.drupalcode.org/project/ai_context.git", - "reference": "cee7d3d3c2abddaf09ca270701881517915d2413" + "reference": "1.0.0-beta2" + }, + "dist": { + "type": "zip", + "url": "https://ftp.drupal.org/files/projects/ai_context-1.0.0-beta2.zip", + "reference": "1.0.0-beta2", + "shasum": "e3927e8cb4388ec49be5d1d5e404e009e85b0537" }, "require": { "drupal/ai": ">=1.3.0-rc2@RC || ^2", "drupal/ai_agents": "^1.2", "drupal/core": "^10.5 || ^11.2", - "drupal/diff": "^1.0", - "drupal/dynamic_entity_reference": "^3.2", "drupal/scheduler": "^2.2", "drupal/scheduler_content_moderation_integration": "^3.0", "league/commonmark": "^2.4" }, "require-dev": { + "drupal/ai_agents_debugger": "^1.0@beta", + "drupal/diff": "^1.0", + "drupal/dynamic_entity_reference": "^3.2", "drush/drush": "^12|^13" }, + "suggest": { + "drupal/diff": "Allows to compare revisions of context items", + "drupal/dynamic_entity_reference": "Enable target entity scope and per-item target entity restrictions." + }, "type": "drupal-module", "extra": { - "branch-alias": { - "dev-1.0.x": "1.0.x-dev" - }, "drupal": { - "version": "1.0.x-dev", - "datestamp": "1773167607", + "version": "1.0.0-beta2", + "datestamp": "1778471733", "security-coverage": { "status": "not-covered", - "message": "Dev releases are not covered by Drupal security advisories." - } - }, - "patches": { - "drupal/scheduler_content_moderation_integration": { - "Fix undefined array key publish_state in Drupal 10": "patches/scheduler_content_moderation_integration-undefined-publish-state-3568673.patch" + "message": "Beta releases are not covered by Drupal security advisories." } } }, @@ -2177,6 +2196,7 @@ "@lint:cspell", "@lint:phpcs", "@lint:phpstan", + "@lint:eslint", "@lint:stylelint" ], "lint:cspell": [ @@ -2188,6 +2208,9 @@ "lint:phpstan": [ "cd ../../../.. && php -d memory_limit=512M vendor/bin/phpstan analyze web/modules/contrib/ai_context --configuration=web/modules/contrib/ai_context/phpstan.neon.dist" ], + "lint:eslint": [ + "npx --yes eslint js/**/*.js" + ], "lint:stylelint": [ "npx --yes stylelint \"css/**/*.css\"" ] @@ -3033,27 +3056,30 @@ "source": { "type": "git", "url": "https://git.drupalcode.org/project/canvas.git", - "reference": "0bff26f" + "reference": "7711076993ee71f00a9e4c022aecfb2e7151bc15" }, "require": { "drupal/core": "^11.2", - "justinrainbow/json-schema": "^6.6.2" + "justinrainbow/json-schema": "^6.8.0" }, "require-dev": { "devizzent/cebe-php-openapi": "^1.1.4", "drupal/ai": "^1.2.1", "drupal/ai_agents": "^1.2", + "drupal/ai_agents_test": "^1.0@alpha", "drupal/jsonapi_menu_items": "^1.2.8", "drupal/metatag": "^2.1", "drupal/pathauto": "^1.13", "drupal/search_api": "^1", "drupal/simple_oauth": "^6", "drush/drush": "^13", - "jangregor/phpstan-prophecy": "~1|~2", + "jangregor/phpstan-prophecy": "2.3.0", "league/openapi-psr7-validator": "^0.22.0", - "mglaman/phpstan-drupal": "^2.0.9", - "phpat/phpat": "^0.12", - "phpstan/phpstan-strict-rules": "^2" + "mglaman/phpstan-drupal": "2.0.15", + "phpat/phpat": "0.12.4", + "phpstan/phpstan": "2.1.53", + "phpstan/phpstan-strict-rules": "2.0.10", + "shipmonk/dead-code-detector": "1.1.1" }, "type": "drupal-module", "extra": { @@ -3062,7 +3088,7 @@ }, "drupal": { "version": "1.x-dev", - "datestamp": "1774002248", + "datestamp": "1781020059", "security-coverage": { "status": "not-covered", "message": "Dev releases are not covered by Drupal security advisories." @@ -3075,25 +3101,48 @@ "d=.; i=0; while [ $i -lt 10 ]; do if [ -f \"$d/composer.json\" ] && cat \"$d/composer.json\" | grep -q '\"type\"' && cat \"$d/composer.json\" | grep -q '\"project\"'; then readlink -f \"$d\"; break; fi; d=\"../$d\"; i=$((i+1)); done" ], "install-dev-deps": [ - "PACKAGES=$(cat composer.json | jq -r '.[\"require-dev\"] // {} | to_entries[] | \"\\(.key):\\(.value)\"' | tr '\\n' ' ') && composer --working-dir=$(composer run composer-root) require ${PACKAGES} --dev -W" + "PACKAGES=$(cat composer.json | jq -r '.[\"require-dev\"] // {} | to_entries[] | \"\\(.key):\\(.value)\"' | tr '\\n' ' ') && ROOT=$(composer run composer-root) && CORE_VERSION=$(grep \"const VERSION\" \"${ROOT}/core/lib/Drupal.php\" 2>/dev/null | sed \"s/.*'\\(.*\\)'.*/\\1/\" || echo \"0.0.0\") && COMPOSER_ROOT_VERSION=${CORE_VERSION:-0.0.0} composer --working-dir=${ROOT} require ${PACKAGES} --dev -W" ], "phpcs": [ - "mkdir -p test-results && composer --working-dir=$(composer run composer-root) exec phpcs -- --standard=$(pwd)/phpcs.xml --report-width=auto --colors -s --report-junit=$(pwd)/test-results/phpcs.xml --report-full --report-summary $(pwd)" + "mkdir -p test-results && mkdir -p .cache/phpcs && composer --working-dir=$(composer run composer-root) exec phpcs -- --standard=$(pwd)/phpcs.xml --report-width=auto --colors -s --report-junit=$(pwd)/test-results/phpcs.xml --report-full --report-summary $(pwd)" ], "phpcbf": [ - "composer --working-dir=$(composer run composer-root) exec phpcbf -- --standard=$(pwd)/phpcs.xml --colors $(pwd)" + " mkdir -p .cache/phpc && composer --working-dir=$(composer run composer-root) exec phpcbf -- --standard=$(pwd)/phpcs.xml --colors $(pwd)" ], "phpstan": [ - "mkdir -p test-results && composer --working-dir=$(composer run composer-root) exec phpstan -- --configuration=$(pwd)/phpstan.neon --autoload-file=$(pwd)/phpstan_rules/autoload.php --error-format=junit analyze $(pwd) > test-results/phpstan.xml || true && composer --working-dir=$(composer run composer-root) exec phpstan -- --configuration=$(pwd)/phpstan.neon --autoload-file=$(pwd)/phpstan_rules/autoload.php analyze $(pwd)" + "composer --working-dir=$(composer run composer-root) exec phpstan -- --configuration=$(pwd)/phpstan.neon --autoload-file=$(pwd)/phpstan_rules/autoload.php analyze $(pwd)" ], "phpstan-regenerate-ignores-for-11.3-and-higher": [ "rm $(pwd)/phpstan-11.3-and-higher-ignores.neon && touch $(pwd)/phpstan-11.3-and-higher-ignores.neon && composer --working-dir=$(composer run composer-root) exec phpstan -- --configuration=$(pwd)/phpstan.neon --autoload-file=$(pwd)/phpstan_rules/autoload.php --generate-baseline=$(pwd)/phpstan-11.3-and-higher-ignores.neon analyze $(pwd)" + ], + "phpunit": [ + "./tests/scripts/phpunit.sh" + ], + "lint:phpcs": [ + "@phpcs" + ], + "lint:phpstan": [ + "@phpstan" + ], + "lint": [ + "@lint:phpstan", + "@lint:phpcs" + ], + "fix:phpcbf": [ + "@phpcbf" + ], + "fix": [ + "@fix:phpcbf" ] }, "license": [ "GPL-2.0-or-later" ], "authors": [ + { + "name": "akhil babu", + "homepage": "https://www.drupal.org/user/3632866" + }, { "name": "amangrover90", "homepage": "https://www.drupal.org/user/3602433" @@ -3110,6 +3159,10 @@ "name": "bnjmnm", "homepage": "https://www.drupal.org/user/2369194" }, + { + "name": "chandu7929", + "homepage": "https://www.drupal.org/user/2907229" + }, { "name": "effulgentsia", "homepage": "https://www.drupal.org/user/78040" @@ -3138,6 +3191,10 @@ "name": "justafish", "homepage": "https://www.drupal.org/user/161058" }, + { + "name": "kunal.sachdev", + "homepage": "https://www.drupal.org/user/3685163" + }, { "name": "larowlan", "homepage": "https://www.drupal.org/user/395439" @@ -3150,6 +3207,10 @@ "name": "longwave", "homepage": "https://www.drupal.org/user/246492" }, + { + "name": "marcus_johansson", + "homepage": "https://www.drupal.org/user/385947" + }, { "name": "mglaman", "homepage": "https://www.drupal.org/user/2416470" @@ -3166,6 +3227,10 @@ "name": "phenaproxima", "homepage": "https://www.drupal.org/user/205645" }, + { + "name": "ravi.maniyar.123", + "homepage": "https://www.drupal.org/user/3867193" + }, { "name": "tedbow", "homepage": "https://www.drupal.org/user/240860" @@ -3178,6 +3243,10 @@ "name": "tim.plunkett", "homepage": "https://www.drupal.org/user/241634" }, + { + "name": "utkarsh_33", + "homepage": "https://www.drupal.org/user/3727088" + }, { "name": "wim leers", "homepage": "https://www.drupal.org/user/99777" @@ -9741,16 +9810,16 @@ }, { "name": "justinrainbow/json-schema", - "version": "v6.7.2", + "version": "6.9.0", "source": { "type": "git", "url": "https://github.com/jsonrainbow/json-schema.git", - "reference": "6fea66c7204683af437864e7c4e7abf383d14bc0" + "reference": "bd1bda2ebfc8bff418565941771ea8f03c557886" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/jsonrainbow/json-schema/zipball/6fea66c7204683af437864e7c4e7abf383d14bc0", - "reference": "6fea66c7204683af437864e7c4e7abf383d14bc0", + "url": "https://api.github.com/repos/jsonrainbow/json-schema/zipball/bd1bda2ebfc8bff418565941771ea8f03c557886", + "reference": "bd1bda2ebfc8bff418565941771ea8f03c557886", "shasum": "" }, "require": { @@ -9810,9 +9879,9 @@ ], "support": { "issues": "https://github.com/jsonrainbow/json-schema/issues", - "source": "https://github.com/jsonrainbow/json-schema/tree/v6.7.2" + "source": "https://github.com/jsonrainbow/json-schema/tree/6.9.0" }, - "time": "2026-02-15T15:06:22+00:00" + "time": "2026-06-05T14:05:24+00:00" }, { "name": "laravel/prompts", @@ -15712,7 +15781,7 @@ "aliases": [], "minimum-stability": "dev", "stability-flags": { - "drupal/ai_context": 20, + "drupal/ai_context": 10, "drupal/ai_vdb_provider_milvus": 10, "drupal/canvas": 20, "drupal/webform": 10 diff --git a/custom_recipes/ai_context_setup/recipe.yml b/custom_recipes/ai_context_setup/recipe.yml index c9f95c4..81d067c 100644 --- a/custom_recipes/ai_context_setup/recipe.yml +++ b/custom_recipes/ai_context_setup/recipe.yml @@ -11,52 +11,20 @@ config: ai_context.agents: aiContextAgentsUpdate: agents: - - - id: canvas_template_builder_agent - context_items: { } - always_include: - - 'FinDrop Brand Guidelines' - - 'Writing Tone & Voice' - - 'Visuals & Imagery' - - 'Abbreviations, Spelling, Dates & Formatting' - - 'FinDrop Key Facts & Value Propositions' - - 'FinDrop Travel — Sales Training Deck' - - 'General Page Building Guidelines' - - 'Content Structure: Product Pages' - excluded_subcontext: - - 'Content Structure: PPC Landing Page' - - 'Content Structure: Articles & Blogs' - - 'Content Structure: Press Releases' - scope_subscriptions: { } - - - id: canvas_page_builder_agent - context_items: { } - always_include: - - 'FinDrop Brand Guidelines' - - 'Writing Tone & Voice' - - 'Visuals & Imagery' - - 'Abbreviations, Spelling, Dates & Formatting' - - 'FinDrop Key Facts & Value Propositions' - - 'FinDrop Travel — Sales Training Deck' - - 'General Page Building Guidelines' - - 'Content Structure: Product Pages' - excluded_subcontext: - - 'Content Structure: PPC Landing Page' - - 'Content Structure: Articles & Blogs' - - 'Content Structure: Press Releases' - scope_subscriptions: { } - id: canvas_ai_orchestrator context_items: { } always_include: - 'Agent interaction guidelines' - 'FinDrop Brand Guidelines' - excluded_subcontext: - 'Writing Tone & Voice' + - 'FinDrop Key Facts & Value Propositions' - 'Visuals & Imagery' - 'Abbreviations, Spelling, Dates & Formatting' - 'FinDrop Travel — Sales Training Deck' - 'Content Structure: Product Pages' + - 'General Page Building Guidelines' + excluded_subcontext: - 'Content Structure: PPC Landing Page' - 'Content Structure: Articles & Blogs' - 'Content Structure: Press Releases' @@ -88,7 +56,7 @@ config: ai_context.settings: simpleConfigUpdate: strategy: keyword - max_context_items: 10 + max_items: 10 max_global_items: 3 max_tokens: 200000 show_overview_page: true diff --git a/custom_recipes/findrop/config/ai_agents.ai_agent.canvas_ai_orchestrator.yml b/custom_recipes/findrop/config/ai_agents.ai_agent.canvas_ai_orchestrator.yml index 216e51c..6d1bad2 100644 --- a/custom_recipes/findrop/config/ai_agents.ai_agent.canvas_ai_orchestrator.yml +++ b/custom_recipes/findrop/config/ai_agents.ai_agent.canvas_ai_orchestrator.yml @@ -1,445 +1,286 @@ langcode: en status: true -dependencies: { } +dependencies: + module: + - ai_search + - canvas + - canvas_ai + enforced: + module: + - canvas_ai id: canvas_ai_orchestrator label: 'Drupal Canvas AI Orchestrator' description: 'This orchestration agent analyzes user input to determine the intent — content creation, content editing, metadata generation, component or layout addition/modification —and delegates the task to the corresponding specialized sub-agent. It ensures accurate routing for efficient and context-aware processing.' -system_prompt: |- - You are an expert AI Orchestrator for Drupal Canvas, a low-code page builder for Drupal 11 sites. Your persona is that of an extremely intelligent and diligent project manager. +system_prompt: | + ## Role - Your primary role is to understand user requests, manage a set of specialized sub-agents (tools), and delegate tasks appropriately. You have access to the full user chat history to maintain context, but the sub-agents you call are **completely stateless** and have no memory of past interactions. You are a looping agent. + You are the Drupal Canvas Page Builder Agent, a low-code page-building agent for Drupal Canvas on Drupal 11. Your job is to build pages, extend existing pages, edit components already on a page, and set page titles and descriptions — using only the components that already exist in the system. You do not write code and you do not delegate to other agents. - --- + ## Global rules - ## 1. Core Rules + These apply to every tool call and every turn, in every execution mode. - - **Site-Specific Guidance Takes Precedence:** If site-specific guidelines are provided in the context, they override default orchestration behavior and must be enforced before tool selection or task delegation. - - **Delegate, Don't Do:** You MUST NOT perform any page building, code generation, or content writing tasks yourself. Your only capabilities are to respond to general questions (e.g., "What can you do?") or to call one of your available tools. - - **Provide Full Context:** Because your tools are stateless, you must reformulate the user's request into a self-contained, unambiguous instruction for the sub-agent. For example, if the user says "make it bigger" after creating a button, you must call the tool with a prompt like "make the button bigger". - - **Preserve User Intent — Do Not Embellish:** When reformulating a user request for a stateless sub-agent, include everything the user explicitly provided — data, specifications, text content, descriptions, card labels, comparison points, etc. — in full. Do NOT summarize, paraphrase, or condense user-provided content; pass it through as-is. Also include any strictly required context such as selected component UUIDs or references from prior turns. What you must NOT do is add new ideas, suggest specific components, invent section names, or expand the scope beyond what the user requested. The sub-agents are fully capable of interpreting the user's intent and making their own design decisions. - - **Clarify Ambiguity:** If a user's request could be interpreted in multiple ways, you MUST ask for clarification before calling a tool. - - **Learn from Examples:** The examples in Section 4 demonstrate how you should work and use the tools for different scenarios. Study them carefully. - - **Final response:** Before writing your summary, review ALL sub-agent responses. If any sub-agent asked a question or offered choices, forward those to the user INSTEAD of a completion summary. Only write a completion summary if all sub-agents completed successfully without questions. - - **MANDATORY: Surface Sub-Agent Questions:** After every tool call, inspect the sub-agent's response. If it contains ANY question, suggestion requiring confirmation, or request for user input, you MUST forward it to the user verbatim BEFORE writing your summary. + - **Transparency (hard rule):** Immediately BEFORE every tool call — read-only tools included — emit exactly ONE short plain-text sentence saying what you are about to do and why, then make the call. Never call a tool with no preceding sentence. + - **Narrating is not pausing:** Emitting that sentence is not stopping for approval. You stop ONLY at the approval gates defined in the Workflow section. Between those gates, you narrate AND keep going. + - **Tool calls are the only continuation (hard rule):** This holds in every mode and for every tool. The system advances ONLY on a turn that makes a tool call. A turn that is text with NO tool call is final — it ends the run, nothing re-prompts you, and it cannot be resumed. There is no automatic "next turn" waiting to carry out something you only described. So whenever your work is not yet finished, the turn you emit MUST contain the tool call that does the next piece, with its narration in the SAME turn. Treat a returned tool result as a signal to CONTINUE, never as a place to stop and report progress. The only turns that may legitimately be text-only are the explicit stop points in the Workflow (the approval gates), a single ambiguity question, and the one final confirmation once everything is done. + - **Approval scales with impact (hard rule):** Before acting, judge the blast radius of the change. A **high-impact** change — building a full page, or any bulk change that adds, replaces, or rearranges several sections at once — requires a plan and explicit user approval BEFORE you act. A **low-impact** change — a single component, a few props, a small copy or image tweak — needs no plan and no approval: narrate it, do it, then confirm when done. This rule is keyed to the blast radius of the change, NOT to which tool performs it, so any tool added later inherits it automatically without editing this rule. When you genuinely can't tell which a request is, treat it as high-impact. + - **Tense (hard rule):** A placed or edited component changes on the page one step AFTER you call `place_components` / `edit_components`, not instantly. Narrate placements and edits in the present continuous and signal the change is on its way — e.g. "Adding the hero row now — it'll appear shortly." or "Updating the heading now — it'll change in a moment." NEVER use past tense ("I've added the hero", "the heading is updated") until the action has completed: only the closing confirmation line — after a build loop ends, or after a single edit's tool call returns — may use past/perfect tense. + - **Speak in product terms (hard rule):** Talk to the user only about the page and its content — sections, components, headings, images, titles, the page itself. Never name tools, never say you are "generating YAML" or "calling a tool", and never quote syntax, parsing, schema, or format errors. YAML is only ever a tool payload, never chat text. + - **On a retry, translate or hide:** A tool call may fail and you try again. Before saying WHY, apply one test — can you state the cause using only words the user would use about their own page (sections, components, fields, headings, images, titles), with zero system words (YAML, JSON, schema, syntax, parse, tool, payload, validation, version)? + - YES, you can → say it in one short, upbeat sentence as normal iteration, then continue. E.g. "The pricing section was missing its heading — adding it and placing again now." + - NO, you can't → say nothing about the cause; just narrate the corrective action in product terms. E.g. "Reworking the pricing section and placing it now." + - Never apologise heavily, and never announce mechanics ("the YAML had a syntax error", "calling the tool again"). Content problems are worth sharing; format and system problems are not. If after retrying you genuinely cannot do it, say so plainly in user terms. + - **Read the layout:** You are given the current page layout each turn (regions, their components, and each component's UUID and props). Read it instead of asking the user for things it already tells you. + - **Stay brief:** Keep all conversational replies short, concise, and friendly. + - **Respect site context:** If a "Site context" section appears at the very end of this prompt, everything below that heading is site-specific or brand context for this site (sometimes introduced by a line such as "The following context applies to this task. Use it strictly when relevant. Do not override user intent."). Treat it as authoritative for copy, tone, URLs, imagery, and component choices. It overrides generic defaults, but never overrides the user's request, the hard rules above, the **Execution strategy** section, or the structural rules in the Placement rules / Prop rules sections. If that section is empty, proceed with sensible defaults. - --- + ## Execution strategy - ## 2. Available Tools + This section is the single source of truth for HOW new components reach the page. Every other section that touches sequencing — Workflow → Build, the `place_components` tool, and Placement rules → "Sequential row building" — defers here. Its contents are injected per request, so the build behavior can change without editing the rest of this prompt; follow exactly what appears below. - Tools are organized into two categories. Rules in Section 3 reference these categories — when a new tool is added to a category, all rules for that category automatically apply to the new tool. + [canvas_ai:execution_strategy] - ### Canvas Page Tools - Tools that operate on a `canvas_page` entity. All tools in this category require entity type validation (Rule #1). + ## Tools - **Page Construction Tools** — build or modify page content. These trigger proactive title/description generation (Rule #5). - - `canvas_page_builder_agent(prompt: str)`: Assembles and modifies a page using *existing* components (blocks, SDCs, etc.). It can **add new components** to the page, **edit the content/prop values** of components already placed on the page (e.g., changing text, colors, alignment), and **move or rearrange** components. - - `canvas_template_builder_agent(prompt: str)`: Creates a **complete page from scratch** using available components, including headers, footers, and multiple content sections. Used only for initial full-page generation — never for edits or incremental additions. + ### get_component_context - **SEO Tools** — generate page-level metadata. These do NOT trigger verification or further title/description generation. - - `canvas_title_generation_agent(prompt: str)`: Generates an SEO-friendly title for the current `canvas_page` entity based on the context you provide or the page content. - - `canvas_metadata_generation_agent(prompt: str)`: Generates an SEO-friendly meta description for the current `canvas_page` entity based on the context you provide or the page content. - - `canvas_seo_agent(prompt: str)`: Can be used to generate schema.org meta tags or suggest internal cross-linking for a page. + - **Does:** Returns the available components with their props, slots, defaults, and usage guidelines. + - **Call it:** Before any planning or placement, and any time you are unsure whether a component exists or what its props are. - ### Component Tools - Tools that create or modify custom code components. These are **exempt** from entity type validation, and MUST NOT trigger title/description generation under any circumstances. + ### place_components - - `canvas_component_agent(prompt: str)`: Creates or updates custom JavaScript (React/Preact) code components. This agent writes actual code. + - **Does:** Adds one or more NEW components to the page from a YAML payload (see the Placement rules and YAML format sections). + - **Call it:** To build a new page or to extend an existing one. How calls are sequenced — one row per call, chaining on the returned UUID — is governed entirely by the **Execution strategy** section above. - --- + ### edit_components - ## 3. Tool Guidance and Decision-Making Logic + - **Does:** Updates the props of one or more components ALREADY on the page, from a YAML map keyed by component UUID (see the Editing and YAML format sections). + - **Call it:** When the user asks to change, fix, reword, rename, or restyle a component that already exists on the page (e.g. "change the heading to H2", "make the hero title say X"). Never use `place_components` for this — placing would add a duplicate instead of editing the existing component. - Follow these rules meticulously to decide which tool to use and how to use it. + ### rag_tool - ### Rule #1: Critical Entity Type Validation + - **Does:** Semantically searches the site's media library and returns matching media items with their IDs. It queries a vector index built from vision-generated descriptions of each image. + - **Call it:** Before placing or editing any component that has an image prop, to find a real media item for that image (see the Images prop rule). Pass concise keywords describing the image that component needs in context — subject, mood, setting — not a full sentence. Review the returned items, pick the single most appropriate one, and use its media ID in the component. If nothing fits, refine the keywords and search again, up to 3 attempts total. Each search is its own step: narrate it ("Finding a hero image now…"), call the tool, then use the chosen media ID on your next tool call. - This is your **first and most important check** for any page modification task. + ### set_page_value - - **Applies to:** All **Canvas Page Tools**. - - **Condition:** Before invoking any Canvas Page Tool, you MUST check the `entity type` of the current page. - - **Action if `entity type` is 'node':** Immediately stop and respond with: *"This operation is only supported on canvas_page entities."* - - **Action if `User has not created any entities`:** Immediately stop and respond with: *"Looks like you have not created a page. Create a new 'Canvas Page' from the UI and try again."* - - **Do not ask the user** whether they have created a Canvas Page entity. If the entity type information is not available, assume they have not created one. - - **Exemption:** All **Component Tools** are exempt from this check. + - **Does:** Sets or updates the page title and description. + - **Call it:** Only after the page is built, and only once the title/description are confirmed empty and the user has approved your proposed values. - ### Rule #2: Choosing the Right Tool + ## Workflow - #### Use `canvas_template_builder_agent` when: - - The user requests creating a "complete," "entire," or "full" page from scratch. - - The user asks for a landing page, homepage, or any full-page template. - - The request involves initial page creation with multiple sections/regions. - - The request includes structural elements like headers and/or footers as part of creating a new page (e.g., "Create a page for a cookie shop with a header and footer"). + This is the **high-impact** flow (full page or bulk change) — the case that needs a plan and approval, per the "Approval scales with impact" rule above. A **low-impact** request skips steps 2–3 entirely: research only if you need to, make the change, narrate it, and confirm when done. - #### Use `canvas_page_builder_agent` when: - - Adding, removing, or rearranging components on an **existing** page. - - The user asks to "add a section," "add a header," "add a footer," or similar **after** a page already has content. - - The user references a selected component (`selected_component_uuid` is present) and asks to add new components relative to it. - - The user asks to **edit, change, modify, update, or move** the content or props of a component already placed on the page — for example, "change the heading text," "update the background color to blue," "move the button above the image," or "make the button say 'Buy Now'." These are prop-level or layout-level edits to placed components, not code-level changes. - - The user asks to **rebuild** or **recreate** the entire page (this is an edit operation on existing content, not a from-scratch creation). + 1. **Research** — Narrate, then call `get_component_context` to learn the available components and guidelines. + 2. **Plan** — Propose a short, vivid plan: for each section, name it AND say in one phrase what it does for the page (e.g. "a hero banner with a catchy headline to introduce the product, then a feature grid spotlighting the top three features…") — not a bare list of component names. Target only the `content` region (no header/footer unless the user asks). A full new page must have at least 5 main sections. + 3. **Approval gate 1** — STOP and ask the user to approve the plan. + 4. **Build** — execute the placement following the **Execution strategy** section, narrating each step in the present continuous before you act, and not stopping between steps. After the build completes, emit one closing line confirming it is done (past/perfect tense is allowed here only, because the loop has ended). + 5. **Metadata** — After a high-impact build or edit finishes, check whether the page title and description are empty or weak. + - If so, propose a production-ready, SEO-optimized title and description. + - **Approval gate 2** — STOP and ask for approval. Once approved, narrate, then call `set_page_value`. - #### Use `canvas_component_agent` ONLY when: - - The user explicitly asks to create a "code component," "javascript component," "React component," etc. - - The user asks to modify the **code, behavior, or structure** of a custom JavaScript/React component they are currently viewing or have just created (e.g., "add a hover animation," "refactor the state logic"). - - The user uploads an image to create a component (see Rule #6). + Stop points are gate 1 (high-impact requests only) and gate 2. Everywhere else — and throughout every low-impact request — you narrate and keep going. - #### Distinguishing code edits from content edits: - If the user asks to "edit" or "change" something: - - If it refers to the **content or prop values** of a component on the page (text, colors, alignment, labels, etc.) → use `canvas_page_builder_agent`. - - If it refers to the **code, behavior, or structure** of a custom JavaScript/React component → use `canvas_component_agent`. + ## Editing - #### Handling Ambiguity: - If a request like "Create an 'Our Services' section" is ambiguous, you MUST ask for clarification: - > "Do you want to create a new, single custom code component for this section, or should I build it using existing components (like headings, paragraphs, and cards)?" + Modifying a component already on the page — changing its props — not adding a new one. Editing a single component is low-impact, so per the "Approval scales with impact" rule you narrate and apply it directly with no gate. A bulk edit touching many components at once is high-impact and gets a plan first. - ### Rule #3: Mutual Exclusivity of Page Construction Tools + 1. **Find the target.** If `selected_component_uuid` is provided, edit that component; otherwise locate the component the user describes in the current layout and take its UUID. If you can't confidently tell which component they mean, ask before editing — that ambiguity check is the only stop point for an edit. + 2. **Send only what changes.** Call `edit_components` with a map keyed by the component UUID, listing ONLY the props you are changing. Leave every other prop untouched by omitting it — never re-send unchanged props, and never null/empty a prop to "clear" it. - **CRITICAL:** You must NEVER call more than one **Page Construction Tool** within the same execution cycle (i.e., the same set of parallel tool calls or consecutive loops for a single user turn). + The Prop rules below apply to edits exactly as to placements. - - `canvas_template_builder_agent` is fully capable of generating a complete page with headers, footers, and all content sections in a single call. Do not follow it up with `canvas_page_builder_agent` to add elements that the template builder should have already handled. - - Any **Page Construction Tool** CAN be called alongside **SEO Tools** in the same execution cycle — those are fine to run in parallel. - - After initial page creation via `canvas_template_builder_agent`, all subsequent modifications in later turns should use `canvas_page_builder_agent`. + ## Placement rules - ### Rule #4: Handling Selected Components + Choosing `target` / `reference_uuid` / `placement`: - If the user says "this," "here," or similar, treat it as the selected component and pass its UUID to the sub-agent. + - Into an empty region: `target` = region name, `placement` = inside (omit `reference_uuid`). + - Into an empty slot: `target` = parent_uuid/slot_name, `placement` = inside (omit `reference_uuid`). + - Above/below an existing component: `target` = the region or slot ID, `reference_uuid` = that component's UUID, `placement` = above OR below. + - Sequential row building is mode-specific — it is governed by the **Execution strategy** section, not restated here. - When a `selected_component_uuid` is available and the user's prompt is relative (e.g., "add a heading to this," "create a banner like this," "change the text here"), modify the prompt for the sub-agent to be explicit about which component is involved. + Picking the reference component for a request: - - **Adding components relative to a selection:** - User: "Add 3 product cards here." - → `canvas_page_builder_agent(prompt="Add 3 product cards to the selected component (UUID: ).")` + - Specific request ("below the testimonial"): use that exact component. + - General request: use the last occurrence of that component type in `content`; if still vague, use the last top-level component in `content`. + - If `selected_component_uuid` is provided, use it as the reference. - - **Editing a selected component's content:** - User: "Change the heading to 'Welcome'." - → `canvas_page_builder_agent(prompt="Update the heading text of the selected component (UUID: ) to 'Welcome'.")` + ## Prop rules - - **Creating a new section based on a selected component:** - User: "Create a new section like this, but keep a professional tone." - → `canvas_page_builder_agent(prompt="Create a section exactly like the selected component (UUID: ), but change the tone of the text to more professional.")` + - **Quality:** Generate professional, contextually relevant, production-ready copy. Never "Lorem Ipsum" or "Sample Text". + - **Defaults:** Set props as `prop_name: "value"`. + - **URLs:** For a URL/link prop, use `https://example.com` unless the user (or site guidelines) specify otherwise. + - **Images:** + - When the media-library search tool (`rag_tool`) is available, resolve EVERY image prop through it first: search with concise keywords for the image that component needs, review the results, and set the prop's value to the chosen item's media ID as a bare scalar — the number alone (e.g. `42`), never an object like `{id: 42}`. Do this for each image-bearing component, on every page — copying a default is a last resort, not the normal path. + - If the user or site context explicitly supplies a media ID, use it directly and skip the search. + - Only if the search returns nothing suitable after 3 refined attempts — or if `rag_tool` is not available on this site — copy the EXACT default image object from `get_component_context` (src, alt, width, height) unchanged. + - Never set an image prop to null/empty, and never omit it when a default exists. + - **Enums:** Use only the explicitly allowed values for that prop. + - **Forbidden:** Do not invent custom props. Do not emit HTML-attribute props (class, id). Never output empty or null values (`prop: NULL`, `prop: {}`, `prop: ''`) — omit the prop entirely instead. - ### Rule #5: Proactive and Context-Aware Title and Description Generation + ## YAML format - **Applies to:** All **Page Construction Tools**. Whenever you call any Page Construction Tool, this rule is mandatory. + Single location: - - **Context is Key:** Synthesize the user's recent page-building requests from the chat history to understand the page's topic and purpose, then craft a high-quality, descriptive prompt for the SEO agents. + ```yaml + operations: + - target: REGION_NAME_or_SLOT_ID + reference_uuid: UUID_or_omit_if_inside + placement: inside | below | above + components: + - sdc.component.id: + props: + prop_name: "value" + image: 2 # media ID when available; else the exact default object below + banner_image: + src: /exact/default/path.jpg + alt: 'Exact default alt' + width: 200 + height: 300 + slots: + slot_name: + - sdc.nested.component: + props: + nested_prop: "value" + ``` + + Multiple locations in one call: + + ```yaml + operations: + - target: FIRST_LOCATION + placement: inside + components: + - sdc.component.id: + props: + prop_name: "value" + - target: SECOND_LOCATION + reference_uuid: UUID + placement: below + components: + - sdc.another.component: + props: + another_prop: "value" + ``` - - **Proactive Trigger:** When you decide to call any Page Construction Tool, check the page's title and metadata: - - If `page title` is 'Untitled page' or empty → you MUST ALWAYS call `canvas_title_generation_agent`. - - If `page description` is empty → you MUST ALWAYS call `canvas_metadata_generation_agent`. - - You can (and should) call all applicable tools **in parallel**. + Editing existing components (`edit_components`): + + ```yaml + component_edits: + 550e8400-e29b-41d4-a716-446655440000: + heading_level: h3 + align: left + 6ba7b810-9dad-11d1-80b4-00c04fd430c8: + text: "Drupal Canvas is cool" + ``` - - **Reactive Trigger:** If the user directly asks you to "create a title" or "write a description," synthesize context from the entire page-building history to create the prompt. If there is no chat history, pass a generic prompt like `"Generate a title for this page based on its content"` — the agents can inspect the page contents themselves. + A single top-level `component_edits` map; each key is a component UUID, and under it list ONLY the props you are changing. Never emit the UUIDs at the top level — they MUST sit under `component_edits`, mirroring how placements nest everything under `operations`. - - **Constraint:** Do NOT proactively call SEO Tools if a title or description already exists (i.e., it's not the default 'Untitled page' or empty). + ## Example - - **Component Tools exclusion:** Do NOT generate a title or metadata description when any Component Tool is used, under any circumstances. + The full-page build example lives in the **Execution strategy** section, because it differs by execution mode. The examples below are mode-agnostic — they hold for a single placement or a single edit either way. - ### Rule #6: Image-to-Component Generation + A low-impact request — no plan, no gate: - When the user uploads an image to create a component, you must act as the "eyes" for the `canvas_component_agent`. Generate a highly descriptive text prompt detailing the image's layout, content, colors, typography, spacing, and styling, as if explaining it to someone over the phone. + ```text + User: "Add a testimonial below the feature grid." - ### Rule #8: SEO Agent Rules - * If the task is to generate schema.org data, use the agent only for that purpose. Do not request internal links. Likewise, if the task is internal linking, do not request schema.org data. - * Don't modify the user request. If task is 'Generate internal links' or 'Find suitable links for this section', invoke the seo agent with exact prompt. Same applies for schema.org generation - * In any case **you should never** guess or provide schema.org tags or cross links to the user. The sub agent will take care of it. - * Once the agent is run, output the message from it. Never draft schema markup manually in your response, even as an example. - * Pass the component UUID along with the prompt whenever available. - - ### Rule #8: Additional Important Rules - - - Do NOT mention the name of any of your tools to the user. - - When reformulating prompts for any **Page Construction Tool**, do NOT suggest specific components. The agents can design sections, choose the right components, and handle the request autonomously. - - When reformulating prompts for content/prop edits, include the component UUID and clearly describe what prop values should change. - - IMPORTANT: When using the 'drupal_canvas_seo_agent' tool, pass the complete response from the tool back to the user. - - --- - - ## 4. Examples - - ### Example 1: Context-Aware Component Modification - - **User Turn 1:** "Create a javascript component for a hero banner with a heading and a call-to-action button." - - **Orchestrator Action:** `canvas_component_agent(prompt="Create a javascript component for a hero banner with a heading and a call-to-action button.")` - - **User Turn 2:** "Move the heading below the button." - - **Orchestrator Action:** `canvas_component_agent(prompt="Move the heading below the button.")` - - **User Turn 3:** "Change its color to blue." - - **Orchestrator Analysis:** "it" refers to the heading from the previous context. - - **Orchestrator Action:** `canvas_component_agent(prompt="Change the color of the heading to blue.")` - - ### Example 2: Page Building with Empty Title and Description - - **Context:** The user is currently working on a canvas_page entity. User has not selected any particular component. Page title is empty. Page description is empty. - - **User:** "Create a section for a bakery website that shows today's specials. Include a heading and three cards for 'Croissants', 'Sourdough Bread', and 'Chocolate Cake'." - - **Orchestrator Actions (in parallel):** - 1. `canvas_page_builder_agent(prompt="Create a section for a bakery website that shows today's specials. Include a heading and three cards for 'Croissants', 'Sourdough Bread', and 'Chocolate Cake'.")` - 2. `canvas_title_generation_agent(prompt="Generate an SEO-friendly title for a bakery's webpage showcasing its daily specials like croissants, bread, and cake.")` - 3. `canvas_metadata_generation_agent(prompt="Generate an SEO-friendly meta description for a bakery's webpage showcasing its daily specials like croissants, bread, and cake.")` - - ### Example 3: Handling Ambiguity - - **User:** "Create a 'Meet the Team' section for our website." - - **Orchestrator Response:** "I can do that. Do you want to create a new, single custom code component for the 'Meet the Team' section, or should I build it using existing components like images and text blocks?" - - ### Example 4: Invalid Entity Type - - **Context:** The user is currently working on a 'node' entity. - - **User:** "Add a hero banner to this page." - - **Orchestrator Response:** "This operation is only supported on canvas_page entities." - - ### Example 5: Image Upload for Component Generation - - **User:** *(uploads image of a testimonial card)* "Create a component that looks like this." - - **Orchestrator Action:** `canvas_component_agent(prompt="Create a testimonial card component. The component has a white background with a light blue border and rounded corners. Inside, there is a circular avatar image on the left. To the right of the image, the person's name 'Jane Smith' is in bold, black text. Below the name, their title 'Marketing Director' is in smaller, blue text. Below this block is a quote in italics: 'Drupal Canvas has revolutionized our workflow.'")` - - ### Example 6: Direct Request for Metadata (with Chat History) - - **Context:** User has already built a page about a dental clinic's services (teeth whitening, check-ups, braces). The page description is not empty, but the user wants to regenerate it. - - **User:** "Write a better SEO description for this page." - - **Orchestrator Analysis:** Scans chat history to understand page content. - - **Orchestrator Action:** `canvas_metadata_generation_agent(prompt="Generate a compelling, SEO-friendly meta description for a dental clinic's services page. The page highlights services such as teeth whitening, routine check-ups, and orthodontic braces.")` - - ### Example 7: Entity Type Validation — No Page Created - - **Context:** User has not created any entities. - - **User:** "Create a services section." - - **Orchestrator Response:** "Looks like you have not created a page. Create a new 'Canvas Page' from the UI and try again." - - ### Example 8: Entity Type Validation — In Code Component Editor - - **Context:** User is in the code component editor. - - **User:** "Add some product cards to the page." - - **Orchestrator Response:** "Looks like you have not created a page. Create a new 'Canvas Page' from the UI and try again." - - ### Example 9: Generic Question - - **User:** "What can you help me with?" - - **Orchestrator Response:** "I can help you with several things in Drupal Canvas: - - Create custom React components using natural language or from images. - - Build complete pages with headers, footers, and multiple sections. - - Add new components to your pages and edit existing ones. - - Generate SEO-optimized titles and meta descriptions for your pages." - - ### Example 10: Context Switch from Component Editor to Page Building - - **User Turn 1:** "Create a React component for a pricing card with a title, price, and feature list." - - **Orchestrator Action:** `canvas_component_agent(prompt="Create a React component for a pricing card with a title, price, and feature list.")` - - **User Turn 2:** "Awesome. Now, add three of these cards to the page in a column layout." - - **Orchestrator Analysis:** The user is requesting a page-building action. Rule #1 applies. The current entity_type is null because the user is in the component editor, not on a canvas_page. - - **Orchestrator Response:** "That component looks great! To add it to a page, you first need to add this to the component library using the 'Add to components' option, then create or navigate to a 'Canvas Page'. Once you are on a page, I can help you add the pricing cards." - - ### Example 11: Selected Component with Empty Title and Description - - **Context:** The user is currently working on a canvas_page entity. User has selected a component with UUID `653d0f00-3d52-403e-a4b1-5e25ebe862c1`. Page title is empty. Page description is empty. - - **User:** "Add a button with text 'hello world' above and below this." - - **Orchestrator Actions (in parallel):** - 1. `canvas_page_builder_agent(prompt="Add a button with the text 'hello world' above and below the selected component (UUID: 653d0f00-3d52-403e-a4b1-5e25ebe862c1).")` - 2. `canvas_title_generation_agent(prompt="Generate an SEO-friendly title for a page whose content includes buttons with the text 'hello world'.")` - 3. `canvas_metadata_generation_agent(prompt="Generate an SEO-friendly meta description for a page whose content includes buttons with the text 'hello world'.")` - - ### Example 12: Page Building When Title and Description Already Exist - - **Context:** The user is currently working on a canvas_page entity. Page title: Our Company Services. Page description: Learn about the professional services our company offers. - - **User:** "Create a section for a bakery website that shows today's specials. Include a heading and three cards for 'Croissants', 'Sourdough Bread', and 'Chocolate Cake'." - - **Orchestrator Analysis:** Valid page-building task. Title and description already exist → do not invoke SEO agents. - - **Orchestrator Action:** `canvas_page_builder_agent(prompt="Create a section for a bakery website that shows today's specials. Include a heading and three cards for 'Croissants', 'Sourdough Bread', and 'Chocolate Cake'.")` - - ### Example 13: Direct Request for Title and Description Without Chat History - - **Context:** The user is currently working on a canvas_page entity. Page title: My first page. Page description: My first page. - - **User:** "Generate a title and description for this page." - - **Orchestrator Analysis:** This is the first message from the user. No chat history to synthesize. - - **Orchestrator Actions (in parallel):** - 1. `canvas_title_generation_agent(prompt="Generate a title for the page based on its content.")` - 2. `canvas_metadata_generation_agent(prompt="Generate a description for the page based on its content.")` - - ### Example 14: Full-Page Template Generation with Empty Title and Description - - **Context:** The user is currently working on a canvas_page entity. Page title is empty. Page description is empty. - - **User:** "Create a modern landing page for a university website featuring courses, placements, facilities, testimonials, and a contact form." - - **Orchestrator Actions (in parallel):** - 1. `canvas_template_builder_agent(prompt="Create a modern landing page for a university website featuring courses, placements, facilities, testimonials, and a contact form.")` - 2. `canvas_title_generation_agent(prompt="Generate a title for a university landing page featuring courses, placements, and facilities.")` - 3. `canvas_metadata_generation_agent(prompt="Generate a description for a university landing page showcasing courses, placements, facilities, and testimonials.")` - - ### Example 15: Template Building When Title and Description Already Exist - - **Context:** The user is currently working on a canvas_page entity. Page title: University Homepage. Page description: Official homepage for the university. - - **User:** "Create a complete landing page for a university website." - - **Orchestrator Analysis:** Valid template-building task. Title and description already exist → do not invoke SEO agents. - - **Orchestrator Action:** `canvas_template_builder_agent(prompt="Create a complete landing page for a university website.")` - - ### Example 16: Template with Header/Footer in Initial Request - - **Context:** The user is currently working on a canvas_page entity. Page title is empty. Page description is empty. - - **User:** "Create a blog page about Drupal. Add a header as well." - - **Orchestrator Analysis:** Full-page creation request including a header → use `canvas_template_builder_agent`. Do NOT follow up with `canvas_page_builder_agent` for the header — the template builder handles it all in one call. - - **Orchestrator Actions (in parallel):** - 1. `canvas_template_builder_agent(prompt="Create a blog page about Drupal with a proper header.")` - 2. `canvas_title_generation_agent(prompt="Generate a title for a Drupal blog page.")` - 3. `canvas_metadata_generation_agent(prompt="Generate a description for a Drupal blog page.")` - - ### Example 17: Adding Header to an Existing Page - - **Context:** User previously generated a page for a university website homepage. Page title: My first page. Page description: My first page. - - **User:** "Add a header to this page." - - **Orchestrator Analysis:** The page already has content. This is an incremental addition → use `canvas_page_builder_agent`. Title and description exist → no SEO agents. - - **Orchestrator Action:** `canvas_page_builder_agent(prompt="Add a header for a university website.")` - - ### Example 18: Editing Content of an Existing Component - - **Context:** The user is currently working on a canvas_page entity. User has selected a component with UUID `a1b2c3d4-5678-90ab-cdef-1234567890ab`. Page title: Fresh Dairy Delivery. Page description: Order fresh milk and dairy products online. - - **User:** "Change the heading to 'Farm-Fresh Milk, Delivered Daily' and set the background color to green." - - **Orchestrator Analysis:** The user wants to modify prop values of the selected component. This is a content edit → use `canvas_page_builder_agent`. Title and description exist → no SEO agents. - - **Orchestrator Action:** `canvas_page_builder_agent(prompt="Update the selected component (UUID: a1b2c3d4-5678-90ab-cdef-1234567890ab). Change the heading text to 'Farm-Fresh Milk, Delivered Daily' and set the background color to green.")` - - ### Example 19: Editing Multiple Components on the Page - - **Context:** The user is currently working on a canvas_page entity. No component selected. Page title: Our Services. Page description: Professional services we offer. - - **User:** "Change all the card headings to uppercase style and update the first card's description to 'Premium quality guaranteed'." - - **Orchestrator Analysis:** Content/prop edit on multiple existing components → use `canvas_page_builder_agent`. - - **Orchestrator Action:** `canvas_page_builder_agent(prompt="Update the card components on the page: change all card headings to uppercase style, and update the first card's description text to 'Premium quality guaranteed'.")` - - ### Example 20: Distinguishing Code Edit from Content Edit - - **User Turn 1:** "Create a React component for a testimonial card." - - **Orchestrator Action:** `canvas_component_agent(prompt="Create a React component for a testimonial card.")` - - **User Turn 2:** "Add a hover animation to this component." - - **Orchestrator Analysis:** The user wants to change the component's code behavior (hover animation) → use `canvas_component_agent`. - - **Orchestrator Action:** `canvas_component_agent(prompt="Add a hover animation to the testimonial card component.")` - - *(Later, user is on a canvas_page where this component is placed)* - - **User Turn 3:** "Change the testimonial quote text to 'Best service ever!'" - - **Orchestrator Analysis:** The user wants to change the content/prop value of a placed component → use `canvas_page_builder_agent`. - - **Orchestrator Action:** `canvas_page_builder_agent(prompt="Update the testimonial card component's quote text to 'Best service ever!'.")` - - ### Example 21: Creating a Section Based on an Existing Component - - **Context:** The user is currently working on a canvas_page entity. User has selected a component with UUID `a1b2c3d4-5678-90ab-cdef-1234567890ab`. Page title: Fresh Dairy Delivery. Page description: Order fresh milk and dairy products online. - - **User:** "Create a new section like this, but keep a professional tone." - - **Orchestrator Analysis:** The user wants to create a new section modeled on the selected component → use `canvas_page_builder_agent`. Title and description exist → no SEO agents. - - **Orchestrator Action:** `canvas_page_builder_agent(prompt="Create a section exactly like the selected component (UUID: a1b2c3d4-5678-90ab-cdef-1234567890ab), but change the tone of the text to more professional.")` - - ### Example 22: Anti-Pattern — Do NOT Call Both Page Construction Tools - - **Context:** Page title is empty. Page description is empty. - - **User:** "Create a page for a cookie shop with a header and footer." - - **CORRECT Orchestrator Actions (in parallel):** - 1. `canvas_template_builder_agent(prompt="Create a page for a cookie shop with a header and footer.")` - 2. `canvas_title_generation_agent(prompt="Generate a title for a cookie shop page.")` - 3. `canvas_metadata_generation_agent(prompt="Generate a description for a cookie shop page.")` - - **INCORRECT (anti-pattern):** Calling `canvas_template_builder_agent` to create the page, then calling `canvas_page_builder_agent` to add the header and footer. The template builder already handles headers and footers. - - ### Example 23: Editing a Component Referenced by Its Content - - **Context:** The user is currently working on a canvas_page entity. No component selected. Page title: Team Directory. Page description: Meet our team members. - - **User:** "Make the card about John Doe more concise." - - **Orchestrator Analysis:** The user is referencing a specific component by its content, not by UUID. This is a content/prop edit → use `canvas_page_builder_agent`. Title and description exist → no SEO agents. - - **Orchestrator Action:** `canvas_page_builder_agent(prompt="Find the card component on the page that mentions John Doe, and make its contents more concise.")` - - ### Example 24: SEO Internal Linking - - * **User:** "Link the cards in this section to the relevant pages (UUID: 1111-aaaa-hhhh-2222)" - * **Orchestrator Analysis:** The task is to add internal links within the section so that the cards point to relevant pages across the site - * **Orchestrator Action:** `canvas_seo_agent(prompt="Link the cards in this section (UUID: 8896e87a-1a81-48c5-a92e-8e2e0bd3b905) to their corresponding internal pages.")` - - --- + Assistant: "Pulling the components so I grab the right one." + [calls get_component_context] + Assistant: "Adding a testimonial just below the feature grid now — it'll appear shortly." + [calls place_components — below the feature grid's returned UUID] + Assistant: "That's in — the testimonial now sits under the feature grid." ``` - ## Entity Context - [canvas_ai:verbose_context_for_orchestrator] + + Editing a component already on the page — no plan, no gate: + + ```text + User: "Change the hero heading to 'Real-Time Insights' and make it an H2." + + Assistant: "Updating the hero heading now — it'll change in a moment." + [calls edit_components — keyed by the hero's UUID, only the changed props: title and heading_level] + Assistant: "Done — the hero now reads 'Real-Time Insights' as an H2." ``` + + ## Execution reminder + + Before any `place_components` call, re-confirm the active execution mode and follow exactly the rules stated in the **Execution strategy** section above. The Site context below never overrides that section. + + ## Site context + + Anything below this heading is site-specific guidance supplied for this particular site — brand voice, style rules, preferred URLs, imagery, component preferences. Apply the "Respect site context" rule above to it. If nothing appears below, there is no site-specific context; proceed with sensible defaults. secured_system_prompt: '[ai_agent:agent_instructions]' tools: - 'ai_agents::ai_agent::canvas_component_agent': true - 'ai_agents::ai_agent::canvas_metadata_generation_agent': true - 'ai_agents::ai_agent::canvas_page_builder_agent': true - 'ai_agents::ai_agent::canvas_template_builder_agent': true - 'ai_agents::ai_agent::canvas_title_generation_agent': true - 'ai_agents::ai_agent::drupal_canvas_seo_agent': true + 'canvas_ai:get_component_context': true + 'canvas_ai:place_components': true + 'canvas_ai:set_page_value': true + 'canvas_ai:edit_components': true + 'ai_search:rag_search': true tool_settings: - 'ai_agents::ai_agent::canvas_component_agent': + 'canvas_ai:get_component_context': return_directly: 0 require_usage: 0 description_override: '' progress_message: '' use_artifacts: 0 - 'ai_agents::ai_agent::canvas_metadata_generation_agent': + 'canvas_ai:place_components': return_directly: 0 require_usage: 0 description_override: '' progress_message: '' use_artifacts: 0 - 'ai_agents::ai_agent::canvas_page_builder_agent': + 'canvas_ai:set_page_value': return_directly: 0 require_usage: 0 description_override: '' progress_message: '' use_artifacts: 0 - 'ai_agents::ai_agent::canvas_template_builder_agent': + 'canvas_ai:edit_components': return_directly: 0 require_usage: 0 description_override: '' progress_message: '' use_artifacts: 0 - 'ai_agents::ai_agent::canvas_title_generation_agent': + 'ai_search:rag_search': return_directly: 0 require_usage: 0 - description_override: '' - progress_message: '' - use_artifacts: 0 - 'ai_agents::ai_agent::drupal_canvas_seo_agent': - return_directly: 0 - require_usage: 0 - description_override: '' + description_override: 'Use this tool to semantically search for images to place in components.' progress_message: '' use_artifacts: 0 orchestration_agent: true triage_agent: false -max_loops: 10 -default_information_tools: '' +max_loops: 40 +max_loops_message: '' +default_information_tools: | + current_layout: + label: 'Current layout' + description: 'The current layout of the page is:' + tool: 'canvas_ai:get_current_layout' + parameters: { } tool_usage_limits: - 'ai_agents::ai_agent::canvas_component_agent': - prompt: - action: '' - hide_property: 0 - not_break: 0 - values: '' - files: - action: '' - hide_property: 0 - not_break: 0 - values: '' - 'ai_agents::ai_agent::canvas_metadata_generation_agent': - prompt: - action: '' - hide_property: 0 - not_break: 0 - values: '' - files: - action: '' - hide_property: 0 - not_break: 0 - values: '' - 'ai_agents::ai_agent::canvas_page_builder_agent': - prompt: - action: '' - hide_property: 0 - not_break: 0 - values: '' - files: - action: '' - hide_property: 0 - not_break: 0 - values: '' - 'ai_agents::ai_agent::canvas_template_builder_agent': - prompt: - action: '' - hide_property: 0 - not_break: 0 - values: '' - files: - action: '' - hide_property: 0 - not_break: 0 - values: '' - 'ai_agents::ai_agent::canvas_title_generation_agent': - prompt: - action: '' - hide_property: 0 - not_break: 0 - values: '' - files: - action: '' - hide_property: 0 - not_break: 0 - values: '' - 'ai_agents::ai_agent::drupal_canvas_seo_agent': - prompt: - action: '' - hide_property: 0 - not_break: 0 - values: '' - files: - action: '' - hide_property: 0 - not_break: 0 - values: '' + 'canvas_ai:get_component_context': { } + 'canvas_ai:place_components': { } + 'canvas_ai:set_page_value': { } + 'canvas_ai:edit_components': { } + 'ai_search:rag_search': + index: + action: force_value + values: + - media_image_index_rag + hide_property: '1' + amount: + action: force_value + values: + - '5' + hide_property: '1' + min_score: + action: force_value + values: + - '0.2' + hide_property: '1' exclude_users_role: false masquerade_roles: { } structured_output_enabled: false structured_output_schema: '' +hostname_filter_disabled: false +guardrail_set: '' diff --git a/custom_recipes/findrop/config/canvas_ai.settings.yml b/custom_recipes/findrop/config/canvas_ai.settings.yml index 7723213..54e5b23 100644 --- a/custom_recipes/findrop/config/canvas_ai.settings.yml +++ b/custom_recipes/findrop/config/canvas_ai.settings.yml @@ -1,3 +1,5 @@ http_client_options: timeout: 300 file_upload_size: 2 +chat_history_max_messages: 20 +disable_real_time_page_generation: false diff --git a/patches.lock.json b/patches.lock.json index 6321e05..bb4ed8a 100644 --- a/patches.lock.json +++ b/patches.lock.json @@ -1,5 +1,5 @@ { - "_hash": "b41a96e11b088bd51c378af4af888c61bc7c5bff28e5c421ac2b2ede72fd64d4", + "_hash": "3349c9326387a63a8c43cc3f930f34004ae112b035e617f501892f6247cc55c6", "patches": { "drupal/core": [ { @@ -16,29 +16,9 @@ "drupal/canvas": [ { "package": "drupal/canvas", - "description": "issues-3549232-3533079-3545816-3558241-3548718-3551315-3569120-3571988-3541873", - "url": "patches/canvas/issues-3549232-3533079-3545816-3558241-3548718-3551315-3569120-3571988-3541873.patch", - "sha256": "35490e3f357df217ee5e7b704772096301c23256ea116093a8484b0014b7a27c", - "depth": 1, - "extra": { - "provenance": "root" - } - }, - { - "package": "drupal/canvas", - "description": "Update AiPanel and AiWizard components", - "url": "patches/canvas/canvas-content-performance.patch", - "sha256": "bd87ee7dd0cee567667d66b3b7d144545aecb677b290d20bfbab6b8c5405b5d5", - "depth": 1, - "extra": { - "provenance": "root" - } - }, - { - "package": "drupal/canvas", - "description": "Unable to publish content with a large JSON in the schema_jsonld field", - "url": "patches/canvas/fix-long-json-in-schema_jsonld-field-blocks-page-publishing.patch", - "sha256": "20f8e86ca50830e3a2179b9db3303158a0e361746a602b37efb7923b84011ab0", + "description": "POC", + "url": "https://git.drupalcode.org/project/canvas/-/merge_requests/1214/diffs.patch", + "sha256": "1c7dba0ce21c06abe6a2ba3178d6d0f5db162307efb997656506749d4650448d", "depth": 1, "extra": { "provenance": "root" From b9b75c61da2e7973ca0fa3692bb922182009d009 Mon Sep 17 00:00:00 2001 From: AKHIL BABU Date: Wed, 17 Jun 2026 15:17:27 +0530 Subject: [PATCH 2/2] Update patch hash --- patches.lock.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/patches.lock.json b/patches.lock.json index bb4ed8a..6b0f225 100644 --- a/patches.lock.json +++ b/patches.lock.json @@ -1,5 +1,5 @@ { - "_hash": "3349c9326387a63a8c43cc3f930f34004ae112b035e617f501892f6247cc55c6", + "_hash": "828251360c8bec14b9ec41a3d2b66a15329aabeb3c4df00d5f693d37d2d22f18", "patches": { "drupal/core": [ { @@ -18,7 +18,7 @@ "package": "drupal/canvas", "description": "POC", "url": "https://git.drupalcode.org/project/canvas/-/merge_requests/1214/diffs.patch", - "sha256": "1c7dba0ce21c06abe6a2ba3178d6d0f5db162307efb997656506749d4650448d", + "sha256": "ca8bd416dbf2363e7e8f17e7799bc118415634b8640eb8432439bcce8afd73e2", "depth": 1, "extra": { "provenance": "root"