fix(adapter): close final foundation review

This commit is contained in:
2026-07-11 21:14:32 +02:00
parent 45d57756aa
commit 3e2ad7955c
15 changed files with 460 additions and 14 deletions
+52 -5
View File
@@ -4,8 +4,10 @@ from tht.ports.vector import (
VectorCapabilities,
VectorHealth,
VectorHit,
VectorReadUnavailable,
VectorWriteRecord,
VectorWriteUnavailable,
require_positive_limit,
)
from tht.vectorstore.rest_client import VectorRestClient
from tht.vectorstore.store import hit_from_metadata
@@ -18,21 +20,63 @@ def _merge(hits: list[VectorHit], limit: int) -> list[VectorHit]:
class ThothHttpVectorStore:
"""Vector port backed by the existing allowlisted REST RPCs."""
def __init__(self, reader: VectorRestClient, writer: VectorRestClient | None):
def __init__(
self,
reader: VectorRestClient | None,
writer: VectorRestClient | None,
expected_dimension: int | None = None,
):
self._reader = reader
self._writer = writer
self._expected_dimension = expected_dimension
@property
def capabilities(self) -> VectorCapabilities:
writable = self._writer is not None
return VectorCapabilities(search=True, existing_hashes=writable, upsert=writable)
return VectorCapabilities(
search=self._reader is not None, existing_hashes=writable, upsert=writable
)
def health(self) -> VectorHealth:
read_reachable, read_detail, read_tables = self._probe(self._reader)
write_reachable, write_detail, write_tables = self._probe(self._writer)
dimensions = tuple(sorted({
dimension
for row in [*read_tables, *write_tables]
if type(dimension := row.get("vector_dimensions")) is int
}))
compatible = (
None
if self._expected_dimension is None or not dimensions
else dimensions == (self._expected_dimension,)
)
reachable = [
status for status in (read_reachable, write_reachable) if status is not None
]
ok = bool(reachable) and all(reachable) and compatible is not False
details = [detail for detail in (read_detail, write_detail) if detail]
return VectorHealth(
ok=ok,
detail="; ".join(details) or None,
read_configured=self._reader is not None,
read_reachable=read_reachable,
read_detail=read_detail,
write_configured=self._writer is not None,
write_reachable=write_reachable,
write_detail=write_detail,
expected_dimension=self._expected_dimension,
observed_dimensions=dimensions,
dimension_compatible=compatible,
)
@staticmethod
def _probe(client: VectorRestClient | None) -> tuple[bool | None, str | None, list[dict]]:
if client is None:
return None, None, []
try:
self._reader.list_tables()
return True, None, client.list_tables()
except Exception as exc:
return VectorHealth(ok=False, detail=str(exc))
return VectorHealth(ok=True)
return False, str(exc), []
def search(
self,
@@ -42,6 +86,9 @@ class ThothHttpVectorStore:
limit: int,
kinds: list[str] | None = None,
) -> list[VectorHit]:
require_positive_limit(limit)
if self._reader is None:
raise VectorReadUnavailable("Vector reader credential is not configured")
hits: list[VectorHit] = []
for collection in collections:
rows = self._reader.search_similar(collection, embedding, limit, kinds=kinds)