π§ Embedders
Embedders decide how batched recall ranks. (Memwal searches server-side - it needs none.) Pick with MEMORY_EMBEDDER or an explicit instance.
import '@lighthouse-ai/embed-local'
import { createEmbedder } from '@lighthouse-ai/core'
import { BatchedEngine } from '@lighthouse-ai/engine-batched'
const embedder = await createEmbedder('local')
const memory = new BatchedEngine(storage, { namespace: 'demo', embedder })
// keyword-only, zero deps:
const keywordOnly = new BatchedEngine(storage, { namespace: 'demo', embedder: null })
Comparisonβ
| Name | Recall | Needs |
|---|---|---|
local (default) | MiniLM all-MiniLM-L6-v2 in-process, hybrid 0.7 Γ cosine + 0.3 Γ keyword, keyword fallback | ~25 MB model download once, then offline |
keyword | Token + tag overlap only, zero deps | nothing (pass embedder: null) |
remote | No local package - the memwal relayer embeds and searches server-side | memwal engine only |
Set MEMORY_EMBEDDER=keyword for word-match only, or pass an embedder explicitly. Tests pin local-fs + keyword explicitly so they stay offline.
local - semantic, on-deviceβ
- Model:
Xenova/all-MiniLM-L6-v2viaembed-local, running fully in-process. The ~25 MB weights download once, then everything is offline - no content leaves the machine. - Embedder id looks like
local:Xenova/all-MiniLM-L6-v2. Vectors carry their model id (embeddingModel); recall only compares same-model vectors, so switching models safely falls back to keyword until backfilled. - If the model cannot load (e.g. offline on first use), recall degrades gracefully to pure keyword scoring -
status()reports which mode is active viaembeddings.
This is what lets "which hosting platform is used for releases?" find "deploys to Vercel on the main branch" with zero shared keywords.
keyword - word-match, zero depsβ
score = hits / βwords + 0.5 per tag appearing in the query
tokenize() lowercases, splits on non-alphanumerics, and drops 1-char tokens. Content-word hits are dampened by memory length (hits / βwords); each tag that appears in the query adds +0.5. Ties break by recency.
Use it when dependencies, model downloads, or network access are unacceptable - e.g. CI, edge functions, air-gapped machines.
Hybrid scoring (batched + local)β
score = 0.7 Γ cosine(query, memory) + 0.3 Γ min(1, keywordScore)
- Semantic component - cosine similarity (0..1) between query and memory vectors of the same
embeddingModel. - Keyword component -
min(1, keywordScore)so long memories with many hits cannot dominate. - With
embedder: null,score = keywordScoredirectly.
recall() returns all three so you can debug ranking:
const [top] = await memory.recall('how does the user ship code?')
console.log(top.score, top.semanticScore, top.keywordScore)
remote - memwal onlyβ
There is no remote package to install. When MEMORY_ENGINE=memwal, embeddings live in the relayer and recall() accepts maxDistance instead of configuring an embedder. See Memwal Engine.