Introduction¶
In the development practices of DeepSeek Harness (DSH), agents can easily fall into logical infinite loops. For example, an agent may call search to query the weather, read the result, and then decide to call search again to query the weather. A single call does not contain an error until a budget or budget limit is reached or human intervention occurs. The dsh-loop-brake plugin solves this problem by detecting and blocking the third consecutive call.
Plugin Introduction¶
dsh-loop-brake is a function plugin for DeepSeek Harness; it is a circuit breaker for identical tool calls.
- Maintainer: jwilson411
- Category: Workflow
- License: MIT
- Core value: Prevents agents from infinitely repeating the same tool call, without requiring model inference or additional runtime dependencies.
Installation and Configuration¶
Installing the plugin requires the official DSH CLI command. The command reads dsh.bundle.patch from the package manifest and appends it to the ordered plugin list in the configuration file.
dsh plugin --profile default add github:jwilson411/dsh-loop-brake
After installation, the plugin applies default settings. The default behavior allows 3 consecutive identical tool calls; the 4th call is rejected. This threshold can be adjusted in the plugin configuration.
Configuration example:
- id: loop-brake
config:
maxRepeats: 5
| Configuration Item | Default Value | Description |
|---|---|---|
maxRepeats |
3 |
The maximum number of consecutive times the same tool call is allowed to execute in a session. The count includes rejected calls; therefore, when set to 3, the first two calls are executed and the third is rejected. |
Note:
* maxRepeats must be an integer of at least 1.
* If the value is 1, all repeated calls are immediately rejected (including the first occurrence), mainly for debugging.
* If the configuration item is missing, the plugin reads the environment variable DSH_LOOP_BRAKE_MAX_REPEATS, but the plugin configuration takes precedence over the environment variable.
How It Works¶
The plugin uses SHA256 hashing for exact matching. Two calls are considered identical if and only if the following hash values are identical:
sha256(toolName + "\n" + canonicalJson(args))
Here, canonicalJson only sorts object keys and performs no other normalization. This means that {"a":1,"b":2} and {"b":2,"a":1} are considered the same call.
Matching Rules:
* Caught: The agent repeats the same call byte-for-byte (for example, search with {q: "weather"}).
* Not caught: Calls whose parameters contain timestamps, nonces, page cursors, or retry counters. These calls may be logically similar, but their hashes are different, so the plugin does not intervene.
* Not caught: Alternation between two calls (for example, A, B, A, B). The plugin tracks only consecutive repeats, not the total count.
Session Isolation:
The count is per session. Repeated-call counts in one session do not affect other sessions. If the counter is interrupted (for example, by calling a different tool), the count is reset.
Error Handling¶
When the plugin triggers the circuit breaker, it throws a LoopBrakeError. The tool body code is not executed. The error object contains the following properties for quickly locating the issue in logs:
code:'LOOP_BRAKE'toolName: the name of the tool that triggered the errorcount: the current repeat count (including the current rejected call)maxRepeats: the configured maximum repeat limithashPrefix: the first 12 hexadecimal characters of the call hash (used to identify the call in logs without recording the full parameters)sessionId: the session ID that triggered the errorplugin: the plugin name'dsh-loop-brake'
For security reasons, the error details do not include the specific parameter contents.
Using the Library Directly¶
In addition to being used as a plugin, the library also provides a standalone API for hosts that want to control circuit-breaker logic directly at the call site.
import { LoopBrake, decorateTool, wrapExecute } from 'dsh-loop-brake/loop-brake'
const brake = new LoopBrake({ maxRepeats: 3 })
// 包装单个执行函数
const guarded = wrapExecute(execute, brake, { tool: 'search', sessionId: 's1' })
// 或复制整个工具定义并包裹其执行逻辑
const braked = decorateTool(definition, brake)
Considerations and Use Cases¶
- Applicable scenarios: The agent repeatedly calls the same tool with exactly identical parameters due to a logic defect or insufficient context.
- Not applicable scenarios: The agent modifies parameters in a loop (such as incrementing a page number), or polls across different tools.
- Dependency requirements: No runtime dependencies; it relies only on the Node.js built-in
node:crypto. - Version requirements: Must be compatible with
@deepseek-ai/dsh-toolsversion0.1.1-rc.2. - Patch mechanism: If this plugin is configured through an
id-targetedpatch, the entireconfigobject must be replaced rather than merged.
Conclusion¶
dsh-loop-brake provides a low-cost way, with no model-call overhead, to prevent agents from falling into an infinite loop of repeated calls. By using a strict hash matching mechanism, it ensures deterministic circuit-breaker behavior, making debugging and troubleshooting easier.
- Directory page: https://www.skillhub.cn/plugins/jwilson411/dsh-loop-brake
- GitHub repository: https://github.com/jwilson411/dsh-loop-brake