SessionStore

The session store sessions.db: one record per session and one row per event, the only history of a session (trove-parts §TPN-3, R7).

Inherits QObject
Group libllmsession

In the namespace octomy::llmsession. Declared in src/libs/libllmsession/llmsession/SessionStore.hpp.

Detailed description

The store is a SQLite file in the door host's base folder. It has two tables:

  • sessions holds one SessionRecord per session (§TPN-2).
  • events holds one SessionEvent per row: session, seq, turn, ts, type, role, blocks_json and tokens_json. The index events_session_seq on (session, seq) serves the cursor read, so that a read never scans the table (§TPT-5).

seq is dense and starts at 1 in each session. It is the cursor of session.events (§TPD-8): events() gives at most 500 events after a cursor, and the cursor for the next read. With a wait, events() waits up to 30 s for the first new event. The wait is a QWaitCondition that append() wakes, not a loop that sleeps, so a reader gets a new event within one call.

The store reads the file through QSQLITE, with one connection per thread (SqlThreadConnection). A QSqlDatabase is usable only on the thread that created it, and OPAL runs each plan on a thread of its own. One mutex serializes the work on the file. A second mutex guards the last seq of each session, for the wait.

A lease (§TPN-6) has a holder and an expiry. claim() refuses a second holder while the lease is live. mayWrite() answers whether a caller can send to, interrupt or close a session: it can when it holds the live lease, or when no live lease exists.

purgeExpired() removes the sessions whose retention has passed since their last activity. An assistant session keeps 24 h by default, a coding session keeps until someone removes it.

Two stores on one file in one process each keep their own cache of the last seq, so an append through one store is late in the other. The door host and the OPAL chat of one base folder therefore take the one store that shared() gives for the file (§TPN-9).

Note: The thread that appends events must not call events() with a wait: it would wait for itself. events() ignores the wait on the thread that owns the store.

See also octomy::llmsession::SessionRecord, octomy::llmsession::SessionEvent, octomy::llmsession::SessionRunner.

In this section