Implemented the Backend Abstraction Layer (BAL) for the Advanced Context Management System, following the specification in docs/specification.md Section ACMS > Backend Abstraction Layer and ADR-014. Key additions: - TextBackend protocol with search(query, scope, max_results) returning list[TextResult], and TextResult frozen dataclass (uko_uri, content, score, metadata fields) - VectorBackend protocol with similarity_search(embedding, scope, top_k) returning list[VectorResult], and VectorResult frozen dataclass - GraphBackend protocol with sparql_query(query, scope), get_triples(subject), and traverse(start, depth) methods returning GraphResult frozen dataclass (triples, metadata fields) - In-memory stub backends (InMemoryTextBackend, InMemoryVectorBackend, InMemoryGraphBackend) that validate arguments and return empty results, serving as development placeholders and test doubles - DI container registration as configurable Singletons with provider selection via override_providers() - Behave BDD feature (35 scenarios / 83 steps) covering protocol compliance, argument validation, result immutability, and DI resolution - Robot Framework smoke tests (6 tests) for integration verification - ASV benchmarks for stub query overhead and instantiation time - Reference documentation at docs/reference/acms_backends.md Design decisions: - Used @runtime_checkable Protocol for structural subtyping, consistent with existing ResourceHandler pattern - Used frozen dataclasses (not Pydantic) for result types to minimize overhead in the hot path of context assembly - scope parameter typed as frozenset[str] for immutability and hashability - Stubs registered as default Singletons; production backends swap via DI ISSUES CLOSED: #498
5.4 KiB
ACMS Backend Abstraction Layer
The Backend Abstraction Layer (BAL) provides a uniform interface to heterogeneous data stores used by the Advanced Context Management System. Context strategies query text, vector, and graph backends through protocol-defined APIs, enabling backend implementations to be swapped without changing strategy code.
Architecture
Strategy ──► ScopedView ──► Backend Protocol ──► Physical Store
│
└── resource_filter (scope)
Each backend type has a Protocol (structural subtyping) and a corresponding
frozen result dataclass. Strategies never instantiate backends directly —
they receive scoped views from the Context Assembly Pipeline via dependency
injection.
Protocol Contracts
TextBackend
Full-text search over indexed resource content.
| Method | Signature | Returns |
|---|---|---|
search |
(query: str, *, scope: frozenset[str], max_results: int = 20) |
list[TextResult] |
Preconditions:
querymust be a non-empty string.max_resultsmust be a positive integer.
Postconditions:
- Returns results ordered by descending
score. - Results are restricted to resources whose ULIDs appear in
scope.
VectorBackend
Embedding similarity search over chunked resource content.
| Method | Signature | Returns |
|---|---|---|
similarity_search |
(embedding: list[float], *, scope: frozenset[str], top_k: int = 20) |
list[VectorResult] |
Preconditions:
embeddingmust be a non-empty list of floats.top_kmust be a positive integer.
Postconditions:
- Returns results ordered by descending
score(cosine similarity). - Results are restricted to resources whose ULIDs appear in
scope.
GraphBackend
Knowledge-graph queries and traversals over UKO triples.
| Method | Signature | Returns |
|---|---|---|
sparql_query |
(query: str, *, scope: frozenset[str]) |
GraphResult |
get_triples |
(subject: str) |
GraphResult |
traverse |
(start: str, *, depth: int = 2) |
GraphResult |
Preconditions:
queryandsubjectandstartmust be non-empty strings.depthmust be a non-negative integer.
Postconditions:
sparql_queryrestricts results to resources inscope.traversereturns triples discovered withindepthhops ofstart.
Result Types
All result types are frozen (immutable) dataclasses.
TextResult
| Field | Type | Description |
|---|---|---|
uko_uri |
str |
UKO URI of the matching information unit (non-empty) |
content |
str |
Matched text content |
score |
float |
Relevance score, 0.0 -- 1.0 |
metadata |
dict[str, str] |
Backend-specific metadata (default: empty) |
VectorResult
| Field | Type | Description |
|---|---|---|
uko_uri |
str |
UKO URI of the matching information unit (non-empty) |
content |
str |
Text content of matched chunk |
score |
float |
Cosine similarity, 0.0 -- 1.0 |
metadata |
dict[str, str] |
Backend-specific metadata (default: empty) |
GraphResult
| Field | Type | Description |
|---|---|---|
triples |
list[tuple[str, str, str]] |
(subject, predicate, object) triples |
metadata |
dict[str, str] |
Backend-specific metadata (default: empty) |
Extension Points
Implementing a Custom Backend
To add a new backend (e.g., Tantivy for text search):
- Create a class that satisfies the corresponding
Protocol(e.g.,TextBackend). - Implement all protocol methods with proper argument validation.
- Register the backend in the DI container by overriding the provider:
from cleveragents.application.container import override_providers
override_providers(text_backend=TantivyTextBackend(index_path="/data/tantivy"))
In-Memory Stubs
The following stubs are provided for development and testing:
| Stub | Protocol | Behaviour |
|---|---|---|
InMemoryTextBackend |
TextBackend |
Returns empty list; validates args |
InMemoryVectorBackend |
VectorBackend |
Returns empty list; validates args |
InMemoryGraphBackend |
GraphBackend |
Returns empty GraphResult; validates args |
Stubs are registered as the default providers in the DI container. They can
be overridden at runtime for production or per-test via override_providers().
DI Container Registration
Backends are registered as singletons in the DI container
(cleveragents.application.container.Container):
text_backend = providers.Singleton(InMemoryTextBackend)
vector_backend = providers.Singleton(InMemoryVectorBackend)
graph_backend = providers.Singleton(InMemoryGraphBackend)
To swap to a production backend, override the provider before first use:
container = get_container()
container.text_backend.override(providers.Singleton(TantivyTextBackend))
Module Locations
| Module | Purpose |
|---|---|
cleveragents.domain.models.acms.backends |
Protocol definitions and result dataclasses |
cleveragents.domain.models.acms.stubs |
In-memory stub implementations |
cleveragents.application.container |
DI container backend registration |
Related
- CRP Reference — Context Request Protocol types
- Specification: ACMS > Backend Abstraction Layer — Authoritative design
- ADR-014: Context Management — Architecture decision record