Skip to main content
Glama

omp-dsh-workers

test

从你的 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 会话,处于 /dvibe 模式

你的 OMP 会话模型

2

DSH 执行者 — 每次运行一个 DSH headless 进程

dsh_spawnmodel,否则是 @dsh 角色,否则是你会话的模型,否则是 DSH 的默认值

因此,当 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。

组件

路径

说明

extensions/dsh-task/

OMP 扩展:dsh_taskdsh_spawndsh_answerdsh_waitdsh_killdsh_senddsh_list、中继脚本(relay.ts)、/dvibe、孤儿看门狗。

tools/dsh-bridge/

bridge-core:在独立的分离进程组中启动、运行注册表、Envelope v1、引导通道、所有者租约和回收。Node ≥ 22,纯 ESM JavaScript,无依赖,无构建步骤。

plugins/dsh-headless-resume/

DSH headless 配置文件中的 Cordis 插件:添加 --resume,打印 Envelope v1,运行模型预检,读取引导通道。

scripts/

安装:符号链接到实际使用的 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-aicommander$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")切换它,该工具保留在收窄后的工具集中。

  • 开启后,工具集收窄为 readtododsh_spawndsh_answerdsh_senddsh_waitdsh_listdsh_killdvibe,外加一条追加到系统提示中的指挥者指令。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_listdsh_answerdsh_send 中找到该运行。

  • 模型记法为 <provider>/<model>[:<effort>];effort 级别:offminimallowmediumhighxhighmax。最后一个 : 之后的后缀仅当它是其中之一时才计为 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 和显式 modeldsh_spawn

指挥者看到的内容

工具卡片为人类渲染,与模型接收到的文本分开:▶ dsh spawn → <label>✓ started <label> (<runId8>) · pid …,然后是带最后输出行的 ⏳ still running,或 ✓ completed · model: … · session: … 加上首批结果行。在跟踪运行期间,编辑器上方会有一个 dsh runs 面板,页脚显示 dsh: N running · M done。工具的文本输出不变:它仍然是契约。

工具

工具

参数

调用者获得的文本

dsh_spawn

task, label?, model?, timeoutMs?, resumeFromRunId?, resumeSessionId?

started <runId> (pid <pid>),以及给出时的 label=… model=…

dsh_answer

runId / label(至少一个;两者都有时,runId 选择目标运行,label 命名新运行),外加 answer

answered <oldRunId> -> <newRunId>

dsh_wait

runId, waitMs?(默认 30000;0 = 单次轮询)

该运行的结果,或 still running: <runId>,或 wait cancelled for <runId>; run still active

dsh_send

runId, text

sent to <runId> / pending: … / NOT delivered: run ended before reading; message lost

dsh_kill

runId

kill <runId>: killed (…)kill <runId>: not killed (…)

dsh_list

no active runs,或每个运行一行

dsh_task

task, model?, timeoutMs?, resumeFromRunId?, resumeSessionId?

该运行的结果(阻塞式,一次性)

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

spawn_failed

DSH 二进制文件未能启动。

nonzero_exit

运行以失败退出码结束。

timeout

运行未在截止时间内完成。

killed

运行被取消。

malformed_output

DSH 未返回有效的 Envelope v1。

resume_not_found

不存在可恢复的会话。

resume_corrupt

持久化的会话已损坏或不受支持。

resume_busy

会话已处于活动状态,或其持久化的准备内容已被占用。

owner_gone

没有人续订运行的租约;看门狗已回收它。

deadline_exceeded

运行超过了截止时间并被回收。

model_not_found

提供商/模型不在 DSH 的目录中。

invalid_model

模型存在,但 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 在 typechecklintformat: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.10.1.0)。接口契约位于 docs/contracts/docs/dsh-update-checklist.md 涵盖 DSH 升级。用户或模型阅读的所有内容均为英文;代码内注释和测试名称为俄文。MIT 许可证.

Related MCP Connectors

Related MCP Servers