fix(session-persistence): address preparation review feedback

This commit is contained in:
imccyu
2026-08-06 04:11:58 +08:00
parent 466390c1af
commit feb2c35cef
35 changed files with 364 additions and 124 deletions
@@ -15,6 +15,11 @@ import { MessageId } from '@deepseek-ai/dsh-llm'
import type { Agent } from '@deepseek-ai/dsh-agent'
import UserInteractionService from '@deepseek-ai/dsh-user-interaction'
import type { SessionEvent, SessionHeader, SessionId } from '@deepseek-ai/dsh-session'
import {
PersistenceCoordinator,
type PersistenceBackend,
type StoredPrefix,
} from '@deepseek-ai/dsh-session-persistence'
import type { RpcRequest } from '@deepseek-ai/dsh-host-apiproxy/api/rpc'
import { RpcId } from '@deepseek-ai/dsh-host-apiproxy/api/rpc'
import { createApiProxy } from '@deepseek-ai/dsh-host-apiproxy'
@@ -114,6 +119,62 @@ describe('attached updatedAt excludes end-seed', () => {
})
})
describe('cold history recovery view', () => {
it('shows in-memory interruption repair without activating the session', async () => {
const ctx = new Context()
await ctx.plugin(SessionStore)
await ctx.plugin(UserInteractionService)
const sessionId = sid('session-interrupted')
const meta = header(sessionId, 1000)
const stored: StoredPrefix<never> = {
meta,
events: [{ type: 'turn/start', seq: 0, time: 1, data: { turn: 1 } }],
}
const backend: PersistenceBackend<never> = {
name: 'history-recovery-test',
loadStored: id => Promise.resolve(id === sessionId ? structuredClone(stored) : undefined),
appendBatch: () => Promise.resolve(),
commitRepair: () => Promise.resolve(),
list: () => Promise.resolve([structuredClone(meta)]),
}
const coordinator = new PersistenceCoordinator(ctx, backend)
ctx.provide('sessionPersistence', {
list: (signal?: AbortSignal) => backend.list(signal),
inspect: (id: SessionId, signal?: AbortSignal) => coordinator.inspect(id, signal),
locate: () => undefined,
} as never)
const api = createApiProxy(ctx, { provider: 'p', model: 'm', cwd: '/tmp', workspaceRoot: '/tmp' })
const history = await api.sessions.history(request({ sessionId, beforeSeq: 2, maxMessages: 10 }))
if (!history.result.ok) throw new Error('history failed')
expect(history.result.value.events.map(entry => entry.event)).toMatchInlineSnapshot(`
[
{
"data": {
"turn": 1,
},
"seq": 0,
"time": 1,
"type": "turn/start",
},
{
"data": {
"reason": {
"kind": "interrupted",
},
"turn": 1,
},
"seq": 1,
"time": 1,
"type": "turn/end",
},
]
`)
expect(ctx.sessions.get(sessionId)).toBeUndefined()
await ctx.fiber.dispose()
})
})
describe('subagent ownership fence', () => {
it('reads a cold child without an Agent and rejects generic resume or adoption', async () => {
const ctx = new Context()