dsh-root-planner-preset 1.0.3 → 1.0.4
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/README.md +27 -14
- package/README.zh.md +16 -8
- package/child-tools.mjs +17 -11
- package/cordis.patch.yml +8 -7
- package/package.json +1 -1
- package/persona.txt +8 -7
package/README.md
CHANGED
|
@@ -18,26 +18,39 @@ This preset turns both of those into structural constraints rather than good int
|
|
|
18
18
|
|---|---|---|
|
|
19
19
|
| Subagents **cannot** create, modify or delete files | A `toolFilter.allow` list on both delegation tools, without `write`, `edit`, `ops_replace` | **Structural**: an absent tool cannot be called |
|
|
20
20
|
| Subagents **have no shell** to work around it | The same list, without `ops_bash`, `pwsh` | **Structural** |
|
|
21
|
-
|
|
|
21
|
+
| Delegation depth is bounded by configuration | The runtime depth cap (`subagent.maxDepth`, a Host setting) | **Structural**: past the cap it throws `SubagentDepthError` |
|
|
22
22
|
| The root agent owns every mutation | Persona rules (the mask applies to children only) | Prompt-level |
|
|
23
|
-
|
|
|
23
|
+
| A heavy task is decomposed rather than ground through | Persona rule 2 | Prompt-level |
|
|
24
24
|
|
|
25
|
-
The mask is an **allow** list, not a deny list: a tool added by a future plugin is invisible to subagents until it is added here
|
|
25
|
+
The mask is an **allow** list, not a deny list: a tool added by a future plugin is invisible to subagents until it is added here — **with one exception, and it is what makes recursion work.**
|
|
26
26
|
|
|
27
27
|
## How it works
|
|
28
28
|
|
|
29
29
|
```
|
|
30
|
-
root agent
|
|
31
|
-
|
|
30
|
+
root agent ──delegates──▶ subagent ──delegates──▶ … until maxDepth
|
|
31
|
+
│ │
|
|
32
|
+
└── the only one with write / edit / shell; every level stays read-only
|
|
32
33
|
```
|
|
33
34
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
35
|
+
Two mechanisms decide how deep the tree goes, and they pull in the same direction:
|
|
36
|
+
|
|
37
|
+
- **The mask** strips every mutation entry point from *every* subagent, at *every*
|
|
38
|
+
level — the guarantee does not weaken with depth.
|
|
39
|
+
- **The depth cap** (`subagent.maxDepth`, a Host setting you control) decides how
|
|
40
|
+
many levels exist. `2` means root → child → grandchild; raise it and the tree
|
|
41
|
+
deepens, set it to `1` and children become leaves.
|
|
42
|
+
|
|
43
|
+
A `toolFilter` is a mask of **global** tools, and `subagent` is not one: with
|
|
44
|
+
`modelSelectionSettings: true` it is mounted inside each composed Agent's own
|
|
45
|
+
scope, so a mask can never name it. That is why it is absent from
|
|
46
|
+
`child-tools.mjs` — **not** because children lack it. Scoped registrations stay
|
|
47
|
+
visible through a restriction, and every child inherits this preset, so each level
|
|
48
|
+
gets its own `subagent` and can delegate onward until the depth cap stops it.
|
|
49
|
+
|
|
50
|
+
An earlier version of this bundle did list `subagent` in the mask, and **every
|
|
51
|
+
subagent creation failed** with
|
|
52
|
+
`tools.restrict() names unknown global tool "subagent"` — the mask rejecting a
|
|
53
|
+
name it could never legally contain, not the tool being missing.
|
|
41
54
|
|
|
42
55
|
- **Root agent**: plans first (goal, success criteria, constraints, ordered task list), delegates reading, searching and locating by default, and reads directly only for one known file, a short targeted range, or to check a claim a subagent made.
|
|
43
56
|
- **Subagent**: reads, locates and summarizes. On finding that a file **needs changing** it does not act; it reports the exact change — target path, location (`file:line`), current content, proposed replacement, and why.
|
|
@@ -89,9 +102,9 @@ Then **start a new session** and pick **Root Planner** in the preset selector. F
|
|
|
89
102
|
|
|
90
103
|
**Verified**: the patch parses as loader YAML; the parsed persona is **byte-identical** to `persona.txt`; both delegation masks exclude every mutation entry point and name only tools the runtime reports as global; a clean checkout passes verification (`.gitattributes` pins LF, without which a Windows clone breaks the byte-identity check); the depth override reached the composed profile.
|
|
91
104
|
|
|
92
|
-
**Fixed after a real failure**: a subagent spawn on a live `root-planner` session failed with `tools.restrict() names unknown global tool "subagent"`. The cause was a design error in this bundle, not a misconfiguration — `subagent` is registered inside each composed Agent's own scope, and a `toolFilter` takes global names only. The mask no longer names it, `verify-patch.mjs`
|
|
105
|
+
**Fixed after a real failure**: a subagent spawn on a live `root-planner` session failed with `tools.restrict() names unknown global tool "subagent"`. The cause was a design error in this bundle, not a misconfiguration — `subagent` is registered inside each composed Agent's own scope, and a `toolFilter` takes global names only, so the mask was naming something it could never contain. The mask no longer names it, `verify-patch.mjs` asserts its absence by intent, and the mask is defined once in `child-tools.mjs` so the generator and the verifier cannot drift apart.
|
|
93
106
|
|
|
94
|
-
**Still not verified**: no subagent has been spawned successfully under this preset yet
|
|
107
|
+
**Still not verified**: **no subagent has been spawned successfully under this preset yet.** Recursion is expected to work for the reason given above — the child inherits the preset and therefore its own scoped `subagent`, and a restriction does not hide scoped registrations — but that reasoning is exactly the kind that this bundle has already been wrong about once. Treat it as unconfirmed until someone reports a two-level delegation working.
|
|
95
108
|
|
|
96
109
|
## Contributing
|
|
97
110
|
|
package/README.zh.md
CHANGED
|
@@ -18,20 +18,28 @@
|
|
|
18
18
|
|---|---|---|
|
|
19
19
|
| 子代理**不能**创建/修改/删除文件 | 两个委派工具上的 `toolFilter.allow` 白名单,不含 `write`、`edit`、`ops_replace` | **结构性**:工具不存在,调不到 |
|
|
20
20
|
| 子代理**没有** shell 可绕过 | 同一白名单,不含 `ops_bash`、`pwsh` | **结构性** |
|
|
21
|
-
|
|
|
21
|
+
| 委派层数由配置决定 | 运行时深度上限(`subagent.maxDepth`,Host 设置) | **结构性**:超过上限直接抛 `SubagentDepthError` |
|
|
22
22
|
| 根 agent 独揽所有修改 | 人设规则(白名单只作用于子级) | 提示词级 |
|
|
23
|
-
|
|
|
23
|
+
| 任务过重时拆分下发而非硬扛 | 人设规则 2 | 提示词级 |
|
|
24
24
|
|
|
25
|
-
白名单是 **allow 而非 deny
|
|
25
|
+
白名单是 **allow 而非 deny**:将来某个插件新增的工具,对子代理默认不可见——**但有一个例外,而正是它让递归得以成立**。
|
|
26
26
|
|
|
27
27
|
## 工作方式
|
|
28
28
|
|
|
29
29
|
```
|
|
30
|
-
根 agent
|
|
31
|
-
|
|
30
|
+
根 agent ──委派──▶ 子代理 ──委派──▶ … 直到 maxDepth
|
|
31
|
+
│ │
|
|
32
|
+
└── 只有它有 write / edit / shell;每一层都保持只读
|
|
32
33
|
```
|
|
33
34
|
|
|
34
|
-
|
|
35
|
+
有两个机制决定树有多深,方向一致:
|
|
36
|
+
|
|
37
|
+
- **白名单**剥掉**每一层**、**每一个**子代理的所有写入入口——这个保证不随深度衰减。
|
|
38
|
+
- **深度上限**(`subagent.maxDepth`,由你控制的 Host 设置)决定有几层。`2` 就是根 → 子 → 孙;调大则更深,设成 `1` 则子代理变叶子。
|
|
39
|
+
|
|
40
|
+
`toolFilter` 是**全局**工具的掩码,而 `subagent` 不是全局工具:因为 `modelSelectionSettings: true`,它被注册进每个被组合 Agent **自身的作用域**,掩码永远写不上它的名字。所以它不在 `child-tools.mjs` 里——**不是**因为子代理没有它。作用域注册**不受限制影响**,而每个子代理都继承本预设,于是每一层都拿到自己的 `subagent`,可以一直往下派到深度上限为止。
|
|
41
|
+
|
|
42
|
+
本包早期版本确实把 `subagent` 写进了白名单,结果是**每一次子代理创建都失败**,报 `tools.restrict() names unknown global tool "subagent"`——那是白名单在拒绝一个它永远不可能合法包含的名字,不是工具缺失。
|
|
35
43
|
|
|
36
44
|
- **根 agent**:先立计划(目标、成功判据、约束、任务清单),把阅读/搜索/定位默认派出去,自己只在「单个已知文件、一小段范围、或核实子代理的某个断言」时才亲自读。
|
|
37
45
|
- **子代理**:只读、只定位、只总结。发现**需要改文件**时不动手,而是回报精确的改动方案——目标路径、位置(file:line)、当前内容、建议替换、理由。
|
|
@@ -83,9 +91,9 @@ dsh plugin --profile web add github:XiaoOu2024/dsh-root-planner-preset
|
|
|
83
91
|
|
|
84
92
|
**已验证**:补丁可被 loader 解析;解析出的人设与 `persona.txt` **逐字节相同**;两个委派工具的白名单排除了所有写入入口、且只包含**运行时报告的全局工具**;干净检出后校验通过(`.gitattributes` 已钉死 LF,否则 Windows 克隆会破坏逐字节校验);深度覆盖已落到合成配置。
|
|
85
93
|
|
|
86
|
-
**因一次真实故障而修复**:在跑着 `root-planner` 的会话里创建子代理失败,报 `tools.restrict() names unknown global tool "subagent"`。根因是本包**设计上的错误**,不是配置错误——`subagent` 注册在每个被组合 Agent 自身的作用域里,而 `toolFilter`
|
|
94
|
+
**因一次真实故障而修复**:在跑着 `root-planner` 的会话里创建子代理失败,报 `tools.restrict() names unknown global tool "subagent"`。根因是本包**设计上的错误**,不是配置错误——`subagent` 注册在每个被组合 Agent 自身的作用域里,而 `toolFilter` 只接受全局工具名,白名单写了一个它永远不可能合法包含的名字。现在白名单不再写它,`verify-patch.mjs` 会**按意图断言它必须缺席**,白名单也收敛到 `child-tools.mjs` 单一真源,生成器与校验脚本不可能再各说各话。
|
|
87
95
|
|
|
88
|
-
|
|
96
|
+
**仍未验证**:**还没有一次成功的子代理派出。** 递归按上面的理由**应当**可用——子代理继承预设、因此拥有自己的作用域 `subagent`,而限制不会隐藏作用域注册——但这个推理恰好就是本包已经错过一次的那类推理。在有人报告"两层委派成功"之前,请当作未确认。
|
|
89
97
|
|
|
90
98
|
## 参与维护
|
|
91
99
|
|
package/child-tools.mjs
CHANGED
|
@@ -5,19 +5,25 @@
|
|
|
5
5
|
* These are the only GLOBAL tools a subagent may call. Everything absent is
|
|
6
6
|
* invisible to the child, including every mutation entry point.
|
|
7
7
|
*
|
|
8
|
-
* `subagent` is deliberately NOT here, and cannot be
|
|
9
|
-
*
|
|
10
|
-
* composed Agent's own scope (`dsh-tool-subagent` mounts it through
|
|
11
|
-
* `installScoped`), and `tools.restrict()` takes a mask of *global* tools only —
|
|
12
|
-
* it throws on a scope-local name exactly as it throws on an unknown one:
|
|
8
|
+
* `subagent` is deliberately NOT here, and cannot be — but that does NOT mean a
|
|
9
|
+
* subagent lacks it. Two separate facts:
|
|
13
10
|
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
11
|
+
* 1. With `modelSelectionSettings: true` the tool is mounted inside each composed
|
|
12
|
+
* Agent's own scope (`dsh-tool-subagent` registers it through
|
|
13
|
+
* `installScoped`), and `tools.restrict()` takes a mask of *global* tools
|
|
14
|
+
* only. It throws on a scope-local name exactly as it throws on an unknown
|
|
15
|
+
* one, which is how this bundle broke: every subagent creation failed with
|
|
16
|
+
* `tools.restrict() names unknown global tool "subagent"`.
|
|
17
|
+
* 2. Restrictions only filter globals — "scoped registrations remain visible".
|
|
18
|
+
* A child inherits this preset, so it gets its own scoped `subagent` and can
|
|
19
|
+
* delegate onward until the runtime depth cap stops it.
|
|
16
20
|
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
+
* So the mask is not what makes a child a leaf; `subagent.maxDepth` is. Listing
|
|
22
|
+
* `subagent` here rejected a name the mask can never legally contain. Do not add
|
|
23
|
+
* it back; `verify-patch.mjs` asserts its absence on purpose.
|
|
24
|
+
*
|
|
25
|
+
* `subagent_fork` IS registered in the preset's own scope and is observable as a
|
|
26
|
+
* global, so it stays in the list.
|
|
21
27
|
*/
|
|
22
28
|
export const CHILD_TOOLS = [
|
|
23
29
|
'read',
|
package/cordis.patch.yml
CHANGED
|
@@ -42,13 +42,14 @@
|
|
|
42
42
|
## Root agent rules
|
|
43
43
|
|
|
44
44
|
1. Plan first. Establish the goal, success criteria, constraints, and an ordered task list before changing anything. Revise the plan when evidence contradicts it.
|
|
45
|
-
2.
|
|
46
|
-
3.
|
|
47
|
-
4.
|
|
48
|
-
5.
|
|
49
|
-
6.
|
|
50
|
-
7.
|
|
51
|
-
8.
|
|
45
|
+
2. When a task feels too heavy, decompose it — do not grind through it serially. Weight is a signal, not a reason to push harder: split the work into independent subtasks and dispatch them, in parallel where they are independent, rather than reading everything yourself in sequence. A task that exceeds a few reads, or that has clearly separable parts, should already have been split. Delegation depth is the environment's business, not yours: delegate until the runtime refuses, then read what remains yourself.
|
|
46
|
+
3. Delegate research by default. The `subagent` tool (fresh child) and the `subagent_fork` tool (child seeded with this conversation) are the normal way to read, search, list, trace, or look something up — not a last resort. Delegate whenever locating an answer would take more than a couple of reads, whenever it spans several files, and whenever you notice you are only "looking around".
|
|
47
|
+
4. Keep delegations independent and concurrent. State every self-contained subtask in one message so they run together, then continue planning while they run. Wait only when your next action needs a specific result.
|
|
48
|
+
5. Read directly only when it is genuinely cheap: one known file, a short targeted range, or checking a specific claim a subagent made. Never bulk-browse a tree, never read a large file "to get oriented", and never re-read what a subagent already summarized.
|
|
49
|
+
6. Ask for the summary shape you need. Tell the subagent which decision its finding must support, what to report (conclusion, evidence with file and line, uncertainty), and what to omit (raw dumps, unrelated context).
|
|
50
|
+
7. You own every mutation. Creating, modifying, and deleting files is yours, driven by your own plan and your own reading of the relevant code. Never delegate it and never infer it from a summary alone.
|
|
51
|
+
8. Treat a summary as evidence, not a verdict. Weigh it against the plan, spot-check claims that are contested or load-bearing, and send back a summary that dodges the question, hedges without evidence, or pads with prose.
|
|
52
|
+
9. Answer a subagent that reports a needed file change. Decide it, then reply with `send_message` so the child can continue: either the change is approved and you are making it, or it is out of scope and why, or what to do instead. An unanswered proposal leaves the child blocked on a decision only you can make.
|
|
52
53
|
|
|
53
54
|
## Subagent rules
|
|
54
55
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-root-planner-preset",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.4",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "DSH agent preset that outsources file reading to strictly read-only subagents, while the root agent keeps the plan and owns every file mutation.",
|
|
6
6
|
"license": "MIT",
|
package/persona.txt
CHANGED
|
@@ -21,13 +21,14 @@ Reading is not planning. Raw file contents and raw query results belong in the a
|
|
|
21
21
|
## Root agent rules
|
|
22
22
|
|
|
23
23
|
1. Plan first. Establish the goal, success criteria, constraints, and an ordered task list before changing anything. Revise the plan when evidence contradicts it.
|
|
24
|
-
2.
|
|
25
|
-
3.
|
|
26
|
-
4.
|
|
27
|
-
5.
|
|
28
|
-
6.
|
|
29
|
-
7.
|
|
30
|
-
8.
|
|
24
|
+
2. When a task feels too heavy, decompose it — do not grind through it serially. Weight is a signal, not a reason to push harder: split the work into independent subtasks and dispatch them, in parallel where they are independent, rather than reading everything yourself in sequence. A task that exceeds a few reads, or that has clearly separable parts, should already have been split. Delegation depth is the environment's business, not yours: delegate until the runtime refuses, then read what remains yourself.
|
|
25
|
+
3. Delegate research by default. The `subagent` tool (fresh child) and the `subagent_fork` tool (child seeded with this conversation) are the normal way to read, search, list, trace, or look something up — not a last resort. Delegate whenever locating an answer would take more than a couple of reads, whenever it spans several files, and whenever you notice you are only "looking around".
|
|
26
|
+
4. Keep delegations independent and concurrent. State every self-contained subtask in one message so they run together, then continue planning while they run. Wait only when your next action needs a specific result.
|
|
27
|
+
5. Read directly only when it is genuinely cheap: one known file, a short targeted range, or checking a specific claim a subagent made. Never bulk-browse a tree, never read a large file "to get oriented", and never re-read what a subagent already summarized.
|
|
28
|
+
6. Ask for the summary shape you need. Tell the subagent which decision its finding must support, what to report (conclusion, evidence with file and line, uncertainty), and what to omit (raw dumps, unrelated context).
|
|
29
|
+
7. You own every mutation. Creating, modifying, and deleting files is yours, driven by your own plan and your own reading of the relevant code. Never delegate it and never infer it from a summary alone.
|
|
30
|
+
8. Treat a summary as evidence, not a verdict. Weigh it against the plan, spot-check claims that are contested or load-bearing, and send back a summary that dodges the question, hedges without evidence, or pads with prose.
|
|
31
|
+
9. Answer a subagent that reports a needed file change. Decide it, then reply with `send_message` so the child can continue: either the change is approved and you are making it, or it is out of scope and why, or what to do instead. An unanswered proposal leaves the child blocked on a decision only you can make.
|
|
31
32
|
|
|
32
33
|
## Subagent rules
|
|
33
34
|
|