dsh-mcp
omp-dsh-workers
从你的 oh-my-pi 会话中运行 DeepSeek Harness (DSH) 工作进程。oh-my-pi (OMP) 是一个终端编码代理;DeepSeek Harness (dsh) 是 DeepSeek 的代理运行时。该会话成为指挥者:它通过 dsh_spawn 分发任务简报,每个工作进程作为持久的 dsh --profile headless 会话运行,工作进程的问题和结果以由脚本中继的原生消息形式返回。
实验性 v0.1:接口已在 docs/contracts/ 中冻结,但这里的一切都尚未经过公开发布周期。
为什么
OMP 的 harness 每个任务都很昂贵,而原生子代理会在每个任务上付出这一成本。在这里,该成本只在指挥者层面支付一次;实际工作在 DSH 中运行,快速且节省 token,两者之间只有一个脚本:每个任务的模型 token 为零。DSH 让运行持久化(在真实会话 id 上使用 --resume)。当你不需要 DSH 时,原生子代理仍然是正确的选择。
Related MCP server: dsh-crew
工作原理
两个模型层级,刻意分开:
层级 | 谁 | 模型来源 |
1 | 指挥者 — 你的主 OMP 会话,处于 | 你的 OMP 会话模型 |
2 | DSH 执行者 — 每次运行一个 DSH headless 进程 |
|
因此,当 dsh_spawn 没有 model 时,@dsh 指定执行者继承的模型——监视器是代码,而不是模型。
flowchart TD
D["Director<br/>main OMP session, /dvibe on"]
B["dsh-bridge<br/>argv spawn · run registry · steer channel"]
X["DSH headless run<br/>+ resume plugin"]
L["relay.ts<br/>script representative, in-process"]
D -->|"dsh_spawn — brief, label, model"| B
B -->|"dsh --profile headless [--resume]"| X
X -->|"Envelope v1 (last stdout line)"| B
B -->|"pollRun, 1s"| L
L -->|"⟨label⟩ question / result / failure (followUp)"| D
D -->|"dsh_answer — resumes the session"| B
D -.->|"steering: dsh_list → dsh_send / dsh_wait by runId"| B
D -.->|"dsh_kill by runId"| B指挥者使用 dsh_spawn 启动,用 dsh_answer 回答,用 dsh_send 引导,用 dsh_wait 等待,用 dsh_kill 取消;dsh_list 将标签解析为 runId。
组件
路径 | 说明 |
| OMP 扩展: |
| bridge-core:在独立的分离进程组中启动、运行注册表、Envelope v1、引导通道、所有者租约和回收。Node ≥ 22,纯 ESM JavaScript,无依赖,无构建步骤。 |
| DSH headless 配置文件中的 Cordis 插件:添加 |
| 安装:符号链接到实际使用的 OMP 目录、DSH 配置文件补丁、插件依赖链接。 |
要求
oh-my-pi v18 — 已针对 18.0.3 / 18.0.4 验证;
@oh-my-pi/*固定为^18.0.4。DSH ≥ 0.1.1-rc.2 位于
PATH上,且存在headless配置文件。bun 用于测试脚本;Node ≥ 22 用于 bridge-core。
在你的 DSH 设置中配置了模型提供商;该扩展与提供商无关:它向 DSH 传递
<provider>/<model>[:<effort>]字符串。
DSH 处于发布候选阶段。 恢复插件按 entry id 挂载,因此重命名这些 id 的发布会让补丁静默停止生效。每次 DSH 升级后重新运行 dsh --profile headless --help:如果 --resume 消失了,说明插件未挂载;docs/dsh-update-checklist.md 中有完整清单。
安装
该仓库是事实来源;实际使用的目录只会收到指向它的符号链接。
1. 将扩展链接到 OMP。
scripts/install-omp-links.sh [--dry-run] [--uninstall] [--omp-dir DIR]在 $OMP_DIR(默认 $HOME/.omp/agent)下创建符号链接 extensions/dsh-task。幂等——同源的链接保持不变,指向其他位置的链接会被重新指向,而目标位置存在真实文件时脚本会中止。--uninstall 只移除指向此处的链接。
2. 将恢复插件挂载到 DSH headless 配置文件中。
scripts/install-resume-plugin.sh # install
scripts/install-resume-plugin.sh --uninstall # remove每次更改前都会备份;需要 dsh 位于 PATH 上,并且存在 ${DSH_HOME:-$HOME/.dsh}/profiles/headless。然后:
将
@deepseek-ai和commander从$DSH_MODULES符号链接到插件的node_modules。添加插件:
dsh plugin --profile headless add link:<plugin dir>,在备份package.json之后。追加一个
cordis.patch.yml块,禁用headless-startup/headless-runner,并插入headless-resume-startup/headless-resume-runner。验证:仅当
dsh --profile headless --help提到--resume时才成功。
3.(仅测试) scripts/link-plugin-deps.sh 自行链接依赖;bun run test:resume 会调用它。
用法
指挥者模式
/dvibe切换指挥者模式;/dvibe on//dvibe off是显式形式。模型也可以通过dvibe工具(action: "on" | "off")切换它,该工具保留在收窄后的工具集中。开启后,工具集收窄为
read、todo、dsh_spawn、dsh_answer、dsh_send、dsh_wait、dsh_list、dsh_kill、dvibe,外加一条追加到系统提示中的指挥者指令。dvibe工具在其结果中返回该指令:模型在before_agent_start运行后调用它,因此回合提示无法携带这些规则。任务简报原样进入
dsh_spawn。工作进程的问题以来自relay.ts的⟨label⟩消息到达,用dsh_answer回答;结果以相同方式到达。投递是至少一次:事件每 120 秒重新宣布一次,直到匹配的
message_start证明 followUp 已进入回合上下文;每个事件最多尝试 3 次。已投递的need_input会一直保持监视,直到dsh_answer。分发完工作了?结束回合:事件会自行作为消息到达。
dsh_wait是同步替代方案,仅当下一步阻塞在该特定运行上且没有其他工作可分发时使用;以这种方式读取的信封绝不会到达两次。在
/dvibe off、关闭或进程内会话切换时,恢复之前的工具集。
任务简报、模型、恢复
为每个任务指定一个简短的
label,并可选择指定model,两者都作为dsh_spawn参数;该标签稍后可在dsh_list、dsh_answer、dsh_send中找到该运行。模型记法为
<provider>/<model>[:<effort>];effort 级别:off、minimal、low、medium、high、xhigh、max。最后一个:之后的后缀仅当它是其中之一时才计为 effort,否则冒号属于模型名称。不允许空白或控制字符;provider/model 各 ≤ 200 字符,spec ≤ 512;格式错误的 spec 会在启动前失败:error [invalid_model]。没有
model时,运行继承 OMP 的@dsh角色(modelRoles.dsh),回退到你会话的模型,再回退到 DSH 自己的默认值。恢复:传入
resumeFromRunId;bridge 查找其sessionId。不要将runId放入resumeSessionId:它们是不同的标识符,你会得到resume_not_found。一旦运行在磁盘上留下了信封,恢复即可工作;没有信封时
dsh_spawn会抛出has no session to resume——无论运行仍在进行中还是已经消失(被提前杀死、启动时崩溃、被清理)。在做出反应前先检查是哪种情况:为仍在工作的运行发送新简报会重复工作。模型覆盖不粘滞:没有
model的恢复会重新计算模型。dsh_answer根本没有model参数;要在另一个模型上继续,请使用带resumeFromRunId和显式model的dsh_spawn。
指挥者看到的内容
工具卡片为人类渲染,与模型接收到的文本分开:▶ dsh spawn → <label>、✓ started <label> (<runId8>) · pid …,然后是带最后输出行的 ⏳ still running,或 ✓ completed · model: … · session: … 加上首批结果行。在跟踪运行期间,编辑器上方会有一个 dsh runs 面板,页脚显示 dsh: N running · M done。工具的文本输出不变:它仍然是契约。
工具
工具 | 参数 | 调用者获得的文本 |
|
|
|
|
|
|
|
| 该运行的结果,或 |
|
|
|
|
|
|
| — |
|
|
| 该运行的结果(阻塞式,一次性) |
dsh_wait 超时是正常的:运行保持存活,可以再次等待;中止等待绝不会停止运行。dsh_send 返回 pending 意味着写入已到达通道,并且重新检查时运行仍然存活——并非确认投递;请等待而不是重新发送。dsh_task 不留下信封,因此其运行无法继续;链式操作通过 dsh_spawn 进行。
指挥者可以依赖的行
这些行会进入工具的文本输出,而不仅仅是 details,因此阅读纯文本的指挥者可以验证执行者、连续性和错误代码:
model: <provider>/<model>[:<effort>]
session: <sessionId>
error [<code>]: <message>
# and one line per run from dsh_list:
<runId> state=<state> label=<label|-> model=<spec|default> started=<ISO-8601>错误代码
每次失败都会以带有信封代码的显式错误回合返回,绝不会是部分成功。
Envelope code | Meaning |
| DSH 二进制文件未能启动。 |
| 运行以失败退出码结束。 |
| 运行未在截止时间内完成。 |
| 运行被取消。 |
| DSH 未返回有效的 Envelope v1。 |
| 不存在可恢复的会话。 |
| 持久化的会话已损坏或不受支持。 |
| 会话已处于活动状态,或其持久化的准备内容已被占用。 |
| 没有人续订运行的租约;看门狗已回收它。 |
| 运行超过了截止时间并被回收。 |
| 提供商/模型不在 DSH 的目录中。 |
| 模型存在,但 effort 或元数据与其不匹配。 |
默认值:运行截止时间 30 分钟;所有者租约 5 分钟,由每个 dsh_wait 窗口续订。
Tests
bun run test # unit + integration + bridge = 370 tests, no installed DSH needed
bun run test:resume # resume plugin — needs an installed DSH已验证此树上的数量:195 个单元测试 + 11 个集成测试 + 164 个桥接测试 = 370 个测试,在未安装 DSH 的情况下全部通过。单元测试模拟 bridge-core;集成测试和桥接测试针对通过 DSH_BINARY 注入的假 dsh 二进制运行。CI 在 typecheck、lint、format:check(严格 tsc、Biome)之后,使用干净的 HOME 运行相同的三个套件。test:resume 在运行时导入 @deepseek-ai/* —— 必须安装 DSH。
Limitations
孤儿进程会被清除,而非预防。 DSH 运行比 OMP 会话存活得更久;清除发生在加载时以及每 30 秒。在干净的
session_shutdown时,扩展会终止自己的运行(SIGTERM同步,SIGKILL尽力而为),但不会清除注册表。无进行中崩溃恢复:回合中途的死亡不会被恢复;只有 DSH 会话 可以恢复。
恢复时的压缩会读取上一次运行的头部,直到写入第一个新的请求头部。
信封中的
model是尽力而为的:最后准备的请求配置,而非派发的证明。模型覆盖是按运行生效的,不会跨
resumeFromRunId继承。Hub 指标看不到 DSH 令牌。
Status, history, license
实验性 v0.1(0.1.0)。接口契约位于 docs/contracts/;docs/dsh-update-checklist.md 涵盖 DSH 升级。用户或模型阅读的所有内容均为英文;代码内注释和测试名称为俄文。MIT 许可证.
This server cannot be deployed
Maintenance
Related MCP Connectors
- mcp-serverOAuthai.cdbx
Build Apps and run code in 30 languages — sandboxed, with persistent sessions for agent loops.
Shared control plane for AI coding agents — tasks, memory, decisions, file locks. 12 tools.
Live SEO workflow tools for Claude Code, Codex, and AI agents.
Turn Claude into a creative studio: DNA-locked characters, images, video, voiceover — 55 tools.
Related MCP Servers
- AlicenseAqualityBmaintenanceEnables Claude Code to delegate tasks to OpenCode subagents asynchronously, with tools for starting tasks, polling status, and fetching results.772 npm2MIT
- AlicenseNot gradedqualityBmaintenanceEnables dispatching work to DeepSeek Harness agents from Claude Code/Codex, with native progress UI, tier policy, and vision/image generation through MCP tools.602 npm149MIT
- AlicenseAqualityBmaintenanceEnables AI coding agents like Claude Code or Codex to delegate tasks to a DeepSeek Harness subagent with its own context window, providing tools for task delegation, result waiting, continuation, and supervision with sandboxed execution.6MIT
- AlicenseAqualityBmaintenanceEnables Codex and Claude Code to delegate implementation, research, debugging, and long-log work to DeepSeek Harness, then observe, continue, or cancel those sessions without leaving the primary workflow.151MIT