How to add a custom chatbot tool
This page is for developers and describes eChat 1.6.0 and later. No configuration is needed in the Magento admin panel - a tool becomes available as soon as the module that ships it is installed.
The eChat extension gives the chatbot a set of tools - actions it can call while it answers a visitor. Out of the box it can look up an order (order_info), an order's invoice (order_invoice), send an email verification code (send_verification_code) and, with Mirasvit Help Desk installed, read and submit tickets (ticket_info, ticket_submit).
You can add your own tools via Magento's dependency injection, for example to check a quote, look up a return or read data from a custom entity. A custom tool can be added from any Magento module - one of your existing modules or a small new one - and you do not need to modify the eChat module. A new module must list Mirasvit_EChat in <sequence> in its etc/module.xml.
Step 1: Create the tool class
Public or protected
Anyone can open the chat, so every tool is protected unless it says otherwise:
- A protected tool implements
Mirasvit\EChat\Tool\ToolInterface. It runs only for an email address the visitor has proven they own: eChat asks for the email, sends a code and checks it before the tool runs. The tool receives the verified email in$params['email']and contains no verification code of its own. - A public tool implements
Mirasvit\EChat\Tool\PublicToolInterfaceinstead. It runs for anyone, with no email and no check.
Public (PublicToolInterface) | Protected (ToolInterface) |
|---|---|
| Stock level or availability of a product | Orders, invoices, shipments, returns |
| Store opening hours, shipping rates by country | Help desk tickets, addresses, account data |
| Catalogue facts, such as a size chart | Wishlists, reward points, anything looked up by email, customer or order number |
If you forget PublicToolInterface, the tool still works - the shopper is just asked to verify their email first. If you add it to a tool that returns personal data, that data is open to anyone. When unsure, leave the tool protected. The same rules are in the docblocks of both interfaces, so they are in front of a developer, or an AI coding assistant, working in your code.
Example
This tool lists the latest orders placed with an email address. It returns one shopper's data, so it is protected:
<?php
declare(strict_types=1);
namespace Vendor\EChatTools\Tool;
use Magento\Framework\Api\SearchCriteriaBuilder;
use Magento\Framework\Api\SortOrderBuilder;
use Magento\Sales\Api\OrderRepositoryInterface;
use Mirasvit\EChat\Tool\ToolInterface;
class RecentOrders implements ToolInterface
{
private OrderRepositoryInterface $orderRepository;
private SearchCriteriaBuilder $searchCriteriaBuilder;
private SortOrderBuilder $sortOrderBuilder;
public function __construct(
OrderRepositoryInterface $orderRepository,
SearchCriteriaBuilder $searchCriteriaBuilder,
SortOrderBuilder $sortOrderBuilder
) {
$this->orderRepository = $orderRepository;
$this->searchCriteriaBuilder = $searchCriteriaBuilder;
$this->sortOrderBuilder = $sortOrderBuilder;
}
public function getDefinition(): array
{
return [
'name' => 'vendor_recent_orders',
'description' => 'List the five most recent orders placed with an email address: number, date, status and total.',
'inputSchema' => [
'type' => 'object',
'properties' => [],
],
];
}
public function execute(array $params): array
{
// eChat calls this only for an email the visitor has verified.
$searchCriteria = $this->searchCriteriaBuilder
->addFilter('customer_email', $params['email'])
->addSortOrder($this->sortOrderBuilder->setField('created_at')->setDescendingDirection()->create())
->setPageSize(5)
->create();
$orders = [];
foreach ($this->orderRepository->getList($searchCriteria)->getItems() as $order) {
$orders[] = [
'number' => $order->getIncrementId(),
'date' => $order->getCreatedAt(),
'status' => $order->getStatusLabel(),
'total' => $order->getOrderCurrency()->formatTxt((float)$order->getGrandTotal()),
];
}
return ['orders' => $orders];
}
public function getJsHandler(): string
{
return '';
}
public function isAvailable(): bool
{
return true;
}
}
For a public tool, implement PublicToolInterface instead of ToolInterface. Nothing else changes.
What you need to implement
| Method | Description |
|---|---|
getDefinition() | The tool as the AI model sees it: name, description and inputSchema (a JSON Schema of the tool's own parameters). The name must be unique across all tools - prefix it with your vendor name. A protected tool does not declare email or verification_code: eChat adds them, with an instruction to verify the email first. |
execute() | Runs the tool. Receives the parameters - for a protected tool, including the verified email - and returns an array, sent back to the model as the result. Return ['error' => '...'] when the call cannot be completed; the model reads the message and decides what to do next. |
getJsHandler() | Return '' to run the tool on the server. A protected tool always runs on the server. |
isAvailable() | Return false to hide the tool, for example when a module it depends on is not installed. |
Step 2: Register the tool in di.xml
Add the tool to the ToolPool via dependency injection in your module's etc/di.xml:
<type name="Mirasvit\EChat\Tool\ToolPool">
<arguments>
<argument name="tools" xsi:type="array">
<item name="vendor_recent_orders" xsi:type="object">Vendor\EChatTools\Tool\RecentOrders</item>
</argument>
</arguments>
</type>
The name attribute of <item> is a key used for DI merging. The tool name the model sees comes from getDefinition().
Step 3: Run setup and test
php -f bin/magento setup:upgrade # for a new module
php -f bin/magento setup:di:compile # in production mode
php -f bin/magento cache:clean
The tool is offered to the chatbot in every new chat. Verify it:
-
Open
/mst_echat/tool/definitionson your storefront. Your tool should be listed, and a protected tool should haveemailandverification_codeadded. -
Call the tool the way the chatbot does, without a code:
curl -X POST https://your-store.com/mst_echat/tool/execute \
-H 'Content-Type: application/json' \
-d '{"tool": "vendor_recent_orders", "params": {"email": "[email protected]"}}'A protected tool must refuse:
{"error":"Verification code is required. Call send_verification_code for this email first."} -
Ask for the data in a new chat on the storefront.
Tell the assistant when to use the tool
The assistant is told when to use the built-in tools. For your tool it has to decide to look for one, and when it thinks the knowledge base can answer, it often does not. Say when to use it:
- for a tool that applies to many conversations, add a line to Settings > AI Assistant > Instructions (see Settings), for example: When a shopper asks about their recent orders, use the vendor_recent_orders tool.
- for a tool that belongs to one scenario, name it in a Guidance rule.
The assistant finds tools by their names and descriptions, so describe the tool in the words shoppers use. Test in a new chat: a chat that was already open may keep the tools it started with.
Reference
How protected tools are verified
- The assistant asks for the shopper's email and calls
send_verification_code. The store emails a 6-digit code, valid for 10 minutes. - The shopper types the code in the chat, and the assistant calls the tool with it. eChat checks it before
execute()runs. - The email then stays verified for 1 hour for this visitor's browser session, in this chat and in new ones, for every protected tool. Asked again,
send_verification_codeanswers that the email is already verified, and no new code is sent. - A logged-in customer asking about their own email needs no code.
- Another visitor using the same email must verify it again. So must a chat that does not run on a store page (a headless storefront or a direct chat link), on every protected call.
What eChat handles for every tool
| Case | What happens |
|---|---|
| Too many calls | eChat allows 30 tool calls per minute for each visitor, before any tool runs. Above that, the call returns an error asking to try again in a minute. Your tool does not handle this. |
| Exceptions | A LocalizedException message is returned to the model as the error. Any other exception is logged, and the model gets a generic message, so no internal details reach the chat. |
| Invalid classes | A class registered in the pool that does not implement ToolInterface is left out, with a warning in the Magento log. |
Keep the result small
eChat does not shorten what execute() returns: the whole result goes into the model's context. Return only the fields that answer the question, and limit lists (the example returns five orders). A long result costs tokens and slows the answer.