Memory
The Memory screen (/memory) shows the long-term knowledge the assistants have accumulated. Memory entries are scoped per-instance: an entry written by support-bot is invisible to sales-bot.
Retrieval model
Memory retrieval uses hybrid search — pgvector cosine similarity merged with PostgreSQL FTS via Reciprocal Rank Fusion (k=60). See packages/engine/src/memory/hybrid-search.ts. Vector results capture semantic similarity; FTS results capture exact keyword and phrase matches; RRF combines the two ranked lists without requiring per-side score calibration.
Embeddings come from the instance’s embedder, chosen on the Settings tab independently of the chat provider: OpenAI text-embedding-3-small or Amazon Titan Text Embeddings v2. Anthropic and Nebius have no embeddings API, so an agent chatting on either needs one of those two configured — not necessarily OpenAI. The Settings tab warns when memoryEnabled is on but the selected embedder has no credentials, surfacing the most common misconfiguration before it produces runtime errors.
Switching the embedder deletes every memory for the agent: vectors are not converted between provider spaces.
Categories
Every memory is tagged with one of six categories:
| Category | Use for | Example |
|---|---|---|
general | Anything not in another category. | ”Acme uses Slack as primary comms tool.” |
preference | A user’s expressed preference. | ”Alice prefers tables over prose answers.” |
fact | A neutral factual statement about the user or domain. | ”Bob’s office is in Munich.” |
event | A specific dated event. | ”Demo with Acme on 2026-05-12 at 15:00 CEST.” |
relationship | A connection between two entities. | ”Carol manages Dan’s team.” |
decision | An explicit decision made. | ”Decided to use Postgres for the prototype.” |
Categories matter because memory search can be filtered by them, and because the auto-extractor uses them to decide priority.
Listing and searching
- Pagination with the same scheme as Conversations.
- Search — hybrid (vector + FTS) with Reciprocal Rank Fusion. The vector search uses the instance embedder; the keyword search uses PostgreSQL FTS; the two ranked lists are merged using RRF (k=60).
- Filters — by instance and by category.
Each row shows: content, category, importance (1–10), source conversation (link), created at.
The underlying /memories API call is instance-scoped: it requires an instanceId query parameter and returns HTTP 400 "instanceId is required" if called without one. The instance picker in the UI drives this param — there is no “all instances at once” view.
Manual creation
The New memory button inserts a memory by hand; it requires the memory:write permission (reading the list requires memory:read). Fill in:
- Content (free text)
- Category (dropdown)
- Importance (1–10)
- Optional source conversation id
Manual memories are immediately available to the assistant on the next turn.
Automatic extraction
When memoryEnabled is on for an instance, the engine runs an extractor in the background after every assistant response:
- The supervisor finishes its reply.
- A fire-and-forget task fires.
- The extractor takes the last 15 messages of the conversation, calls the LLM (tier
fast) with an extraction prompt that returns structured JSON, and gets back a list of (content, category, importance) triples. - Each triple is embedded with the instance embedder.
- For each triple, a deduplication check runs: cosine similarity > 0.90 against an existing memory triggers an UPDATE; otherwise an INSERT.
The user never waits for extraction. If extraction crashes, the conversation is not affected.
Deletion
Delete a memory from its row (trash icon) or bulk-delete from the list. Memories are not soft-deleted; the row is gone immediately.