Merge master into codex/simp-session-log-representation

This commit is contained in:
Tianyi Cui
2026-07-17 21:51:36 +08:00
357 changed files with 18546 additions and 2866 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

@@ -1,7 +1,8 @@
/**
* SQLite durable session-persistence backend. It maps each session header and
* event to rows, and delegates write-path orchestration to
* {@link PersistenceCoordinator}.
* {@link PersistenceCoordinator}. It has no independent per-session artifact,
* so its locator returns `undefined`.
* @module @deepseek-ai/dsh-session-persistence-sqlite
*/
@@ -12,7 +13,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 { SessionEvent, SurfaceEventType, SessionId, SessionHeader } from '@deepseek-ai/dsh-session'
import {
@@ -95,6 +96,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

@@ -189,6 +189,12 @@ describe('SessionPersistenceSqlite: durability and crash semantics', () => {
await mounted.dispose()
})
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')