snailium/dsh-repeat-tool-breaker0

dsh-repeat-tool-breaker

针对重复相同工具调用的硬拦截 DSH 插件。

AI 分析

核心用途是通过同步守护机制,在 Agent 连续发起第二次完全相同的工具调用时进行拦截,防止 Agent 陷入死循环。适合需要限制 Agent 行为、节省 Token 的自动化任务。

套件
dsh-repeat-tool-breaker
版本
0.1.2
授權
MIT
最近更新
2026年9月11日

安裝

此插件尚未提供可驗證的 bundle,或相容性檢查未通過。請先閱讀倉庫說明。 閱讀完整 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:

  • warnAfter must be at least 2, because a notice only makes sense once a repeat has actually happened;
  • it must be below denyAfter, because at denyAfter the 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.