# Develop AI plugins

This tutorial focuses on one topic:

How to add new capabilities to the AI system in BeikeShop through a plugin.

The “AI features” discussed here mainly include four categories:

  1. Adding a new AI assistant (Agent)
  2. Adding new tools (Tool) to an assistant
  3. Connecting plugin capabilities to the admin AI menu and chat scenarios
  4. Adding corresponding permissions so admin roles can control who can use them

This document explains the mechanism using real code from the current project, with a focus on these files:

  • beike/Ai/Support/AiPluginBootstrap.php
  • beike/Ai/Services/AiExtensionService.php
  • beike/Shop/Providers/PluginServiceProvider.php
  • beike/Ai/Support/AiUiConfig.php
  • plugins/AiArticleManager/Bootstrap.php
  • plugins/AiArticleManager/Agents/ArticleManagerAgent.php
  • plugins/AiArticleManager/Tools/Articles/*

# 1. First, Understand What This Mechanism Is

Here is the conclusion first:

Extending AI through a plugin does not mean directly modifying the core AI files. Instead, the plugin registers its capabilities through its own Bootstrap.php.

In other words:

  • The core AI system starts first.
  • The plugin then extends its own Agent, Tool, permissions, and menu through boot().

The benefits of this approach are:

  • It is less likely to break the main system.
  • Plugins can be installed, enabled, and disabled independently.
  • A plugin can focus only on the business capabilities it is responsible for.

# 2. How an AI Plugin Takes Effect Automatically

# 2.1 Plugin Startup Entry

The plugin startup logic in the project is located in:

  • beike/Shop/Providers/PluginServiceProvider.php

The key logic is:

$className = "Plugin\\{$pluginCode}\\Bootstrap";
if (method_exists($className, 'boot')) {
    (new $className)->boot();
}

This code means:

  • As long as the plugin is enabled,
  • and there is a Bootstrap.php file under the plugin directory,
  • the system will automatically call the boot() method of this class.

So when writing an AI plugin, you do not need to manually “register it once again” somewhere else.


# 3. The Core Base Class of an AI Plugin

# 3.1 AiPluginBootstrap

File:

  • beike/Ai/Support/AiPluginBootstrap.php

The purpose of this class is:

To define how an AI plugin should connect to the system.

It requires you to implement three methods:

abstract public function pluginCode(): string;
abstract public function registerAgents(AiExtensionService $ai): void;
abstract public function registerTools(AiExtensionService $ai): void;

It also provides an optional extension point:

protected function registerHooks(): void {}

The final boot() method automatically executes in this order:

  1. registerAgents()
  2. registerTools()
  3. registerHooks()

This order is important because the usual flow is:

  • Register the AI assistant first.
  • Then register tools.
  • Finally add menus, permissions, and scenario descriptions.

# 4. What an AI Plugin Usually Looks Like

There is already a real example in the current project:

  • plugins/AiArticleManager/

Its directory structure is roughly:

plugins/AiArticleManager/
├── Agents/
│   └── ArticleManagerAgent.php
├── Bootstrap.php
├── config.json
├── Migrations/
│   └── 2026_04_29_000000_add_ai_article_manager_permissions.php
└── Tools/
    ├── Articles/
    │   ├── ArticleCreateTool.php
    │   ├── ArticleDeleteTool.php
    │   ├── ArticleListTool.php
    │   └── ArticleUpdateTool.php
    └── Orders/
        └── OrderAnalyticsTool.php

You can understand it this way:

  • Bootstrap.php: the main entry point, responsible for “telling the system what AI capabilities this plugin wants to add.”
  • Agents/: stores AI assistants.
  • Tools/: stores tools that AI can call.
  • Migrations/: stores database changes such as permission migrations.
  • config.json: stores basic plugin information.

# 5. Step 1: Prepare Basic Plugin Information

# 5.1 config.json

File:

  • plugins/AiArticleManager/config.json

This file is not AI-specific, but plugins usually need it to display and install properly.

Example:

{
    "code": "ai_article_manager",
    "name": {
        "zh_cn": "AI文章管理助手",
        "en": "AI Article Manager"
    },
    "description": {
        "zh_cn": "为现有文章模块提供 AI 增删改查能力,并扩展 AI 菜单、快捷提问和权限。",
        "en": "Adds AI CRUD capabilities for existing articles with chat navigation, quick prompts, and permissions."
    },
    "type": "feature",
    "version": "v1.0.0"
}

The most important fields are:

  • code: the unique identifier of the plugin.
  • type: the plugin type.
  • name / description: used for display in the admin panel.

# 6. Step 2: Write the Plugin Bootstrap

# 6.1 Minimal Skeleton

First create:

  • plugins/YourPluginName/Bootstrap.php

Minimal example:

<?php

namespace Plugin\YourPlugin;

use Beike\Ai\Services\AiExtensionService;
use Beike\Ai\Support\AiPluginBootstrap;

class Bootstrap extends AiPluginBootstrap
{
    public function pluginCode(): string
    {
        return 'your_plugin_code';
    }

    public function registerAgents(AiExtensionService $ai): void
    {
    }

    public function registerTools(AiExtensionService $ai): void
    {
    }

    protected function registerHooks(): void
    {
    }
}

This is the main control center of an AI plugin.


# 7. Step 3: If You Want to Add a New AI Assistant

# 7.1 Write the Agent Class

Using the article assistant as an example:

  • plugins/AiArticleManager/Agents/ArticleManagerAgent.php

It extends:

  • Beike\Ai\Agents\BaseAgent

A basic Agent should at least describe:

  1. Who it is
  2. What it is responsible for
  3. What its scenario identifier is
  4. Which quick prompts it recommends

Key method:

public function getScene(): string
{
    return 'articles';
}

This scene is very important. You can understand it as:

The unique scenario name of this AI assistant in the system.

Menu switching, scenario configuration, welcome messages, and quick prompts will all revolve around this name.

# 7.2 Register the Agent in Bootstrap

public function registerAgents(AiExtensionService $ai): void
{
    $ai->registerPluginAgent(
        $this->pluginCode(),
        'articles',
        \Plugin\AiArticleManager\Agents\ArticleManagerAgent::class
    );
}

This means:

  • This plugin is called ai_article_manager.
  • It adds a new scenario called articles.
  • The class corresponding to this scenario is ArticleManagerAgent.

# 7.3 Step 3 Supplement: How to Write a Prompt File for a Newly Added Agent

This section is very important.

Many people may assume that:

  • An Agent can only hard-code instructions() in code, or
  • prompt files can only be placed in the core directory prompts/agents.

That is not how this project currently works.

The current core AI module already supports:

  1. Specifying a prompt file through $promptFile in the Agent.
  2. Placing that file either in the core directory or directly in the plugin directory.

The corresponding core code is in:

  • beike/Ai/Agents/BaseAgent.php

If you are a plugin developer and want to add your own Agent, the recommended structure is:

plugins/YourPlugin/
├── Agents/
│   └── YourAgent.php
└── Prompts/
    └── your-agent.md

That is:

  • Put the Agent class under Agents/.
  • Put the prompt file under Prompts/.
  • Keep both of them inside the plugin.

The benefits are:

  • The plugin carries its complete capability by itself.
  • There is no need to modify the core prompts/agents directory.
  • When the plugin is disabled, it will not pollute the main system.

# 7.3.2 How to Connect the Prompt File in the Agent Class

<?php

namespace Plugin\YourPlugin\Agents;

use Beike\Ai\Agents\BaseAgent;

class YourAgent extends BaseAgent
{
    protected ?string $promptFile = 'plugins/YourPlugin/Prompts/your-agent.md';

    public function description(): string
    {
        return 'Your plugin assistant description';
    }

    public function getScene(): string
    {
        return 'your-scene';
    }
}

This configuration means:

  • The system prompt of this Agent will no longer be loaded from the default directory.
  • Instead, it will directly read your-agent.md from the plugin directory.

# 7.3.3 How to Write the Prompt File

A prompt file is just a normal Markdown text file.

For example:

You are a store operation assistant.

Your responsibilities:
- Help administrators manage campaign configurations
- Prefer calling campaign-related tools
- If parameters are incomplete, ask for the missing information first
- Do not fabricate data or execution results

Operation requirements:
- Confirm filtering conditions before querying data
- Confirm the target object before writing data
- Be especially cautious with delete operations

You can understand this file as:

The “role manual” of this Agent.

# 7.3.4 Real Example in the Project

You can directly refer to:

  • plugins/AiArticleManager/Agents/ArticleManagerAgent.php
  • plugins/AiArticleManager/Prompts/article-manager.md

ArticleManagerAgent is currently connected like this:

protected ?string $promptFile = 'plugins/AiArticleManager/Prompts/article-manager.md';

When adding a new Agent in a plugin, the following approaches are not recommended:

  1. Hard-coding the prompt directly in instructions(), which makes the content long and difficult to maintain.
  2. Placing the plugin Agent’s prompt file into the core prompts/agents directory.

The first approach has high maintenance cost. The second approach couples the plugin too tightly with the main system, which can easily cause problems during future upgrades and uninstallation.


# 7.4 Step 3 Supplement: How to Extend the Prompt of an Existing Agent

This requirement is different from “adding your own Agent.”

If you want to modify an assistant that already exists in the system, such as:

  • admin
  • order-analysis
  • customer-insight
  • product-catalog

Do not directly modify the core prompt files.

For example, do not directly modify these files:

  • prompts/agents/admin-assistant.md
  • prompts/agents/order-analysis.md
  • prompts/agents/customer-insight.md
  • prompts/agents/product-catalog.md

The recommended approach is:

  • Use a Hook in the plugin’s Bootstrap.php.
  • Extend ai.agent.{scene}.instructions.

This capability is also connected in the core:

  • beike/Ai/Agents/BaseAgent.php

# 7.4.1 Append-Style Modification

This is the most recommended approach.

add_hook_filter('ai.agent.order-analysis.instructions', function (string $instructions): string {
    return $instructions . "\n\n【Plugin Extension Capability】\nYou can now additionally use the `orders.xxx` tool for supplemental analysis.";
});

This means:

  • Keep the original order analysis prompt first.
  • Then append a section of the plugin’s own rules at the end.

This is the safest approach because:

  • The original system role definition remains intact.
  • The existing core tool descriptions remain intact.
  • The plugin only adds the parts it cares about.

# 7.4.2 Full Replacement Modification

If you really want to completely take over the prompt of an existing Agent, you can also do this:

add_hook_filter('ai.agent.order-analysis.instructions', function (string $instructions): string {
    return <<<TEXT
You are the new order analysis assistant.

Requirements:
- Prioritize the statistical logic defined by the plugin
- Ask follow-up questions first when information is insufficient
- Do not fabricate analysis results
TEXT;
});

However, I do not recommend this as the default approach.

The reason is simple:

  • It can easily overwrite the original behavioral constraints of the core system.
  • Once the main system improves the original prompt in an upgrade, your plugin will not receive those improvements.

# 7.4.3 How to Determine the Scene Name

The {scene} in ai.agent.{scene}.instructions is the return value of the target Agent’s getScene() method.

Examples:

  • admin
  • order-analysis
  • customer-insight
  • product-catalog
  • articles

You can confirm them from these classes:

  • beike/Ai/Agents/AdminAssistant.php
  • beike/Ai/Agents/OrderAnalysisAgent.php
  • beike/Ai/Agents/CustomerInsightAgent.php
  • beike/Ai/Agents/ProductCatalogAgent.php

# 7.4.4 When to Add a New Agent and When to Extend an Existing Agent

The rule is simple:

  1. If this is an independent business scenario of the plugin, add a new Agent.
  2. If this is only adding capabilities to an existing system assistant, extend an existing Agent.

For example:

  • Article management, after-sales notes, and invoice assistants are usually suitable as new Agents.
  • Order statistics enhancements, customer tag enhancements, and product analysis enhancements are usually suitable for extending existing Agents.

For prompt handling in plugin development, the most recommended conventions are:

  1. For a new Agent: use $promptFile to point to the plugin’s own .md file.
  2. For modifying an existing Agent: use the ai.agent.{scene}.instructions Hook.
  3. Do not directly modify core prompts/agents/*.md files.

# 8. Step 4: If You Want to Add Tools to an Assistant

# 8.1 What Is a Tool?

A Tool can be understood as:

The “capability function” that AI actually uses to do work.

For example:

  • Query article lists
  • Create articles
  • Update articles
  • Delete articles
  • Query order statistics

AI itself only understands the user’s question. The actual database reading, database writing, and structured result returning are handled by Tools.

# 8.2 Minimal Structure of a Tool

Article tool example in the plugin:

  • plugins/AiArticleManager/Tools/Articles/ArticleListTool.php

A Tool usually contains these parts:

  1. description(): tells AI what this tool is used for.
  2. schema(): defines input parameters.
  3. doHandle(): contains the actual handling logic.
  4. requiredPermission: optional, custom permission name.

If you do not define requiredPermission, the system will automatically infer it based on the class name. However, in a plugin, it is recommended that you define it explicitly, which is the most reliable approach.


# 9. Step 5: Register the Tool into the System

# 9.1 Register the Tool Itself

In Bootstrap.php:

public function registerTools(AiExtensionService $ai): void
{
    $tools = [
        'articles.list'   => \Plugin\AiArticleManager\Tools\Articles\ArticleListTool::class,
        'articles.create' => \Plugin\AiArticleManager\Tools\Articles\ArticleCreateTool::class,
        'articles.update' => \Plugin\AiArticleManager\Tools\Articles\ArticleUpdateTool::class,
        'articles.delete' => \Plugin\AiArticleManager\Tools\Articles\ArticleDeleteTool::class,
    ];

    foreach ($tools as $name => $class) {
        $ai->registerPluginTool($this->pluginCode(), $name, $class, 'article');
    }
}

There are three concepts here:

  • $name: the registered tool name used by the AI system for recognition.
  • $class: the tool class.
  • 'article': the tool category.

# 9.2 Attach the Tool to an Agent

Registering a tool alone is not enough.

Registering a tool = the system knows this tool exists. Attaching it to an Agent = a specific assistant can actually call this tool.

For example:

foreach (['articles.list', 'articles.create', 'articles.update', 'articles.delete'] as $toolName) {
    $ai->addToolToAgent('articles', $toolName);
}

This means:

  • The article assistant articles
  • can call these four tools.

# 10. Important: Adding a New Tool and Extending an Existing Agent Are Not the Same Thing

This is the easiest place to make mistakes.

# 10.1 Case A: You Add Your Own New Assistant

For example:

  • You create a new articles assistant.
  • You want it to query and update articles.

Then you should:

  • Register the articles.* tools.
  • Then call addToolToAgent('articles', ...).

# 10.2 Case B: You Are Not Adding a New Assistant, but Extending an Existing One

For example, you want to:

  • Avoid creating a new order assistant.
  • Simply add a plugin tool to the system’s original order-analysis assistant.

The correct approach is:

$ai->registerPluginTool(
    $this->pluginCode(),
    'orders.order-analytics',
    \Plugin\AiArticleManager\Tools\Orders\OrderAnalyticsTool::class,
    'order'
);

$ai->addToolToAgent('order-analysis', 'orders.order-analytics');

Note:

  • The tool belongs to the plugin.
  • But the tool is attached to the existing agent: order-analysis.

# 10.3 Why This Difference Matters

If you attach a tool to the wrong Agent, two types of problems may occur:

  1. Tool responsibilities become mixed up. For example, the article assistant suddenly becomes able to perform order analysis.

  2. UI and prompts become confusing. AI may call unrelated tools in scenarios where they should not appear.

So the rule is simple:

  • Who is this capability for?
  • Attach it to that Agent.

# 11. Step 6: Add UI Extensions for the AI Menu and Scenarios

# 11.1 Why You Should Not Directly Modify the Frontend Menu

Because this project already provides Hooks.

That means:

  • The core frontend first gets the default menu.
  • Plugins can append menu items through Hooks.

This is much more stable than directly modifying core Blade or JS files.

# 11.2 Add an Item to the Left Feature Menu

In plugins/AiArticleManager/Bootstrap.php:

add_hook_filter('ai.ui.navigation.features', function (array $items): array {
    $items[] = [
        'key'         => 'articles',
        'title'       => '文章管理',
        'group'       => 'feature',
        'groupTitle'  => '',
        'action'      => 'scene',
        'target'      => 'articles',
        'icon'        => 'file-earmark-text',
        'sort'        => 60,
        'description' => '文章查询与内容维护',
    ];

    return $items;
});

This configuration means:

  • Add an “Article Management” item to the left menu.
  • Clicking it switches to the articles scenario.

# 11.3 Add a Title and Welcome Message for the Scenario

add_hook_filter('ai.ui.scenes', function (array $scenes): array {
    $scenes['articles'] = [
        'title'          => '文章管理',
        'welcomeMessage' => '你好!我是文章管理助手,可以帮你查询、新建、修改和删除文章。请直接告诉我文章标题、内容或文章编号。',
    ];

    return $scenes;
});

This step determines:

  • The title at the top of the chat page.
  • The welcome message on the empty chat page.
  • Where quick prompts are mounted.

# 11.4 Where the Final Scenario Configuration Is Aggregated

In:

  • beike/Ai/Support/AiUiConfig.php

The core system combines:

  • Default scenarios
  • Plugin-added scenarios
  • Plugin-added menus
  • Quick prompts

into a unified frontend configuration object, which is then used by the AI frontend.


# 12. Step 7: Add Permissions for AI Features

# 12.1 Why Permissions Must Be Added

Because admin AI is not unconditionally available to all administrators.

The system decides based on permissions:

  • Whether the user can enter a certain assistant.
  • Whether the user can execute a certain tool.

# 12.2 Where AI Permissions in the Menu Come From

In:

  • beike/Admin/Repositories/PermissionRepo.php

The system first prepares a batch of default AI permissions, then merges plugin permissions through Hooks:

$routes = hook_filter('ai.permissions.routes', $routes);
$names = hook_filter('ai.permission.names', $names);

So the correct plugin approach is:

  • Use Hooks to append your own permission codes.
  • Then provide display names for these permission codes.

# 12.3 Example

add_hook_filter('ai.permissions.routes', function (array $routes): array {
    return array_merge($routes, [
        'ai_agent_articles',
        'ai_tool_articles_read',
        'ai_tool_articles_write',
        'ai_tool_articles_delete',
        'ai_tool_order_analytics',
    ]);
});

add_hook_filter('ai.permission.names', function (array $names): array {
    return array_merge($names, [
        'ai_agent_articles'       => '访问文章管理助手',
        'ai_tool_articles_read'   => '文章查询工具',
        'ai_tool_articles_write'  => '文章编辑工具',
        'ai_tool_articles_delete' => '文章删除工具',
        'ai_tool_order_analytics' => '订单统计扩展工具',
    ]);
});

# 12.4 What Is Actually Checked When a Tool Executes

During tool execution, the flow eventually goes through:

  • beike/Ai/Tools/BaseTool.php

It checks:

$permissionName = $this->resolvePermissionName($input);

If you write this in a Tool:

protected ?string $requiredPermission = 'articles_write';

Then the system actually checks:

  • ai_tool_articles_write

So remember:

  • The requiredPermission inside the Tool only contains the suffix.
  • The permission stored in the backend permission table is the full name with the ai_tool_ prefix.

# 13. Step 8: Write Permission Migrations

If permissions are only displayed through Hooks but no permission records exist in the database, admin roles still cannot be assigned correctly.

So plugins usually also need a migration file, for example:

  • plugins/AiArticleManager/Migrations/2026_04_29_000000_add_ai_article_manager_permissions.php

Example logic:

private array $permissions = [
    'ai_agent_articles',
    'ai_tool_articles_read',
    'ai_tool_articles_write',
    'ai_tool_articles_delete',
    'ai_tool_order_analytics',
];

up() does two things:

  1. Creates permissions.
  2. Optionally grants them to the admin role by default.

After the plugin is installed, these permission items can then be seen directly in the admin panel.


# 14. Step 9: Configure Quick Prompts for the Agent

# 14.1 Where to Write Quick Prompts

They are usually written in the Agent:

public function quickPrompts(): array
{
    return [
        [
            'key'  => 'article-list',
            'text' => '查看文章列表',
            'tool' => 'articles.list',
            'sort' => 10,
        ],
    ];
}

# 14.2 How Quick Prompts Enter the Frontend

The system uses:

  • beike/Ai/Services/AgentQuickPromptService.php

to collect the Agent’s quickPrompts(), then passes them to:

  • beike/Ai/Support/AiUiConfig.php

Finally, they can be displayed on the frontend chat page.

# 14.3 When Quick Prompts Are Suitable

They are suitable for these scenarios:

  • There are many tools, and users do not know how to start.
  • There are obvious high-frequency actions.
  • You want to guide users to use tools correctly.

They are not suitable for these scenarios:

  • The Agent has only one very simple action.
  • The tool behavior has not stabilized yet.

# 15. Step 10: How to Distinguish “Core Tools” from “Plugin Extension Tools”

There is one important point to note in this project:

The core system already has some Tools, so plugins do not necessarily need to rewrite another copy.

For example, in the order analysis area, the core system already has:

  • beike/Ai/Tools/Orders/OrderAnalyticsTool.php

If your plugin also writes:

  • plugins/AiArticleManager/Tools/Orders/OrderAnalyticsTool.php

then you must first clarify which requirement you have.

# Option A: Simply Add a Plugin Tool

This means:

  • The core tool remains unchanged.
  • Your plugin adds an additional new tool.

This is the safest approach, but avoid confusing names.

# Option B: Extend an Existing Agent

For example:

  • The tool is written inside the plugin.
  • But it is attached to order-analysis.

This is also reasonable.

The key point is:

Do not attach all tools to articles just because the plugin directory is called “Article Management.”

A tool should be attached to the Agent it actually serves.

# Option C: Replace a Core Tool

This is no longer a “normal attachment.”

You need to further design:

  • How to handle old and new tools with the same name.
  • Which one AI should call first.
  • Whether permissions should reuse the old ones or use new ones.

If you only want to make the feature work first, it is recommended to start with Option A or Option B.


# 16. Step 11: How to Verify That the Plugin Extension Works

# 16.1 First Check Whether Registration Works

The current project already has an integration test example:

  • tests/Integration/Ai/ArticleAiPluginBootstrapTest.php

This test verifies:

  • Whether the articles assistant is registered.
  • Whether articles.list/create/update/delete are registered.
  • Whether orders.order-analytics is registered.
  • Whether orders.order-analytics is attached to order-analysis.

This test is especially suitable to run immediately after writing the plugin.

# 16.2 Then Check Whether Scenario Configuration Is Normal

Test file:

  • tests/Feature/Admin/ArticleAiSceneConfigTest.php

It verifies:

  • Whether “Article Management” exists in the left navigation.
  • Whether the scenario configuration contains articles.
  • Whether quick prompts are included in the frontend configuration.
php artisan test tests/Integration/Ai/ArticleAiPluginBootstrapTest.php
php artisan test tests/Feature/Admin/ArticleAiSceneConfigTest.php

If you changed the AI frontend, you can also run:

php artisan test tests/Feature/Admin/AiAgentWidgetAssetTest.php

# 17. Step 12: Write a Minimal Runnable Example

Suppose you want to create an “After-Sales Note Assistant” plugin. The minimal path can follow this order:

# Step 1: Create the Plugin Directory

plugins/AiAfterSaleNote/
├── Bootstrap.php
├── config.json
├── Agents/
│   └── AfterSaleNoteAgent.php
├── Tools/
│   └── Notes/
│       └── NoteCreateTool.php
└── Migrations/
    └── 2026_05_01_000000_add_ai_after_sale_note_permissions.php

# Step 2: Write config.json

First let the system recognize the plugin.

# Step 3: Write Bootstrap.php

  • pluginCode()
  • registerAgents()
  • registerTools()
  • registerHooks()

# Step 4: Write the Agent

At minimum, implement:

  • description()
  • instructions()
  • getName()
  • getDescription()
  • getScene()
  • quickPrompts()

# Step 5: Write the Tool

At minimum, implement:

  • description()
  • schema()
  • doHandle()

# Step 6: Attach the Tool to the Agent

If you only register the tool but do not attach it, AI cannot call it.

# Step 7: Add Permission Hooks and Migrations

Otherwise, the backend role management cannot display them, and the tool may not be executable.

# Step 8: Add Tests

At minimum, verify:

  • Agent registration succeeds.
  • Tool registration succeeds.
  • The tool is attached to the correct Agent.
  • Frontend scenario configuration is normal.

# 18. Common Pitfalls

# Pitfall 1: You Wrote a Tool, but AI Never Uses It

Common reason:

  • You only called registerPluginTool().
  • You did not call addToolToAgent().

# Pitfall 2: The Scenario Appears in the Menu, but the Page Is Blank After Clicking It

Common reason:

  • The frontend hard-coded chat scenarios.
  • The new scenario did not enter the dynamic scenario list.

This project has now been changed to a dynamic scenario approach. When adding plugin scenarios, prioritize the backend navigation + scenes configuration and do not hard-code them again.

# Pitfall 3: Permission Names Are Messy

You need to distinguish two layers:

  1. requiredPermission in the Tool class
  2. ai_tool_xxx in backend role permissions

# Pitfall 4: The Tool Is Attached to the Wrong Agent

For example:

  • The tool is an order analysis tool.
  • But it is attached to the article assistant.

There is only one rule:

Attach the tool to the assistant it is meant for.

# Pitfall 5: There Is Code in the Plugin Directory, but the System Does Not Take Effect

Check these first:

  1. Whether the plugin is enabled.
  2. Whether the namespace of Bootstrap.php is correct.
  3. Whether the class name is Plugin\\PluginDirectoryName\\Bootstrap.
  4. Whether boot() has been executed.

# 19.1 One Plugin Should Manage One Clear Responsibility

For example:

  • The article plugin mainly manages article AI.
  • The order plugin mainly manages order AI.

If cross-domain extensions are indeed needed, that is also possible, but clearly document:

  • Which existing Agent this plugin is extending.

# 19.2 Use “Domain.Action” for Tool Names

For example:

  • articles.list
  • articles.create
  • orders.order-analytics

This makes it immediately clear which business line the tool belongs to.

# 19.3 Keep Permission Names Consistent with Tool Semantics

For example:

  • Article tools should not use order permissions.
  • Order tools should not use article permissions.

# 19.4 Build a Minimal Closed Loop First, Then Add Complex Capabilities

Recommended order:

  1. Create one Agent first.
  2. Attach one Tool first.
  3. Make sure the menu displays.
  4. Make sure it can actually execute once.
  5. Then gradually add more Tools, quick prompts, and permission granularity.

# 20. Template You Can Copy in the Future

If you just want to start quickly, follow this checklist directly:

# Add a New AI Assistant

  1. Create the plugin directory.
  2. Write config.json.
  3. Write Bootstrap.php.
  4. Write the Agent class.
  5. Write the Tool class.
  6. Call registerPluginAgent().
  7. Call registerPluginTool().
  8. Call addToolToAgent().
  9. Add menus, scenarios, and permissions in registerHooks().
  10. Write migrations.
  11. Run tests.

# Extend an Existing Agent

  1. You do not necessarily need to create a new Agent.
  2. Write the plugin Tool directly.
  3. Call registerPluginTool().
  4. Call addToolToAgent('existing-scene', 'your-tool-name').
  5. Add permissions.
  6. Test that “the tool is attached to the correct Agent.”

# 21. Final Rule of Thumb

You can remember these four sentences:

  1. Bootstrap determines what the plugin adds to the system.
  2. Agent determines who the assistant is and what it says.
  3. Tool determines what AI can actually do.
  4. Hook determines how menus, scenarios, and permissions are exposed.

If you continue extending AI later, these four points are basically unavoidable.


# 22. Direct Suggestions Based on the Current Project

Based on the current codebase, if you continue development later, I recommend this division of responsibilities:

  • AiArticleManager: focus on the article AI assistant.
  • If you only add a plugin capability to order analysis along the way, you can keep it inside this plugin, but clearly state that it “extends order-analysis.”
  • If order extensions become more and more numerous, it is better to split them into a separate order AI plugin to avoid making plugin responsibilities increasingly mixed.

This will make future maintenance much easier.