Conversation-isolated memory for chatbot turns inside a single brain. Messages are text chunks tagged by conversation_id; rolling summaries and per-user preferences live as structured rows. The chatbot plugin wires these hooks automatically when this package is present as plugins/chatbot-memory.
| Registry name | chatbot-memory-single-brain |
| Install / folder id | chatbot-memory |
| Version | 1.0.0 |
| BrainAPI | >=2.13.0 |
| Route prefix | /conversations |
| Celery task | chatbot_memory.update_conversation_after_message |
| Queue | chatbot_memory |
Product docs: Chatbot memory.
Ideal for “one brain per user or tenant, many conversation threads.” Isolation is by conversation_id (and optional user_id) within one brain_id — not a brain per chat.
Clone into the directory name the chatbot plugin expects:
git clone https://github.com/Lumen-Labs/brainapi-plugin-chatbot-memory.git plugins/chatbot-memoryRegistry name is the manifest name:
./bin/brainapi install chatbot-memory-single-brain
# then ensure the folder is plugins/chatbot-memory so chatbot can detect itRestart the API and the Celery worker. The worker must consume queue chatbot_memory or meta/preferences will not update after saves.
POST /conversations/messages
(or chatbot inference with conversation_id)
│
▼
save text chunk
metadata: role, conversation_id, kind=chatbot_message
│
▼
Celery: update meta summary + user preferences
│
▼
GET .../context → last messages + meta + preferences
- While the conversation summary stays under
SUMMARY_CTX_MAX_LENGTH(20 000 characters), meta is an id→text map of recent turns. - When it overflows, an updater agent compresses the summary and can emit observations.
- User preferences are updated asynchronously when
user_idis present on the saved chunk. The HTTPPOST /conversations/messagesbody does not includeuser_id; chatbot inference does, via thesave_chatbot_memory_messagehook.
KG enrichment from updater observations is currently disabled in code. Summaries and preferences still persist.
On register, this plugin sets:
context.save_chatbot_memory_messagecontext.get_chatbot_memory_conversation_contextcontext.adapters.conversation_metacontext.adapters.user_preferences
The chatbot plugin detects this package by directory name chatbot-memory.
All routes use normal BrainAPI auth and brain scoping (BrainPAT + brain id).
POST /conversations/messages
{
"message": "Hello",
"role": "user",
"conversation_id": "conv-123"
}Response includes the saved text chunk and enqueues the async meta/preferences updater.
GET /conversations/meta?limit=100&skip=0
Returns { data: ConversationMeta[], total }.
| Method | Path | Notes |
|---|---|---|
POST |
/conversations/{conversation_id}/meta |
Body { "summary": { "...": "..." } } |
GET |
/conversations/{conversation_id}/meta |
404 if missing |
PUT |
/conversations/{conversation_id}/meta |
404 if missing; same body as POST |
ConversationMeta: { conversation_id: string, summary: Record<string, string> }.
GET /conversations/{conversation_id}/messages?limit=100&skip=0
Ordered turns with id, message, role, conversation_id, inserted_at.
GET /conversations/{conversation_id}/context
Returns meta, preferences (only if the controller is called with user_id — the HTTP route currently does not take user_id), and up to 10 last_messages. Chatbot inference calls the controller directly with user_id.
GET /conversations/{user_id}/preferences
Loads the user_preferences structured row for that user in the brain (empty/null if never written).
| Kind | Storage | Discriminator |
|---|---|---|
| Chat turns | Text chunks | metadata.kind = chatbot_message, metadata.conversation_id |
| Conversation summary | Structured data | types: [conversation_meta] |
| User preferences | Structured data | types: [user_preferences] |
curl -X POST "$BRAINAPI_URL/chatbot/inference" \
-H "Content-Type: application/json" \
-H "BrainPAT: $BRAINPAT_TOKEN" \
-H "X-Brain-ID: example01" \
-d '{
"model": "openai::gpt-4o-mini",
"input": "What did we decide last time?",
"conversation_id": "conv-123",
"user_id": "user-456",
"stream": false
}'With both plugins loaded, that call loads memory context, saves the user turn, generates a reply (optionally with MCP tools), and saves the agent turn.
- Worker must listen on queue
chatbot_memory. - Do not point this at LoCoMo/BEAM eval brains unless you intend to mix chat memory into those graphs.
- Folder name must stay
chatbot-memoryfor chatbot detection.
chatbot-memory/
plugin.yaml
main.py
routes/conversations.py
controllers/conversations.py
adapters/conversations.py
agents/updater.py
prompts/updater.py
constants/conversations.py
workers/tasks.py
workers/celery.py # Queue("chatbot_memory")
Pushes to main publish to the BrainAPI registry via GitHub Actions.
Apache License, Version 2.0. See LICENSE.