Issue #3586449: Throw actionable exception when AI Assistant agent ID resolves to a code plugin

Description

Closes #3586449.

When an AI Assistant's ai_agent value resolves through plugin.manager.ai_agents to a code-defined AiAgent plugin instead of a config-entity wrapper (typically because an ai_agent config entity shares its machine name with a
code plugin and is silently dropped by AiAgentManager::findDefinitions()), AgentRunner::runAsAgent() proceeds to call into the ConfigAiAgentInterface-only contract — setProgressThreadId(), fromArray(), toArray(), isFinished(), setLooped(), getChatHistory(). The code plugin doesn't implement any of those, so the request fatals with Error: Call to undefined method ...::setProgressThreadId() (since #3582030 (closed)). The existing chatbot try/catch surfaces
the fatal to admins as that uninformative message, with no hint that the root cause is an agent-ID misconfiguration.

This MR adds an instanceof ConfigAiAgentInterface guard immediately after createInstance() at modules/ai_assistant_api/src/Service/AgentRunner.php:74. When the resolved instance doesn't implement the interface, the runner
throws an \InvalidArgumentException whose message names the offending agent ID, the class actually returned, and a concrete rename suggestion (_config, matching the convention this module already uses for shipped defaults like taxonomy_agent_config).

The exception flows cleanly through the existing chatbot error handler, so end users continue to see the assistant's configured error_message (the friendly fallback) while admins see the full actionable diagnostic at
/admin/reports/dblog.

Save-time prevention of new collisions and a watchdog warning for pre-existing ones ship as a companion MR in the ai_agents project: #3586026 (https://www.drupal.org/i/3586026).

Testing instructions

Additionally enable the AI Assistant API, AI Agents, and AI Chatbot modules (or any UI that calls AgentRunner::runAsAgent):

ddev drush en ai_assistant_api ai_agents ai_chatbot -y

Steps to reproduce and verify:

  1. Create an AI Assistant at /admin/config/ai/ai_assistants (any label, e.g. Topics). The agent dropdown only lists config entities, so this MR's behavior isn't reachable through the form on its own — point the assistant at a code-plugin ID directly via drush to simulate the misconfigured state:

ddev drush config:set ai_assistant_api.ai_assistant.<your_assistant> ai_agent taxonomy_agent -y
ddev drush cr 2. Open the chatbot exposed for that assistant and send any message.
3. Expected with this MR:\

  • Chatbot UI displays the assistant's configured error_message (the polished fallback such as "I am sorry, something went terribly wrong..."). - /admin/reports/dblog, filtered to severity Error, shows the InvalidArgumentException message:

▎ AI Assistant references agent "taxonomy_agent", but plugin.manager.ai_agents resolved it to Drupal\ai_agents\Plugin\AiAgent\TaxonomyAgent, which does not implement Drupal\ai_agents\PluginInterfaces\ConfigAiAgentInterface.
This usually means an ai_agent config entity shares its machine name with a code-defined AiAgent plugin; rename the config entity to a non-colliding ID (for example, "taxonomy_agent_config") and update the assistant.
4. Compare against pre-fix behavior (optional): git stash this MR's commit, ddev drush cr, retry the chatbot. Watchdog now shows Error: Call to undefined method
Drupal\ai_agents\Plugin\AiAgent\TaxonomyAgent::setProgressThreadId() — the unactionable failure this MR replaces. Restore with git stash pop && ddev drush cr.
5. Restore your assistant:

ddev drush config:set ai_assistant_api.ai_assistant.<your_assistant> ai_agent <a_valid_config_entity_agent_id> -y
ddev drush cr

Checklist

  • I have linked the related issue in the MR title or description
  • I have performed a self-review of my own code
  • I have added or updated tests, or explained in the description why this change is not covered by tests
  • I have updated documentation for any new or changed functionality
  • I have written testing instructions and verified them locally
  • I have noted any required post-merge steps (config imports, cache rebuilds, manual changes)
  • This MR contains no breaking API or hook changes, or they are explicitly documented in the description

AI Compliance

Note

Check the one that best describes your usage, or leave all unchecked if AI was not significantly used.

  • AI Assisted Code
    Mainly written by a human; AI used for autocomplete or partial generation under full human supervision.
  • AI Generated Code
    Mainly generated by AI, reviewed and approved by a human before this MR was created.
  • Vibe Coded
    Generated by AI and only functionally reviewed before this MR was created.

The instanceof guard and exception message were generated with Claude Code. Diagnosis (tracing the fatal back to the findDefinitions() collision behavior and the ConfigAiAgentInterface/AiAgentBase split), scope decisions (this guard vs. the broader collision-behavior change), and end-to-end verification were reviewed and approved at each step by a human before the commit.

Closes #3586449

Merge request reports

Loading