Skip to content

09. Unique Engineering Highlights

Prefer distinctive work over ordinary React/Vite plumbing.

1. In-browser Postgres + pgvector RAG store

Problem: Client-side RAG usually means ad-hoc IndexedDB or in-memory vectors without SQL/FTS.
How: PGlite with vector extension on idb://browser-rag; chunks store embeddings; GIN index on to_tsvector.
Why interesting: Real SQL hybrid search in the browser.
Tradeoffs: WASM DB size; sequential vector scans without ANN.
Evidence: src/db/client.ts, src/db/migrations.ts.
Interview line: “We run Postgres-with-pgvector in WASM so retrieval is ordinary SQL plus distance operators.”

2. Hybrid OR-keyword search + Reciprocal Rank Fusion

Problem: Pure vector search misses exact identifiers; pure keyword misses paraphrases.
How: Vector <=> list + ts_rank with &| tsquery rewrite; fuse with RRF 1/(k+rank), k=60.
Why interesting: Production-style fusion adapted to PGlite FTS quirks.
Tradeoffs: OR matching can be noisy; RRF ignores raw score magnitudes.
Evidence: retrieveChunks, reciprocalRankFusion in src/rag/retrieval.ts.
Interview line: “We convert AND tsquery to OR so sparse keyword hits still surface, then RRF merges ranks.”

3. Dual Web Workers for indexing and embeddings

Problem: PDF parse, chunking, and ONNX embedding would freeze the UI.
How: indexing.worker for extract+chunk; embedding.worker for Transformers.js feature-extraction (WebGPU, q8).
Why interesting: Clear ownership split between CPU-ish parse and GPU/WASM embed.
Tradeoffs: Worker message-passing overhead; embedding still sequential per text in the worker loop.
Evidence: src/rag/indexing.ts, src/workers/*, LocalEmbeddingProvider.
Interview line: “Parse and embed never block React — each has its own module worker.”

4. Multi-engine LLM adapter with thinking parsers

Problem: Browser LLM stacks differ (WebLLM vs Transformers vs custom kernels).
How: LLMEngineAdapter map; AI SDK streaming for some engines; parseRawStream + family parsers for kernels; thinking deltas unified.
Why interesting: One chat UX over four backends, including mobile-oriented kernels.
Tradeoffs: Capability matrix complexity; tool path stubbed.
Evidence: src/llm/llm-runtime.ts, src/llm/llm-models.ts, src/llm/parsers/*.
Interview line: “Chat code targets stream events, not a single vendor SDK.”

5. Conversation-aware retrieval rewrite

Problem: Follow-ups like “what about the second one?” fail lexical/vector search.
How: Optional LLM rewrite to a standalone query (128 tokens, no thinking) before retrieval; answer still sees history.
Why interesting: Separates search utterance from answer context.
Tradeoffs: Extra latency/tokens; rewrite failures fall back silently.
Evidence: rewriteQueryForRetrieval in src/rag/orchestrator.ts.
Interview line: “We rewrite for retrieval but answer with the original multi-turn thread.”

6. Retrieval debug panel with stage timings

Problem: Local RAG failures are opaque (bad rewrite? weak vectors? keyword miss?).
How: Emit RagDebugInfo / RetrievalDebugInfo with semantic, keyword, fused hits and embed/vector/keyword/fusion timings.
Why interesting: Turns the chat UI into a pipeline debugger.
Tradeoffs: Debug payload size; UI complexity.
Evidence: src/components/chat/retrieval-debug-panel.tsx, orchestrator yields.
Interview line: “Every answer can show the exact hybrid fusion that produced its citations.”

7. Project-scoped embedding consistency

Problem: Mixing embedding models corrupts nearest-neighbor search.
How: Project stores embedding_model_id; chunks record model id/dims; retrieval filters by model.
Why interesting: Treats embedding model as a schema constraint, not a global setting.
Tradeoffs: Soft UI lock — updates can still change the field without forced reindex.
Evidence: projects table, createProject, retrieveChunks filter.
Interview line: “Each workspace is pinned to one embedding space.”

8. Full workspace backup via PGlite data dir

Problem: Browser apps rarely offer portable DB backups.
How: dumpDataDir / loadDataDir as .tar.gz, with prefs mirrored into settings.
Why interesting: Treats the WASM DB like a real database artifact.
Tradeoffs: Separate file IDB not included; restore is destructive.
Evidence: exportDb / importDb in src/db/client.ts.
Interview line: “You can export the entire vector workspace as a tarball and restore it.”