Skip to content

feat: zvec embedded vector backend - #435

Closed
esafwan wants to merge 11 commits into
feat/redis-knowledge-backendfrom
feat/zvec-knowledge-backend
Closed

feat: zvec embedded vector backend#435
esafwan wants to merge 11 commits into
feat/redis-knowledge-backendfrom
feat/zvec-knowledge-backend

Conversation

@esafwan

@esafwan esafwan commented Jul 25, 2026

Copy link
Copy Markdown
Contributor

feat: zvec embedded vector backend

Adds zvec (Alibaba's in-process vector DB on Proxima, HNSW, cosine) as a built-in knowledge backend — the portable/no-server option alongside sqlite_fts/sqlite_vec. Salvaged from #168's sound backend core and brought onto the current contract architecture; supersedes #149 and #168 (both closed: identical code, uninstallable tridz-zvec dep, 1056 commits behind, conflicting with the #280/#406 line).

Why not the original PRs

  • Upstream zvec ships cp313/cp314 wheels since 0.2.1 (0.6.0 now) — the tridz-zvec fork workaround is moot and was never published to PyPI.
  • The original registered via the hardcoded dict and its filter DSL (==) is a syntax error in zvec 0.6.0 (= required); its scalar fields also lacked the inverted indexes filtering needs.

What's in this PR

  • ZvecBackend(KnowledgeBackend) (~480 lines, contract path 2 direct implementation): HUF-side embeddings, per-source collection in site private files, HNSW + configurable metric (cosine/l2/ip), injection-safe filter expressions (field whitelist + literal escaping), pre-count delete_chunks, dimension validation on collection open, get_advanced_config_schema() (metric, HNSW m/ef), health_check, supports_filters.
  • Built-in registration in _BUILTIN_BACKENDS + knowledge_type option + DocType/JS validation wiring + zvec>=0.2.1 dependency.
  • Pre-existing bug fixed (huf/ai/knowledge/hooks.py): on_knowledge_source_created initialized backends with only chunk settings — dimension-strict backends got stores created with the 1536 fallback before the indexer could initialize. Now uses _build_backend_config(doc).
  • 26 unit tests + E2E.

Testing (bench 16_kbreg, Frappe 16.27, Python 3.14, zvec 0.6.0)

Test Status
Registry discovery: zvec as built-in alongside pgvector + hook-registered redis
Advanced-config schema round-trip via whitelisted API
Full cycle: text input → Gemini gemini-embedding-001 (3072-dim) → index → semantic search (0.673) → stats/health → scoped delete
26 unit tests (filter escaping, metric score normalization, delete path, registry)
ruff check / ruff format on touched files

Notable zvec 0.6.0 behaviors found while testing: collection.stats is a pybind CollectionStats object (dict-looking repr, not subscriptable — attribute access required); collections are single-writer with a LOCK file; delete_by_filter returns None (hence pre-count); upsert buffers until flush().

Dependencies

esafwan added 9 commits July 25, 2026 21:40
Salvages the ZvecBackend from closed PR #168 (feature/zvec-vectorDB-integration)
and adapts it to the knowledge-backend contract:

- delete_chunks() returns the real count (filter-only query before delete)
- get_stats() includes backend_type: zvec
- get_advanced_config_schema() exposes HNSW/metric tuning knobs
- injection-safe filter building (identifier whitelist + quote escaping,
  single '=' zvec filter DSL)
- health_check(), supports_filters(), supports_hybrid_search()
- guarded zvec import with a clear zvec>=0.2.1 install error

Zvec is registered as a built-in backend (_BUILTIN_BACKENDS), wired into
the Knowledge Source DocType (options, vector depends_on, VECTOR_KNOWLEDGE_TYPES,
uses_vectors), the indexer embedding-config tuple, and pyproject dependencies.

Includes mocked unit tests (26) mirroring test_redis_backend.py, plus registry
tests covering built-in resolution and hook-override protection.
The after_insert hook initialized backends with only chunk settings, so
dimension-strict backends (zvec) got collections created with the 1536
fallback before the indexer could initialize with the real config.
Buffered upserts are not reflected in collection.stats until flushed,
so get_stats reported chunk_count=0 right after indexing.
flush() inside get_stats can raise on a leftover collection LOCK and the
exception handler then reports chunk_count=0. add_chunks already flushes
after writing, so stats are current without it.
…script

collection.stats is a pybind CollectionStats object whose repr looks like
a dict; stats['doc_count'] raised TypeError which get_stats swallowed,
reporting chunk_count=0. Add _doc_count() helper and use it in get_stats,
delete_chunks and health_check. Update test mocks to match the real type.
@esafwan esafwan changed the title feat: zvec embedded vector backend (salvaged from #168, supersedes #149/#168) feat: zvec embedded vector backend Jul 26, 2026
Mirror the pgvector frontend parity for the zvec embedded backend:
- add zvec to knowledgeTypes, VECTOR_KNOWLEDGE_TYPES, and labels
- extend KnowledgeType union and zod knowledge_type enum with zvec
- render the schema-driven AdvancedConfigFields card for zvec
  (no connection fields; tuning comes via advanced_config)
…to feat/zvec-knowledge-backend

# Conflicts:
#	frontend/src/components/knowledge/GeneralTab.tsx
#	frontend/src/components/knowledge/types.ts
#	frontend/src/data/knowledge.ts
#	frontend/src/types/knowledge.types.ts
@esafwan

esafwan commented Jul 26, 2026

Copy link
Copy Markdown
Contributor Author

Superseded by consolidated vector backend PR #467, now included in integration PR #468.

@esafwan esafwan closed this Jul 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant