Files
ThothII/harness/tht/adapters/factory.py
T

126 lines
5.1 KiB
Python

"""Central construction of deployment-specific adapters."""
from tht.adapters.dwh import PostgresDwhAdapter, ThothRestDwhAdapter
from tht.adapters.evidence import FilesystemEvidenceSource, HttpManifestEvidenceSource
from tht.adapters.vector import PgVectorStore, ThothHttpVectorStore
from tht.config import Config, ConfigError
from tht.db.connection import make_engine
from tht.ports.dwh import DwhAdapter
from tht.ports.vector import VectorStore
from tht.vectorstore.rest_client import VectorRestClient
def build_dwh(cfg: Config) -> DwhAdapter:
"""Build the DWH adapter selected by the validated workspace resource."""
resource = cfg.dwh
match resource.type:
case "postgres_direct":
return PostgresDwhAdapter(
resource.connection,
statement_timeout_ms=cfg.execution.statement_timeout_ms,
)
case "thoth_rest":
return ThothRestDwhAdapter(resource.database, resource.endpoint)
case other: # pragma: no cover - Pydantic's discriminator rejects this first.
raise ConfigError(f"Adapter DWH non supportato: {other}")
def build_vector_store(cfg: Config, *, require_write: bool = False) -> VectorStore:
"""Build the vector adapter, optionally requiring an HTTP writer credential."""
resource = cfg.vectors
if resource is None:
raise ConfigError("Risorsa vectors non configurata")
match resource.type:
case "pgvector_direct":
reader = resource.reader or resource.connection
if require_write and resource.writer is None:
raise ConfigError("Vector writer non configurato per pgvector_direct")
return PgVectorStore(
reader,
resource.writer,
expected_dimension=cfg.embeddings.dim if cfg.embeddings is not None else None,
)
case "thoth_vector_http":
if require_write and resource.writer is None:
raise ConfigError("Vector writer non configurato")
return ThothHttpVectorStore(
VectorRestClient(resource.reader) if resource.reader is not None else None,
VectorRestClient(resource.writer) if resource.writer is not None else None,
expected_dimension=cfg.embeddings.dim if cfg.embeddings is not None else None,
)
case other: # pragma: no cover - Pydantic's discriminator rejects this first.
raise ConfigError(f"Adapter vector non supportato: {other}")
def build_vector_loader(cfg: Config, collection: str):
"""Compatibility construction for legacy collection sync commands."""
resource = cfg.vectors
if resource is None:
raise ConfigError("Risorsa vectors non configurata")
if cfg.embeddings is None:
raise ConfigError("Embeddings non configurati")
if (
resource.type == "thoth_vector_http"
and resource.writer is not None
and (cfg.profile == "workstation" or resource.direct is None)
):
from tht.vectorstore.rest_writer import RestVectorWriter
return RestVectorWriter(VectorRestClient(resource.writer), table=collection)
connection = (
resource.writer or resource.connection
if resource.type == "pgvector_direct"
else resource.direct
)
if connection is None:
raise ConfigError("Vector writer non configurato")
from tht.vectorstore.store import VectorStore as TableVectorStore
return TableVectorStore(
make_engine(connection),
schema=connection.db_schema,
table=collection,
dim=cfg.embeddings.dim,
)
def build_evidence_sources(cfg: Config):
"""Build configured Evidence sources, including the legacy curated filesystem tree."""
evidence = cfg.evidence
if evidence is None:
return []
sources = []
if evidence.source_root is not None:
sources.append(FilesystemEvidenceSource(evidence.source_root / evidence.evidence_dir))
for resource in evidence.sources:
match resource.type:
case "filesystem":
sources.append(
FilesystemEvidenceSource(
resource.root,
patterns=resource.patterns,
max_bytes=resource.max_bytes,
)
)
case "http":
sources.append(
HttpManifestEvidenceSource(
[url.get_secret_value() for url in resource.urls],
connect_timeout=resource.connect_timeout,
read_timeout=resource.read_timeout,
max_bytes=resource.max_bytes,
max_redirects=resource.max_redirects,
allow_private_hosts=resource.allow_private_hosts,
max_cache_bytes=resource.max_cache_bytes,
)
)
case other: # pragma: no cover - Pydantic rejects unsupported discriminators.
raise ConfigError(f"Adapter evidence non supportato: {other}")
return sources
__all__ = ["build_dwh", "build_evidence_sources", "build_vector_loader", "build_vector_store"]