Files
deepseek-harness/packages/session-query/session-query-sqlite/tests/load-path.e2e.ts
T
Turtle bec6805d6a refactor(session-persistence)!: handle-based seam with a lifecycle-owned write path
The persistence seam is now create/open/stat/list returning per-session
SessionHandles (read/append/flush/close); every log read and write flows
through the owning handle. The seam package exports only the service and
handle contracts, consumer-visible errors, and pure durable-data
validation helpers; each backend owns its complete storage runtime, and
the shared contract suites pin equivalent observable behavior. The
backend routes published sessions' live events by id into the active
write handle; agent-loop only acquires, seeds, and closes the handle.
Resume appends interruptedTurnClosers through its write handle;
session-query owns the revision-keyed cold cache. Legacy-only surfaces
are removed in the same swap: locate/readRaw/supportsRawArtifacts, the
legacy event-shape read migration, zstd torn-frame salvage,
DSH_SESSION_JSONL, and hook transcript_path population; a torn final
zstd frame is discarded whole; the session-list cold blank probe returns
on stat metadata (eventCount derived from the last physical row,
sizeBytes). The WebUI ZIP export serializes the logical log from a read
handle, so both backends export identically.

Refs #3245
2026-09-01 23:19:02 +08:00

71 lines
2.8 KiB
TypeScript

import { createUserMessage } from '@deepseek-ai/dsh-llm'
/**
* Keyless real-Loader-path smoke for the combined SQLite session-query service.
*
* @module @deepseek-ai/dsh-session-query-sqlite/tests/load-path
*/
import { afterEach, describe, expect, it } from 'vitest'
import { Context } from '@deepseek-ai/cordis'
import Loader from '@deepseek-ai/cordis-plugin-loader'
import SessionStore, { SessionSeq, SESSION_FORMAT_VERSION, SessionId } from '@deepseek-ai/dsh-session'
import SessionProjectionRegistry from '@deepseek-ai/dsh-session-projection'
import JsonlSessionPersistence from '@deepseek-ai/dsh-session-persistence-jsonl'
import SqliteSessionQueryEngine, * as queryModule from '@deepseek-ai/dsh-session-query-sqlite'
import { mkdtemp, rm } from 'node:fs/promises'
import { tmpdir } from 'node:os'
import { join } from 'node:path'
const temporaryDirectories: string[] = []
afterEach(async () => {
for (const directory of temporaryDirectories.splice(0)) {
await rm(directory, { recursive: true, force: true })
}
})
async function temporaryPath(name: string): Promise<string> {
const directory = await mkdtemp(join(tmpdir(), 'dsh-session-search-loader-'))
temporaryDirectories.push(directory)
return join(directory, name)
}
describe('dsh-session-query-sqlite real Loader path', () => {
it('unwraps, mounts, and searches the real persistence backend', async () => {
const persistenceRoot = await temporaryPath('canonical')
const searchPath = await temporaryPath('derived.db')
const ctx = new Context()
await ctx.plugin(SessionProjectionRegistry)
await ctx.plugin(SessionStore)
const persistence = await ctx.plugin(JsonlSessionPersistence, {
root: persistenceRoot,
compression: 'none',
})
const loader = Object.create(Loader.prototype) as Loader
const unwrapped = loader.unwrapExports(queryModule) as Parameters<Context['plugin']>[0]
expect(unwrapped).toBe(SqliteSessionQueryEngine)
const query = await ctx.plugin(unwrapped, { path: searchPath })
const id = SessionId('loader-path')
const writer = await ctx.sessionPersistence.create({ version: SESSION_FORMAT_VERSION, id, createdAt: 10, isSeeded: false })
await writer.append([{
type: 'user/message',
seq: SessionSeq(0),
time: 10,
data: createUserMessage({
content: [{ type: 'text', text: 'real Loader needle' }], source: { kind: 'user' },
}),
surfaceOp: 'append',
}])
await writer.close()
await expect(ctx.sessionQuery.searchSessions({ query: 'Loader needle' }))
.resolves.toMatchObject({ items: [{ header: { id }, persisted: true, live: false }] })
await expect(ctx.sessionQuery.listSessions())
.resolves.toMatchObject([{ header: { id }, persisted: true, live: false }])
await query.dispose()
await persistence.dispose()
})
})