@quan-huayan/dsh-research-engine 0.1.0
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 +38 -0
- package/LICENSE +21 -0
- package/README.md +183 -0
- package/cordis.patch.yml +32 -0
- package/package.json +59 -0
- package/presets/research-engine/agent.cordis.yml +305 -0
- package/presets/research-engine/contract/conventions.schema.json +41 -0
- package/presets/research-engine/contract/fields.md +150 -0
- package/presets/research-engine/contract/managed.json +36 -0
- package/presets/research-engine/contract/manifest.schema.json +33 -0
- package/presets/research-engine/contract/note.schema.json +56 -0
- package/presets/research-engine/contract/observations.schema.json +46 -0
- package/presets/research-engine/contract/pipeline.schema.json +43 -0
- package/presets/research-engine/contract/project.schema.json +66 -0
- package/presets/research-engine/contract/templates.schema.json +78 -0
- package/presets/research-engine/plugins/engine-git/main.js +284 -0
- package/presets/research-engine/plugins/exp-ledger/main.js +1324 -0
- package/presets/research-engine/plugins/kb-core/main.js +538 -0
- package/presets/research-engine/plugins/stage-ctrl/main.js +388 -0
- package/presets/research-engine/plugins/task-dispatch/main.js +848 -0
- package/presets/research-engine/preset.yml +3 -0
- package/presets/research-engine/skills/research-engine/SKILL.md +114 -0
- package/scripts/install.mjs +116 -0
- package/startup.js +24 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# 更新日志
|
|
2
|
+
|
|
3
|
+
本文件记录本包对外可见的变化。格式参考 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.1.0/),
|
|
4
|
+
版本号遵循 [语义化版本](https://semver.org/lang/zh-CN/)。
|
|
5
|
+
|
|
6
|
+
## [0.1.0] — 2026-09-08
|
|
7
|
+
|
|
8
|
+
首个发布版本:research-engine preset 从「本机 `$DSH_HOME/.agent-presets/` 里的私有副本」
|
|
9
|
+
变成可分发的 npm 包。
|
|
10
|
+
|
|
11
|
+
### 新增
|
|
12
|
+
|
|
13
|
+
- `presets/research-engine/` —— 引擎本体(唯一真源):`preset.yml`、`agent.cordis.yml`、
|
|
14
|
+
用户面 `SKILL.md`、7 份 JSON schema + `managed.json` + `fields.md`、5 个插件模块。
|
|
15
|
+
- `cordis.patch.yml` + `startup.js` —— 组合包层:把自带的 preset 根注册成 `agent-presets`
|
|
16
|
+
的 `system` 根(`dsh plugin --profile <name> add` 后新会话即可选用)。
|
|
17
|
+
- `scripts/install.mjs` —— 把 preset 同步进 `$DSH_HOME/.agent-presets/` 的幂等安装器
|
|
18
|
+
(`--force` 先备份、`--dry-run` 只报告、`--dir` 换根);覆盖 dsh 0.1.1-rc.x 等
|
|
19
|
+
组合包根不生效的版本。
|
|
20
|
+
- `README.md`、`CHANGELOG.md`、`.gitignore`、`LICENSE`(MIT)。
|
|
21
|
+
|
|
22
|
+
### 变更
|
|
23
|
+
|
|
24
|
+
- 插件依赖解析改为多锚点回退:先按插件自身位置解析(随包安装的 `node_modules`),
|
|
25
|
+
再回退到 `$DSH_HOME/profiles/node_modules` 的扁平安装 —— 同一份代码既能作为 npm 包运行,
|
|
26
|
+
也能作为拷贝进用户 preset 根的副本运行。
|
|
27
|
+
- 仓库结构:规格稿与验收报告移入 `docs/`,v6 存档移入 `archive/preset-v6/`,
|
|
28
|
+
headless 验收 overlay 移入 `overlays/`,测试工程移入 `fixtures/`(gitignore)。
|
|
29
|
+
- 自检脚本默认读仓库内的 preset,可用 `RESEARCH_ENGINE_PRESET` 覆盖。
|
|
30
|
+
|
|
31
|
+
### 已知问题
|
|
32
|
+
|
|
33
|
+
- dsh 0.1.1-rc.x 的启动器会覆写 `agent-presets` 的 `roots`,组合包注册的自带根在该版本不生效;
|
|
34
|
+
请改用 `scripts/install.mjs`。
|
|
35
|
+
- `tools/probe-*.mjs` 在 dsh 沙箱内运行时,`git-lfs` 无法创建命名管道,导致引擎提交 `raw/` 失败、
|
|
36
|
+
探针误报 8 项;在普通终端运行即全绿。
|
|
37
|
+
|
|
38
|
+
[0.1.0]: https://github.com/quan-huayan/dsh-research-engine/releases/tag/v0.1.0
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Quan-huayan
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
# @quan-huayan/dsh-research-engine · 研究引擎
|
|
2
|
+
|
|
3
|
+
> 一个 DeepSeek Harness(dsh)**agent preset**:把研究工程变成「不可变证据 + 一条可重放的过程」。
|
|
4
|
+
> 环境 / 台账 / 状态机 / 执行 / 知识五层由工具独占,模型只能经工具改工程,数字只能由工具从已登记文件里提取。
|
|
5
|
+
|
|
6
|
+
**English** — `@quan-huayan/dsh-research-engine` ships a self-contained dsh agent preset (`research-engine`) plus a
|
|
7
|
+
profile bundle layer that registers it. Inside a research project every mutation goes through a tool, every claim
|
|
8
|
+
points at evidence, and user authority must quote a real answer; the engine keeps its own internal version store the
|
|
9
|
+
model never sees. 21 model-facing tools + 1 internal service, 7 JSON schemas, 5 plugin modules, zero runtime deps
|
|
10
|
+
beyond `js-yaml` / `ajv`.
|
|
11
|
+
|
|
12
|
+
- 版本:**0.1.0**
|
|
13
|
+
- 包名:`@quan-huayan/dsh-research-engine`(npm)
|
|
14
|
+
- 需要:Node ≥ 22;dsh(0.1.1-rc.2 及以上均可);`git` 必需,`git-lfs` 可选(不装则 `raw/` 降级为哈希-only)
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## 1. 根本原则
|
|
19
|
+
|
|
20
|
+
**任何研究结论,都必须能由不可变证据 + 一条可重放的过程重新得到。**
|
|
21
|
+
|
|
22
|
+
三条推论决定引擎的每一个动作:
|
|
23
|
+
|
|
24
|
+
| | 原则 | 物理落点 |
|
|
25
|
+
|---|---|---|
|
|
26
|
+
| P1 | **证据优先**:结论只能指向证据;数字只能由工具从已登记文件里提取 | `experiments/<runId>/{config,manifest,observations}.json` + `raw/` |
|
|
27
|
+
| P2 | **封闭变更**:工程里的所有变更只能经工具发生 | 写类工具前置守卫 + 内建版本库(模型不可见) |
|
|
28
|
+
| P3 | **权威分离**:用户权威 / 证据权威 / agent 提议不得互相冒充 | `conventions[]` + `decision` 事件 / `observations.json` / `.kb/notes` 的 `status` |
|
|
29
|
+
|
|
30
|
+
八要素落点、22 条权责、逐工具流程见 [`docs/`](docs/README.md)。
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## 2. 安装
|
|
35
|
+
|
|
36
|
+
### 方式 A:组合包(推荐,dsh ≥ 0.1.2-rc.1)
|
|
37
|
+
|
|
38
|
+
```sh
|
|
39
|
+
dsh plugin --profile web add @quan-huayan/dsh-research-engine
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
本包声明了 `dsh.bundle.patch`,`dsh` 会把它追加进该 profile 的 `dsh.profile.bundles`;启动时
|
|
43
|
+
[`cordis.patch.yml`](cordis.patch.yml) 把本包自带的 `presets/` 注册成 `agent-presets` roster 的一个
|
|
44
|
+
`system` 根 —— **新建会话即可在 preset 选择器里看到「研究引擎」**,无需重启。
|
|
45
|
+
|
|
46
|
+
先只看组合结果、不启动:
|
|
47
|
+
|
|
48
|
+
```sh
|
|
49
|
+
dsh --profile web --dump-config # 应能看到 "# == @quan-huayan/dsh-research-engine" 这一层
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
卸载:`dsh plugin --profile web remove @quan-huayan/dsh-research-engine`(依赖与层一起移除)。
|
|
53
|
+
|
|
54
|
+
> **dsh 0.1.1-rc.x 的限制**:那一版的启动器会把 `agent-presets` 的 `roots` 覆写为「仅随附根」,
|
|
55
|
+
> 组合包注册的自带根不生效(`--dump-config` 里能看到,启动后没有)。请用方式 B。
|
|
56
|
+
|
|
57
|
+
### 方式 B:装进用户 preset 根(全版本可用)
|
|
58
|
+
|
|
59
|
+
```sh
|
|
60
|
+
node node_modules/@quan-huayan/dsh-research-engine/scripts/install.mjs
|
|
61
|
+
# 或从本仓库直接跑:
|
|
62
|
+
node scripts/install.mjs
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
把 `presets/research-engine/` 同步到 `$DSH_HOME/.agent-presets/research-engine`。
|
|
66
|
+
脚本是幂等的:目标不存在就装;内容相同就跳过;**内容不同会拒绝覆盖并提示**,确认要覆盖加 `--force`
|
|
67
|
+
(先自动备份成 `research-engine.bak-<时间戳>`)。`--dry-run` 只报告将要做什么,`--dir <目录>` 换 preset 根。
|
|
68
|
+
|
|
69
|
+
两种方式可以共存:组合包的 `system` 根排在用户根之前,同名 id 由组合包那份胜出。
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## 3. 用它
|
|
74
|
+
|
|
75
|
+
1. 在目标工作区**新建**会话,选「研究引擎」preset(切换 preset 只在空白会话可用)。
|
|
76
|
+
2. 首句直接说目标,或先让它看现状:
|
|
77
|
+
|
|
78
|
+
```
|
|
79
|
+
project_load → project_verify # 先看现状,别凭记忆断言工程内容
|
|
80
|
+
stage_read → stage_goto # 走到该在的阶段
|
|
81
|
+
(需要新能力)script_declare → template_declare
|
|
82
|
+
run_draft → run_launch → job_output # 跑
|
|
83
|
+
run_observe # 数字来自产出文件本身
|
|
84
|
+
note_write(claim, evidence=[runId]) → note_adjudicate(accept)
|
|
85
|
+
view_render(report) → view_render(notes-skill)
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
新目录接引擎:让它 `project_init`。已经存在的旧工程:`project_init mode=migrate`(原文归档、逐项迁移、
|
|
89
|
+
不删任何既有文件)。
|
|
90
|
+
|
|
91
|
+
### 21 个模型面工具
|
|
92
|
+
|
|
93
|
+
| 域 | 工具 |
|
|
94
|
+
|---|---|
|
|
95
|
+
| 环境 / 台账(7) | `project_init` `project_load` `project_verify` `project_reconcile` `entity_declare` `entity_query` `convention_declare` |
|
|
96
|
+
| 状态机(3) | `stage_declare` `stage_read` `stage_goto` |
|
|
97
|
+
| 执行 / 证据(7) | `template_declare` `script_declare` `run_draft` `run_launch` `run_observe` `run_query` `run_close` |
|
|
98
|
+
| 知识 / 裁决(4) | `note_write` `note_adjudicate` `note_query` `view_render` |
|
|
99
|
+
|
|
100
|
+
内建服务 `research.engineGit` 不注册工具,模型侧看不到任何版本库概念。
|
|
101
|
+
|
|
102
|
+
### 工程里的物理形态
|
|
103
|
+
|
|
104
|
+
```
|
|
105
|
+
project.yaml pipeline.yaml templates.yaml scripts/ registry.jsonl
|
|
106
|
+
experiments/<runId>/{config.json, manifest.json, observations.json, raw/}
|
|
107
|
+
.kb/{notes/*.md, index.yaml} _report/{runs.csv, summary.json}
|
|
108
|
+
.research/{state.json, managed.json, engine.git/}
|
|
109
|
+
skills/<工程>/SKILL.md ← 派生视图,由 view_render 生成
|
|
110
|
+
遗留区(.pth/.png/.txt/.ipynb …) ← 只登记,不改不删
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
## 4. 仓库结构
|
|
116
|
+
|
|
117
|
+
```
|
|
118
|
+
presets/research-engine/ 引擎本体(唯一真源)
|
|
119
|
+
preset.yml agent.cordis.yml
|
|
120
|
+
skills/research-engine/SKILL.md
|
|
121
|
+
contract/ 7 份 schema + managed.json + fields.md
|
|
122
|
+
plugins/{engine-git,exp-ledger,stage-ctrl,task-dispatch,kb-core}/main.js
|
|
123
|
+
cordis.patch.yml 组合包层:把 presets/ 注册成 agent-presets 的 system 根
|
|
124
|
+
startup.js 组合包的提供方行(只暴露 presetsDir 服务)
|
|
125
|
+
scripts/install.mjs 把 preset 装进 $DSH_HOME/.agent-presets/
|
|
126
|
+
tools/ 自检脚本(不进 npm 包)
|
|
127
|
+
overlays/ headless 验收 overlay
|
|
128
|
+
docs/ 规格稿 + 六轮验收报告
|
|
129
|
+
archive/preset-v6/ v6 历史存档
|
|
130
|
+
fixtures/ 测试工程(gitignore,不进包)
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## 5. 自检
|
|
136
|
+
|
|
137
|
+
```sh
|
|
138
|
+
npm run check # 契约 + 插件静态检查 + 197 项工具探针
|
|
139
|
+
npm run check:preset # 用 dsh 自己的 preset 发现器解析 agent.cordis.yml
|
|
140
|
+
node tools/probe-migrate.mjs # 迁移自检
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
| 脚本 | 覆盖 |
|
|
144
|
+
|---|---|
|
|
145
|
+
| `tools/check-contract.mjs` | 7 份 schema 可编译、跨文件引用无环、真实数据差距清单 |
|
|
146
|
+
| `tools/check-plugins.mjs` | 5 插件可加载、21 工具名合法唯一、schema 落在 dsh-tools 支持子集内 |
|
|
147
|
+
| `tools/probe-tools.mjs` | 假 ctx 逐工具跑 197 项断言(严格返回字段、返回文本零版本库词汇、拒绝路径必带修法) |
|
|
148
|
+
| `tools/probe-migrate.mjs` | 旧式工程 → `project_init mode=migrate` → 核对六项产出与幂等复检 |
|
|
149
|
+
| `tools/check-preset.mjs` | 宿主 preset 发现器解析合成文件(含 `!!js`) |
|
|
150
|
+
|
|
151
|
+
> **探针必须在 dsh 沙箱之外跑。** 沙箱禁止创建命名管道,`git-lfs` 因此起不来
|
|
152
|
+
> (`couldn't create signal pipe, Win32 error 5`),引擎提交 `raw/` 失败,探针会误报 8 项。
|
|
153
|
+
> 在普通终端里跑即全绿。
|
|
154
|
+
|
|
155
|
+
`RESEARCH_ENGINE_PRESET` 环境变量可让所有自检改读别的 preset 副本(例如已安装的那份)。
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
## 6. 已知边界
|
|
160
|
+
|
|
161
|
+
- **用户权威落点为空是正常的**:约定与裁决需要真实用户答复,引擎拒绝推断、代答、润色。
|
|
162
|
+
- **`job_output` 在任务结束后可能为空**:进程输出已被收进 `experiments/<runId>/raw/stdout.log`(证据)。
|
|
163
|
+
- **`git-lfs` 不可用时**:`raw/` 降级为哈希-only,证据被改动即 `invalidated`。
|
|
164
|
+
- **前端外观**(client 插件 + host 只读桥)未做;本期只有模型面与派生视图。
|
|
165
|
+
- **preset 副本会漂移**:升级本包后,方式 B 装下的副本需要重跑 `scripts/install.mjs`(脚本会提示)。
|
|
166
|
+
|
|
167
|
+
---
|
|
168
|
+
|
|
169
|
+
## 7. 开发与发布(维护者)
|
|
170
|
+
|
|
171
|
+
改动 `presets/research-engine/` 后:
|
|
172
|
+
|
|
173
|
+
1. 递增 `agent.cordis.yml` 里 `./plugins/*/main.js?v=N` 的 N —— loader 按 URL 缓存 ESM,同进程内改代码只有 URL 变了才重新求值。
|
|
174
|
+
2. 跑 §5 的自检。
|
|
175
|
+
3. 更新 `CHANGELOG.md` 与 `package.json` 的 `version`。
|
|
176
|
+
4. 发布:`npm publish`(`publishConfig.access=public`)。
|
|
177
|
+
预览包内容:`npm pack --dry-run`。
|
|
178
|
+
|
|
179
|
+
---
|
|
180
|
+
|
|
181
|
+
## 8. 许可
|
|
182
|
+
|
|
183
|
+
[MIT](LICENSE) © 2026 Quan-huayan
|
package/cordis.patch.yml
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# @quan-huayan/dsh-research-engine 的组合包层(bundle patch)。
|
|
2
|
+
#
|
|
3
|
+
# 安装后 `dsh plugin --profile web add @quan-huayan/dsh-research-engine` 会把本行加入
|
|
4
|
+
# profile 的 dsh.profile.bundles,本层在启动时按下面的顺序生效:
|
|
5
|
+
#
|
|
6
|
+
# 1) insert:把本包的提供方行挂进 profile(它只暴露 presetsDir 这个服务);
|
|
7
|
+
# 2) id 定向补丁:让 agent-presets 注入该服务,并把本包自带的 presets/ 注册成
|
|
8
|
+
# 一个 system 根 —— 新会话即可在 preset 选择器里看到「研究引擎」。
|
|
9
|
+
#
|
|
10
|
+
# 两点说明:
|
|
11
|
+
# * 行名用包名(Node 从 profile 的 node_modules 解析到已安装代码),不用相对路径;
|
|
12
|
+
# * 路径走 !!js 求值,取的是本包自己的绝对路径,与 cwd / baseUrl 无关。
|
|
13
|
+
# * 补丁按 id 整体替换 config:如果你的 profile 自己也配置了 agent-presets 的 config,
|
|
14
|
+
# 你的层在本层之后应用,会整体覆盖 —— 那时请把下面的 roots 一并重述。
|
|
15
|
+
#
|
|
16
|
+
# 兼容性:DSH >= 0.1.2-rc.1 时 agent-presets 的 roots 由本层决定;
|
|
17
|
+
# DSH 0.1.1-rc.x 的启动器会把 roots 覆写为「仅随附根」,本层不生效 ——
|
|
18
|
+
# 那种版本请改用 `node node_modules/@quan-huayan/dsh-research-engine/scripts/install.mjs`
|
|
19
|
+
# 把 preset 装进 $DSH_HOME/.agent-presets/(用户根)。
|
|
20
|
+
|
|
21
|
+
- insert:
|
|
22
|
+
- id: research-engine-bundle
|
|
23
|
+
name: '@quan-huayan/dsh-research-engine/startup'
|
|
24
|
+
|
|
25
|
+
- id: agent-presets
|
|
26
|
+
inject: [researchEngineBundle]
|
|
27
|
+
config:
|
|
28
|
+
default: standard
|
|
29
|
+
includeUserRoot: true
|
|
30
|
+
roots:
|
|
31
|
+
- path: !!js ctx.researchEngineBundle.presetsDir
|
|
32
|
+
trust: system
|
package/package.json
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@quan-huayan/dsh-research-engine",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"license": "MIT",
|
|
5
|
+
"author": "Quan-huayan",
|
|
6
|
+
"description": "研究引擎(research-engine):把研究工程变成「不可变证据 + 可重放过程」的 DeepSeek Harness agent preset —— 环境/台账/状态机/执行/知识五层由工具独占,21 个模型面工具 + 1 个内建版本库服务。",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"main": "startup.js",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": "./startup.js",
|
|
11
|
+
"./startup": "./startup.js",
|
|
12
|
+
"./package.json": "./package.json",
|
|
13
|
+
"./presets/*": "./presets/*"
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"startup.js",
|
|
17
|
+
"cordis.patch.yml",
|
|
18
|
+
"presets",
|
|
19
|
+
"scripts/install.mjs",
|
|
20
|
+
"README.md",
|
|
21
|
+
"CHANGELOG.md"
|
|
22
|
+
],
|
|
23
|
+
"dsh": {
|
|
24
|
+
"bundle": {
|
|
25
|
+
"patch": "./cordis.patch.yml"
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
"publishConfig": {
|
|
29
|
+
"access": "public"
|
|
30
|
+
},
|
|
31
|
+
"repository": {
|
|
32
|
+
"type": "git",
|
|
33
|
+
"url": "git+https://github.com/quan-huayan/dsh-research-engine.git"
|
|
34
|
+
},
|
|
35
|
+
"homepage": "https://github.com/quan-huayan/dsh-research-engine#readme",
|
|
36
|
+
"bugs": {
|
|
37
|
+
"url": "https://github.com/quan-huayan/dsh-research-engine/issues"
|
|
38
|
+
},
|
|
39
|
+
"keywords": [
|
|
40
|
+
"dsh",
|
|
41
|
+
"deepseek-harness",
|
|
42
|
+
"agent-preset",
|
|
43
|
+
"research-engine",
|
|
44
|
+
"reproducible-research",
|
|
45
|
+
"provenance"
|
|
46
|
+
],
|
|
47
|
+
"engines": {
|
|
48
|
+
"node": ">=22"
|
|
49
|
+
},
|
|
50
|
+
"dependencies": {
|
|
51
|
+
"ajv": "^8.20.0",
|
|
52
|
+
"js-yaml": "^4.3.1"
|
|
53
|
+
},
|
|
54
|
+
"scripts": {
|
|
55
|
+
"check": "node tools/check-contract.mjs && node tools/check-plugins.mjs && node tools/probe-tools.mjs",
|
|
56
|
+
"check:preset": "node tools/check-preset.mjs",
|
|
57
|
+
"install-preset": "node scripts/install.mjs"
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
# The `standard` agent preset: the full coding agent, mounted once per process.
|
|
2
|
+
#
|
|
3
|
+
# This file is an AGENT-PLANE composition. The roster mounts it ONCE under a
|
|
4
|
+
# standing scope; every session naming it joins by scope parentage, so the
|
|
5
|
+
# tools and prompt sections registered here cover each joined agent while a
|
|
6
|
+
# session's own state stays keyed per Session/Agent inside the plugins. The
|
|
7
|
+
# host composition (`base.cordis.yml` + `web.cordis.yml`) keeps everything a
|
|
8
|
+
# preset must not own: the registries themselves, the sandbox and approval
|
|
9
|
+
# stack, persistence, and the model route.
|
|
10
|
+
#
|
|
11
|
+
# A service row here MUST sit inside a group carrying an `isolate` realm.
|
|
12
|
+
# Without one it publishes into the root realm, where it is process-global —
|
|
13
|
+
# another preset publishing the same name collides, and a host reader would
|
|
14
|
+
# resolve one preset's instance for every session; `dsh-agent-presets` rejects
|
|
15
|
+
# that at mount. `true` means an entry-local realm: this standing mount's own
|
|
16
|
+
# private instance, apart from every other preset's. (A shared label does NOT
|
|
17
|
+
# pool instances — `provide()` throws on the second registration under the
|
|
18
|
+
# same realm symbol; labels join REALMS, and are not what this file needs.)
|
|
19
|
+
|
|
20
|
+
# ── identity ────────────────────────────────────────────────────────────────
|
|
21
|
+
|
|
22
|
+
# The preset's own persona, shadowing the deployment default for this agent.
|
|
23
|
+
# `{{model}}` and `{{cwd}}` resolve from the agent's own route and workspace.
|
|
24
|
+
- id: persona
|
|
25
|
+
name: '@deepseek-ai/dsh-persona'
|
|
26
|
+
config:
|
|
27
|
+
text: >-
|
|
28
|
+
You are a research-engine agent powered by the {{model}} model, running on the
|
|
29
|
+
DeepSeek Harness. Your working directory is {{cwd}}.
|
|
30
|
+
|
|
31
|
+
你在「研究引擎」preset 下工作。研究工程的物理形态:project.yaml(身份/受管区/约定)、
|
|
32
|
+
pipeline.yaml(阶段机)、templates.yaml(可执行声明)、registry.jsonl(台账)、
|
|
33
|
+
experiments/<runId>/(证据)、.kb/notes(提议与结论)、_report 与 skills/<工程>/SKILL.md(派生视图)。
|
|
34
|
+
|
|
35
|
+
铁律:工程里的任何变更都只能经工具发生。结论只能指向证据;数字只能由工具从已登记文件里提取。
|
|
36
|
+
用户权威必须来自一次真实提问与用户答复原文,不得推断、润色、代答。
|
|
37
|
+
|
|
38
|
+
开工先加载 skill: research-engine,按里面的路由表工作。默认入口:
|
|
39
|
+
project_load → project_verify → stage_read → run_query → note_query。
|
|
40
|
+
动手前先看清现状,不要凭记忆断言工程内容。
|
|
41
|
+
|
|
42
|
+
- id: agent-instructions
|
|
43
|
+
name: '@deepseek-ai/dsh-agent-instructions'
|
|
44
|
+
config:
|
|
45
|
+
maxBytes: 65536
|
|
46
|
+
|
|
47
|
+
# ── shell ───────────────────────────────────────────────────────────────────
|
|
48
|
+
|
|
49
|
+
# `shell-env` stays in the HOST composition: `apps/cli/src/web.ts` injects it to
|
|
50
|
+
# publish `DSH_WEB_URL`/`DSH_WEB_MODE`, and a host row that injects a service is
|
|
51
|
+
# the criterion for host-plane ownership — injection resolves before any session
|
|
52
|
+
# exists, so there is no agent to key by. Behind a preset realm those variables
|
|
53
|
+
# never reached the model's shell at all. Both shell tools consume the host
|
|
54
|
+
# registry from here; their executors (`bash-sandbox`/`pwsh-sandbox`) are
|
|
55
|
+
# host-plane too.
|
|
56
|
+
- id: tool-bash
|
|
57
|
+
name: '@deepseek-ai/dsh-tool-bash'
|
|
58
|
+
disabled: !!js process.platform === 'win32'
|
|
59
|
+
|
|
60
|
+
- id: tool-pwsh
|
|
61
|
+
name: '@deepseek-ai/dsh-tool-pwsh'
|
|
62
|
+
disabled: !!js process.platform !== 'win32'
|
|
63
|
+
|
|
64
|
+
# ── filesystem ──────────────────────────────────────────────────────────────
|
|
65
|
+
|
|
66
|
+
# Both register into the host `tools` registry and provide nothing, so
|
|
67
|
+
# they need no realm. The `fs` service and its policy stay in the host.
|
|
68
|
+
- id: tool-fs
|
|
69
|
+
name: '@deepseek-ai/dsh-tool-fs'
|
|
70
|
+
|
|
71
|
+
- id: tool-fs-search
|
|
72
|
+
name: '@deepseek-ai/dsh-tool-fs-search'
|
|
73
|
+
config:
|
|
74
|
+
sampleOverCapGlobResults: false
|
|
75
|
+
|
|
76
|
+
# ── background jobs ────────────────────────────────────────────────────────
|
|
77
|
+
|
|
78
|
+
# Only the model-facing controls. The task REGISTRY stays on the host plane:
|
|
79
|
+
# its producers sit outside any realm this file could put it in — `tool-bash`
|
|
80
|
+
# above resolves it with `ctx.get`, and an entry-local realm here is invisible
|
|
81
|
+
# to every sibling row, so `run_in_background` would answer "background jobs
|
|
82
|
+
# unavailable" while these controls sat in the catalog. The registry is keyed by
|
|
83
|
+
# owning agent anyway, so one host instance serves every session. What a preset
|
|
84
|
+
# chooses is whether its agent can collect and stop background work at all.
|
|
85
|
+
- id: tool-jobs
|
|
86
|
+
name: '@deepseek-ai/dsh-tool-jobs'
|
|
87
|
+
|
|
88
|
+
# ── skills ──────────────────────────────────────────────────────────────────
|
|
89
|
+
|
|
90
|
+
# The skill REGISTRY lives in the host composition and is layered per scope:
|
|
91
|
+
# these rows register into THIS preset's layer of it, so they need no realm.
|
|
92
|
+
# `skill-filesystem` contributes local-root discovery for agents on this preset, and
|
|
93
|
+
# `tool-skill` gives them the catalog and loader; the merged catalog also
|
|
94
|
+
# carries whatever the deployment registered globally (repository plugins).
|
|
95
|
+
# research-engine: customSkillDirs 指向 preset 自带的 skills/(baseUrl = 本 preset 目录)
|
|
96
|
+
# ——SKILL.md 随 preset 目录走,新会话免重启即可见。
|
|
97
|
+
- id: skill-filesystem
|
|
98
|
+
name: '@deepseek-ai/dsh-skill-filesystem'
|
|
99
|
+
config:
|
|
100
|
+
customSkillDirs:
|
|
101
|
+
- !!js "process.getBuiltinModule('node:url').fileURLToPath(new URL('skills/', baseUrl))"
|
|
102
|
+
|
|
103
|
+
- id: tool-skill
|
|
104
|
+
name: '@deepseek-ai/dsh-tool-skill'
|
|
105
|
+
|
|
106
|
+
# ── goals ───────────────────────────────────────────────────────────────────
|
|
107
|
+
|
|
108
|
+
# Only the model-facing tool. The goal SERVICE, its session driver, and the
|
|
109
|
+
# `/goal` command stay on the host plane: the Gateway serves the goal domain as
|
|
110
|
+
# Remote endpoints whose receiver comes from a generated descriptor, so it
|
|
111
|
+
# resolves `goals` on the host and an entry-local realm here would hide it. The
|
|
112
|
+
# registry is keyed by session anyway, so one host instance serves every
|
|
113
|
+
# session. What a preset chooses is whether its agent can call the goal tool.
|
|
114
|
+
- id: tool-goal
|
|
115
|
+
name: '@deepseek-ai/dsh-tool-goal'
|
|
116
|
+
|
|
117
|
+
# ── plan mode ───────────────────────────────────────────────────────────────
|
|
118
|
+
|
|
119
|
+
# Plan state is per-agent by nature, so an entry-local realm is not a
|
|
120
|
+
# workaround here — it is the correct lifetime.
|
|
121
|
+
- id: planning
|
|
122
|
+
name: cordis:group
|
|
123
|
+
group: true
|
|
124
|
+
isolate:
|
|
125
|
+
planMode: true
|
|
126
|
+
config:
|
|
127
|
+
- id: plan-mode
|
|
128
|
+
name: '@deepseek-ai/dsh-plan-mode'
|
|
129
|
+
config:
|
|
130
|
+
section: |
|
|
131
|
+
You are in plan mode. Stay in plan mode until exit_plan_mode succeeds or the user switches the session mode. Imperative language to implement changes means plan the implementation, not execute it. A user's conversational agreement — including an answer confirming something you asked — approves nothing and does not end plan mode; fold the confirmed decision into the plan and submit it through exit_plan_mode.
|
|
132
|
+
|
|
133
|
+
Explore first. Use non-mutating reads, searches, static analysis, and checks to ground the plan in the actual repository. Do not edit or write files, change configuration, run formatters or code generation that rewrites tracked files, commit, or otherwise carry out the plan. Prefer existing functions and patterns over new machinery.
|
|
134
|
+
|
|
135
|
+
The tool catalog stays the same across modes for request-cache stability. These plan-mode rules override any later tool description or guidance that suggests using mutation tools; those tools remain listed to keep the tool catalog unchanged. Do not use todo_write to track this planning phase: it tracks implementation after an approved plan, while the plan itself belongs in exit_plan_mode.
|
|
136
|
+
|
|
137
|
+
Resolve discoverable facts by inspection. Use ask_user_question only for user-owned choices or material ambiguity that inspection cannot answer. Do not ask the user where code lives or how current behavior works when you can find out.
|
|
138
|
+
|
|
139
|
+
Make the plan decision-complete: state the goal and success criteria; group implementation changes by subsystem; identify public API, schema, and data-flow changes; cover edge cases, failure modes, tests, acceptance criteria, and explicit assumptions. Keep it concise enough to review but detailed enough that another engineer can implement it without making design decisions.
|
|
140
|
+
|
|
141
|
+
When ready, call exit_plan_mode with the complete plan markdown, starting with a # title. Make exit_plan_mode the only and final tool call in that assistant response: it presents the plan for approval, and implementation begins only in a later step after approval. Do not paste the final plan as a plain reply or ask "should I proceed?" through prose or ask_user_question. If review rejects it, incorporate the feedback and present again. If the review channel is unavailable or aborted, stay in plan mode and ask the user to switch modes manually; do not proceed with implementation.
|
|
142
|
+
|
|
143
|
+
# ── compaction ──────────────────────────────────────────────────────────────
|
|
144
|
+
|
|
145
|
+
# `compaction-basic` reads `toolResultPrune` through `ctx.get`, so the pruner must
|
|
146
|
+
# share this realm rather than sit outside it.
|
|
147
|
+
#
|
|
148
|
+
# `tokenMeter` is deliberately NOT in this realm: the meter stays on the HOST
|
|
149
|
+
# plane, and the rows here resolve that one instance. It takes no configuration,
|
|
150
|
+
# keys every fold by Session, and owns the context-meter projection units the
|
|
151
|
+
# browser reads for every session — behind a realm those units would come and go
|
|
152
|
+
# with whichever presets happen to be mounted. What a preset chooses is whether
|
|
153
|
+
# its agent compacts at all, which is `compaction-basic` below.
|
|
154
|
+
- id: compaction
|
|
155
|
+
name: cordis:group
|
|
156
|
+
group: true
|
|
157
|
+
isolate:
|
|
158
|
+
compaction: true
|
|
159
|
+
toolResultPruner: true
|
|
160
|
+
config:
|
|
161
|
+
- id: compaction-basic
|
|
162
|
+
name: '@deepseek-ai/dsh-compaction-basic'
|
|
163
|
+
|
|
164
|
+
- id: command-compact
|
|
165
|
+
name: '@deepseek-ai/dsh-command-compact'
|
|
166
|
+
|
|
167
|
+
- id: tool-result-pruner
|
|
168
|
+
name: '@deepseek-ai/dsh-compaction-tool-result-pruner'
|
|
169
|
+
config:
|
|
170
|
+
thresholdChars: 8192
|
|
171
|
+
headChars: 4096
|
|
172
|
+
tailChars: 1024
|
|
173
|
+
|
|
174
|
+
# ── delegation and workflows ────────────────────────────────────────────────
|
|
175
|
+
|
|
176
|
+
# The `subagents` registry and its spawn/fork backends live in the HOST
|
|
177
|
+
# composition: the registry is a process singleton whose cross-session queries
|
|
178
|
+
# the api-proxy serves to the browser, and a provider name may only be
|
|
179
|
+
# registered once. This preset contributes the delegation TOOLS, which resolve
|
|
180
|
+
# that host registry.
|
|
181
|
+
#
|
|
182
|
+
# `workflows` is different — nothing outside an agent reads it — so every row
|
|
183
|
+
# that reaches it shares one entry-local realm here, and a consumer left
|
|
184
|
+
# outside would resolve a host registry this preset does not populate.
|
|
185
|
+
#
|
|
186
|
+
# `tool-subagent-report` is host-plane for the same reason as the registry,
|
|
187
|
+
# not because a preset may not want it: it registers a CONTINUABLE SETUP on
|
|
188
|
+
# that singleton rather than a tool this agent calls, and the setup list is
|
|
189
|
+
# not scope-aware — one copy per mounted preset means every child gets
|
|
190
|
+
# `report` registered once per live session, which throws on the second.
|
|
191
|
+
- id: delegation
|
|
192
|
+
name: cordis:group
|
|
193
|
+
group: true
|
|
194
|
+
isolate:
|
|
195
|
+
workflowEngine: true
|
|
196
|
+
config:
|
|
197
|
+
- id: tool-subagent-control
|
|
198
|
+
name: '@deepseek-ai/dsh-tool-subagent-control'
|
|
199
|
+
|
|
200
|
+
- id: tool-subagent-list-agents
|
|
201
|
+
name: '@deepseek-ai/dsh-tool-subagent-control/list-agents'
|
|
202
|
+
|
|
203
|
+
- id: tool-subagent
|
|
204
|
+
name: '@deepseek-ai/dsh-tool-subagent'
|
|
205
|
+
config:
|
|
206
|
+
provider: spawn
|
|
207
|
+
toolName: subagent
|
|
208
|
+
backgroundMode: continuable
|
|
209
|
+
|
|
210
|
+
- id: tool-subagent-fork
|
|
211
|
+
name: '@deepseek-ai/dsh-tool-subagent'
|
|
212
|
+
config:
|
|
213
|
+
provider: fork
|
|
214
|
+
toolName: subagent_fork
|
|
215
|
+
backgroundMode: continuable
|
|
216
|
+
|
|
217
|
+
# Production dsh does not install these optional providers. Install the
|
|
218
|
+
# matching Bundle in this Profile and restart the Host, then copy this
|
|
219
|
+
# preset and remove `disabled` from the matching tool row. Host availability
|
|
220
|
+
# alone grants no tool.
|
|
221
|
+
- id: tool-subagent-codex
|
|
222
|
+
name: '@deepseek-ai/dsh-tool-subagent'
|
|
223
|
+
disabled: true
|
|
224
|
+
config:
|
|
225
|
+
provider: codex
|
|
226
|
+
toolName: subagent_codex
|
|
227
|
+
backgroundMode: one-shot
|
|
228
|
+
maxDepth: provider-managed
|
|
229
|
+
|
|
230
|
+
- id: tool-subagent-claude-code
|
|
231
|
+
name: '@deepseek-ai/dsh-tool-subagent'
|
|
232
|
+
disabled: true
|
|
233
|
+
config:
|
|
234
|
+
provider: claude-code
|
|
235
|
+
toolName: subagent_claude_code
|
|
236
|
+
backgroundMode: one-shot
|
|
237
|
+
maxDepth: provider-managed
|
|
238
|
+
|
|
239
|
+
- id: workflow-worker-thread
|
|
240
|
+
name: '@deepseek-ai/dsh-workflow-worker-thread'
|
|
241
|
+
config:
|
|
242
|
+
provider: spawn
|
|
243
|
+
|
|
244
|
+
- id: tool-workflow
|
|
245
|
+
name: '@deepseek-ai/dsh-tool-workflow'
|
|
246
|
+
|
|
247
|
+
- id: tool-ralph
|
|
248
|
+
name: '@deepseek-ai/dsh-tool-ralph'
|
|
249
|
+
config:
|
|
250
|
+
subagentProvider: spawn
|
|
251
|
+
maxRounds: 64
|
|
252
|
+
|
|
253
|
+
# ── remaining model-facing rows ─────────────────────────────────────────────
|
|
254
|
+
|
|
255
|
+
- id: tool-ask-user
|
|
256
|
+
name: '@deepseek-ai/dsh-tool-ask-user'
|
|
257
|
+
|
|
258
|
+
- id: tool-todo
|
|
259
|
+
name: '@deepseek-ai/dsh-tool-todo'
|
|
260
|
+
config:
|
|
261
|
+
allowParallelInProgress: true
|
|
262
|
+
|
|
263
|
+
# The `web` service and its search provider stay in the host composition; only
|
|
264
|
+
# the model-facing tool is per-session.
|
|
265
|
+
- id: tool-web
|
|
266
|
+
name: '@deepseek-ai/dsh-tool-web'
|
|
267
|
+
config:
|
|
268
|
+
fetch: false
|
|
269
|
+
searchTimeoutMs: 60000
|
|
270
|
+
|
|
271
|
+
# ── research-engine:内建版本库 + 四插件(同一 group,共享一个 entry-local isolate realm)──
|
|
272
|
+
#
|
|
273
|
+
# 行 name 用相对路径(从 preset 自身目录解析)——插件随 preset 目录走,免安装、免重启。
|
|
274
|
+
# 插件源码只用 node:* 内建 + createRequire 锚定 $DSH_HOME/profiles/node_modules(取 js-yaml/ajv),
|
|
275
|
+
# 不 import 兄弟插件文件;跨域调用只走 ctx.get('research.*') 服务。
|
|
276
|
+
#
|
|
277
|
+
# 行名带 `?v=N` 缓存版本:loader 以 `import(new URL(name, baseUrl))` 加载本地文件,Node 按 URL
|
|
278
|
+
# 缓存 ESM 模块——同进程内改写插件后只有 URL 变化才会重新求值。改插件内容时递增 v。
|
|
279
|
+
#
|
|
280
|
+
# isolate 的键 = 本组 provide 的服务名:五个 research.* 服务 → entry-local realm,
|
|
281
|
+
# 绝不漏出 realm(漏出 = 挂载被拒 published process-global service(s))。
|
|
282
|
+
- id: research-engine
|
|
283
|
+
name: cordis:group
|
|
284
|
+
group: true
|
|
285
|
+
isolate:
|
|
286
|
+
research.engineGit: true
|
|
287
|
+
research.expLedger: true
|
|
288
|
+
research.stageCtrl: true
|
|
289
|
+
research.taskDispatch: true
|
|
290
|
+
research.kbCore: true
|
|
291
|
+
config:
|
|
292
|
+
- id: engine-git
|
|
293
|
+
name: './plugins/engine-git/main.js?v=8'
|
|
294
|
+
|
|
295
|
+
- id: exp-ledger
|
|
296
|
+
name: './plugins/exp-ledger/main.js?v=8'
|
|
297
|
+
|
|
298
|
+
- id: stage-ctrl
|
|
299
|
+
name: './plugins/stage-ctrl/main.js?v=8'
|
|
300
|
+
|
|
301
|
+
- id: task-dispatch
|
|
302
|
+
name: './plugins/task-dispatch/main.js?v=8'
|
|
303
|
+
|
|
304
|
+
- id: kb-core
|
|
305
|
+
name: './plugins/kb-core/main.js?v=8'
|