Skip to content

feat: hook-based knowledge backend registry + backend contract doc (depends on #280) - #406

Closed
esafwan wants to merge 4 commits into
feat/pgvector-knowledge-doctypesfrom
feat/knowledge-backend-hook-registry
Closed

feat: hook-based knowledge backend registry + backend contract doc (depends on #280)#406
esafwan wants to merge 4 commits into
feat/pgvector-knowledge-doctypesfrom
feat/knowledge-backend-hook-registry

Conversation

@esafwan

@esafwan esafwan commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

Depends on #280

This PR builds directly on #280 (feat/pgvector-knowledge-doctypes) and is intentionally based on that branch — do not merge before #280 lands. After #280 merges to develop, this PR's base should be retargeted to develop.

What this adds

  1. huf_knowledge_backends hook + dynamic registry — replaces the hardcoded backend dict in huf/ai/knowledge/backends/__init__.py::get_backend() with hook-based discovery, mirroring the existing huf_tools pattern. External Frappe apps can now register their own knowledge backend:

    # external app's hooks.py
    huf_knowledge_backends = {"qdrant": "my_app.knowledge.qdrant_backend.QdrantBackend"}

    Validation: registered classes must subclass KnowledgeBackend; collisions with built-in type keys are logged and skipped (external apps cannot shadow built-ins).

  2. BACKEND_CONTRACT.md — documents the backend contract and the two sanctioned implementation paths:

    • subclass LlamaIndexBackend (added in feat: add PGVector knowledge source #280) for stores LlamaIndex supports — recommended, ~50–100 lines per backend;
    • implement KnowledgeBackend directly for portable/unsupported stores (the sqlite_vec exception).
      Also covers: embeddings stay HUF-side, core connection fields vs advanced_config tuning params, and the live-test bar for new backends.
  3. Teststest_backend_registry.py: hook merging, collision handling, subclass validation (mocked frappe.get_hooks), run green in-bench.

Why

Audited across all knowledge backends: the hardcoded registry was the single blocker to external-app pluggability. This unlocks the standardization plan the historical vector-store PRs (#234, #235, #236, #238, #149, #168, #230, #231, #232) are being re-scoped against — each carries a TODO comment pointing here.

🤖 Generated with Claude Code


Update (2026-07-25): validated end-to-end on Frappe 16 + fix

Live-tested on a disposable bench (16_kbreg, Frappe 16.27, Python 3.14) with pgvector (built-in) and the new Redis backend (#434, registered via this hook — huf dogfooding its own registry).

Bug found & fixed (fix: normalise Frappe dict-of-lists hook shape in backend discovery): frappe.get_hooks() merges dict-valued hooks into a single dict of lists ({"redis": ["path.to.Class"]}), not a list of dicts as discovery assumed — so no hooked backend ever registered on a real site. _iter_hook_backends() now normalises both shapes; first declaration of a type key wins. BACKEND_CONTRACT.md documents the merge behaviour; registry tests mock the real shape.

E2E (real Gemini gemini-embedding-001 embeddings): registry discovery ✅ · advanced-config schema round-trip ✅ · pgvector full cycle (index → search → stats/health → delete) ✅ · redis full cycle ✅. Unit tests 28/30 (2 pre-existing standalone-context errors). ruff clean.

Follow-up: #434 (Redis backend via this hook) is stacked on this PR — merge order: #280#406#434.

esafwan added 2 commits July 25, 2026 03:29
frappe.get_hooks() merges dict-valued hooks into a single dict of lists
({'redis': ['path.to.Class']}), not a list of dicts as _discover_backends()
assumed — so no hooked backend ever registered on a real site. Add
_iter_hook_backends() to normalise both shapes; first declaration of a
type key wins. Document the merge behaviour in BACKEND_CONTRACT.md and
update registry tests to mock the real hook shape.
@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