dsh-dynamic-context 0.1.1-rc.34 → 0.1.1-rc.36
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +3 -3
- package/DSH-COMPATIBILITY.json +7 -8
- package/README.md +3 -3
- package/RELEASING.md +2 -2
- package/VALIDATION.md +1 -1
- package/direct-runtime.mjs +27 -12
- package/host.mjs +1 -3
- package/index.mjs +3 -3
- package/interaction.mjs +10 -8
- package/interop.mjs +1 -0
- package/package.json +38 -39
- package/revision-host.mjs +2 -2
- package/test/interaction.test.mjs +24 -3
- package/test/interop.test.mjs +1 -1
- package/test/revision.test.mjs +1 -1
- package/test/supervision.test.mjs +1 -1
- package/testing/harness.mjs +1 -3
- package/testing/runtime-harness.mjs +0 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
# 0.1.1-rc.
|
|
1
|
+
# 0.1.1-rc.36 — DSH compatibility line
|
|
2
2
|
|
|
3
|
-
- Pin this build to its listed DSH releases and pair it with the other plugin on RC slot
|
|
4
|
-
-
|
|
3
|
+
- Pin this build to its listed DSH releases and pair it with the other plugin on RC slot 6.
|
|
4
|
+
- Persist plugin records in a separate JSONL-host-bound journal while validating native tool evidence against DSH persistence. Adapt the Web read endpoint to the native Session lookup of this host generation.
|
|
5
5
|
|
|
6
6
|
# 0.1.0-rc.24 — task-graph prerequisite and graph provenance (2026-11-13)
|
|
7
7
|
|
package/DSH-COMPATIBILITY.json
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schema": 1,
|
|
3
3
|
"updateRound": 3,
|
|
4
|
-
"slot":
|
|
5
|
-
"branch": "0.2.1-alpha.
|
|
6
|
-
"host": "0.2.1-alpha.
|
|
4
|
+
"slot": 6,
|
|
5
|
+
"branch": "0.2.1-alpha.1",
|
|
6
|
+
"host": "0.2.1-alpha.1",
|
|
7
7
|
"hosts": [
|
|
8
|
-
"0.2.1-alpha.
|
|
9
|
-
"0.2.1-alpha.3"
|
|
8
|
+
"0.2.1-alpha.1"
|
|
10
9
|
],
|
|
11
|
-
"channel": "dsh-0.2.1-alpha.
|
|
12
|
-
"taskgraph": "0.3.1-rc.
|
|
13
|
-
"dynamicContext": "0.1.1-rc.
|
|
10
|
+
"channel": "dsh-0.2.1-alpha.1",
|
|
11
|
+
"taskgraph": "0.3.1-rc.36",
|
|
12
|
+
"dynamicContext": "0.1.1-rc.36"
|
|
14
13
|
}
|
package/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# dsh-dynamic-context:动态上下文与受控请求通道
|
|
2
2
|
|
|
3
|
-
本构建版本为 `0.1.1-rc.
|
|
3
|
+
本构建版本为 `0.1.1-rc.36`。适用宿主和配套版本见 [兼容清单](DSH-COMPATIBILITY.json)。
|
|
4
4
|
|
|
5
|
-
分支 `0.2.1-alpha.
|
|
5
|
+
分支 `0.2.1-alpha.1` 对应 npm 标签 `dsh-0.2.1-alpha.1`,适用于 DSH `0.2.1-alpha.1`,Node.js 要求为 `^22.19.0 || >=24.0.0`。请在同一 DSH profile 先安装 `dsh-bettertaskgraphs@0.3.1-rc.36`,再安装 `dsh-dynamic-context@0.1.1-rc.36`。Bundle 初装默认关闭,完成配置并启用后为新对话提供会话模式选择。
|
|
6
6
|
|
|
7
7
|
前置插件:[dsh-bettertaskgraphs](https://github.com/oldcitynight/dsh-bettertaskgraphs)。开源协议为 GPL-3.0-only;复制的 DeepSeek 压缩策略另保留原 MIT 声明。验证范围和独立测试方法见 [VALIDATION.md](VALIDATION.md)。GitHub 源码发布与 npm 包发布是不同步骤,当前候选可从源码构建安装包。
|
|
8
8
|
|
|
@@ -17,7 +17,7 @@ TMPDIR="$PWD/.test-tmp" npm test
|
|
|
17
17
|
npm run pack:bundle
|
|
18
18
|
```
|
|
19
19
|
|
|
20
|
-
源码构建依赖任务图 `0.3.1-rc.
|
|
20
|
+
源码构建依赖任务图 `0.3.1-rc.36`。该版本发布前,先将同一批次的任务图 tarball 加入 npm 缓存,再执行 npm ci。运行配置见 `examples/`。
|
|
21
21
|
|
|
22
22
|
候选包的独立支持范围是 direct。`native-guarded` 仅为开发对照,依赖另行安装的 context-guard wire hook;干净 DSH 没有该补丁时,在认领任务和创建执行 Agent 前拒绝运行。发布包不修改 DSH 适配器来启用该对照通道。
|
|
23
23
|
|
package/RELEASING.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
## 0.1.1-rc.
|
|
1
|
+
## 0.1.1-rc.36 维护线
|
|
2
2
|
|
|
3
|
-
DSH `0.2.1-alpha.
|
|
3
|
+
DSH `0.2.1-alpha.1`。同批配对任务图 `0.3.1-rc.36` 和动态上下文 `0.1.1-rc.36`,npm 通道为 `dsh-0.2.1-alpha.1`。兼容清单随 Bundle 分发。
|
|
4
4
|
|
|
5
5
|
# 发布候选包 rc.24
|
|
6
6
|
|
package/VALIDATION.md
CHANGED
package/direct-runtime.mjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// SPDX-License-Identifier: GPL-3.0-only
|
|
2
2
|
import fs from 'node:fs'
|
|
3
|
+
import { homedir } from 'node:os'
|
|
3
4
|
import path from 'node:path'
|
|
4
5
|
import { createHash } from 'node:crypto'
|
|
5
6
|
import { AsyncLocalStorage } from 'node:async_hooks'
|
|
@@ -10,9 +11,9 @@ import { defineTool } from '@deepseek-ai/dsh-tools'
|
|
|
10
11
|
import { setSandboxMode } from '@deepseek-ai/dsh-sandbox-policy'
|
|
11
12
|
import { setApprovalPolicy } from '@deepseek-ai/dsh-user-approval'
|
|
12
13
|
import { discoverBaselineInstructionFiles } from '@deepseek-ai/dsh-agent-instructions'
|
|
13
|
-
import { resolveDshHome
|
|
14
|
+
import { resolveDshHome } from '@deepseek-ai/dsh-home-paths'
|
|
14
15
|
import { createAssistantMessage, createSystemMessage, createToolResultMessage } from '@deepseek-ai/dsh-llm'
|
|
15
|
-
import {
|
|
16
|
+
import { Session } from '@deepseek-ai/dsh-session'
|
|
16
17
|
import { digest } from 'dsh-bettertaskgraphs/core'
|
|
17
18
|
import { deepFreeze, textContent } from './request-policy.mjs'
|
|
18
19
|
import { DynamicContextError, fail } from './core.mjs'
|
|
@@ -56,8 +57,8 @@ const nativeModules = {
|
|
|
56
57
|
shell: ['@deepseek-ai/dsh-tool-bash', { enableRunInBackground: false, promoteOnTimeout: false }],
|
|
57
58
|
web: ['@deepseek-ai/dsh-tool-web', {}],
|
|
58
59
|
}
|
|
59
|
-
const requiredServices = { filesystem: ['fs'
|
|
60
|
-
shell: ['shell', 'shellEnv', 'sandbox'
|
|
60
|
+
const requiredServices = { filesystem: ['fs'], search: ['subprocess'],
|
|
61
|
+
shell: ['shell', 'shellEnv', 'sandbox'], web: ['web'], skills: ['skills'], state: [] }
|
|
61
62
|
const readTools = new Set(['read', 'glob', 'grep', 'web_search', 'web_fetch', 'skill', 'dynamic_task_status', 'dynamic_context_source_read'])
|
|
62
63
|
const modes = ['read-only', 'workspace-write', 'danger-full-access']
|
|
63
64
|
const minimumMode = (...values) => modes[Math.min(...values.map(value => modes.indexOf(value)))]
|
|
@@ -72,18 +73,20 @@ const jsonTool = (name, description, parameters, execute) => defineTool({ name,
|
|
|
72
73
|
export async function prepareDirectRuntime({ ctx, config, assembly, sessionId, sourceAgent, control, record, resumeState, sourceReader }) {
|
|
73
74
|
const options = config.direct.runtime
|
|
74
75
|
if (!options) return undefined
|
|
75
|
-
for (const service of ['sandboxPolicy', 'approval',
|
|
76
|
+
for (const service of ['sandboxPolicy', 'approval', ...options.modules.flatMap(name => requiredServices[name])]) {
|
|
76
77
|
if (!ctx.get(service)) fail('DIRECT_RUNTIME_MISSING_SERVICE', service)
|
|
77
78
|
}
|
|
78
|
-
const sandboxPolicy = ctx.get('sandboxPolicy'), approval = ctx.get('approval')
|
|
79
|
+
const sandboxPolicy = ctx.get('sandboxPolicy'), approval = ctx.get('approval')
|
|
79
80
|
const filesystem = ctx.get('fs'), shell = ctx.get('shell'), skills = ctx.get('skills'), sessions = ctx.get('sessions')
|
|
80
81
|
const sandbox = ctx.get('sandbox'), subprocess = ctx.get('subprocess'), credentials = ctx.get('credentials')
|
|
81
82
|
const root = fs.realpathSync(config.projectRoot), cwd = fs.realpathSync(path.resolve(root, options.cwd ?? '.'))
|
|
82
83
|
if (!inside(root, cwd) || !fs.statSync(cwd).isDirectory()) fail('DIRECT_RUNTIME_INVALID_WORKSPACE')
|
|
83
84
|
const stateDirectory = fs.realpathSync(config.directory)
|
|
84
85
|
if (inside(root, stateDirectory)) fail('DIRECT_RUNTIME_STATE_INSIDE_WORKSPACE')
|
|
86
|
+
const sessionRecords = ctx.transactionGraph.sessionRecords
|
|
87
|
+
const recordRoot = sessionRecords.root(true)
|
|
85
88
|
if (process.platform === 'linux' && options.modules.includes('shell') && inside('/tmp', stateDirectory)) fail('DIRECT_RUNTIME_STATE_IN_SHARED_TEMP')
|
|
86
|
-
const instructionHomes = options.instructionHomes ?? { dshHome: resolveDshHome(), agentsHome:
|
|
89
|
+
const instructionHomes = options.instructionHomes ?? { dshHome: resolveDshHome(), agentsHome: path.resolve(process.env.DSH_AGENTS_HOME || path.join(homedir(), '.agents')) }
|
|
87
90
|
if (sourceAgent && ctx.agents.get(sourceAgent.id) !== sourceAgent) fail('DIRECT_RUNTIME_UNOWNED_SOURCE_AGENT')
|
|
88
91
|
const ownerState = () => {
|
|
89
92
|
const policy = sandboxPolicy.resolve(sourceAgent ? { session: sourceAgent.session } : {})
|
|
@@ -112,6 +115,18 @@ export async function prepareDirectRuntime({ ctx, config, assembly, sessionId, s
|
|
|
112
115
|
if (!options.instructions) return []
|
|
113
116
|
const files = await discoverBaselineInstructionFiles({ cwd: directory, projectRoot: root,
|
|
114
117
|
...instructionHomes, signal: control.signal })
|
|
118
|
+
// This host reads DSH_HOME/AGENTS.md and project rules. Include the
|
|
119
|
+
// second user-global file in the same pinned, bounded read as newer hosts.
|
|
120
|
+
const agentsRules = path.join(instructionHomes.agentsHome, 'AGENTS.md')
|
|
121
|
+
if (agentsRules !== path.join(instructionHomes.dshHome, 'AGENTS.md')
|
|
122
|
+
&& !files.some(file => file.absolutePath === agentsRules)) {
|
|
123
|
+
try {
|
|
124
|
+
const info = fs.lstatSync(agentsRules)
|
|
125
|
+
if (!info.isFile()) fail('DIRECT_RUNTIME_INSTRUCTION_PATH_TYPE')
|
|
126
|
+
const global = files[0]?.absolutePath === path.join(instructionHomes.dshHome, 'AGENTS.md')
|
|
127
|
+
files.splice(global ? 1 : 0, 0, { absolutePath: agentsRules, displayPath: agentsRules })
|
|
128
|
+
} catch (error) { if (error.code !== 'ENOENT') throw error }
|
|
129
|
+
}
|
|
115
130
|
const rows = []; let total = 0
|
|
116
131
|
for (const file of files) {
|
|
117
132
|
control.signal.throwIfAborted()
|
|
@@ -166,7 +181,7 @@ export async function prepareDirectRuntime({ ctx, config, assembly, sessionId, s
|
|
|
166
181
|
if (options.protectPrivatePaths) privacy = createPrivatePathGuard({
|
|
167
182
|
sandbox: options.modules.includes('shell') && assembly.tools.includes('bash') ? sandbox : undefined,
|
|
168
183
|
subprocess: options.modules.includes('search') && assembly.tools.some(name => ['glob', 'grep'].includes(name)) ? subprocess : undefined,
|
|
169
|
-
workspaceRoot: cwd, protectedRoots: [config.storageRoot ?? root, stateDirectory,
|
|
184
|
+
workspaceRoot: cwd, protectedRoots: [config.storageRoot ?? root, stateDirectory, recordRoot,
|
|
170
185
|
path.join(config.storageRoot ?? root, '.dsh', 'workflow-witnesses-v1'), ...options.privateReadRoots],
|
|
171
186
|
credentialFiles: [serviceIdentity(credentials)?.spec?.filename,
|
|
172
187
|
path.join(resolveDshHome(), '.credentials.yaml'), path.join(instructionHomes.dshHome, '.credentials.yaml'),
|
|
@@ -221,7 +236,6 @@ export async function prepareDirectRuntime({ ctx, config, assembly, sessionId, s
|
|
|
221
236
|
agentCtx.tools.restrict({ allow: assembly.tools })
|
|
222
237
|
setSandboxMode(agent.session, policy.sandboxMode)
|
|
223
238
|
setApprovalPolicy(agent.session, policy.approvalPolicy)
|
|
224
|
-
appendPluginRecord(agent.session, 'plugin:dynamic-context/execution-host-v1', { taskId: assembly.task.id, contextVersion: assembly.contextVersion, policy })
|
|
225
239
|
// The identity is native, but only this private runner owns its loop.
|
|
226
240
|
for (const method of ['followup', 'inject', 'steer']) Object.defineProperty(agent, method, {
|
|
227
241
|
value: () => fail('DIRECT_RUNTIME_NATIVE_MESSAGE_DISABLED'), configurable: false, writable: false,
|
|
@@ -230,6 +244,7 @@ export async function prepareDirectRuntime({ ctx, config, assembly, sessionId, s
|
|
|
230
244
|
},
|
|
231
245
|
}))
|
|
232
246
|
const { agent } = handle
|
|
247
|
+
sessionRecords.append(agent.session, 'plugin:dynamic-context/execution-host-v1', { taskId: assembly.task.id, contextVersion: assembly.contextVersion, policy })
|
|
233
248
|
const visible = ctx.tools.schemas(agent).map(row => row.name).sort()
|
|
234
249
|
if (JSON.stringify(visible) !== JSON.stringify([...assembly.tools].sort())) fail('DIRECT_RUNTIME_TOOL_SCOPE_MISMATCH')
|
|
235
250
|
const shellConfinement = assembly.tools.includes('bash') ? await sandbox.confine(['true'], {
|
|
@@ -283,12 +298,12 @@ export async function prepareDirectRuntime({ ctx, config, assembly, sessionId, s
|
|
|
283
298
|
]
|
|
284
299
|
const systemPrompt = `${config.systemPrompt}\n\n${rules.join('\n')}\n\n<direct_host_facts>\n${JSON.stringify(facts)}\n</direct_host_facts>`
|
|
285
300
|
const currentPolicy = () => ({ sandboxMode: sandboxPolicy.resolve({ session: agent.session }).mode,
|
|
286
|
-
approvalPolicy: approval.effectivePolicy(agent.session), plan: policy.plan, cwd:
|
|
301
|
+
approvalPolicy: approval.effectivePolicy(agent.session), plan: policy.plan, cwd: agent.session.header.cwd })
|
|
287
302
|
const check = () => {
|
|
288
303
|
control.signal.throwIfAborted()
|
|
289
304
|
if (sourceAgent && ctx.agents.get(sourceAgent.id) !== sourceAgent) fail('DIRECT_RUNTIME_OWNER_DISPOSED')
|
|
290
305
|
if (ctx.agents.get(agent.id) !== agent) fail('DIRECT_RUNTIME_EXECUTION_HOST_DISPOSED')
|
|
291
|
-
for (const [name, service] of Object.entries({ sandboxPolicy, approval,
|
|
306
|
+
for (const [name, service] of Object.entries({ sandboxPolicy, approval, fs: filesystem, sandbox, subprocess, shell, skills, credentials }))
|
|
292
307
|
if (serviceIdentity(ctx.get(name)) !== serviceIdentity(service)) fail('DIRECT_RUNTIME_SERVICE_CHANGED')
|
|
293
308
|
privacy?.check()
|
|
294
309
|
if (digest(ownerState()) !== digest(owner) || digest(currentPolicy()) !== digest(policy)) fail('DIRECT_RUNTIME_POLICY_CHANGED')
|
|
@@ -352,7 +367,7 @@ export async function prepareDirectRuntime({ ctx, config, assembly, sessionId, s
|
|
|
352
367
|
const initial = new Set(initialInstructions.map(row => row.path)), required = new Set(facts.requiredSkills.map(row => row.name))
|
|
353
368
|
return { instructions: [...instructionPins.values()].filter(row => !initial.has(row.path)), skills: [...loadedSkills.values()].filter(row => !required.has(row.name)) }
|
|
354
369
|
},
|
|
355
|
-
checkpoint(reference) {
|
|
370
|
+
checkpoint(reference) { sessionRecords.append(agent.session, 'plugin:dynamic-context/checkpoint-v1', reference) },
|
|
356
371
|
async complete() { await verifySources(); completed = true; await close() },
|
|
357
372
|
async preflight(calls) {
|
|
358
373
|
await verifySources()
|
package/host.mjs
CHANGED
|
@@ -11,7 +11,6 @@ import AgentLoop from '@deepseek-ai/dsh-agent-loop'
|
|
|
11
11
|
import TokenMeter from '@deepseek-ai/dsh-token-meter'
|
|
12
12
|
import SandboxPolicy from '@deepseek-ai/dsh-sandbox-policy'
|
|
13
13
|
import Filesystem from '@deepseek-ai/dsh-fs-sandbox'
|
|
14
|
-
import WorkingDirectory from '@deepseek-ai/dsh-working-directory'
|
|
15
14
|
import Approval from '@deepseek-ai/dsh-user-approval'
|
|
16
15
|
import Subprocess from '@deepseek-ai/dsh-subprocess-local'
|
|
17
16
|
import Sandbox from '@deepseek-ai/dsh-sandbox-local'
|
|
@@ -19,7 +18,7 @@ import Shell from '@deepseek-ai/dsh-bash-sandbox'
|
|
|
19
18
|
import * as ShellEnv from '@deepseek-ai/dsh-shell-env'
|
|
20
19
|
import Skills from '@deepseek-ai/dsh-skill'
|
|
21
20
|
import * as Observations from '@deepseek-ai/dsh-fs-observation-policy'
|
|
22
|
-
import
|
|
21
|
+
import Persistence from '@deepseek-ai/dsh-session-persistence-jsonl'
|
|
23
22
|
import TaskGraph from 'dsh-bettertaskgraphs'
|
|
24
23
|
import * as DynamicContext from './index.mjs'
|
|
25
24
|
|
|
@@ -46,7 +45,6 @@ export async function createDirectHost(input) {
|
|
|
46
45
|
const runtime = config.direct.runtime
|
|
47
46
|
await ctx.plugin(SandboxPolicy, { mode: runtime.sandboxMode, workspaceRoot: config.projectRoot })
|
|
48
47
|
await ctx.plugin(Filesystem, { cwd: config.projectRoot })
|
|
49
|
-
await ctx.plugin(WorkingDirectory, { defaultDirectory: config.projectRoot })
|
|
50
48
|
await ctx.plugin(Approval, { policy: runtime.approvalPolicy })
|
|
51
49
|
await ctx.plugin(Subprocess)
|
|
52
50
|
await ctx.plugin(Sandbox)
|
package/index.mjs
CHANGED
|
@@ -3,7 +3,7 @@ import fs from 'node:fs'
|
|
|
3
3
|
import path from 'node:path'
|
|
4
4
|
import { createHash, randomUUID } from 'node:crypto'
|
|
5
5
|
import { createUserMessage } from '@deepseek-ai/dsh-llm'
|
|
6
|
-
import { SessionId
|
|
6
|
+
import { SessionId } from '@deepseek-ai/dsh-session'
|
|
7
7
|
import { z } from 'zod'
|
|
8
8
|
import { DynamicContextGraph, fail } from './core.mjs'
|
|
9
9
|
import { digest } from 'dsh-bettertaskgraphs/core'
|
|
@@ -142,7 +142,7 @@ export class DynamicContextRuntime {
|
|
|
142
142
|
}
|
|
143
143
|
graphPresence() {
|
|
144
144
|
const presence = this.graph.store.recoveryPlan()
|
|
145
|
-
if (presence.state === 'NEVER_CREATED' && this.controller
|
|
145
|
+
if (presence.state === 'NEVER_CREATED' && this.controller && this.taskGraph.sessionRecords.read(this.controller.session).some(({ event }) =>
|
|
146
146
|
event.type === GRAPH_COMMIT_RECORD && event.ignorable && event.data.workflowId === this.workflowId))
|
|
147
147
|
return { state: 'GRAPH_AND_WITNESS_LOST_AFTER_COMMIT', previouslyCommitted: true, recoveryRequired: true, canRestore: false }
|
|
148
148
|
return presence
|
|
@@ -248,7 +248,7 @@ export class DynamicContextRuntime {
|
|
|
248
248
|
if (this.config.transport === 'direct' && !this.config.direct.runtime && (binding.tools ?? []).some(tool => !this.config.direct.agentlessTools.includes(tool))) fail('DIRECT_TOOL_REQUIRES_EXPLICIT_AGENTLESS_PERMISSION')
|
|
249
249
|
}
|
|
250
250
|
const result = this.graph.submit(proposal)
|
|
251
|
-
if (sourceAgent)
|
|
251
|
+
if (sourceAgent) this.taskGraph.sessionRecords.append(sourceAgent.session, GRAPH_COMMIT_RECORD, { workflowId: this.workflowId,
|
|
252
252
|
graphId: result.graph.state.plan.id, firstChecksum: result.checksum, revision: result.revision })
|
|
253
253
|
this.publish('created'); return result
|
|
254
254
|
}
|
package/interaction.mjs
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
import fs from 'node:fs'
|
|
3
3
|
import path from 'node:path'
|
|
4
4
|
import { defineTool } from '@deepseek-ai/dsh-tools'
|
|
5
|
-
import { appendPluginRecord } from '@deepseek-ai/dsh-session'
|
|
6
5
|
import { digest, normalizePlan } from 'dsh-bettertaskgraphs/core'
|
|
7
6
|
import { connectTaskGraph } from './interop.mjs'
|
|
8
7
|
import { registerControlTools } from './control-tools.mjs'
|
|
@@ -29,8 +28,8 @@ export class SessionInteraction {
|
|
|
29
28
|
this.entries = new Map(); this.filters = new Map(); this.pending = new Set(); this.closed = false
|
|
30
29
|
}
|
|
31
30
|
record(agent) {
|
|
32
|
-
return agent
|
|
33
|
-
&& event.
|
|
31
|
+
return agent && this.template.taskGraph.sessionRecords.read(agent.session).findLast(({ event }) => event.type === MODE_RECORD
|
|
32
|
+
&& event.data.sessionId === agent.session.id)?.event.data
|
|
34
33
|
}
|
|
35
34
|
classic(agent) {
|
|
36
35
|
if (!agent || this.ctx.agents.get(agent.id) !== agent) return null
|
|
@@ -43,7 +42,9 @@ export class SessionInteraction {
|
|
|
43
42
|
linkedPresence(agent) {
|
|
44
43
|
const entry = this.entries.get(agent)
|
|
45
44
|
if (entry) return entry.runner.graphPresence()
|
|
46
|
-
|
|
45
|
+
let events
|
|
46
|
+
try { events = this.template.taskGraph.sessionRecords.read(agent.session).map(({ event }) => event) }
|
|
47
|
+
catch (error) { return { state: 'SESSION_PLUGIN_RECORDS_UNAVAILABLE', previouslyCommitted: null, code: error.code ?? error.name } }
|
|
47
48
|
const key = digest({ id: agent.session.id, createdAt: agent.session.header.createdAt, cwd: agent.session.header.cwd })
|
|
48
49
|
const committed = events.some(event => event.ignorable && event.type === GRAPH_COMMIT_RECORD
|
|
49
50
|
&& event.data.workflowId === `workflow_${key.slice(0, 40)}`)
|
|
@@ -74,7 +75,7 @@ export class SessionInteraction {
|
|
|
74
75
|
text: ({ agent }) => {
|
|
75
76
|
if (!agent || !ctx.agents.roots().includes(agent)) return ''
|
|
76
77
|
const mode = this.mode(agent), entry = this.entries.get(agent)
|
|
77
|
-
const state = { mode, selected: Boolean(this.record(agent)), taskGraphPresent: Boolean(this.classic(agent)), baseGraphPresence: this.basePresence(agent) }
|
|
78
|
+
const state = { mode, selected: mode === 'recovery' ? null : Boolean(this.record(agent)), taskGraphPresent: Boolean(this.classic(agent)), baseGraphPresence: this.basePresence(agent) }
|
|
78
79
|
if (mode !== 'full' || !entry) return JSON.stringify(state)
|
|
79
80
|
const runner = entry.runner
|
|
80
81
|
return JSON.stringify({ ...state, workflowId: runner.config.interop.workflowId, status: runner.status() })
|
|
@@ -163,9 +164,10 @@ export class SessionInteraction {
|
|
|
163
164
|
this.exact(agent); signal?.throwIfAborted()
|
|
164
165
|
if (typeof reason !== 'string' || !reason.trim()) reject('DYNAMIC_CONTEXT_MODE_REASON_REQUIRED')
|
|
165
166
|
if (this.pending.has(agent)) reject('DYNAMIC_CONTEXT_MODE_QUESTION_PENDING')
|
|
167
|
+
const baseGraphPresence = this.basePresence(agent)
|
|
168
|
+
if (!['PRESENT', 'CREATION_PENDING', 'NEVER_CREATED', 'OUTSIDE_SCOPE'].includes(baseGraphPresence.state))
|
|
169
|
+
return { status: 'RECOVERY_REQUIRED', mode: 'recovery', baseGraphPresence, changed: false }
|
|
166
170
|
const prior = this.record(agent)
|
|
167
|
-
if (!['PRESENT', 'CREATION_PENDING', 'NEVER_CREATED', 'OUTSIDE_SCOPE'].includes(this.basePresence(agent).state))
|
|
168
|
-
return { status: 'RECOVERY_REQUIRED', mode: 'recovery', baseGraphPresence: this.basePresence(agent), changed: false }
|
|
169
171
|
const graphPresence = this.entries.get(agent)?.runner.graphPresence()
|
|
170
172
|
if (graphPresence?.recoveryRequired) return { status: 'RECOVERY_REQUIRED', mode: 'full', graphPresence, changed: false, nextTool: 'dynamic_context_recover_graphs' }
|
|
171
173
|
if (prior && !reconsider) return { mode: prior.mode, alreadySelected: true }
|
|
@@ -186,7 +188,7 @@ export class SessionInteraction {
|
|
|
186
188
|
const row = { version: 1, sessionId: agent.session.id, mode, evidence,
|
|
187
189
|
...(mode === 'full' && this.template.config.revision ? { policy: this.policy(agent) } : {}) }
|
|
188
190
|
await this.release(agent)
|
|
189
|
-
|
|
191
|
+
this.template.taskGraph.sessionRecords.append(agent.session, MODE_RECORD, row)
|
|
190
192
|
if (!await this.ctx.sessions.flush(agent.session)) reject('DYNAMIC_CONTEXT_MODE_NOT_DURABLE')
|
|
191
193
|
signal?.throwIfAborted(); this.exact(agent)
|
|
192
194
|
if (mode === 'full') await this.mount(agent, row)
|
package/interop.mjs
CHANGED
|
@@ -13,6 +13,7 @@ export function requireTaskGraph(ctx, expected) {
|
|
|
13
13
|
if (!service || expected && identity(service) !== identity(expected) || service.host?.closed || service.workflows?.closed
|
|
14
14
|
|| service.workflowContract !== WORKFLOW_CONTRACT || service.extensionContract !== EXTENSION_CONTRACT
|
|
15
15
|
|| typeof service.registerWorkflowProvider !== 'function' || typeof service.registerSessionPolicy !== 'function'
|
|
16
|
+
|| typeof service.sessionRecords?.read !== 'function' || typeof service.sessionRecords?.append !== 'function'
|
|
16
17
|
|| typeof service.createExtensionStore !== 'function' || typeof service.inspectGraphPresence !== 'function')
|
|
17
18
|
throw new Error('DYNAMIC_CONTEXT_REQUIRES_ACTIVE_TASK_GRAPH')
|
|
18
19
|
return service
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-dynamic-context",
|
|
3
|
-
"version": "0.1.1-rc.
|
|
3
|
+
"version": "0.1.1-rc.36",
|
|
4
4
|
"description": "Task-scoped direct model execution, native tools and durable context checkpoints for DeepSeek Harness",
|
|
5
5
|
"license": "GPL-3.0-only",
|
|
6
6
|
"type": "module",
|
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
],
|
|
65
65
|
"engines": {
|
|
66
66
|
"node": "^22.19.0 || >=24.0.0",
|
|
67
|
-
"dsh": "0.2.1-alpha.
|
|
67
|
+
"dsh": "0.2.1-alpha.1"
|
|
68
68
|
},
|
|
69
69
|
"scripts": {
|
|
70
70
|
"test": "node scripts/test.mjs",
|
|
@@ -79,41 +79,40 @@
|
|
|
79
79
|
"zod": "4.6.7"
|
|
80
80
|
},
|
|
81
81
|
"peerDependencies": {
|
|
82
|
-
"@deepseek-ai/dsh-fs": "0.2.1-alpha.
|
|
83
|
-
"@deepseek-ai/dsh-credentials-local": "0.2.1-alpha.
|
|
84
|
-
"@deepseek-ai/dsh-authorization": "0.2.1-alpha.
|
|
85
|
-
"@deepseek-ai/dsh-deepseek-account-platform": "0.2.1-alpha.
|
|
86
|
-
"dsh-bettertaskgraphs": "0.3.1-rc.
|
|
82
|
+
"@deepseek-ai/dsh-fs": "0.2.1-alpha.1",
|
|
83
|
+
"@deepseek-ai/dsh-credentials-local": "0.2.1-alpha.1",
|
|
84
|
+
"@deepseek-ai/dsh-authorization": "0.2.1-alpha.1",
|
|
85
|
+
"@deepseek-ai/dsh-deepseek-account-platform": "0.2.1-alpha.1",
|
|
86
|
+
"dsh-bettertaskgraphs": "0.3.1-rc.36",
|
|
87
87
|
"@deepseek-ai/cordis": "4.0.5",
|
|
88
|
-
"@deepseek-ai/dsh-agent": "0.2.1-alpha.
|
|
89
|
-
"@deepseek-ai/dsh-agent-instructions": "0.2.1-alpha.
|
|
90
|
-
"@deepseek-ai/dsh-home-paths": "0.2.1-alpha.
|
|
91
|
-
"@deepseek-ai/dsh-llm": "0.2.1-alpha.
|
|
92
|
-
"@deepseek-ai/dsh-sandbox-policy": "0.2.1-alpha.
|
|
93
|
-
"@deepseek-ai/dsh-scope": "0.2.1-alpha.
|
|
94
|
-
"@deepseek-ai/dsh-session": "0.2.1-alpha.
|
|
95
|
-
"@deepseek-ai/dsh-tools": "0.2.1-alpha.
|
|
96
|
-
"@deepseek-ai/dsh-user-approval": "0.2.1-alpha.
|
|
97
|
-
"@deepseek-ai/dsh-tool-fs": "0.2.1-alpha.
|
|
98
|
-
"@deepseek-ai/dsh-tool-fs-search": "0.2.1-alpha.
|
|
99
|
-
"@deepseek-ai/dsh-tool-bash": "0.2.1-alpha.
|
|
100
|
-
"@deepseek-ai/dsh-tool-web": "0.2.1-alpha.
|
|
101
|
-
"@deepseek-ai/dsh-session-projection": "0.2.1-alpha.
|
|
102
|
-
"@deepseek-ai/dsh-system-prompt": "0.2.1-alpha.
|
|
103
|
-
"@deepseek-ai/dsh-agent-loop": "0.2.1-alpha.
|
|
104
|
-
"@deepseek-ai/dsh-token-meter": "0.2.1-alpha.
|
|
105
|
-
"@deepseek-ai/dsh-fs-sandbox": "0.2.1-alpha.
|
|
106
|
-
"@deepseek-ai/dsh-
|
|
107
|
-
"@deepseek-ai/dsh-
|
|
108
|
-
"@deepseek-ai/dsh-sandbox
|
|
109
|
-
"@deepseek-ai/dsh-
|
|
110
|
-
"@deepseek-ai/dsh-
|
|
111
|
-
"@deepseek-ai/dsh-
|
|
112
|
-
"@deepseek-ai/dsh-
|
|
113
|
-
"@deepseek-ai/dsh-
|
|
114
|
-
"@deepseek-ai/dsh-
|
|
115
|
-
"@deepseek-ai/dsh-
|
|
116
|
-
"@deepseek-ai/dsh-user-questions": "0.2.1-alpha.4 || 0.2.1-alpha.3"
|
|
88
|
+
"@deepseek-ai/dsh-agent": "0.2.1-alpha.1",
|
|
89
|
+
"@deepseek-ai/dsh-agent-instructions": "0.2.1-alpha.1",
|
|
90
|
+
"@deepseek-ai/dsh-home-paths": "0.2.1-alpha.1",
|
|
91
|
+
"@deepseek-ai/dsh-llm": "0.2.1-alpha.1",
|
|
92
|
+
"@deepseek-ai/dsh-sandbox-policy": "0.2.1-alpha.1",
|
|
93
|
+
"@deepseek-ai/dsh-scope": "0.2.1-alpha.1",
|
|
94
|
+
"@deepseek-ai/dsh-session": "0.2.1-alpha.1",
|
|
95
|
+
"@deepseek-ai/dsh-tools": "0.2.1-alpha.1",
|
|
96
|
+
"@deepseek-ai/dsh-user-approval": "0.2.1-alpha.1",
|
|
97
|
+
"@deepseek-ai/dsh-tool-fs": "0.2.1-alpha.1",
|
|
98
|
+
"@deepseek-ai/dsh-tool-fs-search": "0.2.1-alpha.1",
|
|
99
|
+
"@deepseek-ai/dsh-tool-bash": "0.2.1-alpha.1",
|
|
100
|
+
"@deepseek-ai/dsh-tool-web": "0.2.1-alpha.1",
|
|
101
|
+
"@deepseek-ai/dsh-session-projection": "0.2.1-alpha.1",
|
|
102
|
+
"@deepseek-ai/dsh-system-prompt": "0.2.1-alpha.1",
|
|
103
|
+
"@deepseek-ai/dsh-agent-loop": "0.2.1-alpha.1",
|
|
104
|
+
"@deepseek-ai/dsh-token-meter": "0.2.1-alpha.1",
|
|
105
|
+
"@deepseek-ai/dsh-fs-sandbox": "0.2.1-alpha.1",
|
|
106
|
+
"@deepseek-ai/dsh-subprocess-local": "0.2.1-alpha.1",
|
|
107
|
+
"@deepseek-ai/dsh-sandbox-local": "0.2.1-alpha.1",
|
|
108
|
+
"@deepseek-ai/dsh-bash-sandbox": "0.2.1-alpha.1",
|
|
109
|
+
"@deepseek-ai/dsh-shell-env": "0.2.1-alpha.1",
|
|
110
|
+
"@deepseek-ai/dsh-skill": "0.2.1-alpha.1",
|
|
111
|
+
"@deepseek-ai/dsh-fs-observation-policy": "0.2.1-alpha.1",
|
|
112
|
+
"@deepseek-ai/dsh-session-persistence-jsonl": "0.2.1-alpha.1",
|
|
113
|
+
"@deepseek-ai/dsh-tool-call-timeout-policy": "0.2.1-alpha.1",
|
|
114
|
+
"@deepseek-ai/dsh-llm-deepseek": "0.2.1-alpha.1",
|
|
115
|
+
"@deepseek-ai/dsh-user-questions": "0.2.1-alpha.1"
|
|
117
116
|
},
|
|
118
117
|
"dsh": {
|
|
119
118
|
"bundle": {
|
|
@@ -122,12 +121,12 @@
|
|
|
122
121
|
},
|
|
123
122
|
"publishConfig": {
|
|
124
123
|
"access": "public",
|
|
125
|
-
"tag": "dsh-0.2.1-alpha.
|
|
124
|
+
"tag": "dsh-0.2.1-alpha.1",
|
|
126
125
|
"registry": "https://registry.npmjs.org/"
|
|
127
126
|
},
|
|
128
127
|
"devDependencies": {
|
|
129
|
-
"@deepseek-ai/dsh": "0.2.1-alpha.
|
|
130
|
-
"dsh-bettertaskgraphs": "0.3.1-rc.
|
|
128
|
+
"@deepseek-ai/dsh": "0.2.1-alpha.1",
|
|
129
|
+
"dsh-bettertaskgraphs": "0.3.1-rc.36"
|
|
131
130
|
},
|
|
132
131
|
"homepage": "https://github.com/oldcitynight/dsh-dynamic-context#readme",
|
|
133
132
|
"repository": {
|
package/revision-host.mjs
CHANGED
|
@@ -6,14 +6,14 @@ import { copy, digest, GraphError } from 'dsh-bettertaskgraphs/core'
|
|
|
6
6
|
import { artifactProof } from './artifacts.mjs'
|
|
7
7
|
|
|
8
8
|
export function revisionAuthority(ctx, agent) {
|
|
9
|
-
const sessions = ctx.get?.('sessions') ?? ctx.sessions
|
|
9
|
+
const sessions = ctx.get?.('sessions') ?? ctx.sessions
|
|
10
10
|
if (!agent || ctx.agents.get(agent.id) !== agent || sessions.get(agent.session.id) !== agent.session)
|
|
11
11
|
throw new GraphError('REVISION_CONTROLLER_CHANGED')
|
|
12
12
|
const sandbox = ctx.get('sandboxPolicy')?.resolve({ session: agent.session }), goal = ctx.get('goals')?.get(agent)
|
|
13
13
|
const plan = ctx.get('runtimeQuality')?.planActive(agent)
|
|
14
14
|
?? ctx.get('agentPresets')?.serviceFor(agent, 'planMode')?.loggedActive(agent.session)
|
|
15
15
|
?? agent.ctx?.get('planMode')?.loggedActive(agent.session)
|
|
16
|
-
return { cwd:
|
|
16
|
+
return { cwd: ctx.get?.('workingDirectory')?.get(agent.session) ?? agent.session.header.cwd, header: agent.session.header,
|
|
17
17
|
input: agent.session.deriveMessages().filter(message => ['user', 'developer', 'system'].includes(message.role)),
|
|
18
18
|
sandbox: sandbox ? { mode: sandbox.mode, workspaceRoot: sandbox.workspaceRoot } : null,
|
|
19
19
|
approval: ctx.get('approval')?.effectivePolicy(agent.session) ?? null, plan: Boolean(plan),
|
|
@@ -4,7 +4,7 @@ import fs from 'node:fs'
|
|
|
4
4
|
import os from 'node:os'
|
|
5
5
|
import path from 'node:path'
|
|
6
6
|
import UserQuestions from '@deepseek-ai/dsh-user-questions'
|
|
7
|
-
import
|
|
7
|
+
import Persistence from '@deepseek-ai/dsh-session-persistence-jsonl'
|
|
8
8
|
import TaskGraph from 'dsh-bettertaskgraphs'
|
|
9
9
|
import { createUserMessage } from '@deepseek-ai/dsh-llm'
|
|
10
10
|
import { createRuntimeHarness, runtimeProposal } from '../testing/runtime-harness.mjs'
|
|
@@ -73,7 +73,9 @@ for (const mode of ['native', 'task-graph', 'full']) test(`human choice ${mode}
|
|
|
73
73
|
assert.equal(schemaNames(f.h.ctx, first.agent).includes('dynamic_context_submit'), mode === 'full')
|
|
74
74
|
assert.equal((await f.call(first.agent, 'dynamic_context_select_mode', { reason: '重复调用' })).alreadySelected, true)
|
|
75
75
|
assert.equal(f.questions.length, 1)
|
|
76
|
-
|
|
76
|
+
const records = f.h.ctx.transactionGraph.sessionRecords
|
|
77
|
+
assert.ok(records.read(first.agent.session).some(({ event }) => event.type === MODE_RECORD && event.data.mode === mode))
|
|
78
|
+
assert.ok(!first.agent.session.snapshotEvents().some(event => event.type === MODE_RECORD))
|
|
77
79
|
const secondPrompt = await f.h.ctx.systemPrompt.assemble({ agent: second.agent, scope: second.agent })
|
|
78
80
|
assert.doesNotMatch(JSON.stringify(secondPrompt), /FIRST_TASK_CONTRACT|MUST_NOT_LEAK_TEMPLATE_GOAL/)
|
|
79
81
|
if (mode === 'full') {
|
|
@@ -187,7 +189,7 @@ test('session commit receipt prevents fresh creation after both graph and witnes
|
|
|
187
189
|
await f.call(agent, 'dynamic_context_select_mode', { reason: '项目任务' })
|
|
188
190
|
await f.call(agent, 'dynamic_context_submit', { proposal: runtimeProposal([]) })
|
|
189
191
|
const child = f.h.runner.interaction.entries.get(agent).runner
|
|
190
|
-
assert.ok(agent.session
|
|
192
|
+
assert.ok(f.h.ctx.transactionGraph.sessionRecords.read(agent.session).some(({ event }) => event.type === GRAPH_COMMIT_RECORD))
|
|
191
193
|
fs.unlinkSync(child.graph.store.file); fs.unlinkSync(child.graph.store.witness.file)
|
|
192
194
|
assert.equal(child.graphPresence().state, 'GRAPH_AND_WITNESS_LOST_AFTER_COMMIT')
|
|
193
195
|
assert.equal(child.graphPresence().canRestore, false)
|
|
@@ -279,3 +281,22 @@ for (const full of [false, true]) test(`native tool loop reaches ${full ? 'joint
|
|
|
279
281
|
}
|
|
280
282
|
assert.equal(f.questions.length, 1)
|
|
281
283
|
})
|
|
284
|
+
|
|
285
|
+
test('legacy session record loss blocks mode changes while native JSONL remains readable', async t => {
|
|
286
|
+
const f = await fixture(t), { agent } = await f.agent('lost-plugin-records')
|
|
287
|
+
await f.call(agent, 'dynamic_context_select_mode', { reason: '项目任务' })
|
|
288
|
+
await f.call(agent, 'dynamic_context_submit', { proposal: runtimeProposal([]) })
|
|
289
|
+
const records = f.h.ctx.transactionGraph.sessionRecords
|
|
290
|
+
const native = await f.h.ctx.sessionPersistence.open(agent.id, 'read')
|
|
291
|
+
try {
|
|
292
|
+
const { events } = await native.read(0, 100)
|
|
293
|
+
assert.ok(events.some(row => row.type === 'user/message'))
|
|
294
|
+
assert.ok(events.every(row => !row.type.startsWith('plugin:')))
|
|
295
|
+
} finally { await native.close() }
|
|
296
|
+
fs.unlinkSync(path.join(records.directory(agent.session), 'records.json'))
|
|
297
|
+
const status = await f.call(agent, 'dynamic_context_graph_status', {})
|
|
298
|
+
assert.equal(status.mode, 'recovery')
|
|
299
|
+
assert.equal(status.base.code, 'LEGACY_SESSION_RECORD_JOURNAL_MISSING')
|
|
300
|
+
const selection = await f.call(agent, 'dynamic_context_select_mode', { reason: '尝试新建', reconsider: true })
|
|
301
|
+
assert.equal(selection.status, 'RECOVERY_REQUIRED')
|
|
302
|
+
})
|
package/test/interop.test.mjs
CHANGED
|
@@ -3,7 +3,7 @@ import assert from 'node:assert/strict'
|
|
|
3
3
|
import fs from 'node:fs'
|
|
4
4
|
import os from 'node:os'
|
|
5
5
|
import path from 'node:path'
|
|
6
|
-
import
|
|
6
|
+
import Persistence from '@deepseek-ai/dsh-session-persistence-jsonl'
|
|
7
7
|
import TaskGraphPlugin from 'dsh-bettertaskgraphs'
|
|
8
8
|
import { createRuntimeHarness, runtimeProposal } from '../testing/runtime-harness.mjs'
|
|
9
9
|
|
package/test/revision.test.mjs
CHANGED
|
@@ -168,7 +168,7 @@ for (const altered of [false, true]) test(`retained context references are resol
|
|
|
168
168
|
test('host workflow revise port binds the real controller without global goal injection and rejects worker elevation', async t => {
|
|
169
169
|
const {createRuntimeHarness}=await import('../testing/runtime-harness.mjs');
|
|
170
170
|
const {default:TaskGraph}=await import('dsh-bettertaskgraphs');
|
|
171
|
-
const Persistence=await import('@deepseek-ai/dsh-session-persistence-jsonl');
|
|
171
|
+
const Persistence=await import('@deepseek-ai/dsh-session-persistence-jsonl').then(module => module.default);
|
|
172
172
|
const root=fs.realpathSync(fs.mkdtempSync(path.join(os.tmpdir(),'revision-controller-'))), projectRoot=path.join(root,'workspace');fs.mkdirSync(projectRoot);
|
|
173
173
|
const h=await createRuntimeHarness({projectRoot,directory:path.join(root,'state'),config:{storageRoot:root,revision:{policy},exposeControlTools:true,direct:{durable:true},interop:{workflowId:'revision-fixture'}},
|
|
174
174
|
setup:async ctx=>{await ctx.plugin(Persistence,{root:path.join(root,'sessions')});await ctx.plugin(TaskGraph,{projectRoot});},
|
|
@@ -629,7 +629,7 @@ test('a fabricated failed tool identifier cannot close the attempt', async t =>
|
|
|
629
629
|
|
|
630
630
|
test('the real workflow port and controller schema expose only the supervised continuation', async t => {
|
|
631
631
|
const { default: TaskGraph } = await import('dsh-bettertaskgraphs')
|
|
632
|
-
const Persistence = await import('@deepseek-ai/dsh-session-persistence-jsonl')
|
|
632
|
+
const Persistence = await import('@deepseek-ai/dsh-session-persistence-jsonl').then(module => module.default)
|
|
633
633
|
const h = await fixture(t, ({ index }) => index === 1 ? result('COMPLETE', 'Prepared report.') : index === 2 ? accept : current, {
|
|
634
634
|
runtime: true, config: { exposeControlTools: true, interop: { workflowId: 'supervision-fixture' } },
|
|
635
635
|
setup: async (ctx, projectRoot, root) => {
|
package/testing/harness.mjs
CHANGED
|
@@ -9,10 +9,9 @@ import AgentRegistry from '@deepseek-ai/dsh-agent'
|
|
|
9
9
|
import AgentLoop from '@deepseek-ai/dsh-agent-loop'
|
|
10
10
|
import TokenMeter from '@deepseek-ai/dsh-token-meter'
|
|
11
11
|
import TaskGraph from 'dsh-bettertaskgraphs'
|
|
12
|
-
import
|
|
12
|
+
import Persistence from '@deepseek-ai/dsh-session-persistence-jsonl'
|
|
13
13
|
import SandboxPolicy from '@deepseek-ai/dsh-sandbox-policy'
|
|
14
14
|
import Filesystem from '@deepseek-ai/dsh-fs-sandbox'
|
|
15
|
-
import WorkingDirectory from '@deepseek-ai/dsh-working-directory'
|
|
16
15
|
import * as DynamicContext from '../index.mjs'
|
|
17
16
|
import { startFakeLlama } from './fake-llama.mjs'
|
|
18
17
|
|
|
@@ -50,7 +49,6 @@ export async function createHarness({ projectRoot, directory, respond, config =
|
|
|
50
49
|
if (taskGraph && !ctx.get('transactionGraph')) {
|
|
51
50
|
if (!ctx.get('sandboxPolicy')) await ctx.plugin(SandboxPolicy, { mode: 'workspace-write', workspaceRoot: projectRoot })
|
|
52
51
|
if (!ctx.get('fs')) await ctx.plugin(Filesystem, { cwd: projectRoot })
|
|
53
|
-
if (!ctx.get('workingDirectory')) await ctx.plugin(WorkingDirectory, { defaultDirectory: projectRoot })
|
|
54
52
|
if (!ctx.get('sessionPersistence')) await ctx.plugin(Persistence, { root: directory + '/native-sessions' })
|
|
55
53
|
await ctx.plugin(TaskGraph, { projectRoot })
|
|
56
54
|
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import SandboxPolicy from '@deepseek-ai/dsh-sandbox-policy'
|
|
2
2
|
import SandboxedFileSystem from '@deepseek-ai/dsh-fs-sandbox'
|
|
3
|
-
import WorkingDirectory from '@deepseek-ai/dsh-working-directory'
|
|
4
3
|
import Approval from '@deepseek-ai/dsh-user-approval'
|
|
5
4
|
import Subprocess from '@deepseek-ai/dsh-subprocess-local'
|
|
6
5
|
import Sandbox from '@deepseek-ai/dsh-sandbox-local'
|
|
@@ -21,7 +20,6 @@ export async function createRuntimeHarness({ projectRoot, directory, respond, ba
|
|
|
21
20
|
setup: async ctx => {
|
|
22
21
|
await ctx.plugin(SandboxPolicy, { mode, workspaceRoot: projectRoot })
|
|
23
22
|
await ctx.plugin(SandboxedFileSystem, { cwd: projectRoot })
|
|
24
|
-
await ctx.plugin(WorkingDirectory, { defaultDirectory: projectRoot })
|
|
25
23
|
await ctx.plugin(Approval, { policy: approval })
|
|
26
24
|
await ctx.plugin(Subprocess)
|
|
27
25
|
await ctx.plugin(Sandbox)
|