AI Chatbot (DeepChat)
When to Use
Use this guide when integrating the DeepChat chatbot frontend with Drupal. Use AI Assistant API when building the backend assistant logic or custom actions.
The ai_chatbot module provides the frontend for AI assistants: blocks, a REST API, and toolbar integration. It uses the DeepChat web component.
Decision
| Situation | Choose | Why |
|---|---|---|
| Embed chatbot in Drupal page | ai_deepchat_block block |
No custom code; configure in block UI |
| Call from decoupled frontend | REST API with CSRF flow | Session-based; requires credentials: 'include' |
| Toolbar chatbot button | Set placement: toolbar on block |
hook_toolbar() registers automatically |
| Reset conversation | /ajax/chatbot/reset-session/{id}/{thread} |
Flood-protected: 3 resets per session |
| Custom chat front-end (Slack bot, etc.) | Implement ChatProcessorInterface |
Stable API contract for any UI to back-end |
Dependencies
ai_assistant_api(required)league/commonmark(optional, for Markdown rendering)
REST API Endpoints
| Endpoint | Method | Purpose | Permission |
|---|---|---|---|
/api/deepchat/session |
POST | Get CSRF token (plain text) | access deepchat api |
/api/deepchat |
POST | Send/receive messages | access deepchat api + CSRF |
/ajax/chatbot/reset-session/{assistant_id}/{thread_id} |
POST | Reset conversation (flood-protected: 3/session) | access deepchat api |
/ajax/chatbot/message-skeleton/{assistant_id}/{thread_id}/{user} |
GET | Get message HTML skeleton | access deepchat api |
API Request Format
{
"assistant_id": "my_assistant",
"thread_id": "optional-uuid",
"stream": 1,
"messages": [{"role": "user", "text": "Hello"}],
"contexts": {"current_route": "/node/1"},
"structured_results": false,
"show_copy_icon": true,
"verbose_mode": false
}
API Response Format
Non-streamed:
{"html": "<p>Response</p>", "should_continue": false}
Streamed (SSE):
data: {"html": "<p>partial</p>", "overwrite": true}\n\n
Each SSE chunk is a data: line with JSON containing html (the accumulated HTML so far) and overwrite: true (the client replaces the previous content rather than appending). The final chunk includes should_continue.
should_continue: true means the assistant called a tool and needs another round-trip — the frontend automatically re-requests.
Authentication Flow (for decoupled frontends)
// 1. Get CSRF token
const sessionRes = await fetch('/api/deepchat/session', {
method: 'POST',
credentials: 'include',
});
const csrfToken = await sessionRes.text();
// 2. Send message with token
const chatRes = await fetch(`/api/deepchat?token=${csrfToken}`, {
method: 'POST',
credentials: 'include',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
assistant_id: 'my_assistant',
stream: 0,
messages: [{ role: 'user', text: 'Hello' }],
}),
});
const data = await chatRes.json();
// data.html contains sanitized response
Block Configuration (ai_deepchat_block)
| Setting | Type | Description |
|---|---|---|
ai_assistant |
string | Assistant entity ID |
bot_name |
string | Display name |
bot_image |
text | Avatar URL |
first_message |
text | Initial bot greeting |
stream |
integer | Enable SSE streaming |
placement |
string | sticky, toolbar, or inline |
toggle_state |
string | remember, open, close |
width / height |
string | CSS dimensions |
style_file |
string | Custom DeepChat YAML theme path |
show_structured_results |
boolean | Show action results under messages |
show_copy_icon |
boolean | Copy button per message |
verbose_mode |
boolean | Show intermediate agent steps |
XSS Sanitization
The DeepChatApi controller sanitizes all LLM output with Xss::filter(), allowing only safe HTML tags: <a>, <b>, <br>, <code>, <em>, <h1>-<h6>, <hr>, <i>, <li>, <ol>, <p>, <pre>, <span>, <strong>, <table>, <td>, <th>, <tr>, <ul>, <img>, <details>, <summary>. All other HTML is stripped.
Toolbar Integration
When a DeepChat block is placed with placement: toolbar, the module implements hook_toolbar() to add a toolbar tray. The ChatbotHooks service handles toolbar, topbar, and theme suggestions. The toolbar variant uses the ai-deepchat--toolbar.html.twig template and the toolbar.yml style file.
DeepChat Theme Files
Place .yml files in {theme}/deepchat_styles/ or {module}/deepchat_styles/. Bundled: bard.yml, bing.yaml, chatgpt.yml, toolbar.yml.
Hooks
hook_deepchat_settings(array &$deepchat_settings) // Alter DeepChat component attributes
hook_deepchat_buttons_alter(array &$buttons) // Add/alter per-message buttons
hook_deepchat_prepend_message($message, $type, $assistant_id, $thread_id) // Prepend to responses
Setup Steps
- Enable
ai_chatbot(enablesai_assistant_apiautomatically) - Install
league/commonmarkfor Markdown rendering - Create an assistant at
/admin/config/ai/ai-assistant - Place the "AI DeepChat Chatbot" block; select assistant, configure placement
- Grant
access deepchat apito relevant roles - Toolbar button appears automatically when block is placed
ChatProcessor Plugins (New in 1.4)
ChatProcessorInterface (#[ChatProcessor] plugin type, manager plugin.manager.ai.chat_processor) is the contract between a conversational UI and whatever generates the reply — usually an AI assistant/agent, but it can be any custom logic (naive RAG, an ECA flow, a remote command). It lets contrib ship alternative chat front-ends (e.g. a Slack bot) against a stable Drupal-side API.
Key methods: setInput(ChatInput) / getInput(), setOutput(ChatOutput) / getOutput(), doExecute(): ChatOutput (the processing logic), execute(): ChatOutput (validates input, calls doExecute(), stores the output), plus thread-ID management. Extend ChatProcessorBase (Drupal\ai\Base\ChatProcessorBase) rather than implementing the interface directly.
Common Mistakes
| Mistake | Why it's wrong |
|---|---|
| Using WebFetch from frontend | Must use proper REST API with CSRF token |
Not including credentials: 'include' |
Session-based history requires cookies |
| Forgetting flood protection on reset | 3 attempts per session — design UI accordingly |
See Also
- AI Assistant API
- Security
- Reference:
web/modules/contrib/ai/modules/ai_chatbot/