import { readFile, writeFile } from 'node:fs/promises' import { dirname, join } from 'node:path' import { fileURLToPath } from 'node:url' import { Context } from 'cordis' import { normalizeSessionLog, scrubRequestHeaders, type NormalizeContext } from '@deepseek-ai/dsh-acp-snapshot' import { LOADER_SMOKE_TEST_TIMEOUT_MS, runLoaderSmoke } from '@deepseek-ai/dsh-loader-smoke' import { CallId } from '@deepseek-ai/dsh-llm' import SessionStore, { SESSION_FORMAT_VERSION, SessionId, type SessionEvent, type SessionHeader } from '@deepseek-ai/dsh-session' import SessionPersistenceJsonl from '@deepseek-ai/dsh-session-persistence-jsonl' import { describe, expect, it } from 'vitest' const fixtureDir = join(dirname(fileURLToPath(import.meta.url)), 'semantic-checkpoint-snapshots/tool-outcome-unknown') const replayFixture = join(fixtureDir, 'replay.jsonl') const replayOverride = join(fixtureDir, 'replay.override.json') const sessionExpected = join(fixtureDir, 'session.expected.jsonl') const configPath = fileURLToPath(new URL('../semantic-checkpoint.cordis.snapshot.yml', import.meta.url)) const binScript = fileURLToPath(new URL('../../../packages/examples/cli-demo/src/bin.ts', import.meta.url)) const tsconfigPath = fileURLToPath(new URL('../../../tsconfig.json', import.meta.url)) const sessionId = SessionId('semantic-checkpoint-unknown-outcome') const refreshing = process.env.DSH_SNAPSHOT === 'refresh' const task = 'Continue safely from the interrupted operation.' async function seedInterruptedSession(root: string, cwd: string): Promise { const ctx = new Context() await ctx.plugin(SessionStore) await ctx.plugin(SessionPersistenceJsonl, { root, compression: 'none' }) const meta: SessionHeader = { version: SESSION_FORMAT_VERSION, id: sessionId, createdAt: 1, cwd, delegationDepth: 0, } const events: SessionEvent[] = [ { type: 'turn/start', seq: 0, time: 10, data: { turn: 1, trigger: { kind: 'message', source: { kind: 'user' } } } }, { type: 'user/message', seq: 1, time: 11, data: { content: [{ type: 'text', text: 'Perform one side-effecting remote mutation.' }], source: { kind: 'user' } }, surfaceOp: 'append' }, { type: 'step/start', seq: 2, time: 12, data: { turn: 1, step: 1 } }, { type: 'assistant/message', seq: 3, time: 13, data: { turn: 1, step: 1, content: [{ type: 'tool-call', id: CallId('unknown-outcome-call'), name: 'write_remote', arguments: '{"value":1}' }], provenance: { provider: 'deepseek', model: 'deepseek-v4-flash' }, }, surfaceOp: 'append', }, { type: 'tool/call', seq: 4, time: 14, data: { turn: 1, step: 1, callId: CallId('unknown-outcome-call'), name: 'write_remote', arguments: '{"value":1}', }, }, ] try { await ctx.sessionPersistence.create(meta) await ctx.sessionPersistence.append(sessionId, events) const location = ctx.sessionPersistence.locate(meta) if (location === undefined) throw new Error('JSONL backend did not locate the seeded session') return location.path } finally { await ctx.fiber.dispose() } } describe('semantic checkpoint recovery snapshot', () => { it('resumes an unknown tool outcome through the headless stream-json app', async () => { let cwd = '' let sessionPath = '' const result = await runLoaderSmoke({ label: 'semantic checkpoint headless stream-json snapshot', tempDirPrefix: 'dsh-semantic-snapshot-', binScript, configPath, binArgs: ['--config', configPath, '--output-format', 'stream-json', task], tsconfigPath, env: { DSH_SNAPSHOT_FILE: replayFixture, DSH_SNAPSHOT_OVERRIDE: replayOverride, }, prepare: async (runCwd) => { cwd = runCwd sessionPath = await seedInterruptedSession(join(runCwd, '.sessions'), runCwd) }, inspect: async () => { const normalization: NormalizeContext = { sessionIds: [sessionId], cwd } const session = scrubRequestHeaders(normalizeSessionLog(await readFile(sessionPath, 'utf8'), normalization)) if (refreshing) await writeFile(sessionExpected, session) expect(session).toBe(await readFile(sessionExpected, 'utf8')) expect(session).toContain('TOOL_OUTCOME_UNKNOWN') expect(session).toContain('Do not retry blindly.') }, }) expect(result.stderr).toBe('') const records = result.stdout.trimEnd().split('\n').map(line => JSON.parse(line) as Record) expect(records.at(-1)).toMatchObject({ type: 'result', success: true, sessionId, result: 'I will verify the external state before deciding whether to retry the side-effecting operation.', reason: { kind: 'completed' }, }) }, LOADER_SMOKE_TEST_TIMEOUT_MS) })