deepseek-harness
deepseek-ai
DeepSeek Harness: Everything is a Plugin.
PROJECT TOPICS
INSTALL REFERENCE
dsh plugin --profile web add github:toujianjian/dsh-do
该命令指向仓库当前默认分支;尚无绑定当前 commit 的完整验证结果。
PROJECT README
Detail Optimization —— DeepSeek Harness(DSH)的细节优化插件:Claude Code 同款自主循环(含 /loop 斜杠命令)+ 断连重试参数可视化配置 + 模型循环自动截停/压缩/重发 + 侧边栏 GitHub 插件发现/一键 AI 安装 + 右键添加工作区。
项目名 dsh-DO(Detail Optimization);npm 包名因 npm 规范必须小写,为
dsh-do。源码:https://github.com/toujianjian/dsh-do
这是一个插件、一个安装包、一个配置注册行,内部包含 Host 与 Client 两端(不是多个插件):
loop_start 启动后,驱动在同一会话里一轮接一轮自动续跑,直到 loop_done(完成)、轮次预算耗尽(自动 block)、loop_cancel(取消)或用户中断。人类也可以用 /loop 斜杠命令直接驱动同一套循环。loop_start / loop_status / loop_done / loop_cancel。max_rounds(默认 20),到顶自动 block(round-limit),防失控空转。dsh-goal-round-driver 模式):agent/status idle 驱动下一轮;agent/inbox/inserted 检测竞争提示自动暂停;agent/pre-step waterfall 校验轮次预约(round 编号/内容/loop 身份),拒绝陈旧或外来轮次并归还其它已认领消息;turn/end aborted/max-tokens、agent/error、卸载时全部正确清理。loop_start 仅直接人类轮(顶层 agent + 本轮含 source.kind === 'user' 消息),拒绝子代理;loop_done/loop_cancel 仅人类轮或当前循环轮。user/message + source.kind === 'loop')为准,检查点只作提示,重放同一事件序列得到同一状态。/loop 斜杠命令(人类直接驱动)把 Claude Code 的 /loop [interval] <prompt> 语法与 DSH /goal 的控制动词合到一条命令上,人类不必再让模型代劳:
30s/5m/2h/1d,或尾部 every 20 minutes / every 2h。前导 token 优先于尾部子句(与 Claude Code 一致);every 后面不是时间表达式时按普通正文处理,所以 /loop check every PR 仍是合法目标。无间隔时默认 10 分钟;低于 1 分钟按 Claude Code 的粒度上取整到 1 分钟。intervalMs 随检查点持久化),首轮立即执行——与 Claude Code"先立刻执行一次,再按 cron 重复"一致。不写间隔则空闲即续跑。/loop(查看状态)、pause、resume、edit <objective>(替换目标、保留预算)、done [summary]、cancel [reason](clear 为别名)。/loop <objective> 会整条替换(新目标、新预算、新节奏)并明确告知——/loop <objective> 的语义就是"跑这个目标",不该悄悄留下旧目标。/loop edit <objective> 则保留已用轮次,用于中途修正目标。armed 的循环永不被覆盖(先 edit/pause/clear)。tools/post-execute,对每个 agent 统计连续相同工具调用;参数先做深度键排序再比较,所以属性顺序不同不算差异,数组顺序不同则算。真实人类消息(agent/pre-step 中 source.kind === 'user')会重置链条与干预预算。agent.cancel({kind:'hook'}) 中断该轮 → await whenIdle() → ctx.compaction.compactNow() 压缩历史 → agent.followup() 重发请求,提示词告知模型"刚才那个重复调用不是有效下一步"。maxInterventions 限制单轮干预次数,到顶后降级为提示,防止恢复流程自己变成循环。max-tokens 结束(回答被输出 token 上限截断)时,不再暂停循环,而是追加一轮 <output_limit_continue>,要求模型从断点接着写、不要重来。maxContinuations 次就停下,按原有方式暂停循环并写 <loop_paused> 提示(原因写明"连续 N 次撞上限"),防止失控的超长回答无限续写。正常结束的回合或一条真人消息会把计数清零。agent/request-error 瀑布上,并且先调用下游:提供方自己的重试策略(dsh-llm-retry)照常对同一模型退避重试;只有它放弃之后才切换。agent/request 瀑布落地,以 prepend 注册为最外层,所以会话自己的模型选择先解析,再被替换 provider/model;旧模型的 reasoningEffort 会被去掉,避免新模型不支持。RATE_LIMIT(429)、QUOTA、SERVER、TIMEOUT、TRANSPORT、EMPTY_RESPONSE;鉴权失败(INVALID_CREDENTIAL)、上下文超长(CONTEXT_WINDOW_EXCEEDED)默认不切,因为换模型通常解决不了。dsh-llm-retry 本身无配置)实际位于各 provider 适配器配置里,由路由注册时捕获:llm-pi-ai 命名空间的 providers.<id>.retryPolicyllm-deepseek 命名空间的 retryPolicyagent-default-model)。可改 mode(normal/always)、maxRetries、initialDelayMs、maxDelayMs、jitterRatio。{op:'set', path:['providers','huoshan','retryPolicy']}),因此不会把整个 providers 映射物化成用户覆写,同提供方的其它字段(如 apiKey)原样保留。重置即 unset 该路径,回到组合默认。mode 是 schema 必填项,所以一次保存总是写入完整策略对象;retryableCodes 有意不写,保留适配器内置错误码列表。ctx.settings.mutate(ns, ops, expectedRevision) 保留 revision 围栏与 schema 校验,冲突返回 409 且保留草稿。sidebar.footer.action slot:GitHub Octocat 图标(内联 SVG),窄侧边栏只显图标、宽侧边栏图标 + 文字。dsh-plugin 相关仓库,结果带 AI 安装按钮。topic:/dsh-plugin 前缀只在留空浏览时作为默认查询),因此能搜到 Deepseek-Harness-EAC 这类没打标签的仓库。POST /dsh-do/ai-install → 创建全新会话并注入安装提示词 → 新会话出现在侧边栏列表,agent 自动开始安装。dsh.bundle 与产物完整可加载,再 dsh plugin --profile web add github:<owner>/<repo>,最后验证 --dump-config 并提示是否需要重启。$DSH_HOME/dsh-do-installs/install-<uuid>,DSH_HOME 未设置时用 ~/.dsh),注册为正式 DSH 工作区,并把该目录作为新会话的 cwd —— 安装 agent 只在自己独立的工作区里干活,不会跑进用户其它工作区。{{model}}/{{cwd}} 不缺值。agents.create 的 setup 里 agentPresets.mount,并把 preset id 记进 session meta),因此和普通会话一样拥有完整工具能力(bash/fs/web/…),不是一个空工具列表的裸会话。aria-label 中英匹配):右键它 → 弹出输入框 → 粘贴目录路径(Windows C:\... / POSIX /... 均可)→ 回车注册为 DSH 正式工作区(走 ctx.workspaces.create),侧边栏立即出现。env(safe-area-inset-bottom))。window.__ModuleLoader__.load 包装、CSS Modules 内联注入、跨包纯度门、sourcemap。ctx.inject 惰性挂载(不抢跑兄弟 provider),请求体有大小上限、统一 JSON 错误与 no-store 缓存策略。/loop 命令语法与渲染、模型循环检测与判定、检查点往返/原子性、设置写入请求校验与重试策略读写,加上驱动竞态、节奏等待、安装 HTTP、Client 状态与真实 Cordis 注册/卸载(node --test 覆盖 188 个用例;设置 DSH_COMPOSITION_RUNTIME_MANIFEST 后含真实 Loader 用例也一并实跑,否则该项跳过)。用户 → 模型: "帮我完成 X"
模型 → loop_start { objective: X, max_rounds: N } ← 本轮内调用,要求直接人类输入
│ 驱动记录 loop: { phase: active, armed: true },原子写检查点
▼
当前轮结束 → agent/status idle → 驱动队列 round 1 (<loop_round>)
▼
round 1 执行(模型工作、调用工具、验证)
▼
轮结束 → 模型调用了 loop_done?→ phase=completed,写检查点,停止
│ 否则:轮数 >= maxRounds?→ phase=blocked(round-limit),写检查点,停止
▼
队列 round 2 …(循环)
只支持从 GitHub 安装(构建产物已提交,无需本地构建):
npx -p @deepseek-ai/dsh dsh plugin --profile web add github:toujianjian/dsh-do
安装成功后重启目标 profile 生效。验证:
npx -p @deepseek-ai/dsh dsh --profile web --dump-config # 应出现 dsh-do 行
cordis.patch.yml 的 config)整段替换语义,覆盖时需重述全部键;这一层是 dsh-do 命名空间的 base:
| 键 | 类型 | 默认 | 含义 |
|---|---|---|---|
defaultMaxRounds |
number | 20 |
loop_start 省略 max_rounds 时的轮次预算 |
checkpointDir |
string | "" |
检查点目录;空串 = $DSH_HOME/loops(DSH_HOME 未设置时为 ~/.dsh/loops) |
persist |
boolean | true |
置 false 仅内存保存(不落盘) |
loopDetection.enabled |
boolean | true |
是否启用模型循环检测 |
loopDetection.repeatThreshold |
number | 4 |
连续相同工具调用多少次判定为循环 |
loopDetection.compact |
boolean | true |
恢复前是否压缩历史 |
loopDetection.maxInterventions |
number | 2 |
单轮最大干预次数 |
autoContinue.enabled |
boolean | true |
输出被 token 上限截断时自动继续 |
autoContinue.maxContinuations |
number | 3 |
同一段回答连续自动继续的上限,到顶后暂停循环并提示 |
autoContinue.onlyWhileLooping |
boolean | true |
只在循环运行中自动继续;false 时普通对话也会续写 |
modelFallback.enabled |
boolean | false |
模型失败时自动切换到候选模型 |
modelFallback.candidates |
string[] | [] |
候选模型,按顺序,写作 provider/model |
modelFallback.triggerCodes |
string[] | RATE_LIMIT, QUOTA, SERVER, TIMEOUT, TRANSPORT, EMPTY_RESPONSE |
触发切换的错误码 |
$DSH_HOME/settings.yaml 的 dsh-do: 段)在设置区 dsh-DO 面板里改的值写到这里,热生效、无需重启:轮次预算与检测策略由工具/驱动实时读取;persist/checkpointDir 变化会换用新的检查点 store(改动只影响之后写入的检查点,不会迁移或复活已有循环)。
直接改文件:settings.yaml 由 DSH 自带的 settings-file 提供方以文件监视方式读取(web 与 tui 两个 profile 都挂载),保存后约 0.1 秒内重新载入,不用重启。只写你想改的键,其余沿用默认;写错的值会被 schema 拒绝并在日志里报警,原值保持不变。最简示例:
dsh-do:
autoContinue:
maxContinuations: 5
modelFallback:
enabled: true
candidates:
- deepseek/deepseek-chat
- openai/gpt-4o
命令行改(TUI 推荐):/do-config,同时注册在 Web 的命令服务和 TUI 的 tui.commands,写入同一个 dsh-do: 段,立即生效。
| 命令 | 作用 |
|---|---|
/do-config |
列出全部设置及当前值 |
/do-config <路径> |
查看一项,如 /do-config modelFallback.candidates |
/do-config <路径> <值> |
修改,如 /do-config modelFallback.enabled on |
/do-config reset <路径> |
去掉覆写,回到默认 |
/do-config file |
显示设置文件位置 |
值的写法很宽松:布尔接受 true/false、on/off、开/关;列表接受逗号、空格、换行或 JSON 数组;路径可只写唯一的末段(candidates 等同 modelFallback.candidates)。
同一面板还能编辑断连重试策略,它写进的是提供方自己的命名空间(llm-pi-ai / llm-deepseek),不是 dsh-do:
llm-pi-ai:
providers:
huoshan:
retryPolicy:
mode: normal
maxRetries: 5
backoff:
initialDelayMs: 500
maxDelayMs: 10000
jitterRatio: 0.1
| 工具 | 用途 | 权限 |
|---|---|---|
loop_start { objective, max_rounds? } |
启动循环;已有 active 循环时:armed → 报错,paused → 用新目标整条替换(新 id、预算归零) | 仅直接人类轮;拒绝子代理 |
loop_status |
读当前循环(id/objective/phase/armed/轮次/预算/原因) | 当前驱动内的调用 agent |
loop_done { summary? } |
标记完成;循环轮内调用会注入 <loop_complete> 收尾提示 |
直接人类轮 或 当前循环轮 |
loop_cancel { reason? } |
标记取消;同上注入 <loop_cancelled> 收尾提示 |
直接人类轮 或 当前循环轮 |
工具均要求:调用 agent 处于活跃驱动、当前 turn 未关闭(复用官方 dsh-tool-goal 的权威校验模式)。
| 命令 | 用途 |
|---|---|
/loop |
查看当前循环(phase / objective / 轮次 / 节奏 + 可用动词提示) |
/loop <objective> |
启动循环;已 armed 时报错并提示改用 edit/pause/clear |
/loop 5m <objective> |
启动并按 5 分钟节奏续跑(every 20 minutes 等价) |
/loop pause / /loop resume |
停止 / 恢复自动续跑 |
/loop edit <objective> |
替换目标,保留预算与已用轮次 |
/loop done [summary] |
标记完成 |
/loop cancel [reason](clear 同义) |
取消循环 |
/loop 与四个工具驱动同一套循环状态,可混用;一个会话同时只有一个 active 循环。
dsh-do 的 Host 半在 dsh-tui(@huiliyi37/dsh-tianshu-tui)的 profile 下完整可用:该 profile 由 dsh-base + TUI 组成,agents / tools / systemPrompt / commands / settings / compaction 都在,因此四个工具、/loop、循环检测与设置存储都正常挂载;只有 Web 专属的 /dsh-do/settings 路由不安装(TUI 没有 webServer,由 ctx.inject 门控自动跳过)。
斜杠命令注册两处:DSH 的 commands 服务(Web 消费)与 TUI 自己的 tui.commands 注册表。TUI 不读前者,它自己 provide('tui.commands', …) 并在源码里注明 ctx.get('tui.commands')?.register(...) 是扩展点。dsh-do 用 ctx.inject(['tui.commands']) 等待该服务出现——Web/headless 下它永不出现,注册即静默跳过,不产生副作用。
安装到 TUI profile:
dsh plugin --profile tui add <dsh-do 的 tarball 或包名>
dsh --profile tui --dump-config # 应看到唯一的 `id: do` 行与 `id: tui-runner` 并存
下列 dsh / dsh-tui 组合都做过真实 TTY 验收(/loop 敲进去、状态栏 ◆ 循环 段渲出来),可用 test-docker/ 复现:
| dsh | dsh-tui |
|---|---|
| 0.1.0-rc.8 | 0.1.1-rc.6 |
| 0.1.5-rc.3 | 0.1.2-rc.31 |
| 0.1.7-rc.2 | 0.1.2-rc.31 |
| 0.2.0-rc.2 | 1.0.0-rc.2 |
跨版本差异已在插件内处理:
Session.events getter,改为 snapshotEvents()(整段日志)与 ownEvents()(排除 fork 继承前缀)。src/session-log.ts 按能力探测并回退,一份构建同时服务新旧两代。^0.1.0-rc.6 || ^0.2.0-rc.1。dsh 0.2.x 有版本闸门,范围不覆盖就会被拒绝装载(skipping profile bundle "dsh-do"),不是崩溃。
升级提醒:如果你在 peer 范围放宽之前装过 dsh-do,把 dsh 升到 0.2.x 后插件会被静默跳过——症状是 /do-config、/loop 一起消失(在 TUI 里敲 /do-config 会被当成普通消息发给模型,看起来像命令坏了),而 dsh 自身一切正常。重装一次即可:dsh plugin --profile <profile 名> add <dsh-do 的 tarball 或包名>;装完 dsh --profile <profile 名> --dump-config 里搜 skipping profile bundle 应为 0 条。projectStatusPanel(...) 的单行与跨行展开两种调用形状;形状再变时明确失败且不写文件。Windows 黑窗:上游 dsh-subprocess-local 从 0.1.5-rc.3 起才在 spawn 处带 windowsHide。停留在 0.1.0-rc.8 时子进程会闪黑窗,升级即消失——这一层不在本插件内。
pnpm install
pnpm typecheck # host + client 双 tsc --noEmit
pnpm build # build:host(tsc)+ build:client(tsc + tsdown → lib/client.js)
pnpm test # 完整构建 + node:test(状态/驱动/HTTP/Client/真实 Cordis/包契约)
pnpm watch # tsdown --watch(client HMR 构建)
验证分层:类型检查与构建;纯函数/文件/驱动/HTTP 测试;真实 Cordis 注册与卸载;临时 DSH_HOME 的 tarball 安装与 --dump-config(注册行 id 为 do,包名 dsh-do)。配置打印不等于完整运行。
可选真实 Loader 测试:设置 DSH_COMPOSITION_RUNTIME_MANIFEST 为本机已安装 DSH 的 package.json 绝对路径,再运行 pnpm test;未设置时该测试明确跳过。该测试不启动 Web 或调用模型,浏览器与真实安装会话仍须单独验收。
TUI 的 ◆ 循环 段由 scripts/patch-tui-status-panel.mjs 打到已安装的 dsh-tianshu-tui 上(幂等,--check 只校验,已打旧版可就地升级)。该补丁落在 node_modules 内,TUI 包升级会丢失,届时重跑脚本即可。 数据来源是 loops 服务(ctx.reflect.get('loops', false)),不是 loop 投影——投影是对会话日志的纯 fold,只含 { loopId, roundsStarted, lastRoundAt },没有目标/暂停原因;早先按投影取字段会喂 undefined 给截断器并在渲染定时器里抛错,直接掀掉整个 TUI 进程。test/tui-patch.test.mjs 用投影的真实形状钉住了这个崩法。
端到端 loop 验证(需要模型凭证):
npx -p @deepseek-ai/dsh dsh --profile web "用 loop_start 启动一个循环,目标:打印三行 hello;max_rounds 设 2;完成后调用 loop_done"
预期:第一轮完成打印 → 驱动自动队列第 2 轮 → 模型 loop_done → 循环 phase=completed,
$DSH_HOME/loops/loop-*.json 出现终止记录。
浏览器 UI 验证:重启 web profile 后:
dsh-do-install-* 新会话自动安装;$DSH_HOME/settings.yaml 出现 dsh-do: 段;huoshan)→ 改「最大重试次数」为 9 → 保存 → settings.yaml 的 llm-pi-ai.providers.huoshan.retryPolicy.maxRetries 变为 9,且同提供方的 apiKey 等字段未被改动。/loop 命令验证(需要模型凭证):在会话里输入 /loop 1m 打印一行 hello,首轮应立即执行;/loop 查看状态;/loop cancel 结束。
完整模块关系、修复记录和后续风险见 架构梳理(源码仓库文档)。根包不再依赖未接入的本地 link:dsh-loop-detector;该历史实验目录仅保留参考,不是需要额外安装的插件。其中的"模型自循环检测"思路已按 DSH 的真实事件契约重写为 src/loop-detect.ts(tools/post-execute 计数 + agent/pre-step 重置),不再使用历史实验的 @dsh-std/* 协议。
Host 半源码:src/index.ts(入口)、loop.ts(纯状态机)、controller.ts(注册表 + 检查点提交)、checkpoint.ts(原子文件存储)、driver.ts(轮次驱动 + 竞态围栏)、tools.ts(四个模型工具)、command.ts(/loop 语法与执行)、loop-detect.ts(循环检测与恢复)、settings.ts(dsh-do 命名空间)、settings-route.ts(浏览器读写桥)、prompt.ts、ai-install.ts。
Client 半源码:src/client/index.ts(入口)、github.ts(纯解析 + 请求通道)、GitHubSearchButton.tsx、doSettings.ts(纯逻辑)、DoSettingsPage.tsx(设置页)、addWorkspace.ts、AddWorkspaceDialog.tsx。
修复包括:工具输出 schema 注册失败、自动轮次与用户输入竞态、损坏检查点恢复、Client 旧请求隔离、GitHub 响应校验,以及安装请求防跨站/依赖预检/失败回滚。源码构建不会自动替换已通过 GitHub 安装的副本;升级后再重启目标 profile,不能仅重启旧安装。
aria-label 匹配现有按钮(中/英),官方若改文案需同步更新选择器。loop_cancel 或等其结束)。dsh-storage-json 同语义);多进程写同一 root 不保证。roundsStarted 以会话日志为准;无持久化后端的会话在重启后不会自动续跑(新会话 id 与已存 loop 不匹配,属预期)。loop_done",预算耗尽只是兜底;与 goal 工具一样依赖模型的完成判断。providers.<id>.retryPolicy),而 scope 的 set 只写顶层字段,且 bind() 硬依赖 connection/remote 两个客户端服务。因此读写都走本插件自己的 /dsh-do/settings 路由(与既有 GitHub/AI 安装链路同构),revision 围栏与 schema 校验仍由 Host 的 ctx.settings.mutate 承担。代价是面板不会自动跟随其它界面(如 Models 页)对同一命名空间的改动,需点「放弃修改并重新读取」。/loop 的间隔是轮次间最小延迟,不是 cron;DSH 没有重复执行斜杠命令的调度器,节奏由 dsh-do 自己的驱动实现。间隔的起点记在驱动内存里,所以进程重启后的首轮立即执行、其后才按节奏——与"先立刻执行一次"的语义一致。/loop 走 TUI 自己的注册表:dsh-tui 不消费 DSH 的 commands 服务,而是自己 provide('tui.commands', …)。dsh-do 两者都注册(Host 侧各自 ctx.inject 门控),所以在 Web 与 TUI 下 /loop 都可用;TUI 未安装时该注册静默跳过。TUI 的命令行参数提示由 TUI 渲染,dsh-do 只提供 argsHint 文本。CLASSIFICATION EVIDENCE
系统优先读取 GitHub Topics,再与站内分类词典和词根规则比对。当前命中: 无有效分类标签。