feat: expose agent session log location

This commit is contained in:
Yichen Jiang
2026-07-10 20:52:27 +08:00
parent 42ebbfdf8f
commit eea0a99985
40 changed files with 526 additions and 70 deletions

View File

@@ -2,6 +2,8 @@
A SQLite durable session-persistence backend — a second `SessionPersistence` implementation ([session persistence](../../../docs/rfc/implemented/architecture/2026-06-14-session-persistence.md)), built to validate that the abstract seam and the shared `runPersistenceContract` suite are genuinely backend-agnostic. It satisfies the SAME contract as `dsh-session-persistence-jsonl` (append-only, contiguous-seq, lazy materialization, interrupted-turn close on load), expressed over `node:sqlite` rows instead of file bytes.
`locate(meta)` returns `undefined`: all sessions share one database, so there is no honest independent per-session transcript path.
> **TODO:** this backend talks to `node:sqlite` directly. If a cordis database service (`cordis/db` / a `@cordisjs` SQL driver plugin) is adopted, route through that instead of holding a raw `DatabaseSync` here — the contract surface (`SessionPersistence`) would not change, only the storage driver.
## Storage model

View File

@@ -11,8 +11,9 @@
* Like the JSONL backend it supplies ONLY the storage primitives (the
* {@link PersistenceBackend} hooks below — INSERT/DELETE/SELECT inside
* transactions); all the write-path orchestration lives in the backend-agnostic
* {@link PersistenceCoordinator} this class composes. The four public
* {@link SessionPersistence} methods delegate to the coordinator.
* {@link PersistenceCoordinator} this class composes. The four stateful public
* {@link SessionPersistence} methods delegate to the coordinator; the pure
* locator remains backend-owned.
*
* @module @deepseek-ai/dsh-session-persistence-sqlite
*/
@@ -24,7 +25,7 @@ import { mkdir } from 'node:fs/promises'
import { dirname, resolve } from 'node:path'
import {
SessionPersistence, PersistenceCoordinator,
type PersistenceBackend, type StoredPrefix,
type PersistenceBackend, type SessionLocation, type StoredPrefix,
} from '@deepseek-ai/dsh-session-persistence'
import type { Session, SessionEvent, SurfaceEventType, SessionId, SessionHeader } from '@deepseek-ai/dsh-session'
import {
@@ -109,6 +110,11 @@ export class SessionPersistenceSqlite extends SessionPersistence implements Pers
// --- SessionPersistence service surface (delegated to the coordinator) ---
/** SQLite has one database, not an independent local artifact per session. */
locate(_meta: SessionHeader): SessionLocation | undefined {
return undefined
}
create(meta: SessionHeader): Promise<void> {
return this.coordinator.create(meta)
}

View File

@@ -144,6 +144,12 @@ describe('scanRows', () => {
})
describe('SessionPersistenceSqlite: durability and crash semantics', () => {
it('has no independent per-session log location', async () => {
const { ctx, dispose } = await backend()
expect(ctx.sessionPersistence.locate(meta('sqlite-location'))).toBeUndefined()
await dispose()
})
it('an interrupted turn (rows after the last turn/end) is PRESERVED and closed during load', async () => {
const path = await freshDbPath()
const m = meta('crash')