Skip to main content

🧠 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​

NameRecallNeeds
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
keywordToken + tag overlap only, zero depsnothing (pass embedder: null)
remoteNo local package - the memwal relayer embeds and searches server-sidememwal 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-v2 via embed-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 via embeddings.

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 = keywordScore directly.

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.