nodebb-plugin-search-agent
v0.0.943
Published
NodeBB plugin that adds a floating chat assistant to help users find relevant forum topics using TF-IDF text similarity
Maintainers
Readme
nodebb-plugin-search-agent
A NodeBB plugin that adds a floating chat assistant in the bottom-left corner of every forum page.
Users can type a natural-language question and receive a ranked list of relevant forum topic links — powered entirely by an in-process TF-IDF cosine-similarity engine (no external ML services required).
Features
- Floating Action Button (FAB) — always visible in the bottom-left corner, out of the way of existing UI.
- Chat panel — opens upward from the FAB with a smooth animation.
- Natural-language query — accepts free-form questions, not just keywords.
- TF-IDF similarity ranking — titles weighted ×3 over body text; smoothed IDF over the indexed corpus.
- In-memory index with TTL cache — built once every 5 minutes; instant subsequent queries.
- Admin settings page — configure topic limit, max results, and guest access from the ACP.
- Accessible — ARIA roles, keyboard navigation, focus management,
Escapeto close. - Zero extra npm dependencies — works on any NodeBB installation as-is.
- i18n-ready — translations for
en-US,en-GB, anddeincluded.
Architecture
Browser NodeBB Server
────────────────────────────── ───────────────────────────────────────────
public/lib/main.js library.js
• Injects FAB + chat panel • static:app.load → registers admin route
• Sends POST on submit • static:api.routes → registers API route
• Renders result bubbles • filter:admin.header.build → ACP nav link
│ │
│ POST /api/v3/plugins/ │
│ search-agent/query │
└──────────────────────────────────►│
▼
lib/controllers.js
handleQuery()
│
▼
lib/searchHandler.js
getIndex() ──► cache (5 min TTL)
search()
│
▼
lib/similarity.js
buildIndex() (TF-IDF vectors)
query() (cosine similarity)
│
NodeBB database
db.getSortedSetRevRange('topics:recent')
topics.getTopicsFields()
posts.getPostsFields()Similarity algorithm
- Tokenisation – lowercase, strip HTML, remove punctuation, discard stop-words, keep tokens ≥ 3 chars.
- Document construction – topic title repeated ×3 then concatenated with main-post body (title bias).
- TF – raw term frequency within the document.
- IDF – smoothed:
log((N+1) / (df+1)) + 1to avoid zero-division on rare terms. - TF-IDF vector – sparse
Map<term, weight>per document. - Query vector – raw TF of the query tokens (no IDF, since it is a single document).
- Cosine similarity – dot product of query × doc divided by the product of their L2 norms.
- Ranking – sort descending, return top-N (default 10).
Installation
From the NodeBB Plugin Directory
Search for Search Agent in ACP → Extend → Plugins and click Install.
Manual (development)
# Inside your NodeBB installation root
cd node_modules
git clone https://github.com/your-org/nodebb-plugin-search-agent
cd nodebb-plugin-search-agentThen in the NodeBB ACP → Extend → Plugins, find Search Agent and click Activate, then Rebuild & Restart.
Configuration
Navigate to ACP → Plugins → Search Agent.
| Setting | Default | Description |
|---|---|---|
| topicLimit | 500 | Maximum number of recent topics loaded into the index. |
| maxResults | 10 | Maximum results returned per query. |
| guestsAllowed | off | When enabled, guests (logged-out users) can also use the widget. |
Settings are stored under the key search-agent via meta.settings.
API Reference
POST /api/v3/plugins/search-agent/query
Requires a valid session or Bearer token (unless guestsAllowed is enabled).
Request body
{ "query": "how do I reset my password?" }Success response
{
"status": { "code": "ok", "message": "OK" },
"response": {
"results": [
{ "tid": 42, "title": "Password reset guide", "url": "/topic/42/password-reset-guide", "score": 0.71 },
{ "tid": 17, "title": "Account recovery options", "url": "/topic/17/account-recovery", "score": 0.54 }
]
}
}Error codes
| HTTP | Meaning | |---|---| | 400 | Empty or too-long query | | 401/403 | Not authenticated | | 500 | Server-side error (check NodeBB logs) |
File Structure
nodebb-plugin-search-agent/
├── library.js Main plugin: registers hooks & routes
├── plugin.json Plugin manifest (hooks, assets, modules)
├── package.json
├── lib/
│ ├── controllers.js Route handlers (admin page + query API)
│ ├── searchHandler.js NodeBB DB integration + index caching
│ └── similarity.js Pure-JS TF-IDF engine
├── public/lib/
│ ├── main.js Frontend: FAB injection, chat panel, API calls
│ ├── admin.js ACP settings page module
│ └── acp-main.js ACP-bundled bootstrap script
├── scss/
│ └── search-agent.scss All styles: FAB, panel, bubbles, animations
├── templates/
│ └── admin/plugins/
│ └── search-agent.tpl ACP settings page template
└── languages/
├── en-US/search-agent.json
├── en-GB/search-agent.json
└── de/search-agent.jsonDesign Decisions
Why TF-IDF instead of a vector embedding model?
External ML services (OpenAI, HuggingFace) require API keys, network calls, and add latency. A neural embedding approach also demands significant RAM for local inference. TF-IDF runs entirely in the Node.js process with zero memory or network overhead and is very fast (<10 ms per query on 500 topics), making it the right default for a self-hosted forum plugin.
Why cache the index instead of building it per request?topics.getTopicsFields + posts.getPostsFields are database calls that add 50–200 ms. The index build itself adds another 20–50 ms. Caching amortises this to near zero. A 5-minute TTL means new topics appear within one cache window.
Why title ×3 weight?
Forum users almost always phrase questions using words that appear in topic titles. Over-weighting the body would dilute the signal for short replies and off-topic content in long threads.
Why restrict the index to topics:recent?
For large forums (100 k+ topics) building a full-corpus index at startup would consume excessive memory. The 500-topic default covers the most active/relevant content and can be raised in settings.
Local Development
# 1. Clone NodeBB
git clone https://github.com/NodeBB/NodeBB && cd NodeBB
npm install
# 2. Link the plugin
cd node_modules
git clone <this-repo> nodebb-plugin-search-agent
# 3. Start NodeBB
cd ../..
./nodebb setup # follow the setup wizard
./nodebb start
# 4. Activate the plugin in ACP and rebuildLicense
MIT
