Dead-loop brake for DSH agent sessions: detects repeated identical tool calls, repeating call sequences, and duplicate text, then reminds the agent or refuses the call before it runs.
Install
# from GitHub (first run asks for allowBuilds approval — follow the hint, retry)
dsh plugin --profile web add github:Mlte0907/dsh-brake
Any plugin you install runs third-party code with your own permissions — it can read your files, use your credentials, and reach the network, and tool approvals don’t sandbox it. GitHub-sourced plugins also run build scripts at install time — pnpm blocks those until you allow them, so an install can stop with ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED or ERR_PNPM_IGNORED_BUILDS; dsh prints the exact key to add under allowBuilds in your profile’s pnpm-workspace.yaml, and the install works on the next run. Allowing a build is a trust decision: only install sources you trust, and pin a commit (github:owner/repo#sha).
README
English | 中文
Summary
dsh-brake is a DSH plugin that keeps agent sessions from spinning: it watches executed tool calls and newly injected context, and warns the model when the same work repeats without progress. It detects repeated identical calls, repeating call sequences, and duplicated text blocks, then attaches a plugin-sourced notice to the next model request. By default it only advises; an opt-in deny mode adds a monotonic guard that refuses a confirmed repeated call before it runs.
Table of Contents
- Use this package
- Understand the implementation
- Model Experience
- Known Limitations and Deferred Work
- Dev Note
Use this package
Install into a profile
cd ~/.dsh/profiles/web # or your profile directory
pnpm add /path/to/dsh-brake
Then add "dsh-brake" to the dsh.profile.bundles array in the profile's package.json.
What you get
- Repeated-call notices. The same tool name with the same normalized arguments, counted across executions. First notice at
callWarnCount(default 6), re-notice only aftercallReWarnEveryfurther repeats (default 5) — never one notice per call. - Sequence-loop notices. A repeating window of
sequenceLengthdistinct calls (default 4, minimum 2) — e.g.grep → curl → read → bashcycling — noticed atsequenceCountrepetitions (default 3). Sequence identity includes arguments, so varying the query is a different sequence. - Duplicate-context notices. The same text block (fingerprinted after newline normalization, minimum
minimumDuplicateCharschars) injected repeatedly withinduplicateTextWindowMsacross different message ids, or repeated inside one message. Counted per message id, so replayed history never accumulates; throttled byduplicateTextCooldownMsper fingerprint. The notice names the sources observed. - Opt-in denial. With
mode: 'deny', actx.tools.guardrefuses the exact repeated call identity aftercallDenyCountrepeats. Everything else stays advisory. Human messages reset all counters for that agent.
Configuration
- id: dsh-brake
config:
mode: remind # remind | deny
callWarnCount: 6 # repeats before the first call warning
callDenyCount: 10 # deny-mode threshold; must be > callWarnCount
callReWarnEvery: 5 # repeats between re-warnings on one chain
sequenceLength: 4 # calls per sequence (min 2)
sequenceCount: 3 # sequence repetitions before a warning
duplicateTextThreshold: 3 # injections within the window before a warning
duplicateTextWindowMs: 120000
duplicateTextCooldownMs: 30000
minimumDuplicateChars: 80
Invalid values throw at plugin load; nothing falls back silently.
Tests
node test/test-brake.js
Drives the real plugin entry (lib/index.js) through the two waterfalls and the guard contract: thresholds, throttling, per-argument identity, deny scope, duplicate-text counting with id dedupe and cooldown, human-message reset, downstream preservation, and fail-loud config.
Understand the implementation
apply() registers two waterfall listeners and, in deny mode, one guard. tools/post-execute always calls next() first, then folds notices onto the downstream decision's additionalContexts; denied calls flow through the same waterfall, so a model hammering a denied call still counts. agent/pre-step checks only messages claimed for this step (deduplicated by message id), appends notices to an enter decision's messages, and resets all state when a human message (source.kind === 'user') is present. Notices are createUserMessage() values with { kind: 'plugin', plugin: 'dsh-brake', form: 'notice' } sources, so they carry stable ids and render as plugin notices rather than user prompts. Per-agent state lives in a WeakMap keyed by the agent; the guard denies only call identities whose post-execute count reached callDenyCount, and never denies calls without an agent. Fingerprints use FNV-1a over key-sorted canonical JSON (arguments) or newline-normalized text; text entries are bounded and pruned by recency.
Further Exploration
repeat-tool-reminder(in-repo) covers consecutive identical tool+argument chains with escalating detail; dsh-brake adds sequence loops, duplicate context, and optional denial. Both can run together.
Model Experience
Notices are user-role plugin-source messages that enter the next request's history and persist in the session log like any other injected context. Each notice is short and names the observed fact (tool, count, sequence, or duplicated text preview) without replying the full duplicated payload. Detection reads executions and inbox messages only; it never rewrites tool results or removes logged content.
Known Limitations and Deferred Work
- Near-duplicate detection (minor wording edits) is not implemented; only exact fingerprints after whitespace/newline normalization count.
- Denial covers exact call identities only; sequence loops are never denied.
- Live streaming output is not monitored; assistant text is only observable after it is committed.
- The plugin assumes the DSH
tools/post-execute,agent/pre-step, andctx.tools.guardcontracts; it has not been exercised against other Cordis hosts.
Dev Note
Tests are plain Node scripts (no dependencies) and require @deepseek-ai/dsh-llm to be resolvable from the plugin directory — true in a DSH profile checkout. Real-loop composition coverage (agent-loop + Loader) is deferred; see the limitation above.
Links
More in this category
DayuanJiang/next-ai-draw-io#dsh-plugin★ 36599
Draws draw.io diagrams in DeepSeek Harness through the next-ai-drawio MCP server: the link in the reply opens a live preview in the right sidebar, you can edit the diagram by hand, and each AI change is a version you can restore. Node.js 18+; npx downloads the MCP server on first use.
Tencent/WeKnora#dsh-weknora★ 36302
Four read-only tools over a WeKnora knowledge base: list knowledge bases, hybrid passage search, reassemble one document's chunks in order, and WeKnora's own cited RAG or ReAct-agent answer with a resumable session id.
superdesigndev/treg★ 7042
Tool catalog for agents: search ~2,600 external endpoints (SEO and SERP, backlinks, social, people and company enrichment, ad libraries, scraping) by the task you want done, read each one's parameters and per-call price, then call it with the credential injected server-side. Ships the skill plus an MCP row that stays disabled until TREG_TOKEN is set.
T-Auto/dsh-ops★ 5074
Provides bash, PowerShell 7, and high-performance Rust tools for DSH on Windows to reduce token usage.
sixtysevenlf/dsh-blender-plugin★ 1575
Lets a DSH agent drive a local Blender over a direct TCP channel with 15 tools: viewport frames, custom-angle renders, Python execution, headless and job offload, transaction rollback, and a planning layer of 228 ops across 34 families.
TencentCloudBase/CloudBase-AI-Toolkit#dsh-plugin★ 1155
Tencent CloudBase backend for DeepSeek Harness — scaffold and deploy full-stack apps from chat, render query results as table cards with paging, sorting and CSV export, preview a deployment on its domain, and call the CloudBase MCP toolset (`mcp__cloudbase__*`) with device-code login.
Community comments
Comments are public GitHub Discussions. Loading them connects to GitHub and Giscus; a GitHub account is required to post.