dsh-paoding 0.2.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/LICENSE +21 -0
- package/README.md +95 -0
- package/README_en.md +95 -0
- package/bin/dsh-paoding.mjs +12 -0
- package/cordis.patch.yml +6 -0
- package/docs/architecture.md +292 -0
- package/docs/architecture_en.md +363 -0
- package/docs/configuration.md +551 -0
- package/docs/configuration_en.md +560 -0
- package/docs/images/1.png +0 -0
- package/docs/images/2.png +0 -0
- package/docs/images/3.png +0 -0
- package/docs/images/4.png +0 -0
- package/docs/images/5.png +0 -0
- package/docs/images/6.png +0 -0
- package/docs/installation.md +364 -0
- package/docs/installation_en.md +367 -0
- package/docs/orchestration.md +254 -0
- package/docs/orchestration_en.md +255 -0
- package/install.sh +31 -0
- package/package.json +29 -0
- package/plugins/paoding-config-ui/api-core.mjs +100 -0
- package/plugins/paoding-config-ui/index.mjs +327 -0
- package/plugins/paoding-config-ui/lib/base.css +615 -0
- package/plugins/paoding-config-ui/lib/client.js +1154 -0
- package/plugins/paoding-config-ui/package.json +23 -0
- package/plugins/paoding-config-ui/runtime-inventory.mjs +212 -0
- package/presets/orchestrator/agent.cordis.yml +323 -0
- package/presets/orchestrator/preset.yml +6 -0
- package/presets/orchestrator/restrict.mjs +191 -0
- package/tools/install.mjs +24 -0
- package/tools/lib/alloc.mjs +138 -0
- package/tools/lib/cli.mjs +522 -0
- package/tools/lib/compose.mjs +647 -0
- package/tools/lib/config.mjs +297 -0
- package/tools/lib/host.mjs +288 -0
- package/tools/lib/skills.mjs +146 -0
- package/tools/lib/spans.mjs +188 -0
- package/tools/lib/state.mjs +328 -0
- package/tools/lib/util.mjs +26 -0
- package/tools/lib/wizard.mjs +516 -0
- package/tools/lib/yaml.mjs +266 -0
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
← [dsh-paoding](../README.md) | [架构](architecture.md) | [安装](installation.md) | **编排** | [配置](configuration.md)
|
|
2
|
+
[中文](orchestration.md) · [English](orchestration_en.md)
|
|
3
|
+
|
|
4
|
+
# 编排
|
|
5
|
+
|
|
6
|
+
编排行为是 dsh-paoding 的核心:主 agent 拆解任务、沿任务纹理委派、集成结果;子 agent 按角色只带必要工具、跑完即弃。本文面向想了解或调优这些行为的用户:失败如何被发现与恢复、one-shot 与多轮迭代(continuable)的取舍、以及可选的 `implement_cont` 增强如何启用。与源码冲突处一律以源码为准;本文所有配置引用均取自 `presets/orchestrator/agent.cordis.yml` 与 `presets/orchestrator/restrict.mjs`。
|
|
7
|
+
|
|
8
|
+
## 编排总览
|
|
9
|
+
|
|
10
|
+
dsh-paoding 把 DSH 从「单体 agent 全量加载工具」改造成「主 agent 编排 + 角色子 agent 分工」。分工遵循任务纹理:
|
|
11
|
+
|
|
12
|
+
- **热路径——内部文件问题不委派。** 找代码、查引用、读文件这类问题由主 agent 自己用只读工具解决:`glob` / `grep` / `read` / `read_image` / `bash` 全部在主 agent 白名单内,零委派往返延迟。persona 文案里的 `codegraph` 是 host MCP 工具,仅在安装期检测到 codegraph 服务器并经 `main_agent_extra` 注入后才真正可用(详见[配置](configuration.md)与[安装](installation.md))。
|
|
13
|
+
- **冷路径——只干自己那活的角色子 agent。** 外部调研委派 `search_external`(只带 `web_search` + tavily 五工具 + 本地只读)、UI/前端设计委派 `design`(读参考 + 设计技能 + 出 spec,不写最终代码)、代码实现委派 `implement`(读上下文 → 精准修改 → 验证)、超大仓库全量探索委派 `search_internal_deep`(第四角色,2026-09 加入,见下节与[架构](architecture.md))。每个子 agent 只在真正被委派的那一次才加载工具面(按需加载)。
|
|
14
|
+
- **运行中指挥。** 子 agent 运行期间,主 agent 可用 `send_message` 追加指示、`list_agents` 查看状态、`interrupt_agent` 叫停(三者由 `dsh-tool-subagent-control` 注册,属「子 agent 管理」工具面)。
|
|
15
|
+
- **完成后只集成摘要。** 主 agent 从不把子 agent 的完整上下文倒进自己的上下文——它只收一份摘要(见第 5 节「上下文隔离」)。
|
|
16
|
+
|
|
17
|
+
主 agent 的模型可见工具面由 `restrict.mjs` 在 `system-prompt/assemble` 瀑布上按白名单裁剪(失败自动放行全量,不会锁死会话;空 allow 拒绝加载)。delegation 组里另有通用委派行 `subagent` / `subagent_fork`(均为 `backgroundMode: continuable`)、`workflow`、`ralph`——这些是组合内的注册行,主 agent 白名单刻意不向其暴露,模型可见的委派面只有四个角色工具与子 agent 管理工具(默认四个角色;其中 `search_external` / `design` / `implement` 三个可经 `roles_remove` 整条删除,删后委派面相应缩小,见[配置](configuration.md) 2.3)。
|
|
18
|
+
|
|
19
|
+
| 面 | 白名单内容(`MAIN_AGENT_ALLOW`,21 项常量;运行时另可经 `config.allow` 覆盖) |
|
|
20
|
+
|---|---|
|
|
21
|
+
| 角色委派 | `search_external` / `design` / `implement` / `search_internal_deep` |
|
|
22
|
+
| 子 agent 管理 | `send_message` / `list_agents` / `interrupt_agent` |
|
|
23
|
+
| 内部搜索(热路径) | `glob` / `grep` / `read` / `read_image` / `bash` |
|
|
24
|
+
| 协调 | `todo_write` / `ask_user_question` / `get_goal` / `create_goal` / `update_goal` / `exit_plan_mode` / `job_output` / `job_list` / `job_kill` |
|
|
25
|
+
| 主 agent 刻意看不到 | `web_search`、`mcp__tavily__*`、`write` / `edit`、`skill`、`workflow`、`ralph`、裸 `subagent` / `subagent_fork` |
|
|
26
|
+
|
|
27
|
+
每请求工具开销(估算,随注册面浮动):主 agent 全量 ~16.2k tokens → 白名单后 ~5.5k;`search_external` ~3.0k / `design` ~3.2k / `implement` ~3.7k,仅在真正委派时发生(数值来源:`agent.cordis.yml` 头部注释)。
|
|
28
|
+
|
|
29
|
+
### 主 agent persona(编排人设)原文摘录
|
|
30
|
+
|
|
31
|
+
来自 `presets/orchestrator/agent.cordis.yml` 的 `- id: persona` 行(YAML `text: |-` 块标量,内容行缩进 6 空格)。编排与委派的总指引(persona 原文为英文,照录如下):
|
|
32
|
+
|
|
33
|
+
```text
|
|
34
|
+
You are the orchestrator agent powered by the {{model}} model. Your working directory is {{cwd}}.
|
|
35
|
+
|
|
36
|
+
Decompose the task, delegate to role agents, integrate results.
|
|
37
|
+
- Internal file questions (finding code, references, reading files): solve yourself with glob/grep/read/codegraph — never delegate them.
|
|
38
|
+
- External research: delegate to search_external.
|
|
39
|
+
- UI/design work: delegate to design.
|
|
40
|
+
- Code implementation: delegate to implement.
|
|
41
|
+
Keep your own context lean; integrate only summaries. Use todo_write to plan, and ask_user_question only for user-owned choices.
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
中文释意:
|
|
45
|
+
|
|
46
|
+
- 主 agent 是编排者:**拆解 → 委派 → 集成**三步循环,而不是自己把活全干完。
|
|
47
|
+
- 「内部文件问题(找代码、查引用、读文件)自己用 glob/grep/read/codegraph 解决,**绝不委派**」——内部搜索是热路径,委派有往返与冷启动成本,主 agent 自带全套只读工具,直达即可。(注:`codegraph` 属 host MCP 工具,需运行时注入白名单才可用,见上。)
|
|
48
|
+
- 任务纹理决定去向:联网 → `search_external`;UI/设计 → `design`;代码 → `implement`(全仓探索 → `search_internal_deep`)。
|
|
49
|
+
- **保持自己上下文精简**:只集成摘要;用 `todo_write` 规划;`ask_user_question` 只用于用户拥有的选择,可自查的问题不打扰用户。
|
|
50
|
+
- 失败处理 SOP 内联在 persona 里,随会话天然生效、无需额外配置——见下节。
|
|
51
|
+
|
|
52
|
+
## 子 agent 失败处理
|
|
53
|
+
|
|
54
|
+
DSH 没有原生自动重试——恢复是编排层的职责,具体地说就是主 agent。本 preset 围绕委派失败设计了三层防护:**预防 → 检测 → 恢复**。
|
|
55
|
+
|
|
56
|
+
### 失败如何呈现
|
|
57
|
+
|
|
58
|
+
委派运行的失败在运行时有两种呈现(persona SOP 原文见下文「第 3 层:恢复」):前台调用抛出的工具错误,或失败的 background job。两者都携带子 agent 的**部分输出**和一个**停止原因**:`error` / `max-tokens` / `refusal` / `aborted` / `completed-but-poor`。恢复动作以停止原因为分诊依据,而非盲目重试。
|
|
59
|
+
|
|
60
|
+
### 第 1 层:预防
|
|
61
|
+
|
|
62
|
+
子 agent 创建时,DSH 会对 `toolFilter.allow` 做 `tools.restrict()` 校验:allow 里的每个名字必须存在于子 agent 可见注册面(= 本组合注册全量 + host 层 MCP/插件工具)内,否则**创建被拒**(`tools.restrict() ... unknown tools`)。
|
|
63
|
+
|
|
64
|
+
本 preset 在安装期消除这类失败:`./install.sh`(tools/install.mjs)读取 host patch 层(home / profile / `--patch`),检测实际启用的 MCP 服务器与本地工具插件,解析出精确工具名(静态已知表优先,未知服务器走实时 JSON-RPC 握手),然后把各角色 allow 重写为「静态意图 ∩ 实际检测到的工具」——组合保证的基础工具原样保留,未启用/无法解析的 host 工具被剔除。握手失败或 transport 不支持的 MCP 会被跳过:对应角色只是缺这些工具,安装不报错。宿主停用/启用了 MCP 或插件后,重跑一次 `./install.sh --auto` 即可同步 allow(`--dry-run` 先预览)。细节见[安装](installation.md)。
|
|
65
|
+
|
|
66
|
+
注意:安装器的 allow 重写只覆盖三个内置角色(`search_external` / `design` / `implement`,`tools/install.mjs` 的 `ROLES` 常量)。手写新增的 `delegation-*` 块(例如第 4 节的 `implement_cont`)**原样生效、不会被自动清洗**——其中的 host 依赖工具名必须自己与宿主实际启用的插件保持同步,否则创建被拒。这正是 2026-09-02 起各角色 allow 剔除 `memory_search` / `mcp__codegraph__codegraph_explore` 的原因(插件停用时这些名字不在注册面;重开插件时按需加回,见 `agent.cordis.yml` 中 `delegation-search-internal-deep` 的注释)。
|
|
67
|
+
|
|
68
|
+
### 第 2 层:检测
|
|
69
|
+
|
|
70
|
+
四个角色(`search_external` / `design` / `implement` / `search_internal_deep`——失败汇报协议适用于**全部**角色,第四角色 2026-09 加入)的 persona 内置同一段**失败汇报协议**(四个实例逐字相同,原文为英文,照录如下;此为默认全员——前三个角色可经 `roles_remove` 整条删除,删掉的角色不再携带该协议,`search_internal_deep` 删不掉,见[配置](configuration.md) 2.3):
|
|
71
|
+
|
|
72
|
+
```text
|
|
73
|
+
On tool failure, do not retry a denied operation: report the failure compactly — what you completed, the exact error, which tool/permission you lack, and your suggested next step — so the orchestrator can re-delegate or adjust.
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
即:工具失败时子 agent 报告四件事——① 已完成部分;② 确切错误;③ 缺什么工具或权限;④ 建议的下一步。它遵守 DSH 规则:**被拒操作不重试、只上报**。子 agent 自己不是恢复者,它只把诊断喂回给编排者,由主 agent 决定重委派或调整。
|
|
77
|
+
|
|
78
|
+
### 第 3 层:恢复
|
|
79
|
+
|
|
80
|
+
主 agent persona 内置**委派失败处理 SOP**(英文原文,为 `agent.cordis.yml` persona 全文的第三段,照录如下):
|
|
81
|
+
|
|
82
|
+
```text
|
|
83
|
+
Delegation failure handling (SOP):
|
|
84
|
+
- A delegated run reports failure either as a thrown tool error (foreground)
|
|
85
|
+
or as a failed background job; both carry the child's partial output and
|
|
86
|
+
a stop reason (error / max-tokens / refusal / aborted / completed-but-poor).
|
|
87
|
+
- Diagnose by stop reason, never retry blindly:
|
|
88
|
+
· error (runtime/tool-level) → re-delegate ONCE as a fresh task (not a continuation);
|
|
89
|
+
if the failure cites a missing tool or permission, pick a different role or do it yourself.
|
|
90
|
+
· max-tokens → split the task into smaller steps and re-delegate, or ask the child to
|
|
91
|
+
output incrementally.
|
|
92
|
+
· refusal → do NOT retry the same task: adjust the task's scope or framing, switch roles,
|
|
93
|
+
or handle it yourself (a refusal is a policy decision, not a transient error).
|
|
94
|
+
· aborted → only re-delegate when the cancellation was accidental.
|
|
95
|
+
· completed but poor output → re-delegate with concrete missing points, or send_message
|
|
96
|
+
to ask a continuable child to finish the gaps.
|
|
97
|
+
- If the same task fails twice, stop retrying: report to the user what failed, why,
|
|
98
|
+
and what you already tried. Never loop a failing delegation.
|
|
99
|
+
- When re-delegating (fresh task or continuation), always include your integration
|
|
100
|
+
summary of the previous attempt (what was done, what failed, what to pick up from),
|
|
101
|
+
so the child never re-derives it from a cold context.
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
按停止原因分流的行为清单(覆盖完整,与 persona 逐条一致):
|
|
105
|
+
|
|
106
|
+
| stop reason | 主 agent 行为 |
|
|
107
|
+
|---|---|
|
|
108
|
+
| `error`(运行/工具级) | 重委派**一次**:全新任务,不是续跑;若失败指向缺工具或权限,换角色或自己做 |
|
|
109
|
+
| `max-tokens` | 把任务拆小再重委派,或要求子 agent 分步输出 |
|
|
110
|
+
| `refusal` | **不重试同一任务**:调整任务范围/表述、换角色,或自己处理——refusal 是策略决定,不是瞬时错误 |
|
|
111
|
+
| `aborted` | 仅当取消是意外才重委派 |
|
|
112
|
+
| completed 但产出差 | 带具体缺失点重委派;子 agent 为 continuable 时用 `send_message` 让它补完缺口 |
|
|
113
|
+
| 同一任务失败 **2 次** | 停止重试,向用户报告失败原因与已尝试方案;绝不循环一个失败的委派 |
|
|
114
|
+
| 任何重委派 | **必须携带上次的集成摘要**:做了什么 / 败在哪 / 从哪接续——子 agent 无需从冷上下文重新推导 |
|
|
115
|
+
|
|
116
|
+
设计要点:SOP 是 persona 文本而非代码逻辑,因此可以按需编辑——直接改 `presets/orchestrator/agent.cordis.yml` 中 persona 段落(YAML 块标量,内容行缩进 10 空格,注意保持缩进),再重跑 `./install.sh --auto` 应用。例如想让失败任务更频繁地退回主 agent 自己做、或对某个角色采用不同的重试上限,都可在此调整。
|
|
117
|
+
|
|
118
|
+
## one-shot 与多轮迭代
|
|
119
|
+
|
|
120
|
+
### 默认:one-shot(用完即弃)
|
|
121
|
+
|
|
122
|
+
四个角色委派实例(`delegation-search-external` / `delegation-design` / `delegation-implement` / `delegation-search-internal-deep`)只配置 `provider: spawn`,**不设 `backgroundMode`**,因此取 `dsh-tool-subagent` 的配置默认值 `one-shot`。任一角色还可经 `roles.<toolName>.model` / `.provider` 固定专用模型——配置后该角色固定用自己的模型,不随主 agent 会话切换模型而变(见[配置](configuration.md) 2.5)。含义:
|
|
123
|
+
|
|
124
|
+
- 一次委派 = 一个用完即弃的子会话。调用默认等子 agent 跑完、把结果交回主 agent(也可按工具参数 `run_in_background` 转为后台 job,用 `job_output` 收结果、`job_kill` 叫停)。
|
|
125
|
+
- 子会话在任务结束时即弃,其工具面与上下文只为该次运行而加载(**按需加载 + 上下文隔离**,这是本 preset 的核心设计)。
|
|
126
|
+
- 与组合里另外两个通用委派行不同——`tool-subagent`(`subagent`,continuable)与 `tool-subagent-fork`(`subagent_fork`,continuable)是通用、可续的委派工具,但主 agent 白名单刻意不向其暴露;模型可见的委派面只有上述 one-shot 角色工具。
|
|
127
|
+
|
|
128
|
+
### 需要多轮迭代时的两条路
|
|
129
|
+
|
|
130
|
+
- **路径 A(推荐,零成本):集成摘要 → 重委派。** 主 agent 手里已有上轮集成摘要,直接以摘要为起点重委派一个新 one-shot 任务。子 agent 依旧用完即弃,主 agent 的摘要就是跨轮的「记忆」,重派成本可控,不改变任何持久化/生命周期模型。这是默认 SOP 对 `error` / `completed-but-poor` 等场景的处理方式(见上节)。
|
|
131
|
+
- **路径 B(可选增强):`backgroundMode: continuable`。** 新增一个可续的 `implement` 实例(`implement_cont`,启用方法见第 4 节)。continuable 调用的工具语义(`dsh-tool-subagent` 工具描述):默认**后台运行**、立即返回一个持久的子 agent id,子会话**跨轮保留**;该轮跑完后运行时向主 agent 发送结果通知(结果 + 最后一条 assistant 消息);之后主 agent 用 `send_message` 在**同一个子会话**开启后续轮次。收益:失败或产出不满意时无需重推——子 agent 记得自己查过什么、改到哪,`send_message` 就地续修即可。
|
|
132
|
+
|
|
133
|
+
### 代价与前提(如实说明)
|
|
134
|
+
|
|
135
|
+
continuable 不是免费的,启用前请确认以下四点:
|
|
136
|
+
|
|
137
|
+
1. **前置:continuable 需要 `sessionPersistence` 后端。** standard 设计把 persistence 放在 **host 层**(preset 不拥有它),所以要在 `~/.dsh/cordis.patch.yml` 挂 `@deepseek-ai/dsh-session-persistence-jsonl`(`config.root` **必填**,见插件 schema)。未挂载时 continuable 创建/续跑会直接报错:`continuable subagents require session persistence (load a dsh-session-persistence backend)`(错误码 `PERSISTENCE_UNAVAILABLE`)。这是**机器级全局改动**——persistence 影响该机器上所有会话,不是 preset 内改动,卸载 preset 也不会撤销它。
|
|
138
|
+
2. **持久化会话无 TTL**,会持续写盘累积(`config.root` 目录下按项目/会话组织 JSONL 落盘)。需要自行 `interrupt_agent` 停用不再需要的会话、并清理落盘文件。
|
|
139
|
+
3. **token 成本随轮次上升。** continuable 子 agent 每轮携带自己累积的上下文,长期挂着每轮成本只增不减——这与「用完即弃 / 按需加载」的设计初衷相悖。建议只对 implement 类**多轮打磨**任务用(这正是 `implement_cont` 的名字由来)。
|
|
140
|
+
4. **权限规则不变。** continuable 不改变 DSH 的权限语义:被拒操作依然不重试、只能换路;角色失败汇报协议与主 agent 的委派失败 SOP 对 continuable 子 agent 同样适用(SOP 里 `send_message` 分支就是为它写的)。
|
|
141
|
+
|
|
142
|
+
对照小结:
|
|
143
|
+
|
|
144
|
+
| 维度 | one-shot(默认角色) | continuable(`implement_cont`) |
|
|
145
|
+
|---|---|---|
|
|
146
|
+
| 会话生命周期 | 任务结束即弃 | 跨轮保留(durable subagent id) |
|
|
147
|
+
| 续修方式 | 主 agent 摘要 → 重委派新任务 | `send_message` 同一会话就地续修 |
|
|
148
|
+
| 持久化要求 | 无 | host 层 `sessionPersistence` 后端(机器级) |
|
|
149
|
+
| 长期成本 | 每轮只付新任务 | 每轮携带累积上下文,成本上升 |
|
|
150
|
+
| 适用 | 一切委派(默认) | 仅 implement 类多轮任务 |
|
|
151
|
+
|
|
152
|
+
## implement_cont 启用示例
|
|
153
|
+
|
|
154
|
+
本节把第 3 节的路径 B 落到配置,共 5 步。默认 preset **不含** `implement_cont`——需要时自行启用,用完可整体移除。所有 YAML 均为配置原文(来自 [README.md](../README.md) 的示例,已与源码核对)。
|
|
155
|
+
|
|
156
|
+
### 第 1 步 —— host 层挂 persistence 后端(机器级,全局生效)
|
|
157
|
+
|
|
158
|
+
编辑 `~/.dsh/cordis.patch.yml`,插入:
|
|
159
|
+
|
|
160
|
+
```yaml
|
|
161
|
+
# ~/.dsh/cordis.patch.yml —— host 层(机器级,影响所有会话)挂 persistence 后端
|
|
162
|
+
- insert:
|
|
163
|
+
- id: session-persistence
|
|
164
|
+
name: '@deepseek-ai/dsh-session-persistence-jsonl'
|
|
165
|
+
config:
|
|
166
|
+
root: ~/.dsh/sessions # 必填:持久化会话落盘目录
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
说明:`config.root` 必填(插件 schema `z.string().required()`)。这是机器级改动,见第 3 节「代价与前提」。已挂载过则跳过本步。
|
|
170
|
+
|
|
171
|
+
### 第 2 步 —— 静态源加 `delegation-implement-cont` 实例
|
|
172
|
+
|
|
173
|
+
在 `presets/orchestrator/agent.cordis.yml` 的 delegation 组 `config` 列表**末尾**(`# ── remaining model-facing rows` 注释之前,缩进与相邻 `delegation-*` 行一致)加入:
|
|
174
|
+
|
|
175
|
+
```yaml
|
|
176
|
+
# implement_cont:可续的实现子 agent(backgroundMode: continuable),
|
|
177
|
+
# 失败/产出不满意时主 agent 用 send_message 就地续修;默认不启用。
|
|
178
|
+
- id: delegation-implement-cont
|
|
179
|
+
name: '@deepseek-ai/dsh-tool-subagent'
|
|
180
|
+
config:
|
|
181
|
+
provider: spawn
|
|
182
|
+
toolName: implement_cont
|
|
183
|
+
backgroundMode: continuable
|
|
184
|
+
persona: |-
|
|
185
|
+
You are the iterative implementation agent. You write and edit code,
|
|
186
|
+
verify, and keep working across turns — the orchestrator sends you
|
|
187
|
+
incremental follow-ups via send_message. Report progress compactly.
|
|
188
|
+
toolFilter:
|
|
189
|
+
allow:
|
|
190
|
+
- read
|
|
191
|
+
- write
|
|
192
|
+
- edit
|
|
193
|
+
- glob
|
|
194
|
+
- grep
|
|
195
|
+
- bash
|
|
196
|
+
- skill
|
|
197
|
+
- memory_search
|
|
198
|
+
- web_search
|
|
199
|
+
- ask_user_question
|
|
200
|
+
- todo_write
|
|
201
|
+
- job_output
|
|
202
|
+
- job_list
|
|
203
|
+
- job_kill
|
|
204
|
+
- get_goal
|
|
205
|
+
- create_goal
|
|
206
|
+
- update_goal
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
注意两点:
|
|
210
|
+
|
|
211
|
+
- `memory_search` 依赖 host 层的 magic-memory 插件:**插件未启用时必须从 allow 删去该行**,否则子 agent 创建时 `tools.restrict()` 以 unknown tools 拒绝创建。这与 2026-09-02 起各角色 allow 剔除 `memory_search` / `mcp__codegraph__codegraph_explore` 的决策一致(见 `agent.cordis.yml` 内注释);且安装器的 allow 重写只覆盖三个内置角色,**手写的 `implement_cont` 块不会被自动清洗**——它自己的 allow 必须手工与宿主实际启用的插件保持同步。
|
|
212
|
+
- persona 用 YAML `|-` 块标量,内容行缩进 10 空格,改文本时保持缩进。
|
|
213
|
+
|
|
214
|
+
### 第 3 步 —— 让主 agent 能调 `implement_cont`(二选一)
|
|
215
|
+
|
|
216
|
+
主 agent 只能调用白名单内的工具,二选一:
|
|
217
|
+
|
|
218
|
+
- **推荐:配置文件注入(不动源码)。** 在 `~/.dsh/dsh-paoding.config.yml` 顶层加:
|
|
219
|
+
|
|
220
|
+
```yaml
|
|
221
|
+
main_agent_extra:
|
|
222
|
+
- implement_cont
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
安装时 `implement_cont`(非 host 依赖名)会被并入生成的 `config.allow`。也可在配置 UI(设置 → **庖丁配置** → 主 agent 卡)勾选,见[配置](configuration.md)。
|
|
226
|
+
|
|
227
|
+
- **或:改 `restrict.mjs` 常量。** 在 `presets/orchestrator/restrict.mjs` 的 `MAIN_AGENT_ALLOW`(21 项白名单常量,`new Set([...])`)中加一行 `'implement_cont'`。注意**覆盖语义**:运行时 `allow = config.allow ?? MAIN_AGENT_ALLOW`(空 allow 拒绝加载)。安装器从 `restrict.mjs` 源码现场解析该常量作为 base,生成 `config.allow = base + main_agent_extra(仅检测到的 host 名保留)− main_agent_remove`,且**只在结果与 base 不同时才注入** `config.allow` 行。因此:改完常量必须重跑安装(base 重新解析、安装副本刷新);若运行中的 `agent.cordis.yml` 已有注入的 `config.allow`,运行时以它为准、常量只作回退。
|
|
228
|
+
|
|
229
|
+
无论哪条路,改完都需要重跑安装应用(见第 4 步)。
|
|
230
|
+
|
|
231
|
+
### 第 4 步 —— 应用
|
|
232
|
+
|
|
233
|
+
```bash
|
|
234
|
+
cd dsh-paoding
|
|
235
|
+
./install.sh --auto # 重新生成 preset(含新 delegation 块与白名单变更)
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
然后**重启 host 或新建会话**生效。第 3 步若走了配置文件路径,配置会持久化到 `~/.dsh/dsh-paoding.config.yml`,之后改动配置重跑 `./install.sh --auto` 幂等应用。
|
|
239
|
+
|
|
240
|
+
### 第 5 步 —— 用后清理
|
|
241
|
+
|
|
242
|
+
continuable 会话**无 TTL**,会持续写盘累积:
|
|
243
|
+
|
|
244
|
+
- 用 `interrupt_agent` 停掉不再需要的 `implement_cont` 会话;
|
|
245
|
+
- 长期不再用时,移除第 2 步的 delegation 块与第 3 步的白名单项,重跑 `./install.sh --auto`;persistence 插件本身留在 host 层即可(机器级,见第 3 节),也可一并移除并清理 `~/.dsh/sessions/` 下的落盘文件。
|
|
246
|
+
|
|
247
|
+
## 上下文隔离
|
|
248
|
+
|
|
249
|
+
收尾一句设计原则:**worker 上下文小而专,主 agent 只收摘要。** 具体落在三处:
|
|
250
|
+
|
|
251
|
+
1. **角色工具面即上下文边界。** 每个角色子 agent 只带干自己那活的工具(`toolFilter.allow`),persona 又指引它只产出本角色的产物(调研摘要 / 设计 spec / 代码改动)。大输出在子上下文内部消化,不回灌主 agent。
|
|
252
|
+
2. **主 agent 只集成摘要。** 委派返回后,主 agent 的上下文里只有子 agent 的(结构化)结果/失败诊断,子 agent 的完整历史、中间搜索 dump、逐段 diff 都不进入主上下文——单体会话里「每次搜索 dump、每轮设计稿、每段 diff 都累积」的问题由此消除。
|
|
253
|
+
3. **全仓探索的 dump 隔离。** `search_internal_deep`(第四角色,2026-09 加入)把「超大仓库全量探索」隔离到子上下文:工具面 = 内部搜索全量(`glob`/`grep`/`read`/`read_image`/`bash`,**无 write/edit、无网络**),persona 要求只回浓缩摘要——查了什么、关键文件带行号、找到的定义/符号、主 agent 决策所需要点——并**绝不回传大 dump**。主 agent 遇到这类任务应委派而非自做(热路径上的单文件读、精准 grep 仍自做,零委派延迟)。详见[架构](architecture.md)。
|
|
254
|
+
4. **one-shot 与隔离的关系。** one-shot 让隔离边界落在「每次委派」:用完即弃,天然不跨轮泄漏。continuable 是有意把某个子上下文跨轮保留(见第 3 节),隔离边界放宽到「每次会话」——即便如此,主 agent 依然只收摘要,累积只发生在那个 continuable 子会话内部。
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
← [dsh-paoding](../README_en.md) | [Architecture](architecture_en.md) | [Installation](installation_en.md) | **Orchestration** | [Configuration](configuration_en.md)
|
|
2
|
+
[中文](orchestration.md) · English
|
|
3
|
+
|
|
4
|
+
# Orchestration
|
|
5
|
+
|
|
6
|
+
Orchestration is the core of dsh-paoding: the main agent (the orchestrator) decomposes the task, delegates along its texture, and integrates the results; role subagents carry only the tools their role needs and are discarded once their run settles. This document is for users who want to understand or tune these behaviors: how failures surface and recover, the one-shot vs multi-turn (continuable) trade-off, and how to enable the optional `implement_cont` enhancement. Where this document conflicts with the source code, the source wins; every configuration reference here is taken from `presets/orchestrator/agent.cordis.yml` and `presets/orchestrator/restrict.mjs`.
|
|
7
|
+
|
|
8
|
+
## Orchestration overview
|
|
9
|
+
|
|
10
|
+
dsh-paoding turns DSH from "a single agent that loads every tool" into "a main agent that orchestrates plus role agents that specialize". The split follows the texture of the task:
|
|
11
|
+
|
|
12
|
+
- **Hot path — internal file questions are never delegated.** Finding code, chasing references, and reading files are solved by the main agent itself with its read-only tools: `glob` / `grep` / `read` / `read_image` / `bash` are all on the main-agent allow list, so there is zero delegation round-trip latency. `codegraph` in the persona copy is a host MCP tool: it is only actually available when the install-time detection finds the codegraph server and it is injected through `main_agent_extra` (see [Configuration](configuration_en.md) and [Installation](installation_en.md)).
|
|
13
|
+
- **Cold path — role agents that carry only their own tools.** External research goes to `search_external` (only `web_search` + the five tavily tools + local reads); UI/frontend design goes to `design` (reads references, loads design skills, produces specs, never writes final code); code implementation goes to `implement` (read context → surgical change → verify); whole-repo deep exploration goes to `search_internal_deep` (a fourth role added 2026-09, see next section and [Architecture](architecture_en.md)). Each subagent is paid for only the run in which it is actually used (pay-per-use).
|
|
14
|
+
- **Directing a running child.** While a subagent runs, the main agent can append instructions with `send_message`, inspect status with `list_agents`, and stop it with `interrupt_agent` (all three are registered by `dsh-tool-subagent-control` and belong to the "child management" surface).
|
|
15
|
+
- **Integrate summaries only.** The main agent never dumps a child's full context into its own — it receives one summary (see section 5, Context isolation).
|
|
16
|
+
|
|
17
|
+
The main agent's model-facing surface is narrowed by `restrict.mjs` on the `system-prompt/assemble` waterfall against an allow list (fail-open: a filter bug exposes the full catalog rather than bricking the session; an empty allow list refuses to load). The delegation group also ships generic rows — `subagent` / `subagent_fork` (both `backgroundMode: continuable`), `workflow`, `ralph` — registered in the composition but deliberately hidden from the main agent: its visible delegation surface is only the four role tools plus the child-management tools (four roles by default; three of them — `search_external` / `design` / `implement` — can be deleted wholesale via `roles_remove`, which shrinks the delegation surface accordingly, see [Configuration](configuration_en.md) 2.3).
|
|
18
|
+
|
|
19
|
+
| Surface | Allow-list contents (`MAIN_AGENT_ALLOW`, a 21-entry constant; runtime may be overridden by `config.allow`) |
|
|
20
|
+
|---|---|
|
|
21
|
+
| Role delegation | `search_external` / `design` / `implement` / `search_internal_deep` |
|
|
22
|
+
| Child management | `send_message` / `list_agents` / `interrupt_agent` |
|
|
23
|
+
| Internal search (hot path) | `glob` / `grep` / `read` / `read_image` / `bash` |
|
|
24
|
+
| Coordination | `todo_write` / `ask_user_question` / `get_goal` / `create_goal` / `update_goal` / `exit_plan_mode` / `job_output` / `job_list` / `job_kill` |
|
|
25
|
+
| Deliberately hidden from the main agent | `web_search`, `mcp__tavily__*`, `write` / `edit`, `skill`, `workflow`, `ralph`, bare `subagent` / `subagent_fork` |
|
|
26
|
+
|
|
27
|
+
Per-request tool tax (estimates; they float with the registered surface): full monolithic main agent ~16.2k tokens → ~5.5k after the allow list; `search_external` ~3.0k / `design` ~3.2k / `implement` ~3.7k, incurred only when actually delegated (figures from the header comment of `agent.cordis.yml`).
|
|
28
|
+
|
|
29
|
+
### Main-agent persona (excerpt, verbatim)
|
|
30
|
+
|
|
31
|
+
Taken from the `- id: persona` row of `presets/orchestrator/agent.cordis.yml` (a YAML `text: |-` block scalar whose content lines are indented 6 spaces). The overall orchestration-and-delegation guidance:
|
|
32
|
+
|
|
33
|
+
```text
|
|
34
|
+
You are the orchestrator agent powered by the {{model}} model. Your working directory is {{cwd}}.
|
|
35
|
+
|
|
36
|
+
Decompose the task, delegate to role agents, integrate results.
|
|
37
|
+
- Internal file questions (finding code, references, reading files): solve yourself with glob/grep/read/codegraph — never delegate them.
|
|
38
|
+
- External research: delegate to search_external.
|
|
39
|
+
- UI/design work: delegate to design.
|
|
40
|
+
- Code implementation: delegate to implement.
|
|
41
|
+
Keep your own context lean; integrate only summaries. Use todo_write to plan, and ask_user_question only for user-owned choices.
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Reading notes:
|
|
45
|
+
|
|
46
|
+
- The main agent is an orchestrator running the **decompose → delegate → integrate** loop rather than doing everything itself.
|
|
47
|
+
- "Internal file questions (finding code, references, reading files): solve yourself with glob/grep/read/codegraph — **never delegate them**": internal search is the hot path — delegation costs round-trips and cold starts, and the main agent already carries a full read-only set, so it goes direct. (Note: `codegraph` is a host MCP tool and is only usable once injected into the allow list at runtime, see above.)
|
|
48
|
+
- Task texture decides the destination: networked research → `search_external`; UI/design → `design`; code → `implement` (whole-repo exploration → `search_internal_deep`).
|
|
49
|
+
- **Keep your own context lean**: integrate only summaries; plan with `todo_write`; use `ask_user_question` only for user-owned choices — questions that inspection can answer must not bother the user.
|
|
50
|
+
- The failure-handling SOP lives inline in the persona, so it is active in every session with zero extra configuration — see the next section.
|
|
51
|
+
|
|
52
|
+
## Failure handling
|
|
53
|
+
|
|
54
|
+
DSH has no native automatic retry — recovery is the orchestration layer's job, concretely the main agent's. This preset defends delegated work with three layers: **prevent → detect → recover**.
|
|
55
|
+
|
|
56
|
+
### How a failure surfaces
|
|
57
|
+
|
|
58
|
+
A delegated run reports failure in two runtime shapes (verbatim from the persona SOP below): a thrown tool error for foreground calls, or a failed background job. Both carry the child's partial output plus a stop reason: `error` / `max-tokens` / `refusal` / `aborted` / `completed-but-poor`. Recovery triages by stop reason rather than retrying blindly.
|
|
59
|
+
|
|
60
|
+
### Layer 1: prevention
|
|
61
|
+
|
|
62
|
+
At child creation, DSH validates `toolFilter.allow` through `tools.restrict()`: every allow name must exist in the child's visible registry (= this composition's full registration plus host-layer MCP/plugin tools), otherwise creation is rejected (`tools.restrict() ... unknown tools`).
|
|
63
|
+
|
|
64
|
+
The preset eliminates this class of failure at install time: `./install.sh` (tools/install.mjs) reads the host patch layers (home / profile / `--patch`), detects which MCP servers and local tool plugins are actually enabled, resolves exact tool names (a static known-tools table first, then a live JSON-RPC handshake for unknown servers), and rewrites each role's allow list as "static intent ∩ actually detected tools" — composition-guaranteed base tools stay untouched, host tools that are disabled or unresolvable are removed. MCPs that fail the handshake or use an unsupported transport are skipped: the role simply lacks those tools and installation does not error. After enabling/disabling MCPs or plugins on the host, re-run `./install.sh --auto` to sync the allow lists (`--dry-run` previews first). Details in [Installation](installation_en.md).
|
|
65
|
+
|
|
66
|
+
Note that the installer's allow rewriting covers only the three built-in roles (`search_external` / `design` / `implement` — the `ROLES` constant in tools/install.mjs). Hand-written extra `delegation-*` blocks (e.g. `implement_cont` in section 4) ship **as-is and are never auto-cleaned**: host-dependent names inside them must be kept in sync with the plugins actually enabled on the host, or child creation is rejected. That is exactly why role allow lists dropped `memory_search` / `mcp__codegraph__codegraph_explore` as of 2026-09-02 (those names are not in the registry while the plugins are off; add them back when you re-enable the plugin — see the comment on `delegation-search-internal-deep` in `agent.cordis.yml`).
|
|
67
|
+
|
|
68
|
+
### Layer 2: detection
|
|
69
|
+
|
|
70
|
+
All four roles (`search_external` / `design` / `implement` / `search_internal_deep` — the reporting protocol applies to **every** role; the fourth joined in 2026-09) carry the same failure-reporting protocol in their personas (verbatim, identical in all four instances; this is the default full set — the first three can be deleted wholesale via `roles_remove`, so deleted roles simply stop carrying the protocol, while `search_internal_deep` cannot be deleted, see [Configuration](configuration_en.md) 2.3):
|
|
71
|
+
|
|
72
|
+
```text
|
|
73
|
+
On tool failure, do not retry a denied operation: report the failure compactly — what you completed, the exact error, which tool/permission you lack, and your suggested next step — so the orchestrator can re-delegate or adjust.
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
That is: on a tool failure the child reports four things — ① what it completed, ② the exact error, ③ which tool/permission it lacks, and ④ its suggested next step. It obeys the DSH rule: **a denied operation is never retried, only reported**. The child is not the recoverer; it feeds diagnostics back to the orchestrator, and the main agent decides whether to re-delegate or adjust.
|
|
77
|
+
|
|
78
|
+
### Layer 3: recovery
|
|
79
|
+
|
|
80
|
+
The main-agent persona embeds the delegation failure handling SOP (verbatim, the third paragraph of the persona in `agent.cordis.yml`):
|
|
81
|
+
|
|
82
|
+
```text
|
|
83
|
+
Delegation failure handling (SOP):
|
|
84
|
+
- A delegated run reports failure either as a thrown tool error (foreground)
|
|
85
|
+
or as a failed background job; both carry the child's partial output and
|
|
86
|
+
a stop reason (error / max-tokens / refusal / aborted / completed-but-poor).
|
|
87
|
+
- Diagnose by stop reason, never retry blindly:
|
|
88
|
+
· error (runtime/tool-level) → re-delegate ONCE as a fresh task (not a continuation);
|
|
89
|
+
if the failure cites a missing tool or permission, pick a different role or do it yourself.
|
|
90
|
+
· max-tokens → split the task into smaller steps and re-delegate, or ask the child to
|
|
91
|
+
output incrementally.
|
|
92
|
+
· refusal → do NOT retry the same task: adjust the task's scope or framing, switch roles,
|
|
93
|
+
or handle it yourself (a refusal is a policy decision, not a transient error).
|
|
94
|
+
· aborted → only re-delegate when the cancellation was accidental.
|
|
95
|
+
· completed but poor output → re-delegate with concrete missing points, or send_message
|
|
96
|
+
to ask a continuable child to finish the gaps.
|
|
97
|
+
- If the same task fails twice, stop retrying: report to the user what failed, why,
|
|
98
|
+
and what you already tried. Never loop a failing delegation.
|
|
99
|
+
- When re-delegating (fresh task or continuation), always include your integration
|
|
100
|
+
summary of the previous attempt (what was done, what failed, what to pick up from),
|
|
101
|
+
so the child never re-derives it from a cold context.
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Behavior by stop reason (complete coverage, one-to-one with the persona):
|
|
105
|
+
|
|
106
|
+
| Stop reason | Main-agent behavior |
|
|
107
|
+
|---|---|
|
|
108
|
+
| `error` (runtime/tool-level) | Re-delegate **once** as a fresh task (not a continuation); if the failure cites a missing tool or permission, pick a different role or do it yourself |
|
|
109
|
+
| `max-tokens` | Split the task into smaller steps and re-delegate, or ask the child to output incrementally |
|
|
110
|
+
| `refusal` | Do **not** retry the same task: adjust the task's scope or framing, switch roles, or handle it yourself — a refusal is a policy decision, not a transient error |
|
|
111
|
+
| `aborted` | Re-delegate only when the cancellation was accidental |
|
|
112
|
+
| completed but poor output | Re-delegate with concrete missing points; if the child is continuable, `send_message` it to finish the gaps |
|
|
113
|
+
| Same task fails **twice** | Stop retrying; report to the user what failed, why, and what you already tried; never loop a failing delegation |
|
|
114
|
+
| Any re-delegation | **Always carry the previous integration summary** — what was done, what failed, what to pick up from — so the child never re-derives it from a cold context |
|
|
115
|
+
|
|
116
|
+
Design note: the SOP is persona text, not code, so it is tunable: edit the persona block in `presets/orchestrator/agent.cordis.yml` (YAML block scalar; content lines are indented 10 spaces — keep the indentation), then re-run `./install.sh --auto`. For example, you can make failures bounce back to the main agent more often, or give a specific role a different retry ceiling.
|
|
117
|
+
|
|
118
|
+
## One-shot vs continuable
|
|
119
|
+
|
|
120
|
+
### Default: one-shot (run-and-discard)
|
|
121
|
+
|
|
122
|
+
The four role delegation instances (`delegation-search-external` / `delegation-design` / `delegation-implement` / `delegation-search-internal-deep`) configure only `provider: spawn` and do **not** set `backgroundMode`, so they take `dsh-tool-subagent`'s config default, `one-shot`. Any role can additionally be pinned to a dedicated model via `roles.<toolName>.model` / `.provider` — once configured, the role runs on its own model and no longer follows the main agent's session model switches (see [Configuration](configuration_en.md) 2.5). Meaning:
|
|
123
|
+
|
|
124
|
+
- One delegation = one run-and-discard child session. The call waits for the child to finish and hands the result back to the main agent by default (or becomes a background job via the tool's `run_in_background` parameter, collected with `job_output` and stopped with `job_kill`).
|
|
125
|
+
- The child session is discarded when the task settles; its tool surface and context are paid for only for that one run (**pay-per-use + context isolation** — the preset's core design).
|
|
126
|
+
- This differs from the two generic delegation rows in the composition — `tool-subagent` (`subagent`, continuable) and `tool-subagent-fork` (`subagent_fork`, continuable) are generic, continuable delegation tools, but the main-agent allow list deliberately hides them; the model-visible delegation surface is only the one-shot role tools above.
|
|
127
|
+
|
|
128
|
+
### Two paths when you need multiple iterations
|
|
129
|
+
|
|
130
|
+
- **Path A (recommended, zero cost): integration summary → re-delegate.** The main agent already holds the previous integration summary, so it simply re-delegates a fresh one-shot task seeded with that summary. The child is still run-and-discard; the main agent's summary is the cross-turn "memory"; re-delegation cost stays bounded and no persistence/lifecycle model changes. This is how the default SOP handles `error` / `completed-but-poor` and similar cases (see the previous section).
|
|
131
|
+
- **Path B (optional enhancement): `backgroundMode: continuable`.** Add a continuable `implement` instance (`implement_cont`; how to enable it is section 4). Continuable tool semantics (from the `dsh-tool-subagent` tool description): it runs **in the background by default**, immediately returns a durable subagent id, and **keeps the child conversation available for later turns**; when that run settles, the runtime sends the parent a notice with the outcome and final assistant message; afterwards the main agent starts later turns in the **same child conversation** with `send_message`. Payoff: on failure or unsatisfactory output there is no cold restart — the child remembers what it searched and what it changed, and `send_message` finishes the gaps in place.
|
|
132
|
+
|
|
133
|
+
### Costs and prerequisites
|
|
134
|
+
|
|
135
|
+
Continuable is not free; confirm all four before enabling:
|
|
136
|
+
|
|
137
|
+
1. **Prerequisite: continuable requires a `sessionPersistence` backend.** The standard design keeps persistence at the **host layer** (the preset does not own it), so you mount `@deepseek-ai/dsh-session-persistence-jsonl` in `~/.dsh/cordis.patch.yml` (`config.root` is **required**, per the plugin schema). Without it, continuable creation/resumption fails loudly: `continuable subagents require session persistence (load a dsh-session-persistence backend)` (error code `PERSISTENCE_UNAVAILABLE`). This is a **machine-level, global change** — persistence affects every session on that host, it is not a preset-local change, and uninstalling the preset does not undo it.
|
|
138
|
+
2. **Persisted sessions have no TTL** and keep accumulating on disk (JSONL artifacts under `config.root`, organized by project/session). You must `interrupt_agent` sessions you no longer need and clean up the on-disk files yourself.
|
|
139
|
+
3. **Token cost grows per turn.** A continuable child carries its accumulated context on every turn, so a long-lived child only gets more expensive — which runs against the run-and-discard / pay-per-use philosophy. Use it only for implement-class **multi-round polishing** tasks (that is where the name `implement_cont` comes from).
|
|
140
|
+
4. **Permission rules are unchanged.** Continuable does not alter DSH's permission semantics: a denied operation is still never retried — only a different path is taken; the role failure-reporting protocol and the main agent's delegation SOP apply to continuable children too (the SOP's `send_message` branch exists precisely for them).
|
|
141
|
+
|
|
142
|
+
Quick comparison:
|
|
143
|
+
|
|
144
|
+
| Dimension | one-shot (default roles) | continuable (`implement_cont`) |
|
|
145
|
+
|---|---|---|
|
|
146
|
+
| Session lifetime | discarded when the task settles | kept across turns (durable subagent id) |
|
|
147
|
+
| Follow-up fixing | main-agent summary → re-delegate a fresh task | `send_message` in the same session, fix in place |
|
|
148
|
+
| Persistence required | none | host-layer `sessionPersistence` backend (machine-level) |
|
|
149
|
+
| Long-term cost | each turn pays only the new task | each turn carries the accumulated context, cost grows |
|
|
150
|
+
| Fit | every delegation (default) | only implement-class multi-round tasks |
|
|
151
|
+
|
|
152
|
+
## Enabling implement_cont
|
|
153
|
+
|
|
154
|
+
This section turns Path B of section 3 into concrete configuration — 5 steps. The default preset does **not** ship `implement_cont`; enable it when you need it and remove it entirely when you no longer do. All YAML below is verbatim configuration (adapted from the example in [README.md](../README_en.md) and checked against the source).
|
|
155
|
+
|
|
156
|
+
### Step 1 — mount the persistence backend at the host layer (machine-level, global)
|
|
157
|
+
|
|
158
|
+
Edit `~/.dsh/cordis.patch.yml` and insert:
|
|
159
|
+
|
|
160
|
+
```yaml
|
|
161
|
+
# ~/.dsh/cordis.patch.yml — host layer (machine-level, affects every session): mount the persistence backend
|
|
162
|
+
- insert:
|
|
163
|
+
- id: session-persistence
|
|
164
|
+
name: '@deepseek-ai/dsh-session-persistence-jsonl'
|
|
165
|
+
config:
|
|
166
|
+
root: ~/.dsh/sessions # required: on-disk directory for persisted sessions
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
`config.root` is required (the plugin schema declares `z.string().required()`); it is the on-disk directory for persisted sessions. This is a machine-level change that affects every session on the host — see "Costs and prerequisites" in section 3. Skip this step if a backend is already mounted.
|
|
170
|
+
|
|
171
|
+
### Step 2 — add the `delegation-implement-cont` instance to the static source
|
|
172
|
+
|
|
173
|
+
At the **end** of the delegation group's `config` list in `presets/orchestrator/agent.cordis.yml` (right before the `# ── remaining model-facing rows` comment; indentation must match the neighbouring `delegation-*` rows), insert:
|
|
174
|
+
|
|
175
|
+
```yaml
|
|
176
|
+
# implement_cont: a continuable implementation subagent (backgroundMode: continuable) —
|
|
177
|
+
# the main agent resumes it in place with send_message when output fails or disappoints;
|
|
178
|
+
# not enabled by default.
|
|
179
|
+
- id: delegation-implement-cont
|
|
180
|
+
name: '@deepseek-ai/dsh-tool-subagent'
|
|
181
|
+
config:
|
|
182
|
+
provider: spawn
|
|
183
|
+
toolName: implement_cont
|
|
184
|
+
backgroundMode: continuable
|
|
185
|
+
persona: |-
|
|
186
|
+
You are the iterative implementation agent. You write and edit code,
|
|
187
|
+
verify, and keep working across turns — the orchestrator sends you
|
|
188
|
+
incremental follow-ups via send_message. Report progress compactly.
|
|
189
|
+
toolFilter:
|
|
190
|
+
allow:
|
|
191
|
+
- read
|
|
192
|
+
- write
|
|
193
|
+
- edit
|
|
194
|
+
- glob
|
|
195
|
+
- grep
|
|
196
|
+
- bash
|
|
197
|
+
- skill
|
|
198
|
+
- memory_search
|
|
199
|
+
- web_search
|
|
200
|
+
- ask_user_question
|
|
201
|
+
- todo_write
|
|
202
|
+
- job_output
|
|
203
|
+
- job_list
|
|
204
|
+
- job_kill
|
|
205
|
+
- get_goal
|
|
206
|
+
- create_goal
|
|
207
|
+
- update_goal
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
Two caveats:
|
|
211
|
+
|
|
212
|
+
- `memory_search` depends on the host magic-memory plugin: **if the plugin is not enabled, remove that line from the allow list** or child creation is rejected by `tools.restrict()` with unknown tools. This is consistent with the 2026-09-02 decision to strip `memory_search` / `mcp__codegraph__codegraph_explore` from role allow lists (see the in-file comment in `agent.cordis.yml`); and since the installer's allow rewriting covers only the three built-in roles, the hand-written `implement_cont` block is **never auto-cleaned** — keep its allow list in sync with the plugins actually enabled on the host by hand.
|
|
213
|
+
- The persona in the block above is a YAML `|-` block scalar whose content lines are indented 10 spaces; preserve the indentation when editing the text.
|
|
214
|
+
|
|
215
|
+
### Step 3 — let the main agent call `implement_cont` (pick one of two)
|
|
216
|
+
|
|
217
|
+
The main agent can only call tools on its allow list; you have two ways to add `implement_cont`.
|
|
218
|
+
|
|
219
|
+
**Recommended: config-file injection (no source edit).** Add `main_agent_extra` at the top level of `~/.dsh/dsh-paoding.config.yml`:
|
|
220
|
+
|
|
221
|
+
```yaml
|
|
222
|
+
main_agent_extra:
|
|
223
|
+
- implement_cont
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
At install time `implement_cont` — not a host-dependent name — is merged into the generated `config.allow`. You can equally tick it in the config UI (Settings → 庖丁配置 → the main-agent card); see [Configuration](configuration_en.md).
|
|
227
|
+
|
|
228
|
+
**Alternative: edit the `restrict.mjs` constant.** Add a line `'implement_cont'` to `MAIN_AGENT_ALLOW` (the 21-entry allow constant, `new Set([...])`) in `presets/orchestrator/restrict.mjs`. Mind the **override semantics**: at runtime `allow = config.allow ?? MAIN_AGENT_ALLOW` (an empty allow refuses to load). The installer re-extracts this constant from `restrict.mjs` source as its base and generates `config.allow = base + main_agent_extra (only detected host names kept) − main_agent_remove`, injecting the `config.allow` row **only when the result differs from the base**. So after editing the constant you must re-run the installer (the base is re-extracted and the installed copy refreshed); and when the running `agent.cordis.yml` already has an injected `config.allow`, that generated list wins at runtime and the constant only serves as fallback.
|
|
229
|
+
|
|
230
|
+
Either way, re-run the installer to apply (next step).
|
|
231
|
+
|
|
232
|
+
### Step 4 — apply
|
|
233
|
+
|
|
234
|
+
```bash
|
|
235
|
+
cd dsh-paoding
|
|
236
|
+
./install.sh --auto # regenerate the preset (new delegation block + allow-list changes)
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
Then **restart the host or open a new session** for it to take effect. If step 3 used the config-file path, the choice is persisted in `~/.dsh/dsh-paoding.config.yml`; change it later and re-run `./install.sh --auto` for an idempotent re-apply.
|
|
240
|
+
|
|
241
|
+
### Step 5 — clean up after use
|
|
242
|
+
|
|
243
|
+
Continuable sessions have **no TTL** and keep accumulating on disk:
|
|
244
|
+
|
|
245
|
+
- `interrupt_agent` any `implement_cont` session you no longer need;
|
|
246
|
+
- when you stop using it for good, remove the delegation block from step 2 and the allow entry from step 3, then re-run `./install.sh --auto`; the persistence plugin itself may stay at the host layer (machine-level, see section 3), or be removed together with the artifacts under `~/.dsh/sessions/`.
|
|
247
|
+
|
|
248
|
+
## Context isolation
|
|
249
|
+
|
|
250
|
+
Closing design principle: **worker contexts stay small and specialized; the main agent only receives summaries.** Concretely:
|
|
251
|
+
|
|
252
|
+
1. **The role tool surface is the context boundary.** Each role subagent carries only the tools for its own job (`toolFilter.allow`) and its persona directs it to produce only its own deliverable (research summary / design spec / code changes). Large outputs are digested inside the child context and never poured back into the main agent.
|
|
253
|
+
2. **The main agent only integrates summaries.** After a delegation returns, the main agent's context holds only the child's (structured) result or failure diagnostics — not the child's full history, intermediate search dumps, or per-hunk diffs. This removes the monolith-session problem where every search dump, every design round, and every diff accumulates forever.
|
|
254
|
+
3. **Whole-repo exploration dumps are isolated.** `search_internal_deep` (the fourth role, added 2026-09) isolates "very large repository exploration" into a child context: its tool surface is the full internal-search set (`glob`/`grep`/`read`/`read_image`/`bash`, **no write/edit, no network**) and its persona demands a concise summary only — what was searched, key files with line numbers, definitions/symbols found, and the takeaway the orchestrator needs to decide next — and says to **never echo large dumps back** (condense aggressively). The main agent should delegate such tasks rather than doing them itself (single-file reads and precise greps on the hot path stay in-house, zero delegation latency). See [Architecture](architecture_en.md).
|
|
255
|
+
4. **One-shot and isolation.** One-shot keeps the isolation boundary at "each delegation": run-and-discard, so nothing leaks across turns by construction. Continuable deliberately keeps one child context across turns (section 3), widening the boundary to "each session" — but even then the main agent only receives summaries; accumulation happens inside that one continuable child session only.
|
package/install.sh
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
#
|
|
3
|
+
# dsh-paoding installer — thin shell wrapper around tools/install.mjs, which
|
|
4
|
+
# installs the orchestrator preset into $DSH_HOME/.agent-presets/ (the roster
|
|
5
|
+
# root dsh-agent-presets scans for locally authored presets). The Node
|
|
6
|
+
# generator detects the host's enabled MCP servers and local tool plugins at
|
|
7
|
+
# install time, resolves their exact tool names, and rewrites the role
|
|
8
|
+
# toolFilter.allow lists in agent.cordis.yml — so tools.restrict() never
|
|
9
|
+
# rejects a child agent for an unknown host-tool name.
|
|
10
|
+
#
|
|
11
|
+
# Usage: ./install.sh [--profile <name>] [--patch <file> ...] [--dry-run] [--help]
|
|
12
|
+
# npx equivalent: npx dsh-paoding [options] (same options; defaults to --auto --config-ui)
|
|
13
|
+
# After installing: restart the dsh host (or open a new session), then pick
|
|
14
|
+
# 「编排模式 (Orchestrator)」 in the new-session preset selector. To make it
|
|
15
|
+
# the default, set it in Settings → Agent Presets.
|
|
16
|
+
#
|
|
17
|
+
# Uninstall: rm -rf "${DSH_HOME:-$HOME/.dsh}/.agent-presets/orchestrator"
|
|
18
|
+
|
|
19
|
+
set -euo pipefail
|
|
20
|
+
|
|
21
|
+
DSH_HOME="${DSH_HOME:-$HOME/.dsh}"
|
|
22
|
+
export DSH_HOME
|
|
23
|
+
|
|
24
|
+
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
25
|
+
|
|
26
|
+
if ! command -v node >/dev/null 2>&1; then
|
|
27
|
+
echo "error: node (>=18) is required to run the dsh-paoding installer" >&2
|
|
28
|
+
exit 1
|
|
29
|
+
fi
|
|
30
|
+
|
|
31
|
+
exec node "$REPO_ROOT/tools/install.mjs" "$@"
|
package/package.json
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "dsh-paoding",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "庖丁 — DSH (DeepSeek Harness) 编排模式安装器:host 感知的角色工具过滤 + Web 设置页可视化配置器",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"bin": { "dsh-paoding": "bin/dsh-paoding.mjs" },
|
|
8
|
+
"files": ["bin/", "tools/", "presets/", "plugins/", "docs/", "install.sh", "README.md", "README_en.md", "LICENSE", "cordis.patch.yml"],
|
|
9
|
+
"engines": { "node": ">=18" },
|
|
10
|
+
"keywords": ["dsh", "deepseek-harness", "orchestrator", "agent-preset", "config-ui"],
|
|
11
|
+
"repository": { "type": "git", "url": "git+https://github.com/lifangjin/dsh-paoding.git" },
|
|
12
|
+
"main": "plugins/paoding-config-ui/index.mjs",
|
|
13
|
+
"exports": {
|
|
14
|
+
".": "./plugins/paoding-config-ui/index.mjs",
|
|
15
|
+
"./client": "./plugins/paoding-config-ui/lib/client.js",
|
|
16
|
+
"./package.json": "./package.json"
|
|
17
|
+
},
|
|
18
|
+
"dsh": {
|
|
19
|
+
"client": {
|
|
20
|
+
"platform": "web",
|
|
21
|
+
"inject": [
|
|
22
|
+
"@deepseek-ai/dsh-client-runtime",
|
|
23
|
+
"@deepseek-ai/dsh-client-ui-settings",
|
|
24
|
+
"@deepseek-ai/dsh-client-connection"
|
|
25
|
+
]
|
|
26
|
+
},
|
|
27
|
+
"bundle": { "patch": "./cordis.patch.yml" }
|
|
28
|
+
}
|
|
29
|
+
}
|