Skip to content

symfonic.agent.transcript_sqlite_reader

transcript_sqlite_reader

The native transcript reader over a SQLite checkpoint saver.

The local authority composes it over its own saver; the compatibility factory composes it over a saver it opens. It lives in the facade layer so both can: the platform may import the facade, never the reverse. The checkpoint record it checks is declared in symfonic.core.contracts.conversation_reader.

Rows are the facade's public TranscriptMessage shape, built by the same pure helper from the same checkpoint channel, so /chats/{id}/transcript answers what the compatibility facade answered. No facade, provider or engine is composed; whoever composes the reader owns the saver and its lifetime.

Timestamps keep the facade's semantics: each message carries the ts of the oldest checkpoint holding its id. The authority records that on its own write (http_introduced_at), so an authorized read decodes only the row it authorized. Ids without a record (checkpoints filed before the record existed, or by another writer) are found by walking the thread's history oldest first in short pages: saver.lock is held only to fetch a page, decoding happens off the event loop after release, and the walk stops once every id is found.

SqliteTranscriptReader

SqliteTranscriptReader(saver: Any, start: Callable[[], Awaitable[None]])

Read native-family transcripts the local authority filed.

read_owned reads a checkpoint the authority already authorized for a verified principal. get_transcript keeps the reader slot's scope-keyed signature; like the PostgreSQL reader it has no principal, so it answers only a native-family checkpoint whose tenant, sub-tenant, namespace and session match, and raises TranscriptReadRefused otherwise. Only a valid native empty conversation returns []. A scope conversation_owner would refuse as ambiguous raises the same ConversationRefused before any read.

Source code in src/symfonic/agent/transcript_sqlite_reader.py
def __init__(self, saver: Any, start: Callable[[], Awaitable[None]]) -> None:
    self._saver, self._start = saver, start

aclose async

aclose() -> None

Nothing to release: the composer owns the saver.

Source code in src/symfonic/agent/transcript_sqlite_reader.py
async def aclose(self) -> None:
    """Nothing to release: the composer owns the saver."""