snailium/dsh-repeat-tool-breaker ↗★ 0
dsh-repeat-tool-breaker
Hard break on repeated identical tool calls: a synchronous ctx.tools.guard monotonic gate that denies the 2nd identical (tool name + canonical arguments) call per agent, with an optional same-path read guard and advisory first-repeat warning.
AI Analysis
核心用途是通过同步守护机制,在 Agent 连续发起第二次完全相同的工具调用时进行拦截,防止 Agent 陷入死循环。适合需要限制 Agent 行为、节省 Token 的自动化任务。
Install
This plugin has no verified bundle, or compatibility checks failed. Read the repository notes first. Read the full README ↗
README
Read the full README ↗Configuration
Mount via a --patch overlay or a profile's cordis.patch.yml. The plugin
exports an object form ({ name, inject: ['tools'], apply }); inject: ['tools']
defers apply until the real ToolRuntime service is live, at which point
ctx.tools.guard is the genuine method.
- insert:
- id: repeat-tool-breaker
name: /ABSOLUTE/PATH/dsh-repeat-tool-breaker/index.js
config:
denyAfter: 2 # identical (tool + canonical args) call #2 is denied (>=2)
warnAfter: 2 # advisory tier; inert unless 2 <= warnAfter < denyAfter
registerAdvisory: true
exclude: [todo_write] # never count/reset these tools (include/exclude are *-wildcards)
include: [] # non-empty = ONLY these tools are tracked
readTools: [read, Read, read_file, read-file, file-read, fs-read]
matchReadBySubstring: true
pathAliases: [path, filePath, file, target_file]
maxSamePath: 3
previewChars: 400
resultPreviewChars: 800
(The - insert: list is required to add a new plugin; a flat - id: entry is
a reconfig of an already-present id and fails with "entry not found" for a plugin
that isn't yet in the composed tree.)
Here name is an absolute POSIX path to this directory's index.js (dev/overlay
loop). When the package is installed into a profile it can instead be the package
specifier dsh-repeat-tool-breaker.
About the advisory tier
The warnAfter notice is deliberately inert unless 2 <= warnAfter < denyAfter:
warnAftermust be at least 2, because a notice only makes sense once a repeat has actually happened;- it must be below
denyAfter, because atdenyAfterthe call is blocked and the deny reason already explains why.
With the default denyAfter: 2 the gate blocks on the very first repeat, so there
is no room for a separate pre-block nudge and nothing is emitted. Set
denyAfter: 3, warnAfter: 2 to get one warning after the first repeat and the
block on the second.
This matters: an advisory keyed only on count === warnAfter would fire on every
ordinary tool call (every fresh call starts a new run at count 1), attaching a
misleading "you repeated this" message to each one.