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.