DeepSeek Harness Plugin Hub

Publish and manage complete Harness Profiles. Discover Plugins for your next setup.

Explore

PluginsPresetsDocsNews

Community

Publish a pluginContactReport an issue

Resources

Plugin Hub on GitHubDeepSeek HarnessSystem statusPrivacy notice
© 2026 DeepSeek Harness Plugin HubPowered byPaxTech

Independent and unofficial. Not affiliated with, authorized by, or endorsed by DeepSeek.

Dupguard — DSH Plugin for DeepSeek Harness
← Plugins

dsh-dupguard

Dupguard

Real-time repetition guard for DeepSeek Harness (DSH): stops model generation when the same string repeats >=10 times in the streamed output. 实时检测 DSH 大模型流式输出中的重复内容,同一字符串重复十次以上立即停止生成。

The plugin will be installed here. Keep web if you are unsure.

npx -y @deepseek-ai/dsh plugin --profile web add dsh-dupguard@1.3.0
READMECompatibilityVersions

Compatibility and provenance

Dupguard is published as dsh-dupguard and currently resolves to version 1.3.0. The Hub verifies its manifest and preserves the exact installation source for reproducible installs.

DSH compatibility
*
Runtime surfaces
web
Release source
npm
Registry updated
9/20/2026

Versions

1.3.0stable
9/19/2026
1.2.1stable
9/9/2026
1.2.0stable
9/8/2026

Related plugins

Loading related plugins…

Latest
1.3.0
DSH
*
HMR
Process restart
Tree shaking
Declares sideEffects: false
Unpacked size
88.3 kB
Files
8
Surface
web
License
MIT
Source
npm
GitHub
★ 1
Weekly downloads
110
Security scan
✓ v1.3.0 scan passed
Last push
9/19/2026
View source ↗Project homepage ↗
README badge

Click the badge to copy Markdown for your README.

Do you maintain this Plugin?Claim benefit · Priority security scan

Verify the GitHub repository declared in package.json to manage this listing. After you claim it, Hub will prioritize a security scan of the current version and publish the result when it passes.

Claim this Plugin →
Report an issue
DeepSeek Harness Plugin Hub
ProfilesPluginsCategoriesNewsDocsSign inManage Profiles
ProfilesPluginsCategoriesNewsDocsSign in

Related plugins

More verified plugins in models-usage.

Usage@linxin666/dsh-usageUsage statistics plugin for the dsh web GUI: per-provider balance and coding-plan quota detection plus a live token usage ledger, with a dedicated pet bubble for the current providerWhale Widgetdsh-whale-widgetDeepSeek balance whale widget in the bottom-right corner of the DSH Web interface: balance/today’s usage/peak-off-peak pricing, customizable bubble click sequence (text/balance/today/peak-off-peak/image/random phrases and parallel weighted selection), per-line styles and fonts, floating quick editinUsage Stats@ychris12138/dsh-usage-statsToken usage heatmap, provider balances, and subscription quotas for the dsh web GUICodex Connectdsh-codex-connectChatGPT OAuth and Codex models for DeepSeek Harness.

README

dupguard · DSH 大模型重复输出守卫

dupguard — a real-time repetition guard for DeepSeek Harness (DSH): stops model generation as soon as the same string repeats ≥ 10 times (configurable) in the streamed output.

dupguard 是 DeepSeek Harness (DSH) 的实时重复输出守卫插件:当最新输出中同一字符串连续重复 10 次及以上(可配置)时,立即停止本次生成。

触发后,已生成的内容会正常提交为助手消息,本轮对话干净结束——不会报错、不会丢弃输出、不会污染会话日志。

When triggered, the already-generated text is committed as a normal assistant message and the turn ends cleanly — no errors, no lost output, no session-log pollution.


特性 / Features

  • 实时检测:逐 token(text-delta)检测,复读出现即停,延迟为单个增量。
  • 多种复读形态:单字符循环、词语循环、带空格/换行分隔的复读均能识别(默认去空白后检测)。
  • 思考守卫:默认同时检测 reasoning(思考)文本,思考中的复读同样会被截停(可通过 monitorReasoning 关闭)。
  • 真正的服务端停止:提前关闭流迭代 → 适配器 consumer.abort() → 中断 HTTP 连接,模型在服务端停止生成。
  • 安全停止:绝不 abort() agent 步骤信号;补发协议合规的 block-end + finish(stop),消息正常提交。
  • Markdown 表格友好:默认忽略连字符与竖线(ignoredChars 白名单),表格分隔行与长分隔线不会被误判为复读。
  • 图形化设置页(npm 常驻版):在 DSH 设置面板注册与「通用设置 / 模型 / 插件 / Agent 预设」并列的 「重复守卫」分节,可视化编辑白名单与全部检测参数(阈值、最小/最大单元长度、检测窗口、空白与 reasoning、工具参数开关)并持久化(dsh-dupguard 设置命名空间),修改即时生效;窗口小于 阈值 × 最大单元长度时给出「窗口长度需要提高」提示。
  • 零配置开箱即用:默认配置即可用;全部检测参数均可在设置页按需调整。
  • 双入口交付:动态插件(plugin/host.js)+ npm 组合挂载(lib/index.js + lib/client.js),行为一致、CI 防漂移。
  • 内置 DSH 兼容补丁(fixStandingMountConflict,默认开启):幂等化 cordisInspect.register, 修复 DSH ≤ 0.1.2-rc.1 的 preset standing-mount 多代并存冲突(见下文"已知限制")。

快速开始 / Quick Start

方式一:动态插件(无需安装,进程内生效)/ Dynamic plugin (no install)

把 plugin/host.js 的全部内容作为 code.host 提交给 cordis_define,再 cordis_run 激活即可:

  1. cordis_define:kind 选 new,idPrefix 例如 dupguard,code.host 填入 plugin/host.js 内容;
  2. cordis_run:激活返回的 packageId(首次使用 mode run)。

动态插件随 DSH 进程存在;重启后需重新 define + run。

Paste the entire content of plugin/host.js as code.host in cordis_define, then activate the returned packageId with cordis_run.

方式二:npm 安装 + 组合挂载(常驻,随 DSH 启动)/ npm + composition (persistent)

插件已发布到 npm:dsh-dupguard。

1. 安装(DSH ≥ 0.1.2-rc.1,一条命令):

dsh plugin --profile web add dsh-dupguard

本包自带 bundle 补丁层(dsh.bundle.patch → cordis.patch.yml): dsh plugin 把参数转发给 profile 目录下的 pnpm,安装后自动把声明了 dsh.bundle 的依赖 加入 dsh.profile.bundles;DSH 按 bundles 顺序应用各层补丁,本插件的层插入宿主行 { id: dupguard, name: dsh-dupguard }。无需手改任何 YAML。

  • 验证:dsh --profile web --dump-config 末尾应出现 dupguard 行;loader 日志出现 apply plugin dupguard。
  • 升级:dsh plugin --profile web update dsh-dupguard; 卸载:dsh plugin --profile web remove dsh-dupguard(依赖与 bundles 层一并移除)。

2. 手工补丁层(旧版 DSH 或不想加入 bundles 时仍受支持):在 profile 的用户补丁层 cordis.patch.yml 自行插入同一行:

# $DSH_HOME/profiles/web/cordis.patch.yml
- insert:
    - id: dupguard
      name: dsh-dupguard

用户补丁层在 bundle 层之后应用;运行中的 DSH 通过 watchUserPatches 热重载它—— 保存即生效,无需重启,加载失败会事务性回滚。

⚠️ 两种方式不要同时使用:loader 对重复 entry id 直接抛 duplicate loader entry id: dupguard。从手工方式切换到 bundle 方式时,请删除手工 insert 项。

本地开发:未发布/调试时,name 也可直接用 file: URL 指向仓库内的 lib/index.js(CJS 导出 { name, apply },与 loader 的 unwrapExports 兼容,零构建)。

The plugin is published on npm as dsh-dupguard and ships its own bundle patch layer (dsh.bundle.patch → cordis.patch.yml). Install it with one command (DSH ≥ 0.1.2-rc.1):

dsh plugin --profile web add dsh-dupguard

dsh plugin forwards its arguments to pnpm in the profile directory and appends any dependency declaring dsh.bundle to dsh.profile.bundles; DSH then applies each bundle layer's patch in order, and this plugin's layer inserts the host row { id: dupguard, name: dsh-dupguard }. No YAML editing needed. Verify with dsh --profile web --dump-config or the loader log line apply plugin dupguard; upgrade with dsh plugin --profile web update dsh-dupguard and uninstall with dsh plugin --profile web remove dsh-dupguard.

Manual layer (still supported): without a bundles entry, insert the same row into the profile's user patch layer cordis.patch.yml; the running DSH hot-reloads that file (watchUserPatches) with a transactional rollback on failure. Do not combine both — the loader throws duplicate loader entry id: dupguard. The file: URL form also remains handy for local development against lib/index.js (CJS, module.exports = { name, apply }, compatible with the loader's unwrapExports, no build step).


配置 / Configuration

检测参数的默认值定义在 plugin/host.js 与 lib/index.js 顶部的 CONFIG(两个入口需保持同步, CI 会校验行为一致性)。npm 常驻版:下表参数除 fixStandingMountConflict 外全部可在设置页 「重复守卫」分节中动态调整并持久化到 settings.yaml,改动即时生效(动态版固定取常量)。

Defaults live in the CONFIG block of both entries (CI verifies behavioral parity). In the npm build every option below except fixStandingMountConflict is editable from the "Dupguard" settings section and persisted to settings.yaml; the dynamic build uses the constants.

配置项 / Option默认 / Default说明 / Description
threshold10触发阈值:同一字符串连续重复 ≥ 该值时停止 / stop when the same string repeats ≥ this many times
minUnitLength1最小重复单元长度 / minimum repeating-unit length (1 also catches single-char loops like aaaaaaaaaa)
maxUnitLength80最大重复单元长度 / maximum repeating-unit length
detectionWindow8192检测滚动窗口(字符,去空白后),需 ≥ 阈值 × 最大单元长度 / rolling detection window in chars (after whitespace removal); must be ≥ threshold × max unit length
stripWhitespacetrue检测前移除空白/换行,识别带分隔符的复读 / strip whitespace so "x x x" and "x\nx\nx" are caught
ignoredChars['-', '|']检测时忽略的字符白名单:Markdown 表格分隔行(连字符与竖线)不参与重复统计 / whitelist of characters ignored during detection, so Markdown table separators don't count
monitorReasoningtrue是否检测思考文本(思考中的复读同样消耗 token,默认截停;只检测可见输出时置 false)/ also guard reasoning (thinking) text — on by default; set false to guard visible output only
monitorToolArgumentsfalse是否检测工具调用参数 / also guard tool-call JSON args — off by default (base64/JSON repeats are common)
fixStandingMountConflicttrueDSH ≤ 0.1.2-rc.1 兼容补丁:幂等化 cordisInspect.register,修复 preset standing-mount 多代并存冲突(仅代码常量)/ idempotent cordisInspect.register patch for the DSH ≤ 0.1.2-rc.1 standing-mount conflict (code constant only)

窗口约束 / Window constraint:detectionWindow 必须 ≥ threshold × maxUnitLength;否则长度超过 floor(detectionWindow / threshold) 的重复单元凑不满重复次数,无法被识别(例如窗口 80、阈值 10 时, 超过 8 字符的单元不再触发)。设置页在该约束被违反时显示 「⚠ 检测窗口长度需要提高:至少 N(当前 M = 阈值 × 最大单元)」的提示,宿主日志同时打印一条告警; 该约束只提示不拒绝写入,便于按需权衡内存占用与可识别单元长度。

The settings page shows a "detection window is too small" hint (and the host logs a matching warning) whenever detectionWindow < threshold × maxUnitLength; the write is still accepted.


工作原理 / How it works

1. 拦截流式输出 / Intercept the stream

监听 llm/stream 瀑布事件(包裹每次流式模型调用),返回包装后的 AsyncIterable。与 DSH 自带 @deepseek-ai/dsh-llm invariant 插件、dsh-session-checkpoint-policy 同款接入方式。

Listens to the llm/stream waterfall (wraps every streaming model call) and returns a wrapped AsyncIterable.

2. 检测算法 / Detection

  • 按块索引(chunk.index)分别累积文本,多块交替输出互不干扰;
  • 去空白后做尾部连续重复检测:文本以某个单元(长度 1..80)连续重复 ≥ 阈值结尾即触发。 模型一旦复读,重复必然在尾部,因此尾部检测即可实时捕获所有循环,同时避免全窗口词频的误报 (如正常中文里高频的"的")。

Tails-only consecutive-run detection on the whitespace-stripped buffer: catches every loop in real time without the false positives of whole-window frequency counting.

3. 停止机制 / Stopping

守卫生成器提前结束 → for await 调用上游 iterator.return() → 适配器 finally 中 consumer.abort() 中断 HTTP 连接 → 服务端真正停止生成。绝不直接 abort() options.signal(对 loop 请求它就是 agent 步骤信号,直接中止会以 aborted 结束并丢弃消息)。

Graceful early end: iterator.return() propagates to the adapter, whose finally aborts the HTTP connection server-side. We never abort options.signal directly (for loop requests it is the agent step signal).

4. 协议合规收尾 / Protocol-compliant closure

停止时补发所有打开块的 block-end(携带完整已生成文本)与 finish{kind:'stop'},满足 llm-invariant 校验器要求;agent-loop 将已生成内容正常提交为助手消息。

Emits synthetic block-ends plus finish(stop) to satisfy the llm-invariant validator, so the agent-loop commits the partial text as a normal assistant message.


触发示例 / What gets stopped

形态 / Pattern示例 / Example
单字符循环 / single-char loopaaaaaaaaaa
词语循环 / word loop哈哈 ×10
带空格复读 / space-separatedhello hello hello ... ×10
逐行复读 / line repeats抱歉,我无法完成。 ×10 行
前缀后循环 / loop after prefix好的,下面开始回答: + 循环 ×10
思考复读 / reasoning loop思考中 想 ×10(默认截停)

不会触发 / Won't trigger:正常文本中的高频词(检测只针对连续重复)、重复 9 次及以下、 工具参数(默认关闭)、Markdown 表格分隔行与长分隔线(连字符与竖线在白名单中,默认忽略)。 / high-frequency words in normal prose (consecutive runs only), ≤9 repeats, tool args (off by default), Markdown table separator rows and horizontal rules (whitelisted by default).


项目结构 / Project layout

.
├── plugin/
│   └── host.js                 # 动态插件形式(cordis_define 的 code.host)
├── lib/
│   ├── index.js                # npm/组合常驻形式(package.json main 入口,含设置集成)
│   └── client.js               # 浏览器端设置页(ModuleLoader 格式,dsh.client 入口)
├── tests/
│   ├── detector.test.js        # 端到端测试:双入口防漂移 + reasoning 开关 + settings 集成
│   ├── client.test.js          # 设置页组件测试:最小 React/DSH 桩驱动写路径
│   └── experiment-cancel.mjs   # 诊断实验(不进 CI):验证截停不阻塞于底层流取消
├── .github/workflows/ci.yml    # GitHub Actions:Node 20/22/24
├── cordis.patch.yml            # bundle 补丁层(dsh.bundle.patch:插入宿主行)
├── package.json
├── CHANGELOG.md
├── LICENSE                     # MIT
└── README.md

测试 / Tests

npm test                      # 两个测试文件
node tests/detector.test.js   # 检测端到端(48 项)
node tests/client.test.js     # 设置页组件(6 项)

同一套 15 项用例分别驱动两个入口(plugin/host.js 经 new Function 求值、lib/index.js 经 require 加载),覆盖:透传完整性、各类复读形态、阈值边界、协议闭合、上游 return() 调用、 默认不检测 reasoning/工具参数、未闭合工具调用块的闭合、多次调用状态隔离等。client.test.js 用最小 React 与 DSH 客户端桩驱动设置页组件,断言写入走 settingsScope 控制器 (set/unset)而非已移除的 connection.api。CI 在 Node 20/22/24 上运行 (与 DSH 一致,不支持 Node 18)。

The same 15-test suite drives both entries, guarding against drift between the two forms. CI runs on Node 20/22/24 (matching DSH; Node 18 is not supported).


已知限制 / Limitations

  • 停止时若恰有未闭合的工具调用块(顺序输出块的适配器几乎不可能),该块会按已累积参数闭合并可能被执行。
  • 服务端停止依赖适配器在流关闭时中止底层请求的语义(已验证 dsh-llm-deepseek;自定义适配器需自查)。
  • 阈值语义为 >= threshold:第 10 次重复出现时即停止。

DSH 运行期间编辑 preset 后的 standing-mount 冲突(DSH ≤ 0.1.2-rc.1 缺陷,本插件已内置补丁)

现象:对某个会话执行模型选择等操作时报 resume failed ... preset ... failed to mount ... Host Cordis inspect provider "Service" is already registered, 此后该错误持续出现,只有重启 DSH 才能恢复。

机制:preset 以 standing mount 方式每 preset 挂载一次并常驻;当 preset 的 composition 文件在 DSH 运行期间被编辑过(mtime/size 变化),下一次对"无活跃 agent 的会话"的操作(模型切换、打开历史会话等) 会新建一代 standing mount,而旧代从不销毁(DSH 注释明示 "a superseded one is never disposed while the process lives")。tool-cordis 在每次挂载时向进程全局的 cordisInspect 注册表注册 Service/Event/Builtin/Tool 四个 provider,新旧两代并存即冲突;失败的新代回滚、旧代残留, 重试永远重复冲突——这正是报错后"必须重启才能恢复"的原因。

本插件的修复(默认开启):apply 时把 cordisInspect.register 幂等化——同 id 已有注册时 共享既有注册并返回 no-op disposer,多代并存不再冲突。补丁进程内常驻(卸载本插件后仍生效, 重启后由本插件重新安装;HMR 重载不会叠加)。依赖 cordisInspect.providers 为可读 Map (rc.6 / rc.7 / 0.1.1-rc.1 / 0.1.2-rc.1 实测如此);0.1.2-rc.1 上游仍留有 "reclaim the superseded generation" 的 TODO,缺陷未修复,故默认开启。 DSH 升级修复后可将 CONFIG.fixStandingMountConflict 置为 false 关闭。

仍建议的操作纪律:运行期间编辑已挂载 preset 后重启 DSH(补丁消除的是报错,旧代残留的 组合仍占用资源,这是 DSH 的既有行为);根治仍待上游修复。

If you edit a mounted preset's agent.cordis.yml while DSH is running, the next session resume (triggered e.g. by the model picker on a session whose agent is gone) mounts a NEW standing-mount generation of that preset while the old generation is never disposed — tool-cordis then registers its process-global Host inspect providers (Service …) twice and every retry fails with Host Cordis inspect provider "Service" is already registered until DSH restarts. This plugin patches it by default: cordisInspect.register is made idempotent (a same-id registration shares the existing one and gets a no-op disposer), so coexisting generations no longer collide. The patch is process-resident (survives plugin unload, reinstalled on restart; HMR reload does not stack it); set CONFIG.fixStandingMountConflict to false once a fixed DSH ships. Still open in 0.1.2-rc.1: upstream carries a TODO to reclaim superseded generations.

License

MIT