oh_my_deepseek_harness
DeepSeek Harness 多智能体编排模式 — 灵感来自 oh-my-opencode-slim
以 Orchestrator 为控制平面,调度 Explorer / Librarian / Observer / Oracle / Designer / Fixer 六个职责严格隔离的专职子代理,在 DeepSeek Harness 中实现“调查 → 判断 → 执行 → 验证”的完整工作流。
本插件是一个 DSH agent preset(可切换的模式):安装后可在 Web 界面
的 Agent preset 选择器中与 standard(标准模式)、code、minimal、
cordis 并列选择,随时切换,互不影响。
⚠️ 最终版声明(FINAL RELEASE):因开发者没有 Money 承担 DeepSeek 的 API,本项目自 v0.1.6(2026-08-17) 起停止功能迭代,这是最后一版。 后续问题请自行解决;欢迎 fork / PR,但作者不再承诺响应 issue 或发布新版本。
更新记录(简要)
详细变更见 CHANGELOG.md。自
6a252cd起共六轮更新,v0.1.6 为最终版:
- v0.1.6(2026-08-17) — 审查修复批次:自定义角色真正可见且可写(单写者锁同步)、并行委派预算预留、workspace fingerprint 内容哈希、持久化状态即时可读、broker_status 输出 receipt 详情、Linux CI 修复。
- v0.1.5(2026-08-16) — 轨迹计数器客户端插件(
We need… vs Let me…): 在 composer dock 实时显示首行轨迹分布,bundle 可复现构建与单测覆盖。 - v0.1.4(2026-08-16) — 融合 dsh-anchored-standard 的锚定首请求:
新会话首个模型请求仅暴露控制平面工具,首个信号后自动晋升完整委派面;
$DSH_ORCHESTRATION_BOOTSTRAP可关闭/自定义。 - v0.1.3(2026-08-16) — 完成门禁 + 审查闭环 + pytest 分层减量 +
broker_route路由工具:任务状态自动派生 (PLANNED → RUNNING → IMPLEMENTED → VERIFIED → COMPLETE),Oracle 复审 BLOCKED 机械阻断该任务后续委派;测试 receipt 支持[risk=R0-R3,exit,counts,fail]注解、同 fingerprint 重复验证机械标记、 每任务 receipt 预算;Fixer 内置 R0-R3 风险分层 / 变更测试选择 / 失败分类 规则,Observer 不再重跑 Fixer 已验命令。 - v0.1.2(2026-08-16) — P1/P2:ArtifactStore 持久化(结果/状态落盘,
崩溃恢复与任务 replay)、workspace fingerprint、测试 receipt 提取与去重
查询、自定义角色注册(
roles.json)、预算环境变量配置、npm run status/npm run metricsCLI。 - v0.1.1(2026-08-15) — 机械编排运行时(OrchestrationBroker):单写者
锁改为 workspace 粒度并修复 ask 审批洞、TASK_ID 协议、每任务预算机械
强制、envelope 结果门禁(坏信封被 block)、
broker_status报告工具; 构建/安装适配(YAML 安全、force 整目录替换)。
更新细则(v0.1.6)
本版本为最终版,主要修复上一轮审查发现的问题:
- 自定义角色运行时可见:新增
runtime-catalog.mjs;dist 构建复制内置目录,npm run build:local按roles.json重新生成。orchestration.mjs从该目录 展开 Orchestrator allow-list,自定义subagent_<id>不再被根代理边界隐藏。 - 自定义 executor 可写:
roles.json的权限现在支持显式write/edit布尔开关;声明后可获得写工具,并自动进入单写者锁集合。 - 并行预算预留:broker 在
tools/pre-executegate 阶段即预留任务总委派、 每 specialist 尝试、连续失败容量;settle / 取消 / deny / throw 路径按 token 释放,并行委派无法再绕过 12/3/3 机械上限。 - workspace fingerprint 内容哈希:
git status --porcelain从长度改为 sha256 哈希;Observer / 非 writer settle 时重新采样,外部改动不会再被 误判为“同一 workspace”。 - 持久化即时可读:
broker_status/snapshot()会先加载$DSH_ORCHESTRATION_HOME下的持久化状态,进程重启后无需先触发委派即可查看。 - broker_status receipt 详情:现在输出每个 receipt 的 risk / exit / success / fingerprint / result,Fixer 与 Observer 跑测试前可据此决定是否跳过。
- 测试与 CI 修复:Linux 下
tests/artifacts.test.mjs不再失败;renderComposition(root)尊重传入 root;路由表头不再重复渲染。 - CLI 兼容自定义角色:持久化状态记录
writerTools,status/metricsCLI 对自定义 executor 的状态推导一致。
灵感来源
本项目是对 oh-my-opencode-slim (opencode 平台的精简多智能体套件)在 DeepSeek Harness 上的移植与适配。
| 概念 | oh-my-opencode-slim(opencode) | 本项目(DeepSeek Harness) |
|---|---|---|
| 模式/Agent 定义 | opencode.json + markdown 模式文件 |
agent.cordis.yml 组合文件 + prompts/*.md |
| 子代理 | 内置 task 工具 + 模式切换 |
@deepseek-ai/dsh-tool-subagent 委派工具 × 6 |
| 权限隔离 | 每模式 allow/deny 工具列表 |
每子代理 toolFilter → 编译为 tools.restrict() |
| 委托深度限制 | 角色内配置 | 宿主 maxDepth 机制 |
| 模型混用 | 每 Agent 指定 model | agentOptions(provider/model/maxTokens) |
| 宿主 | opencode | DeepSeek Harness(零侵入,纯增量 preset) |
设计文档中的角色分工(Orchestrator 路由、信息生产者/决策者/执行者分离、 envelope 返回协议)均与 oh-my-opencode-slim 一脉相承,并利用 DSH 的 原生能力做了机械化的权限强制。
特性
- 🎛️ Orchestrator 控制平面:理解目标、拆解任务、路由调度、整合结果、向用户汇报
- 🔍 Explorer:仓库静态事实(文件、符号、调用链、结构、已有模式)
- 📚 Librarian:外部知识(官方文档、第三方库、API、版本、标准)
- 👀 Observer:运行事实(测试输出、日志、已有截图、UI 输出、复现)
- 🧠 Oracle:深度技术推理(根因、架构权衡、并发、安全、性能)
- 🎨 Designer:视觉/交互判断(UI/UX、布局、可访问性、规范输出)
- 🔧 Fixer:执行修改(唯一拥有 write/edit 的代理)
- 🛡️ 权限隔离:工具面由
toolFilter机械强制,非仅提示词约束。只有 Fixer 拥有 write/edit 工具;Explorer 与 Observer 仍保留可执行 shell(bash/pwsh),因为 DSH 权限层无法表达只读 shell——它们“只读”完全依赖 prompt 纪律,并非权限层强制。所以不要用无条件的“只有 Fixer 能修改”来描述:可执行 shell 的代理在技术上仍可经 shell 写文件,只是被 prompt 禁止 - 🚫 禁止代理图:
maxDepth: 1+ 过滤器双重保证 specialist 无法再生成代理 - ⚙️ 模型混用:每个 specialist 可独立配置 provider / model / maxTokens
- 🔌 零侵入:不修改宿主任何文件,卸载即删目录
- 🧮 机械编排运行时(OrchestrationBroker):workspace 粒度单写者锁(审批期间保持)、每 TASK_ID 预算(12 委派 / 3 尝试 / 3 连续失败硬停)、envelope 结果门禁(坏信封被 block)、
broker_status只读报告——全部在真实工具链上机械强制 - ✅ 完成门禁 + 审查闭环:broker 按记录自动派生任务状态
PLANNED → RUNNING → IMPLEMENTED → VERIFIED → COMPLETE;完成前必须 Fixer SUCCESS + Observer SUCCESS +(咨询过 Oracle 时)Oracle SUCCESS;Oracle 复审 BLOCKED 会机械阻断该 TASK_ID 的全部后续委派 - 🧭
broker_route路由工具:Orchestrator 可随时把子问题文本交给与提示词同源的评分模型,拿到建议角色与候选(advisory,不强制) - ⚓ 锚定首请求(anchored bootstrap):融合 dsh-anchored-standard 的机制——新会话的第一个模型请求只暴露控制平面工具(read/grep/glob/ask/todo/broker_*,8 个),首个回复或首次工具调用后自动晋升完整 16 工具面(含全部委派工具),首轮成为干净的"理解任务"回合;恢复会话与 one-shot 子代理恒不锚定。
$DSH_ORCHESTRATION_BOOTSTRAP=0关闭,JSON 数组自定义 - 🧾 测试 receipt 分层与去重:VERIFICATION/OBSERVED 支持
[risk=R0-R3,exit,counts,fail]注解;Fixer/Observer 先查broker_status避免重跑相同命令;同 fingerprint 的重复验证被机械标记;每任务报告式 receipt 预算(默认 12 条);风险分层/变更测试选择/失败分类规则内嵌 Fixer prompt - 💾 持久化(可选):设置
$DSH_ORCHESTRATION_HOME后,每次委派的结果全文与解析元数据、会话状态(预算/结果/receipts/fingerprint/任务状态)自动落盘——支持崩溃恢复、任务 replay 与质量统计 - 🧩 自定义角色(本地构建):
roles.json声明新 specialist(write/edit显式开启后可成为真正可写 executor),npm run build:local合并为额外的委派工具并同步进 Orchestrator allow-list 与单写者锁,隔离保证与内置六角色一致 - 📊 状态/指标 CLI:
npm run status/npm run metrics从存储渲染运行状态(含任务状态与 receipt 分层)与历史质量指标 - 🎛️ 多模型子代理:每个 specialist(含自定义角色)可经
model-routing.json独立配置 provider / model / maxTokens——Explorer 用轻量快模型、Oracle/Fixer 用强模型,互不影响
快速开始
环境要求
- DeepSeek Harness(Web 界面,默认 http://127.0.0.1:3080)
- Node.js ≥ 22(仅构建/安装脚本需要,运行时不需要)
安装
方式一:直接使用已构建的 preset(推荐,无需构建)
# 把 preset 目录复制到 DSH 用户目录
$dsHome = if ($env:DSH_HOME) { $env:DSH_HOME } else { "$env:USERPROFILE\.dsh" }
Copy-Item -Recurse .\preset\orchestrator "$dsHome\.agent-presets\orchestrator"
方式二:通过脚本安装(自动构建 + 复制)
node scripts/build.mjs # 从 src/ + prompts/ 生成 preset/orchestrator/
node scripts/install.mjs # 复制到 $DSH_HOME/.agent-presets/orchestrator/
方式三:npm 包(需先将包发布到 npm registry 后方可使用)
npm pack dsh-multi-agent-orchestrator # 或 clone 仓库
tar -xzf dsh-multi-agent-orchestrator-*.tgz
node package/scripts/install.mjs
启用与切换(Web 界面)
安装后无需重启,Web 界面实时读取 $DSH_HOME/.agent-presets/。两种启用路径:
- 按会话启用:打开“新会话”界面(composer 上方),在 Agent preset 选择 chip(位于 workspace 选择旁边)中点击,选择 多智能体编排, 然后开始会话。该选择只影响这一个会话。
- 设为默认:设置(Settings)→ General → Agent preset → 选择 多智能体编排 → 点击 Set as default。之后新建的会话默认使用该模式。
切换回标准模式:同样路径选择 标准模式(standard) 即可。
注意:preset 在会话创建时固定。已产生内容的会话不能中途切换 preset (工具目录会与历史日志不一致);空白会话可在创建后、首次输入前切换。
卸载
$dsHome = if ($env:DSH_HOME) { $env:DSH_HOME } else { "$env:USERPROFILE\.dsh" }
Remove-Item -Recurse "$dsHome\.agent-presets\orchestrator"
删除目录即完成卸载,宿主恢复原样,不影响任何其他模式。
验证安装
node scripts/validate.mjs # 真实 loader 方言解析 + 行名解析 + 过滤器校验
node --test # 测试套件(含真实挂载集成测试)
node scripts/smoke-mount.mjs # 真实启动 harness 并挂载 preset 的集成验证
使用指南(速查)
完整步骤见上文的“快速开始”与下文的“详细使用说明”;这里是常用命令速查。
| 场景 | 命令 / 操作 |
|---|---|
| 直接安装已构建 preset | 复制 preset/orchestrator/ 到 $DSH_HOME/.agent-presets/orchestrator/ |
| 重新构建标准版(不读本地配置) | node scripts/build.mjs |
重新构建本地版(读 model-routing.json / roles.json) |
npm run build:local |
| 安装 / 覆盖安装 | node scripts/install.mjs --force |
| 启用模式 | Web 会话的 Agent preset chip 选择“多智能体编排”,或在 Settings 设为默认 |
| 验证安装 | npm run validate → npm test → npm run smoke |
| 配置多模型子代理 | 复制 model-routing.json.example 为 model-routing.json,再 npm run build:local |
| 配置自定义角色 | 新建 roles.json + prompts/<id>.md,再 npm run build:local |
| 开启结果/状态持久化 | 设置 $DSH_ORCHESTRATION_HOME,用 npm run status / npm run metrics 查看 |
| 覆盖预算 | 设置 $DSH_ORCHESTRATION_BUDGETS='{"maxDelegationsPerTask":20,...}' |
| 关闭/自定义锚定首请求 | 设置 $DSH_ORCHESTRATION_BOOTSTRAP=0,或给 JSON 工具数组 |
| 日常委派纪律 | 每次委派首行写 TASK_ID: <id>;重试沿用 id,新子问题换新 id |
| 查询任务状态 | Orchestrator 调 broker_status;Fixer/Observer 跑测试前先查 receipt |
客户端插件:轨迹计数器(We need… vs Let me…)
融合 dsh-anchored-standard 的测量口径后,会话的「首行轨迹」现在可以直接在 界面上看到:
- 位置:与宿主状态行(
10 轮 · 396 步 | LLM … | 首 token 平均 … | 缓存命中 … | 输入/输出 tok)同一条 composer dock,紧随其后渲染; - 内容:
We need… 12 (63%) · Let me… 3 (16%) · 其他 4 (21%),绿/琥珀/灰 圆点区分,hover 显示完整明细;随会话实时更新; - 口径:当前会话每条
assistant/message的首行分类 (We need/We've/We're…→ we;Let me/Let's…→ let;其余 → other), 与 dsh-anchored-standard 的轨迹测量一致——直接观察锚定/晋升后的风格分布; - 实现:
client/trajectory-counter/(npm 包dsh-trajectory-counter): 客户端插件(dsh.client声明 +__ModuleLoader__bundle),注册到conversation.composer.dock槽(idtrajectory-counter,order 10,紧随 宿主 stats 之后);分类逻辑在src/classify.js(纯函数,单测覆盖), bundle 由scripts/build-client.mjs生成(可复现,测试门禁)。
安装客户端插件
npm run build:client # 生成 client/trajectory-counter/client/client.js
node scripts/install-client-plugin.mjs # 复制包到部署的 node_modules(支持 --checkout 指定)
然后(宿主只为已注册的 loader 条目服务客户端 bundle):
- 在部署中注册
dsh-trajectory-counter插件条目(部署的插件管理 /dsh plugin,或启动配置加一行); - 重启 DeepSeek Harness;
- 验证 boot manifest 出现
/plugins/dsh-trajectory-counter/client.js; - 打开会话,composer dock 的状态行旁即可看到计数。
槽名 conversation.composer.dock 与 rc.6 运行实例的 conversation 包逐字核对
一致(该槽即宿主 StatsLine 的注册位置)。若未来宿主升级改名,只需同步
src/component.cjs 中的槽名并重新 build。
详细使用说明
1. 工作流
Orchestrator 强制执行:
facts before decisions
decisions before actions
actions before verification
verification before completion
- 理解 — 复述目标,仅对用户拥有的选择提问
- 调查 — 并行委派 Explorer / Librarian / Observer
- 决策 — 根因/设计复杂时,先把证据交给 Oracle(技术)或 Designer(视觉)
- 执行 — 目标明确后委派 Fixer(携带问题、文件、根因、期望行为、约束、验收标准、验证步骤)
- 验证 — Fixer 完成后由 Observer 或测试确认
- 汇报 — 总结发现、变更、验证、不确定性、下一步
2. 委派协议(envelope)
每个 specialist 返回统一信封:
STATUS: SUCCESS | PARTIAL | BLOCKED | NOT_APPLICABLE
SUMMARY:
FINDINGS:
EVIDENCE:
UNCERTAINTIES:
RECOMMENDED_NEXT_STEP:
- Fixer 追加
CHANGES:/VERIFICATION: - Observer 追加
OBSERVED:/EXPECTED:/DIFFERENCE: - Designer 输出可交给 Fixer 的
SPECIFICATION:(组件、当前问题、期望 行为、布局、间距、排版、响应式规则、交互、无障碍、验收标准) - 信息不足返回
UNKNOWN/BLOCKED,禁止编造;Fixer 发现根因与输入不符时 停止扩大修改并以STATUS: BLOCKED返回,附REASON:字段说明为何被阻塞
3. 权限矩阵
每个代理的工具面(allow 列表;未列出的一律不可见):
| Agent | Read | Search | Web | Shell | Edit | Jobs | Ask user |
|---|---|---|---|---|---|---|---|
| Orchestrator | read, read_image | grep, glob | web_search | — | — | — | ask_user_question |
| Explorer | read, read_image | grep, glob | — | bash/pwsh* | — | — | — |
| Librarian | — | — | web_search | — | — | — | — |
| Observer | read, read_image | grep, glob | web_search | bash/pwsh* | — | job_* | — |
| Oracle | read, read_image | grep, glob | web_search | — | — | — | — |
| Designer | read, read_image | grep, glob | web_search | — | — | — | — |
| Fixer | read, read_image | grep, glob | web_search | bash/pwsh | write, edit | job_* | — |
* Explorer 与 Observer 的 shell 是“只读纪律”:DSH 无法在权限层表达只读 shell(属已知限制),它们的 prompt 硬性限制为非变更/观测命令;可变更工具 (write/edit)在权限层被移除。Designer 与 Oracle 无 shell。
要点:
- 只有 Fixer 拥有 write/edit 工具;Explorer 与 Observer 拥有 shell,但
仅凭 prompt 纪律保持只读(DSH 权限层无法表达只读 shell,属已知限制);
只有 Orchestrator 拥有
subagent_*委派工具与ask_user_question - 边界安装失败时 fail-closed:
agent/created监听内同步 throw 会否决 该代理发布——工具注册表不可用时拒绝创建根代理,绝不 fail-open 运行 - 所有过滤器均为 allow 白名单(deny-by-default)
bash仅在非 Windows 注册、pwsh仅在 Windows 注册;含 shell 的过滤器 生成!!js process.platform === 'win32' ? [...] : [...]表达式,由 loader 激活时求值,避免tools.restrict()对未注册工具名抛错- Orchestrator 自身被边界行(
orchestration.mjs)限制为控制平面集合, 不能写文件、不能跑 shell、不能直接执行
4. 路由策略
Orchestrator 的 prompt 内嵌路由表(由 src/routing/policy.js 渲染,
测试与提示词共享同一来源):
| Specialist | 何时使用 |
|---|---|
| Explorer | where / which file / implementation / call chain / repository structure / existing pattern / configuration |
| Librarian | documentation / third-party library / framework behavior / API / version compatibility / standards |
| Observer | screenshot / runtime behavior / UI rendering / test output / console / network / logs |
| Oracle | multiple solutions / high-risk change / complex root cause / architecture tradeoff / concurrency / security / performance |
| Designer | UI / UX / layout / interaction / accessibility / visual consistency |
| Fixer | 仅当修改目标/根因/验收标准明确时 |
核心纪律:模糊的 bug 报告先调查后修复(route() 对无明确目标的任务回退
到调查代理);信息代理之间冲突时,证据交给 Oracle 而非自行裁决。
5. 为不同 Agent 配置不同 provider / model
把 model-routing.json.example 复制为 model-routing.json 并修改,然后
用本地构建模式重新构建安装(见下方要点:普通 npm run build 的 dist
模式故意忽略本地的 model-routing.json):
Copy-Item model-routing.json.example model-routing.json
# 编辑 model-routing.json:为每个 specialist 指定 provider / model / maxTokens
node scripts/build.mjs --local # 或等价的 npm run build:local
node scripts/install.mjs --force
{
"explorer": { "provider": "deepseek-official", "model": "deepseek-v4-flash", "maxTokens": 8000 },
"librarian": { "provider": "deepseek-official", "model": "deepseek-v4-flash", "maxTokens": 4000 },
"observer": { "provider": "deepseek-official", "model": "deepseek-v4-flash", "maxTokens": 8000 },
"oracle": { "provider": "deepseek-official", "model": "deepseek-v4-flash", "maxTokens": 16000 },
"designer": { "provider": "deepseek-official", "model": "deepseek-v4-flash", "maxTokens": 8000 },
"fixer": { "provider": "deepseek-official", "model": "deepseek-v4-flash", "maxTokens": 12000 }
}
要点:
model-routing.json已在.gitignore中(可包含密钥相关配置);示例文件model-routing.json.example随仓库分发- provider 必须已在宿主中注册(如
deepseek-official,或通过 Settings → Models 配置的 pi-ai 等适配器),model 必须是该 provider 提供的 模型名。未配置的 specialist 保持继承 Orchestrator 的路由 - 三个字段(provider / model / maxTokens)全部必填——这是
dsh-tool-subagent的 schema 要求,缺失会构建失败 maxTokens是该 specialist 单次输出的上限;oracle这类深度推理角色建议 给更大预算,librarian这类短查询角色可以收紧- 构建模式区分(重要):
npm run build(dist 模式)刻意不读取任何model-routing.json——它生成的是随仓库提交、CI 验证的标准继承 preset (所有 specialist 继承 Orchestrator 的 provider/model)。只有npm run build:local(即node scripts/build.mjs --local)才会读取本地的model-routing.json,把agentOptions写入每个委派行,用于个人按 specialist 定制路由。本地模式不会改变 dist 构建产物,两者互不影响 - 因此:配置完
model-routing.json后必须用本地构建再安装;否则沿用 文档命令npm run build(dist)时,你的路由配置不会生效,specialist 仍 全部继承 Orchestrator 的路由
6. 自定义提示词与权限
- 提示词:编辑
prompts/*.md(七个代理各一个),然后node scripts/build.mjs && node scripts/install.mjs --force - 权限:编辑
src/permissions/agent-permissions.js(每个代理的 allow 列表),然后重新构建安装 - 路由规则:编辑
src/routing/policy.js(ROUTING_RULES数组), 路由表会自动渲染进 Orchestrator 的 prompt - Agent 目录:编辑
src/agents/catalog.js(工具名、persona 文件、 委派参数)
7. 项目结构
preset/orchestrator/ # 生成的可安装 preset(可直接复制使用)
├── agent.cordis.yml # 组合文件:Orchestrator persona + 六个委派工具 + 边界行
├── preset.yml # 显示元数据(选择器中的名称/描述)
└── orchestration.mjs # 边界行:agent/created 时收紧根代理的工具面
prompts/ # 七个代理的系统提示词(Orchestrator + 6 specialists)
src/
├── agents/catalog.js # 六个 specialist 的定义(工具名、persona、过滤器)
├── config/ # schema 校验、默认值、模型路由、组合 loader
├── orchestration/orchestration.mjs # 边界行(根代理工具收窄;零依赖)
├── permissions/agent-permissions.js # 每代理权限矩阵(唯一事实来源)
└── routing/ # 路由规则 + scoreTask/route + envelope 模板
scripts/ # build / install / validate / smoke-mount
tests/ # 测试套件(node:test)
.github/workflows/ci.yml # GitHub Actions:build + validate + test
8. 架构说明
- 模式 = DSH agent preset:DSH 原生机制,会话代理的工具、提示词、能力 由 preset 组合文件决定;Web UI 有原生选择器
- specialist = 委派工具实例:每个 specialist 是
@deepseek-ai/dsh-tool-subagent的一个实例,自带专属 persona、toolFilter、maxDepth;子代理通过宿主ctx.subagents生成,上下文完全隔离(spawn,不继承父对话) - maxDepth: 1:Orchestrator(深度 0)可生成 specialist(深度 1);
specialist 再试图生成任何代理会被宿主拒绝(深度 2 > 1)——加上过滤器
不暴露
subagent_*工具,双重机械保证 - 边界行 orchestration.mjs:监听
agent/created,只对根代理调用agent.ctx.tools.restrict(...),把 Orchestrator 收窄为控制平面 - 零侵入:不修改宿主行、不覆盖 provider/MCP、不动 shipped 预设、 不写 profile patch 层
9. 测试
node --test
| 测试文件 | 覆盖 |
|---|---|
routing.test.mjs |
路由策略:模糊任务不直接路由 Fixer |
permissions.test.mjs |
权限矩阵:Explorer 不能写、Librarian 仅 web、Fixer 可写且唯一、Designer 无 shell、任何 specialist 看不到 subagent_* |
delegation.test.mjs |
六个委派工具 spawn 语义、maxDepth 1、边界行只收窄根代理、preset 行只导入同目录兄弟模块 |
model-routing.test.mjs |
每 Agent 模型路由配置的加载与校验、agentOptions 的 YAML 安全引号发射 |
envelope.test.mjs |
信封状态与字段校验(v2 多行协议):parseEnvelope/isKnownStatus/extractTaskId 接受四个标准状态与 TASK_ID,拒绝未知/缺失/重复字段,多行 CHANGES/VERIFICATION/SPECIFICATION 段完整捕获,缺可选 section 给 warning |
handoff.test.mjs |
handoff 委派提示词渲染:role-specific 约束 + 每个委派首行声明 TASK_ID + 内嵌信封模板 |
broker.test.mjs |
OrchestrationBroker 单元:workspace 键写锁与所有权、TASK_ID 门禁、每任务预算/重试/连续失败、envelope 门禁(含角色证据段)、receipt 注解解析与重复验证检测、workspace fingerprint、持久化恢复、任务状态派生与 Oracle 审查阻断、rootSessionKey、预算 env 解析 |
artifacts.test.mjs |
ArtifactStore 单元:落盘/读取/列表/内容哈希、启用语义(仅 $DSH_ORCHESTRATION_HOME)、损坏状态降级、会话枚举 |
roles.test.mjs |
自定义角色:roles.json 加载/校验(id 冲突、toolName 派生、权限键)、dist 不读 / local 合并、隔离配置一致 |
orchestration.test.mjs |
控制平面运行时机制:fail-closed 边界安装 + 单写者守卫(workspace 粒度、ask/deny 保持锁、throw 释放、完成/错误路径解锁) |
harness-compat.test.mjs |
无 host patch 层、不改宿主行、无 provider/MCP 行、确定性构建、工具结果裁剪预算(20000/12000/3000) |
mount.test.mjs |
真实集成:启动 harness、挂载 preset、断言组合激活与边界生效、真实工具链探针(并发 Fixer 被拒、坏 envelope 被 block、ask 审批期间锁保持) |
暂存问题 / 限制与已知问题(v0.1.6 最终版)
以下问题在最终版中暂存(pending),不再安排官方修复。由于开发者已无 Money 承担 DeepSeek API,请自行解决或 fork 处理。
暂存问题速览
- Explorer / Observer 的 shell 不是权限层只读——理论上可经 shell 写文件; 在 approval=never 且 sandbox=workspace-write 的部署中风险更高。
- 无跨进程全局锁——单写者锁与 broker 状态均为进程本地,多进程同项目仍可能并发写。
- Observer 不能截图 / 驱动浏览器——只能读已有图片、日志、测试输出。
- 无 continuable / 后台委派——六个 specialist 均为 one-shot,并行靠同消息多工具调用。
- web_fetch 未启用——保持宿主默认 SSRF 防护;且无法经
toolFilter下发给子代理。 - 无真实模型端到端测试——CI 只验证挂载 / 权限 / 工具链探针,不跑付费 LLM 回合。
- 工具结果整体裁剪——pruner 无字段排除,长结果连同 envelope 一起裁剪。
- 动态模型选择 / Web 运行面板未实现——模型路由为构建期静态
agentOptions。
以下限制都是如实记录,而非未支持的借口——它们来自当前 DSH rc 版本的真实 能力边界,或是有意的架构取舍。
版本兼容性(DSH 与 npm 生态)
- 本项目构建并测试于
@deepseek-ai/dsh@0.1.0-rc.6(dsh-base、dsh-tool-subagent、dsh-compaction-tool-result-pruner均为0.1.0-rc.6)。rc 阶段的 API 具有波动风险:任一底层包的接口调整都 可能影响本 preset,升级前请先跑npm test与scripts/smoke-mount.mjs。 - 更早的
0.0.1-rc.1 / rc.3这条线无法从公共 npm 安装(依赖树损坏), 因此不在支持范围内。请使用0.1.0-rc.x及以上。
运行时调度是“模型跟随 + 机械门禁”
- 路由表 + ROUTING PRECEDENCE(风险门 → 明确目标 → 信号强度 → 默认
Explorer)是内嵌在 Orchestrator prompt 里的纪律。
route()/scoreTask()是 CI 验证的参考实现,不是运行时钩子——它们不参与实际 分发决策。 - 机械门禁由
orchestration.mjs+broker.mjs在真实工具链上强制(在tools/pre-execute/tools/execute/tools/post-execute瀑布中):- TASK_ID 协议:每次委派 prompt 必须以
TASK_ID: <id>开头;缺失即 在门前被机械 DENY。 - 每任务预算:每个 TASK_ID 最多 12 次委派、每个 specialist 每任务最多 3 次尝试、每任务 3 次连续非 SUCCESS 后机械停止;换新 TASK_ID 即重置。
- envelope 门禁:每次委派返回后,结果文本被机械解析并校验 (多行 CHANGES / VERIFICATION / SPECIFICATION / OBSERVED 等段均支持); STATUS / SUMMARY / TASK_ID 缺失、TASK_ID 与 prompt 不一致、重复段、 SUCCESS 但缺少角色证据段(Fixer 的 CHANGES+VERIFICATION、Observer 的 OBSERVED、Designer 的 SPECIFICATION)都会被 block 并以错误形式返回 给 Orchestrator,不会当作成功结果。
- broker_status 工具:Orchestrator 可随时读取每任务预算、尝试次数、 连续失败数与最近结果。
- TASK_ID 协议:每次委派 prompt 必须以
parseEnvelope()/renderDelegationPrompt()不再是纯参考工具:解析器 已接入 post-execute 真实执行路径(上述 envelope 门禁),委派提示词模板 也内嵌 TASK_ID 协议。route()/scoreTask()仍只供 prompt 渲染与测试。
TASK_ID 协议
- 每个子问题一个
TASK_ID(如t1、t2…),重试/追问沿用同一 id, 新子问题开新 id。broker 以 (session, taskId) 为键记录预算与结果; envelope 必须原样回显 prompt 里的 TASK_ID,否则被机械拒绝。 - 这是“任务边界”的机械近似:id 分配纪律仍由 prompt 约束(滥用同一 id 会合并预算;换 id 绕过预算属于违规用法)。
子代理皆为 one-shot
- 六个 specialist 均为 one-shot:每次调用都把上下文重新转录给子 代理,子代理不保留跨调用会话。
- 未开启 continuable 会话。DSH 的 continuation 机制把跟随子代理的
send_message工具注册在一个 continuable 子代理开始之后,而 Orchestrator 的 allow-list 边界在会话设置时就安装完毕;tools.restrict()在 restrict 时就对当前未注册的名字抛错(dsh-tools/lib/index.js:2777-2785), 且restrictableNames只覆盖继承/全局层工具(dsh-tools/lib/types/index.js:504-508)。 因此send_message无法被加入 Orchestrator 的 allow-list,continuable 子代理 将无法被 Orchestrator 触达——这是架构性限制,未实现。 - 并行是通过一条消息内多个 one-shot 工具调用实现的(见 prompt)。
工具结果裁剪预算
- 结果裁剪预算为 thresholdChars 20000 / headChars 12000 / tailChars 3000, 对**整个结果(含 envelope)**生效。DSH 的 pruner 没有字段排除机制 (无法只保留 envelope 而裁剪正文),因此六个 specialist prompt 都被指示 保持简短输出、把 envelope 与关键证据放在 head 窗口内(详见各 prompt 的 Brevity 小节)。
单写者(single-writer)
- Fixer 委派由机械守卫 + prompt 规则双重串行:
orchestration.mjs在tools/pre-execute按规范化 workspace(会话 cwd,大小写折叠)取锁、tools/execute的finally解锁(tools/post-execute兜底),保证同一 项目上任意时刻最多一个写能力的委派在途;两个会话打开同一项目也会互相 串行,不同项目互不阻塞。 - 锁在
ask审批期间保持持有:DSH 的tools/pre-execute每次执行只跑 一次,审批通过后直接 dispatch、不会重跑 pre-execute(dsh-tools lib/index.js:3098-3130),因此审批中的 Fixer 也必须占住锁。拒绝/取消/ 通过后的释放均由 execute-finally 或 post-execute 按 token 所有权完成, 不会悬挂也不会被无关调用误释放。此行为由 smoke 真实链探针验证。 - 不存在自动 workspace 回滚。Fixer 按
TRANSACTION RULES返回完整 diff 并在PARTIAL/BLOCKED时给出明确的 keep-vs-revert 决策(可回滚则git checkout -- <files>,否则列出遗留修改的文件与原因),由 Orchestrator 决定保留还是回滚——这是文档化的显式策略,不是自动能力。
预算(经费)是机械强制 + prompt 分配纪律
- 每 TASK_ID 最多 12 次 specialist 委派、每个 specialist 每 TASK_ID
最多 3 次尝试(1 次初始 + 2 次重试)、每 TASK_ID 3 次连续非 SUCCESS
即机械停止——由 broker 在
tools/pre-execute机械 DENY(附原因),broker_status可查当前计数。TASK_ID 的分配与“何时该停”仍由 Orchestrator 的 BUDGET & TERMINATION 提示词纪律决定。
web_fetch 限制
见下方 FAQ:由 preset 行注册在 agent 平面,无法经 toolFilter / restrict
下发给子代理。此处不重复。
stub 模型 / 评估说明
- 完整的“真实模型调用”行为评估需要活的 provider。CI 验证
挂载 / 权限 / 路由 / handoff / envelope / 真实工具链门禁探针(用 stub
工具影子化
subagent_fixer驱动真实tools.execute())等机械机制; 不跑真实模型回合。 - 仓库的 devDeps 中没有可用的 stub / mock LLM provider(已检查
node_modules/@deepseek-ai),因此未提供真实调用的集成测试。
持久化 / 可观测配置(P1/P2,可选开启)
$DSH_ORCHESTRATION_HOME:设置后启用 ArtifactStore——每次委派的结果 全文 + 解析元数据落到<root>/artifacts/<session>/<taskId>/…,会话状态 (预算、结果、receipts、workspace fingerprint)落到<root>/state/<session>.json;进程重启后 broker 自动恢复该会话状态 (崩溃恢复 / 任务 replay)。未设置时运行纯内存模式,不写盘。$DSH_ORCHESTRATION_BUDGETS:JSON 覆盖预算上限,例如{"maxDelegationsPerTask": 20, "maxConsecutiveFailures": 5}。$DSH_ORCHESTRATION_BOOTSTRAP:控制锚定首请求(默认开启)——0/off关闭;1/on用默认控制平面集(8 个工具);JSON 数组 自定义首请求工具(如["read","grep","ask_user_question"])。恢复的会话 与 one-shot 子代理不受影响。晋升时工具目录变化一次,KV 前缀缓存在该点 断开(与上游行为一致)。npm run status [sessionId]/npm run metrics:从存储渲染单会话 状态(任务、结果、receipts、fingerprint、artifacts)或跨会话质量指标 (各 specialist 的 SUCCESS/PARTIAL/BLOCKED/ERROR 分布与成功率、协议 block 率、receipt 总数)。也支持--home <path>指定存储根。- 自定义角色:项目根放
roles.json(格式见docs/audit-verification-and-modification.md与src/config/roles.js头部注释),npm run build:local会连同model-routing.json一起合并 出额外的委派工具行;dist 构建永不读取它们。
其余已知限制(如实记录)
- 无跨进程全局锁:单写者锁与 broker 状态是进程本地的。同机多进程同时 打开同一项目时,进程间不能互相看到对方的锁;审计建议的 lockfile 方案 需要宿主支持,当前未实现。
- 对话内仍受 pruner 裁剪:模型看到的结果仍整体经过 pruner
(20000/12000/3000,无字段排除);但完整原文已由 ArtifactStore 保存
(开启
$DSH_ORCHESTRATION_HOME时),broker_status --includeArtifacts与npm run status可回看。 - 根代理身份靠持久化的
parentSession头判断:恢复/导入一个曾是子代理 的会话时,其头仍带parentSession,会被当作子代理而不安装 Orchestrator 边界(即不会收窄工具)。这是 rc.6 宿主没有 “活根会话”信号导致的边界情况,已记录。 - 没有机械的完成状态机:IMPLEMENTED → VERIFIED → REVIEWED → COMPLETE 的流转仍由 Orchestrator 模型执行;机械门禁只保证“坏结果进不来、预算 超不了、写不并发”。完整的任务图状态机需要宿主级调度器,超出 preset 范围。
- Explorer / Observer 的 shell 只读仍是 prompt 纪律(DSH 权限层无法 表达只读 shell),它们理论上可用 shell 写文件,从而绕过 Fixer 写锁; 这是宿主的权限模型限制,README 与对应 prompt 均已明示。
- 动态模型选择 / 运行状态面板未实现:按成本延迟动态换模型需要宿主
在 spawn 时解析路由(当前为构建期静态
agentOptions);Web 面板需要 宿主 client 插件集成。两者均超出 preset 范围,已记录。
常见问题
- 选择器里看不到该模式? 确认
$DSH_HOME/.agent-presets/orchestrator/存在且包含agent.cordis.yml;Web 端选择器实时读盘,无需重启 - 改了 prompts 没生效? prompts 在构建时内联进
agent.cordis.yml, 改完运行node scripts/build.mjs && node scripts/install.mjs --force(--force现在是整目录替换,旧版本残留文件不会存活) - 委派被 DENY 说“TASK_ID”/“budget exhausted”? 每次委派 prompt 首行
必须是
TASK_ID: <id>(同子问题复用、新子问题开新 id);预算按 TASK_ID 计数,broker_status可查当前计数。超限后要么开新子问题的 新 id,要么停止并报告。 - 结果被 block 说“envelope rejected”? specialist 未按协议返回信封 (缺 STATUS/SUMMARY/TASK_ID、TASK_ID 不匹配、Fixer SUCCESS 缺 CHANGES/VERIFICATION 等)。重新委派并明确要求完整信封;该次尝试已计入 预算。
- 测试跑了两遍 / 想避免重复 pytest? Fixer/Observer 会先查
broker_status(传taskId)再决定是否重跑相同命令;也可开启$DSH_ORCHESTRATION_HOME让 receipt 与结果全文落盘,用npm run status回看。 - 如何开启持久化 / 自定义预算 / 自定义角色? 见上文“持久化 / 可观测
配置”:
$DSH_ORCHESTRATION_HOME、$DSH_ORCHESTRATION_BUDGETS、roles.json+npm run build:local。 - 想要后台委派 / fork? 当前六个委派工具为前台 one-shot(并行通过一条
消息内多个工具调用实现)。continuable 会话因架构限制未启用:DSH 把跟随
子代理的
send_message工具注册在 continuable 子代理开始之后,而tools.restrict()对当前未注册的名字在 restrict 时就抛错,send_message无法被加入 Orchestrator 的 allow-list(详见上文“限制与已知问题”) - web_fetch 未启用? 与宿主默认一致(SSRF 防护);需要时在组合的
tool-web行打开fetch: true并挂载相应 fetch provider。注意:DSH 的web_fetch由 preset 行注册在 agent 平面,无法通过toolFilter/restrict下发给子代理(restrict只接受宿主/祖先层注册的全局工具名) - 如何贡献? 欢迎 PR:新 specialist、路由规则、权限调整、测试
最终声明
因开发者没有 Money 承担 DeepSeek 的 API,所以该版本为最后一版,有问题自行解决。
本项目自 v0.1.6(2026-08-17) 起停止维护:不再承诺新功能、修复、issue 响应或 API 适配。你仍可 fork 并自行修改,仓库采用 MIT 许可证。感谢使用。
许可证
致谢
- oh-my-opencode-slim — 本项目的角色体系与工作流设计的灵感来源
- dsh-anchored-standard — 锚定首请求 / 晋升机制(v0.1.4 融合)的机制与实测依据来源
- DeepSeek Harness — 提供全部底层能力的宿主平台
No comments yet. Be the first to write one.