025d379946
CI / benchmark-publish (pull_request) Has been skipped
CI / lint (pull_request) Successful in 14s
CI / quality (pull_request) Successful in 17s
CI / build (pull_request) Successful in 15s
CI / typecheck (pull_request) Successful in 33s
CI / security (pull_request) Successful in 42s
CI / unit_tests (pull_request) Successful in 2m36s
CI / docker (pull_request) Successful in 40s
CI / integration_tests (pull_request) Successful in 3m17s
CI / coverage (pull_request) Successful in 4m21s
CI / lint (push) Successful in 12s
CI / build (push) Successful in 15s
CI / quality (push) Successful in 16s
CI / security (push) Successful in 30s
CI / typecheck (push) Successful in 33s
CI / benchmark-regression (push) Has been skipped
CI / unit_tests (push) Successful in 2m36s
CI / docker (push) Successful in 40s
CI / integration_tests (push) Successful in 3m57s
CI / coverage (push) Successful in 5m22s
CI / benchmark-publish (push) Has been cancelled
CI / benchmark-regression (pull_request) Successful in 25m12s
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
168 lines
5.4 KiB
Markdown
168 lines
5.4 KiB
Markdown
# 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:**
|
|
|
|
- `query` must be a non-empty string.
|
|
- `max_results` must 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:**
|
|
|
|
- `embedding` must be a non-empty list of floats.
|
|
- `top_k` must 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:**
|
|
|
|
- `query` and `subject` and `start` must be non-empty strings.
|
|
- `depth` must be a non-negative integer.
|
|
|
|
**Postconditions:**
|
|
|
|
- `sparql_query` restricts results to resources in `scope`.
|
|
- `traverse` returns triples discovered within `depth` hops of `start`.
|
|
|
|
## 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):
|
|
|
|
1. Create a class that satisfies the corresponding `Protocol` (e.g., `TextBackend`).
|
|
2. Implement all protocol methods with proper argument validation.
|
|
3. Register the backend in the DI container by overriding the provider:
|
|
|
|
```python
|
|
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`):
|
|
|
|
```python
|
|
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:
|
|
|
|
```python
|
|
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](crp.md) — Context Request Protocol types
|
|
- [Specification: ACMS > Backend Abstraction Layer](../specification.md) — Authoritative design
|
|
- [ADR-014: Context Management](../adr/ADR-014-context-management-acms.md) — Architecture decision record
|