Memory
Munin has two memory layers. They solve different problems and are both local.
Vector memory
MemoryService stores semantically searchable snippets from chat messages. The production implementation is FlutterGemmaMemoryService.
The implementation uses:
- Gecko embeddings through
flutter_gemma. SqliteVectorStorefromflutter_gemma_rag_sqlite.- A local database named
munin_memory.dbin the application documents directory.
Every remembered message stores:
- The message id as document id.
- The message text as document content.
- The embedding vector.
- Metadata containing conversation id and sender flag.
Initialization
Memory initializes lazily through _ensureReady. Startup also calls warmUp() after the first frame so the first real turn does not pay the full embedder and store setup cost.
If the embedder or vector store cannot initialize, memory marks itself unavailable and all methods become safe no-ops. Chat continues without memory.
Remembering messages
ChatController calls memory.remember for user messages after they are saved. It also remembers assistant replies after finalization.
The remember path:
- Trim text.
- Ensure embedder and vector store are ready.
- Generate an embedding.
- Add a document to the vector store.
- Ignore individual failures so a failed embed does not break chat.
Recalling messages
Before a model reply, ChatController calls memory.recall(query) with a timeout. The service embeds the query and searches similar vectors with:
topK: default 6.threshold: 0.35.
The controller injects up to three recalled snippets into the prompt, skipping the current user message and duplicate content.
Profile memory
MemoryProfileService maintains durable user facts. These facts are stored in SharedPreferences under StorageKeys.memoryFacts.
Profile memory exists because vector search alone can miss direct identity questions. For example, a query like "what is my name" may not be close enough to the original message where the user introduced themselves. Profile facts are always injected into every turn.
Learning profile facts
After a successful assistant reply, the controller calls MemoryProfileService.learnFrom asynchronously.
The utility model receives one exchange and extracts lasting facts only:
- Name.
- Location.
- Job or role.
- Stable preferences.
- Ongoing projects.
- Goals.
- Important relationships.
Transient task details are ignored. The model must return a JSON array of short third-person strings.
Merging facts
The profile service deduplicates and updates facts:
- Single-valued attributes such as name, age, location, and job replace older facts about the same attribute.
- Near-duplicate facts collapse using significant-word overlap.
- Multi-valued preferences and projects can accumulate.
- The list is capped at 40 facts.
User management
The memory settings page lets users:
- Search saved facts.
- Add a fact manually.
- Remove one fact.
- Forget all saved facts.
Wiping profile memory does not delete conversations. Clearing chats is handled separately.
Forgetting vector memory
The MemoryService contract supports:
forgetMessagesfor messages deleted with a conversation.forgetAllfor full memory wipe.
These operations are defensive. If the vector store is unavailable, they return without crashing.