Files

77 lines
2.4 KiB
Python

"""Repository contract for model-stream truncation events."""
from __future__ import annotations
from abc import ABC, abstractmethod
from dataclasses import dataclass
from datetime import datetime
from typing import Any
# Hard retention cap. The user-facing promise is "最多存一个月" of truncation
# records; the SQL repository enforces it on every insert so no scheduler is
# required for the cap to hold.
RETENTION_DAYS = 30
@dataclass
class StreamTruncationEvent:
"""In-memory shape of a truncation event before persistence."""
id: str
created_at: datetime
model_name: str | None = None
provider_completion_id: str | None = None
run_id: str | None = None
# silent_no_terminal / incomplete_stream_error / length_truncated /
# content_filter / midstream_error
event_type: str = "silent_no_terminal"
strict_mode: bool = False
finish_reason: str = "none"
status: str = "success"
error_type: str | None = None
chunk_count: int = 0
duration_ms: int = 0
first_chunk_ms: int = -1
detail: str | None = None
@dataclass
class StreamTruncationQuery:
"""Filter set for the admin list endpoint."""
model_name: str | None = None
event_type: str | None = None
since: datetime | None = None
until: datetime | None = None
limit: int = 100
offset: int = 0
class StreamTruncationStore(ABC):
"""Persistence contract for the model-layer recorder + admin API."""
@abstractmethod
async def record(self, event: StreamTruncationEvent) -> None:
"""Persist one event and enforce the retention cap. Must never raise."""
raise NotImplementedError
@abstractmethod
async def list(self, query: StreamTruncationQuery) -> list[dict[str, Any]]:
"""Return matching rows (newest first), paginated by ``query``."""
raise NotImplementedError
@abstractmethod
async def count(self, query: StreamTruncationQuery) -> int:
"""Return the unpaginated row count for ``query``."""
raise NotImplementedError
@abstractmethod
async def model_breakdown(self, query: StreamTruncationQuery) -> list[dict[str, Any]]:
"""Per-model aggregate: ``[{model_name, event_type counts..., total, last_at}]``."""
raise NotImplementedError
@abstractmethod
async def purge_before(self, cutoff: datetime) -> int:
"""Delete rows older than ``cutoff``; return the deleted row count."""
raise NotImplementedError