AI second brain: on-device semantic vector tier — 0211 LIVE (checks off) - #236
Merged
Conversation
…cks off) Wakes the dormant @xnetjs/vectors engine behind the createGraphContextRetriever seam, making the *semantic* half of the AI second brain live in the assistant. - ai-vector-search.ts: createVectorEntrySearch — opt-in, lazy. The heavy @xenova model + usearch load via a dynamic import only on the first search after opt-in (zero boot/bundle cost when off, the 0204 constraint). Once warm it RRF-fuses vector + keyword; until warm and on ANY failure it falls back to keyword, so enabling it can only match or improve results, never break them. - ai-vector-storage.ts: IndexedDB BlobStore so the index restores across sessions instead of re-embedding the graph each time. - AiChatPanel: opt-in toggle (off by default); the live flag is read via a ref so toggling never tears down the AI runtime mid-conversation. - brain/persist.ts: realm-robust Uint8Array check (Symbol.toStringTag) — a plain instanceof mangles bytes across the dynamic-import / IndexedDB structured-clone boundary; and clear-on-failed-restore so "false ⇒ cold" truly means a clean slate. (Both surfaced by an adversarial review.) Verified end-to-end in-browser (warm → hybrid hit; IndexedDB persist → restore → found). 17 tests. Flips 0211 to [x]: the full hybrid GraphRAG (vector + keyword + graph-walk, budgeted, with memory + JIT expand) is now live. Remaining items (managed /ai/embed, data-bridge locality, WorkingSetPrewarm) are justified defers documented in the exploration. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Contributor
🖼️ UI changes in this PRNo visual differences detected in the changed UI. |
The production vite/rollup build follows the dynamic import('@xnetjs/vectors')
into usearch, a native Node HNSW addon that imports node:fs / node-gyp-build and
can't bundle for the browser ("existsSync is not exported by
__vite-browser-external"). @xnetjs/vectors already falls back to a pure-JS
LinearVectorIndex when usearch is absent — which is what runs in the browser — so
mark usearch external like the other optional dynamically-imported native deps.
The dev server tolerated it; only the production build (typecheck job) bundles
dynamic-import targets. @xenova/transformers bundles fine as a lazy chunk.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Contributor
|
Preview removed for PR #236. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The final piece of exploration 0211 — wakes the dormant
@xnetjs/vectorsengine behind the retriever seam, making the semantic half of the AI second brain live. After #228 (engine), #230 (seam), #232 (graph-aware retrieval live), and #233 (xnet_graph_expand), this flips 0211 to[x].What ships
ai-vector-search.ts—createVectorEntrySearch(opt-in, lazy, fallback-safe):@xenovamodel +usearchload via a dynamic import only on the first search after opt-in — zero boot/bundle cost when off (the 0204 constraint).ai-vector-storage.ts— IndexedDBBlobStoreso the index restores across sessions instead of re-embedding the graph each time.AiChatPanel— an opt-in toggle (off by default); the flag is read via a ref so toggling never tears down the AI runtime mid-conversation.Adversarial review caught 3 real bugs (fixed here)
A 22-agent review (18 findings → 15 false positives killed by verification → 3 confirmed) surfaced:
loadVectorTierreturnedfalseon a partial restore but left the index half-populated → now clears on failure so "false ⇒ cold" is honest.storage) → re-embedded every session and the realm-fix was dead in prod → now wired via IndexedDB.surface→ reset the active thread mid-conversation → now decoupled via a ref.Plus a realm-robustness fix in
brain/persist.ts: a plaininstanceof Uint8Arraymangles bytes across the dynamic-import / IndexedDB structured-clone boundary; theSymbol.toStringTagbrand holds.Verification
source: "hybrid"); IndexedDB persist → restore (no re-embed) → query found the node. The cross-realm persist fix exercised under real production conditions.tscclean for@xnetjs/brain+xnet-web; eslint + prettier clean;fallow audit— "✓ No issues in 10 changed files."Justified defers (documented in the 0211 doc; none block the core)
/ai/embedroute — the server-side embedding upgrade path; dead infra until demand, so it follows demand.apps/webnever instantiates aremoteNodeQueryClient, so there's no remote read path to route to.WorkingSetPrewarmplanner scores — marginal until per-node frequency/pinned signals are tracked at boot (it already ranks by recency).🤖 Generated with Claude Code