How it works

The extract → classify → store pipeline and search-time ranking.

Every memory.add() runs a pipeline before anything is written.

Pipeline overview

messages
  → extractFacts (LLM, latest turn)
  → embed
  → resolveEntity (align entity label — optional similarity + LLM)
  → ensureEntityInRegistry (optional, useEntityRegistry)
  → Pass 1: own history (ADD | UPDATE | REPLACE | NOOP)
  → if ADD: Pass 2 — label other agents' claims, then recency or authority on contradictions
  → apply op (write claim row + sync vector index)

1. Extract

extractFacts() sends the latest user/assistant turn to an LLM. Output is validated with Zod:

{ "facts": [{ "entity": "user.diet", "text": "The user is vegetarian", "type": "semantic" }] }

With useEntityRegistry: true, the prompt includes known keys from the entities table and the LLM must pick an existing key or use new:user.<domain>.

2. Resolve entity

resolveEntity() aligns the extracted label with existing active claims when fact text is semantically similar. Prevents user.timezone vs user.location drift from fragmenting memory.

SimilarityBehavior
≥ 0.85Auto-align to incumbent entity
0.70 – 0.85Optional LLM disambiguation
< 0.70Keep extracted entity

See Claims and entities for registry and config options.

3. Pass 1 — same agent

Vector search finds similar active claims from the same sourceAgent. The LLM classifies:

OpMeaning
ADDNew information
UPDATERefines without contradicting
REPLACEContradicts / supersedes own prior claim
NOOPRestates existing claim — nothing written

If pass 1 is not ADD, pass 2 is skipped.

4. Pass 2 — other agents

When pass 1 returns ADD, Vault loads every active claim on the same entity from other agents (from SQL, not similarity search). One LLM call labels each claim:

LabelResult
equivalentWrite nothing, unless another claim contradicts
compatibleStore the new claim active; leave the others active
contradictsApply recency or authority to those claims only

Search

memory.search(query) embeds the query, hits the vector store, hydrates rows from SQL, and applies recency-weighted scoring at query time. Stored confidence is not mutated.

Cross-agent search uses the exported search(db, vectorStore, embed, query, opts) with no sourceAgent filter.

Each agent process holds its own FAISS index. Call vectorStore.rebuild(db) before reads/writes when another process may have written claims — see Vector store.