DeepSeek Harness Plugin Hub

发布与管理完整 Harness Profiles,发现适合你的插件。

探索

插件目录环境预设文档中心动态

社区

发布插件联系我们报告问题

相关链接

Plugin Hub GitHubDeepSeek Harness 官方项目系统状态隐私说明
© 2026 DeepSeek Harness Plugin HubPowered byPaxTech

独立、非官方社区项目,与 DeepSeek 官方无隶属、授权或背书关系。

Output Loop Guard — DeepSeek Harness 插件(DSH Plugin)
DeepSeek Harness Plugin Hub
ProfilesPlugins分类动态文档登录管理 Profiles
ProfilesPlugins分类动态文档登录
← Plugins
O

dsh-output-loop-guard

Output Loop Guard

DSH 防止模型流式输出中的自我重复:检测推理或可见文本中的退化循环,中止失控的轮次,并通过纠正性通知唤醒代理。

插件会安装到这里;不确定时保持 web。

npx -y @deepseek-ai/dsh plugin --profile web add github:ADistanceThereIs/dsh-output-loop-guard#80587a5f4cdac7fb63c5bb29380066eb2789d142
README兼容性版本

兼容性与来源证明

Output Loop Guard 以 dsh-output-loop-guard 发布,当前版本为 0.1.0。Plugin Hub 会校验它的 manifest,并保存精确安装来源,便于复现安装结果。

DSH 兼容范围
*
运行环境
any
发布来源
github
Registry 更新时间
2026/10/16

版本

0.1.0stable
2026/10/16

相关插件

正在加载相关插件…

最新版
0.1.0
DSH
*
HMR
重启进程
Tree shaking
未声明可安全裁剪
解包体积
未提供
文件数
未提供
Surface
any
许可证
MIT
发布源
github
GitHub
★ 0
周下载
0
最近提交
2026/10/16
查看源码 ↗
README Badge

点击下方 Badge 复制 Markdown,粘贴到 README 即可。

这是你的 Plugin?认领权益 · 优先安全扫描

验证 package.json 声明的 GitHub 仓库,即可管理这个公开页面。认领后,Hub 会优先安排当前版本的安全扫描,并在通过后公开展示结果。

认领这个 Plugin →
报告问题

相关插件

继续浏览 agents-orchestration 分类下经过校验的插件。

Headless@deepseek-ai/dsh-headlessdsh one-shot bundle:基于 dsh-base 的直接核心 Agent/Session 运行器,不包含 Host、HTTP 或浏览器层Experimental Agent Team Profile@deepseek-ai/dsh-experimental-agent-team-profile在一个实验性捆绑包中提供 Agent Teams 协作、工具和 Web UIExperimental Ralph Bundle@deepseek-ai/dsh-experimental-ralph-bundle使用全新代理执行明确请求的重复工作。Subagent Codex@deepseek-ai/dsh-subagent-codex基于官方 app-server 协议的一次性 Codex 子代理提供程序

README

dsh-output-loop-guard

An output self-repetition watchdog for DeepSeek Harness. When a model starts cycling the same short block instead of producing a tool call, the guard aborts that generation and wakes the agent with a corrective notice — no human stop button, and no human typing "continue".

  • Bundle for DSH >= 0.2.0-rc.2, ESM, zero runtime dependencies.
  • 21 self-contained regression checks (npm test).
  • Calibrated against 27 real sessions / 1,783 assistant steps: 24 detections, 0 false positives.

The gap it fills

DSH ships @deepseek-ai/dsh-repeat-tool-reminder, which only sees duplicate tool calls (same tool, same arguments, 3/5/8 times in a row). A degeneration loop in the reasoning channel is invisible to it. In the session that motivated this plugin:

  • the model repeated 好。→(执行)→好。→Write.→… in its reasoning for 112,109 characters, emitted in 50,196 stream chunks over 126 seconds of continuous decoding, and produced zero tool calls — so repeat-tool-reminder could not fire;
  • automatic compaction never ran either: its trigger is floor(min(W × 0.8, W − O − B)) ≈ 678k tokens for a 1M window with a 256k output cap, while the session peaked around 508k tokens;
  • the loop only ended when the human pressed stop, and the polluted text stayed in the transcript, which made further loops more likely (self-imitation).

output-loop-guard listens on the live agent/assistant-stream frames and looks at the text itself.

How it works

A sliding window over streamed output (1,200 characters by default, inspected every 64 new characters) feeds four signals:

SignalRuleCatches
repeated-blockShortest-period block (≥2 newlines, ≥2 distinct non-whitespace chars) repeated ≥6 timesMulti-line cycles, e.g. the 106-character 好。→(执行)→Write. cycle
dominant-gramOne n-gram covers ≥55% of the window with ≥24 occurrences and spans ≥2 linesLoops whose tail is ragged but where repetition already dominates
repeated-lineSingle-line runs: ≥40 in the reasoning channel, ≥60 in visible text (singleLineTextMinRepeats, 0 disables)Reasoning spinning on one line, runaway line duplication in answers
flat-ticWhitespace-free short gram covering ≥25% of the window with ≥48 occurrences, reasoning onlyLine-less tics (好。好。好。…)

Two design rules keep it precise:

  • Only the shortest period counts. When one line repeats, 2× and 3× the line length are also "periods"; judging on an arbitrary period turned an ordinary bullet list into a "multi-line cycle" during calibration. The guard therefore looks only at the shortest period and requires that block itself to span ≥2 newlines.
  • Channel awareness. Repeated lines in visible output are usually legitimate content (generated fixtures, config files, lists), so the visible-text single-line threshold is higher (60) than the reasoning one (40), and line-less tics are only judged in the reasoning channel. Indentation runs, ==== / ---- rule lines and blank-line runs never trip the guard.

On detection the guard:

  1. calls agent.cancel({ kind: 'hook', reason: 'output-loop-guard: …' }) — the in-flight generation is aborted and recorded as interrupted, so the degenerate text stops growing;
  2. calls agent.steer(<notice>) — because the signal is already aborted, steer upgrades to a fresh turn and wakes the driver, so the agent immediately continues with an explicit correction (stop restating, emit the next action or finish);
  3. after maxTripsPerTurn trips in one turn it stops auto-continuing and only injects the notice, so a genuinely broken model cannot spin forever.

Install

The package is a DSH bundle: the loader reads dsh.bundle.patch from package.json (dsh.plugin.json is optional metadata used by some local plugin indexes — the official runtime ignores it), and cordis.patch.yml inserts the output-loop-guard row.

# A. from a git host, pinned to a commit (requires `git` on the PATH of the DSH process)
dsh plugin --profile <profile> add "github:ADistanceThereIs/dsh-output-loop-guard#<commit>"

# B. from the release tarball — no git required
#    download dsh-output-loop-guard-0.1.0.tgz from the Releases page, then:
dsh plugin --profile <profile> add ./dsh-output-loop-guard-0.1.0.tgz

# C. straight from the release asset URL (needs Node to trust your system CA store)
dsh plugin --profile <profile> add \
  https://github.com/ADistanceThereIs/dsh-output-loop-guard/releases/download/v0.1.0/dsh-output-loop-guard-0.1.0.tgz

All three append the package to dsh.profile.bundles and compose the bundle's patch layer. Restart DSH for the row to activate.

Uninstall:

dsh plugin --profile <profile> remove dsh-output-loop-guard

Configuration

Override the row in the profile's cordis.patch.yml (a patch replaces the row's whole config, so restate every key you want to keep):

- id: output-loop-guard
  name: dsh-output-loop-guard
  config:
    dryRun: false                 # true = detect and log only, never cancel
    autoContinue: true            # wake the agent with the corrective notice
    maxTripsPerTurn: 2            # auto-continue budget per turn
    windowChars: 1200
    checkEveryChars: 64
    minPeriodRepeats: 6           # repeats required for a multi-line cycle
    singleLineMinRepeats: 40      # reasoning-channel single-line threshold
    singleLineTextMinRepeats: 60  # visible-text single-line threshold (0 = off)
    useDominantGram: true
    dominantGramCoverage: 0.55
    dominantGramMinCount: 24
    useFlatTic: true
    ticMinCount: 48
    ticMinCoverage: 0.25
    verbose: false

Start with dryRun: true if you want to observe detections in your own sessions before letting the guard abort anything.

Evidence

Corpus calibration

Replayed over 27 real sessions / 1,783 assistant steps (a corpus containing both healthy and degenerate real output):

  • 24 detections, 0 false positives;
  • every loop step of the motivating session was caught, plus a same-pattern loop in an unrelated session;
  • detection latency: the 112,109-character runaway was caught after 2,944 characters (2.6 %); other loops were caught within 1,152–7,808 characters — hundreds of milliseconds instead of 20–126 seconds of spinning.

Runtime verification

End-to-end check in a live DSH runtime, on a task engineered to repeat two lines 300 times. The session log of that run contains:

{"type":"turn/end","data":{"turn":1,"reason":{"kind":"aborted","reason":{"kind":"hook","reason":"output-loop-guard: repeated output (repeated-block)"}}}}
{"type":"assistant/message","interrupted":true}          // cut off after 9 repetitions, not 300
{"type":"user/message","source":{"kind":"output-loop-guard","form":"notice"}}

The agent then delivered the same content as a file instead of continuing to repeat it, which is exactly the intended outcome: the guard stops runaway output, it does not kill the task.

Regression suite

npm test runs 21 self-contained checks (no corpus needed): the real degeneracy must be aborted (24,180-character stream caught after 576 characters), healthy long documents must be untouched, realistic written output (lists, code blocks, tables, rule lines, fixtures) must not trip, runaway written lines must trip, dryRun must not cancel, a disabled plugin must attach nothing, and a throwing agent handle must not break the stream.

Limitations

  • Visible-text single-line repetition needs ≥60 identical consecutive lines (that protects legitimate fixtures and lists); disable with singleLineTextMinRepeats: 0.
  • Detection is structural (periodicity and density), not semantic: a modified near-repeat may escape repeated-block, though dominant-gram / flat-tic usually covers it.
  • Trips are counted per agent and per attempt; subagents do not share counters.
  • A trip discards the tool call that step had not emitted yet — one retry is the price for not spinning for minutes. Use dryRun to observe first.

Event contract used

  • agent/assistant-stream with payload { agent, frame }, where frame = { type: 'start' | 'chunk' | 'end', attemptId, revision, …, chunk } and chunk is a StreamChunk (reasoning-delta / text-delta / …).
  • Agent.cancel(cause, options) — the closed cause union is user | parent | disposed | hook; hook records its reason in turn/end, which is what this guard uses.
  • Agent.steer() is send(message, 'next-step', true); when the active signal is already aborted, send upgrades the target to next-turn and wakes the driver — hence cancel(); steer(notice) means "abort this generation, then continue in a new turn".

Troubleshooting

dsh plugin add github:… fails with resolveGit / resolveRef errors. pnpm resolves git dependencies with the git executable, and DSH inherits the environment of the process that started it. If you installed Git after starting DSH, the new PATH entry is not visible to it. Put Git on the PATH of the shell you use (or restart DSH) and retry, e.g.:

$env:PATH = 'C:\Program Files\Git\cmd;' + $env:PATH
dsh plugin --profile <profile> add "github:ADistanceThereIs/dsh-output-loop-guard#<commit>"

Pin an exact commit (or tag) so a later push cannot silently change what runs on your machine.

dsh plugin add https://… fails with fetch failed / unable to verify the first certificate. Node's fetch uses its bundled CA list, so TLS-inspecting security software (corporate proxies, some antivirus products) can break it while curl still works. Node 22.15+/24 can use the system trust store instead:

$env:NODE_OPTIONS = '--use-system-ca'
dsh plugin --profile <profile> add https://github.com/ADistanceThereIs/dsh-output-loop-guard/releases/download/v0.1.0/dsh-output-loop-guard-0.1.0.tgz

Downloading the tarball yourself and adding the local file avoids the issue entirely.

The guard tripped on output you wanted. Set dryRun: true to keep detection but stop the cancellation, raise the thresholds, or set singleLineTextMinRepeats: 0 to stop judging single-line repetition in visible text.

The guard seems inactive. The bundle's row only activates after a DSH restart, and the row must appear in the composed profile — for a non-application profile you can check it with dsh --profile <profile> --dump-config | Select-String output-loop-guard.

Development

node test/guard.test.mjs   # or: npm test

detector.mjs is dependency-free and importable on its own (dsh-output-loop-guard/detector), so the detection logic can be reused or calibrated outside DSH.

License

MIT — see LICENSE.