← Back to Plugins
Voice

Tool Guard

noajoliver By noajoliver 👁 531 views ▲ 0 votes

OpenClaw plugin: prevents malformed tool call loops with dedup detection, hard caps, and model attribution logging

GitHub

Install

npm install
npm

README

# openclaw-tool-guard

An OpenClaw plugin that prevents malformed tool call loops. When models (especially non-Anthropic models like MiniMax M2.5) generate tool calls with missing required parameters, the current behavior is an infinite retry loop until timeout. This plugin detects and breaks those loops early.

Related issue: [openclaw/openclaw#14729](https://github.com/openclaw/openclaw/issues/14729)

## How it works

Tool Guard uses a 3-layer defense:

### Layer A: Corrective Error Messages

When a tool call fails with a deterministic validation error (missing required param, type mismatch), the generic error is replaced with a corrective message that tells the model what went wrong, what the correct call looks like, and what it actually sent.

Instead of:
> `Missing required parameter: path (path or file_path)`

The model sees:
> `[TOOL ERROR] read() requires 'path'. Correct usage: read({ path: "path/to/file" }). You sent: read({}). Fix your call and retry.`

### Layer B: Per-Turn Dedup Loop Breaker

Tracks `(toolName, args, errorSignature)` tuples within each assistant turn. After 2 identical failing calls (configurable), returns a terminal error:

```
[LOOP DETECTED] Tool "read" failed 2 times with identical arguments.
This is a non-retryable error. Do NOT retry this call.
Try a different approach or report the issue.
```

### Layer C: Hard Cap Per Turn

After 5 total tool failures (configurable) in a single assistant turn, stops tool execution:

```
[TOOL ERROR LIMIT] 5 tool failures in this turn.
Stopping tool execution. Review your approach before continuing.
```

### Layer D: Model Attribution Logging

Logs which model generated each malformed tool call to `~/.openclaw/tool-guard.log` (configurable) in JSON lines format, including model ID inferred from tool call ID prefix (`call_*` = Fireworks/OpenAI-compat, `toolu_*` = Anthropic).

## Install

Link for development (recommended β€” changes are live on restart):

```bash
openclaw plugins install -l /path/to/openclaw-tool-guard
```

Or add manually to your `openclaw.json`:

```json5
{
  plugins: {
    load: { paths: ["/path/to/openclaw-tool-guard"] },
    entries: {
      "tool-guard": { enabled: true }
    }
  }
}
```

Then restart the gateway.

## Configuration

Add to your `openclaw.json`:

```json5
{
  plugins: {
    entries: {
      "tool-guard": {
        enabled: true,
        config: {
          maxIdenticalFailures: 2,   // Loop break threshold (default: 2)
          maxFailuresPerTurn: 5,     // Hard cap per turn (default: 5)
          logPath: "~/.openclaw/tool-guard.log"  // Attribution log path
        }
      }
    }
  }
}
```

All config fields are optional and have sensible defaults.

## Supported tools

Corrective messages include usage hints for these tools:

- `read` β€” requires `path` (alias: `file_path`)
- `edit` β€” requires `path`, `old_string` (alias: `oldText`), `new_string` (alias: `newText`)
- `write` β€” requires `path`, `content`
- `exec` β€” requires `command`

Unknown tools get a generic corrective message.

## Development

```bash
npm install
npm test
npm run build
```

Requires Node 22+.

## Troubleshooting

**Plugin not activating:** Ensure the plugin is enabled in `openclaw.json` under `plugins.entries.tool-guard.enabled`. Restart the gateway after config changes.

**Log file not created:** The log directory is created automatically. Check that the configured `logPath` is writable.

**False positives:** If legitimate retries are being blocked, increase `maxIdenticalFailures`. Only deterministic validation errors (missing params, type mismatches) are treated as non-retryable β€” timeouts and network errors are always allowed to retry.

## OpenClaw Plugin API Notes

This plugin uses `api.on()` for runtime hook registration (typed hooks) and `api.registerHook()` for display in `openclaw hooks list`. Key hooks:

- `before_agent_start` β€” resets failure counters each turn
- `tool_result_persist` β€” intercepts tool results, classifies errors, injects corrective messages
- `before_tool_call` / `after_tool_call` β€” available for diagnostics

The `tool_result_persist` hook is **synchronous** β€” do not return Promises.

Tested on OpenClaw 2026.2.6-3 with MiniMax M2.5 (Fireworks) and Claude Sonnet 4.6.

## License

MIT
voice

Comments

Sign in to leave a comment

Loading comments...