fix(session): add semantic crash checkpoints

This commit is contained in:
Yichen Jiang
2026-07-21 14:50:06 +08:00
parent 9a5c81f9e5
commit 6d12e3ab41
56 changed files with 1016 additions and 61 deletions

View File

@@ -38,6 +38,7 @@
"@deepseek-ai/dsh-command-goal": "^0.0.1",
"@deepseek-ai/dsh-agent-spine-demo": "^0.0.1",
"@deepseek-ai/dsh-workspace-context": "^0.0.1",
"@deepseek-ai/dsh-session-checkpoint-policy": "^0.0.1",
"@deepseek-ai/dsh-session-persistence-jsonl": "^0.0.1",
"@deepseek-ai/dsh-tools": "^0.0.1",
"@deepseek-ai/dsh-user-interaction": "^0.0.1",
@@ -56,6 +57,7 @@
"@deepseek-ai/dsh-tools": "workspace:^",
"@deepseek-ai/dsh-system-prompt": "workspace:^",
"@deepseek-ai/dsh-workspace-context": "workspace:^",
"@deepseek-ai/dsh-session-checkpoint-policy": "workspace:^",
"@deepseek-ai/dsh-session-persistence-jsonl": "workspace:^",
"@deepseek-ai/dsh-user-interaction": "workspace:^",
"cordis": "^4.0.0-rc.7",

View File

@@ -21,6 +21,7 @@ import SessionPersistenceJsonl, {
JsonlCompressionSchema,
type JsonlCompression,
} from '@deepseek-ai/dsh-session-persistence-jsonl'
import * as sessionCheckpointPolicy from '@deepseek-ai/dsh-session-checkpoint-policy'
import UserInteractionService from '@deepseek-ai/dsh-user-interaction'
export const name = 'acp-demo'
@@ -110,5 +111,6 @@ export function apply(ctx: Context, config: Config): void {
root: config.persistenceRoot ?? DEFAULT_PERSISTENCE_ROOT,
...(config.persistenceCompression === undefined ? {} : { compression: config.persistenceCompression }),
})
ctx.plugin(sessionCheckpointPolicy)
ctx.plugin(acp, { provider: config.provider, model: config.model })
}

View File

@@ -35,7 +35,8 @@ const dshPackages = [
'core/tools', 'core/agent-loop', 'llm/llm', 'bash/bash',
'bash/bash-local', 'bash/tool-bash', 'context/workspace-context', 'support/invariants', 'ui/app-boot',
'session-persistence/session-persistence',
'session-persistence/session-persistence-jsonl', 'ui/acp', 'examples/acp-demo', 'util/paths',
'session-persistence/session-checkpoint-policy', 'session-persistence/session-persistence-jsonl',
'ui/acp', 'examples/acp-demo', 'util/paths',
]
const vendorPackages = [
'cordis', 'loader', 'include', 'timer', 'hmr', 'logger-console',

View File

@@ -44,6 +44,9 @@
{
"path": "../../ui/tool-ask-user"
},
{
"path": "../../session-persistence/session-checkpoint-policy"
},
{
"path": "../../session-persistence/session-persistence-jsonl"
}

View File

@@ -37,6 +37,7 @@
"@deepseek-ai/dsh-app-boot": "^0.0.1",
"@deepseek-ai/dsh-llm": "^0.0.1",
"@deepseek-ai/dsh-session": "^0.0.1",
"@deepseek-ai/dsh-session-checkpoint-policy": "^0.0.1",
"@deepseek-ai/dsh-session-persistence-jsonl": "^0.0.1",
"@deepseek-ai/dsh-tools": "^0.0.1",
"@deepseek-ai/dsh-workspace-context": "^0.0.1",
@@ -51,6 +52,7 @@
"@deepseek-ai/dsh-app-boot": "workspace:^",
"@deepseek-ai/dsh-llm": "workspace:^",
"@deepseek-ai/dsh-session": "workspace:^",
"@deepseek-ai/dsh-session-checkpoint-policy": "workspace:^",
"@deepseek-ai/dsh-session-persistence-jsonl": "workspace:^",
"@deepseek-ai/dsh-system-prompt": "workspace:^",
"@deepseek-ai/dsh-tools": "workspace:^",

View File

@@ -15,6 +15,7 @@ import SessionPersistenceJsonl, {
JsonlCompressionSchema,
type JsonlCompression,
} from '@deepseek-ai/dsh-session-persistence-jsonl'
import * as sessionCheckpointPolicy from '@deepseek-ai/dsh-session-checkpoint-policy'
import * as workspaceContext from '@deepseek-ai/dsh-workspace-context'
const DEFAULT_PERSISTENCE_ROOT = './.sessions'
@@ -91,4 +92,5 @@ export function apply(ctx: Context, config: Config): void {
root: config.persistenceRoot ?? DEFAULT_PERSISTENCE_ROOT,
...(config.persistenceCompression === undefined ? {} : { compression: config.persistenceCompression }),
})
ctx.plugin(sessionCheckpointPolicy)
}

View File

@@ -15,7 +15,8 @@ const dshPackages = [
'examples/agent-spine-demo', 'examples/cli-demo', 'core/agent', 'core/session',
'core/system-prompt', 'core/tools', 'core/agent-loop', 'llm/llm', 'bash/bash',
'bash/bash-local', 'bash/tool-bash', 'support/invariants', 'ui/app-boot',
'session-persistence/session-persistence', 'session-persistence/session-persistence-jsonl',
'session-persistence/session-persistence', 'session-persistence/session-checkpoint-policy',
'session-persistence/session-persistence-jsonl',
'context/workspace-context',
]
const vendorPackages = ['cordis', 'loader', 'include', 'timer', 'schemastery', 'cosmokit']

View File

@@ -16,6 +16,7 @@
{ "path": "../../core/system-prompt" },
{ "path": "../../core/tools" },
{ "path": "../agent-spine-demo" },
{ "path": "../../session-persistence/session-checkpoint-policy" },
{ "path": "../../session-persistence/session-persistence-jsonl" },
{ "path": "../../ui/app-boot" }
]

View File

@@ -41,6 +41,7 @@
"@deepseek-ai/dsh-agent-spine-demo": "^0.0.1",
"@deepseek-ai/dsh-workspace-context": "^0.0.1",
"@deepseek-ai/dsh-session": "^0.0.1",
"@deepseek-ai/dsh-session-checkpoint-policy": "^0.0.1",
"@deepseek-ai/dsh-session-persistence-jsonl": "^0.0.1",
"@deepseek-ai/dsh-tui": "^0.0.1",
"@deepseek-ai/dsh-tool-ask-user": "^0.0.1",
@@ -62,6 +63,7 @@
"@deepseek-ai/dsh-system-prompt": "workspace:^",
"@deepseek-ai/dsh-workspace-context": "workspace:^",
"@deepseek-ai/dsh-session": "workspace:^",
"@deepseek-ai/dsh-session-checkpoint-policy": "workspace:^",
"@deepseek-ai/dsh-session-persistence-jsonl": "workspace:^",
"@deepseek-ai/dsh-tui": "workspace:^",
"@deepseek-ai/dsh-tool-ask-user": "workspace:^",

View File

@@ -21,6 +21,7 @@ import SessionPersistenceJsonl, {
JsonlCompressionSchema,
type JsonlCompression,
} from '@deepseek-ai/dsh-session-persistence-jsonl'
import * as sessionCheckpointPolicy from '@deepseek-ai/dsh-session-checkpoint-policy'
import UserInteractionService from '@deepseek-ai/dsh-user-interaction'
import * as toolAskUser from '@deepseek-ai/dsh-tool-ask-user'
import * as uiTui from '@deepseek-ai/dsh-tui'
@@ -109,6 +110,7 @@ export function composeTuiApp(ctx: Context, config: Config): void {
root: config.persistenceRoot ?? DEFAULT_PERSISTENCE_ROOT,
...(config.persistenceCompression === undefined ? {} : { compression: config.persistenceCompression }),
})
ctx.plugin(sessionCheckpointPolicy)
ctx.plugin(UserInteractionService)
ctx.plugin(uiTui, {
...config.ui,

View File

@@ -44,6 +44,7 @@ describe('dsh-tui-demo app', () => {
'CommandService',
'command-goal',
'SessionPersistenceJsonl',
'session-checkpoint-policy',
'UserInteractionService',
'ui-tui',
'agent-spine-demo',
@@ -51,10 +52,10 @@ describe('dsh-tui-demo app', () => {
])
expect(calls[0]?.config).toBeUndefined()
expect(calls[2]?.config).toEqual({ root: '/tmp/tui-sessions', compression: 'none' })
const tuiConfig = calls[4]?.config as { sessionId: string }
const tuiConfig = calls[5]?.config as { sessionId: string }
expect(tuiConfig).toMatchObject({ welcome: 'TUI ready', color: false, maxToolOutputLines: 3 })
expect(tuiConfig.sessionId).toMatch(/^main-session-[0-9a-f-]{36}$/)
const spineConfig = calls[5]?.config as {
const spineConfig = calls[6]?.config as {
readonly agents: Array<Record<string, unknown>>
readonly goals: Record<string, never>
readonly maxParallelToolCalls: number
@@ -88,8 +89,8 @@ describe('dsh-tui-demo app', () => {
})
expect(calls[2]?.config).toEqual({ root: './.sessions' })
expect(calls[4]?.config).toEqual({ welcome: 'ready.', sessionId: 'persisted-session' })
expect((calls[5]?.config as { agents: Array<Record<string, unknown>> }).agents[0]).toMatchObject({
expect(calls[5]?.config).toEqual({ welcome: 'ready.', sessionId: 'persisted-session' })
expect((calls[6]?.config as { agents: Array<Record<string, unknown>> }).agents[0]).toMatchObject({
id: 'main',
resumeSessionId: 'persisted-session',
})
@@ -105,12 +106,12 @@ describe('dsh-tui-demo app', () => {
workspaceContext: false,
})
const tuiConfig = calls[3]?.config as { sessionId: string }
const tuiConfig = calls[4]?.config as { sessionId: string }
expect(tuiConfig.sessionId).toMatch(/^main-session-[0-9a-f-]{36}$/)
expect((calls[4]?.config as { agents: Array<Record<string, unknown>> }).agents[0])
expect((calls[5]?.config as { agents: Array<Record<string, unknown>> }).agents[0])
.toMatchObject({ sessionId: tuiConfig.sessionId })
expect(calls.map(call => call.name)).not.toContain('command-goal')
expect(calls[4]?.config).toMatchObject({ goals: false })
expect(calls[5]?.config).toMatchObject({ goals: false })
})
it('has the namespace-plugin export shape so the Loader keeps its schema', () => {

View File

@@ -47,6 +47,9 @@
{
"path": "../../ui/tool-ask-user"
},
{
"path": "../../session-persistence/session-checkpoint-policy"
},
{
"path": "../../session-persistence/session-persistence-jsonl"
}