Embedding provider boundary v0.1
August 15, 2026 ยท View on GitHub
Current status
The provider seam, native Google Gemini and OpenAI-compatible HTTP adapters, vector validation, cosine similarity, a rebuildable SQLite embedding cache, exact-scope semantic search, and reciprocal-rank fusion are implemented and tested. Hybrid recall and resumable background cache maintenance are available behind separate opt-ins.
Identity and dimension
An embedding space is identified by provider, model, and dimensions. Vectors
from different identities must never share an index or be compared. The Gemini
adapter requests outputDimensionality; the OpenAI-compatible adapter leaves
dimension negotiation to its upstream configuration. Both validate that every
returned vector has exactly the configured dimension.
Credential boundary
The live probe reads credentials only from environment variables. The API key
is used solely in the outbound authentication header and is absent from the
provider's public identity, errors, and probe output. .env.local and other
environment files are ignored by Git; .env.example contains no credential.
Copy .env.example to .env.local, fill the local values, build, then run:
node --env-file=.env.local scripts/probe-embedding.mjs
google-gemini uses Google's native batchEmbedContents endpoint and sends
the key in x-goog-api-key. newapi and openai-compatible select the retained
OpenAI-compatible /embeddings adapter and Bearer authentication. Unknown
provider names fail before any network request. NewAPI is therefore optional
rather than an architectural dependency.
The default example uses the stable gemini-embedding-2 model at 3072
dimensions. Changing model or dimensions creates a different embedding space
and requires a separate index or full vector rebuild.
The probe sends one fixed Chinese phrase and prints only provider/model, dimension, finiteness, and vector norm. It does not print or persist the vector.
Live connectivity verification
On 2026-08-15, the native adapter successfully called
gemini-embedding-2 directly through the Gemini API. The response contained
exactly 3072 finite components and had a vector norm of approximately 1.0.
Neither the credential nor the returned vector was printed or persisted.
An end-to-end smoke test then embedded three synthetic records in one batch and embedded one synthetic paraphrased query separately. Lexical trigram retrieval returned no candidate for that paraphrase, while semantic retrieval ranked the intended passive-memory record first with cosine similarity 0.795248. No real conversation or existing local database content was used.
A nine-query synthetic calibration followed. Semantic and hybrid retrieval ranked the intended record first for all six paraphrased positive queries; lexical retrieval did so for one of six. The minimum intended-record score was 0.727359, the maximum top score among three unrelated negative queries was 0.515617, and the narrowest positive top-one margin was 0.092378. A provisional minimum score of 0.62 lies inside this synthetic separation interval. This is a small engineering gate, not evidence that 0.62 generalizes to real memories.
Rebuildable cache
Schema version 4 introduced vectors stored by (provider, model, dimensions, content_sha256). Identical content is embedded once and can back multiple L0
records without weakening exact user/agent/workspace scope checks. Vector blobs
are little-endian Float32 values with strict byte-length and finiteness checks.
The cache is derived data: L0 remains authoritative, and a change of embedding
identity creates a separate cache namespace.
Schema version 5 retained this cache unchanged and added the independent L1 episode tables. Schema version 6 retained both while recording the L1 model-selection policy explicitly. Current schema version 7 adds a rebuildable L1 text index and content-free active memory-tool audits; embedding cache semantics remain unchanged.
The current semantic ranker intentionally uses an exact in-process linear scan. That keeps the reference behavior transparent and testable, but its memory and latency costs grow linearly with cached evidence. It is not the final vector index design.
Fusion baseline
Lexical BM25 and semantic cosine scores are not assumed to share a scale. Reciprocal-rank fusion combines their ordinal rankings; evidence present in both legs receives contributions from both. A later evaluation will choose the rank constant, candidate depths, recency/importance features, and diversity policy.
Background maintenance and availability
Document embedding no longer runs in the user request path. A bounded, lifecycle-owned maintenance pass uses the content-addressed cache as its durable resume point. It starts on mount, repeats at a configured interval, prevents overlapping runs, and is aborted before the SQLite store closes. Each direct request therefore sends only its query to the provider.
Failures use bounded exponential retry. A content-free runtime snapshot reports state, run/success/failure counts, consecutive failures, timestamps, next attempt time, the sanitized error class, and the last pass's numeric result. It never contains provider response text, evidence text, prompts, vectors, or credentials.
External query-embedding failures can either fall back to local lexical recall or fail the request. The audit stores only the sanitized failure class. Local store and validation errors remain fatal under both policies.
Before production-scale activation
- replace the exact linear scan with a measured indexed vector backend;
- expand semantic and hybrid evaluation with realistic, independently labelled samples;
- export maintenance health to an optional persistent metrics/UI boundary.