feat: implement GEWU service and local agent workflows
CI / quality (push) Canceled after 0s

This commit is contained in:
vasily committed 2026-10-14 19:21:35 +08:00
1 parent 4db3f45164
commit d25c04cdd2
175 files changed
+56243 -15

No files matched your search

+177
View File
@@ -0,0 +1,177 @@
"""Application-owned ports implemented by replaceable persistence adapters."""
from __future__ import annotations
import re
import sqlite3
from collections.abc import Iterable, Mapping
from dataclasses import dataclass
from pathlib import Path, PurePosixPath
from typing import Protocol
from gewu.domain.contracts import AutoAcceptPolicy, ProjectRecord
class CanonicalRepositoryError(RuntimeError):
"""A committed-record operation failed without exposing backend details."""
class CanonicalConflictError(CanonicalRepositoryError):
"""Expected-head publication lost its compare-and-swap race."""
_CANONICAL_PATH = re.compile(r"^[A-Za-z0-9._/-]+$")
def validate_canonical_path(path: str) -> None:
"""Enforce portable, relative POSIX paths for all repository implementations."""
pure = PurePosixPath(path)
if (
not path
or path.startswith("/")
or "\\" in path
or not _CANONICAL_PATH.fullmatch(path)
or pure.as_posix() != path
or any(part in {"", ".", ".."} for part in pure.parts)
):
raise CanonicalRepositoryError("Canonical record path is invalid")
class CanonicalRepository(Protocol):
"""Committed reads and expected-head atomic publication.
``history`` returns newest-first revisions that changed the requested path;
``introducing_commit`` returns the oldest revision in that path history.
Paths use ``validate_canonical_path``. Implementations raise the port-owned
errors above, never backend exceptions.
"""
def head(self) -> str: ...
def read_file(self, revision: str, path: str) -> bytes | None: ...
def list_files(self, revision: str, prefix: str) -> tuple[str, ...]: ...
def publish_files(
self,
*,
expected_head: str,
files: Mapping[str, bytes],
message: str,
index_directory: Path,
) -> str: ...
def introducing_commit(self, revision: str, path: str) -> str | None: ...
def history(self, revision: str, path: str, limit: int) -> tuple[str, ...]: ...
class ProjectRegistry(Protocol):
"""Versioned project and policy registry with serialized lifecycle writes."""
def records(self) -> tuple[ProjectRecord, ...]: ...
def create(self, project: ProjectRecord, policy: AutoAcceptPolicy) -> ProjectRecord: ...
def update_content(self, project_id: str, *, description: str, north_star: str, key_questions: tuple[str, ...]) -> ProjectRecord: ...
def archive(self, project_id: str) -> ProjectRecord: ...
class EmbeddingProvider(Protocol):
"""Replaceable, normalized text-vector provider for derived retrieval indexes."""
@property
def dimensions(self) -> int: ...
@property
def model_id(self) -> str: ...
@property
def artifact_sha256(self) -> str: ...
def embed_queries(self, texts: tuple[str, ...]) -> tuple[tuple[float, ...], ...]: ...
def embed_passages(self, texts: tuple[str, ...]) -> tuple[tuple[float, ...], ...]: ...
@dataclass(frozen=True, slots=True)
class VectorHit:
node_id: str
project_id: str
distance: float
@dataclass(frozen=True, slots=True)
class VectorGeneration:
generation_id: str
revision: str
model_id: str
artifact_sha256: str
content_profile: str
dimensions: int
node_count: int
class VectorIndex(Protocol):
"""Scoped vector candidate lookup over an activated immutable generation."""
def search(
self,
*,
query: tuple[float, ...],
project_ids: tuple[str, ...],
include_shared: bool,
limit: int,
expected_generation_id: str | None = None,
) -> tuple[VectorHit, ...]: ...
def active_generation(self) -> VectorGeneration | None: ...
def generation(self, generation_id: str) -> VectorGeneration | None: ...
def build_generation(
self,
*,
generation_id: str,
revision: str,
model_id: str,
artifact_sha256: str,
content_profile: str,
dimensions: int,
vectors: Iterable[tuple[str, str, tuple[float, ...]]],
) -> None: ...
def activate(self, generation_id: str, *, expected_active: str | None) -> str | None: ...
def active_generation_in_transaction(
self, connection: sqlite3.Connection
) -> VectorGeneration | None: ...
def generation_in_transaction(
self, connection: sqlite3.Connection, generation_id: str
) -> VectorGeneration | None: ...
def build_generation_in_transaction(
self,
connection: sqlite3.Connection,
*,
generation_id: str,
revision: str,
model_id: str,
artifact_sha256: str,
content_profile: str,
dimensions: int,
vectors: Iterable[tuple[str, str, tuple[float, ...]]],
) -> None: ...
def activate_in_transaction(
self,
connection: sqlite3.Connection,
generation_id: str,
*,
expected_active: str | None,
) -> str | None: ...
def deactivate_in_transaction(self, connection: sqlite3.Connection) -> None: ...