npm package: @ncdlabs/openclaw-difficulty-router
Description: OpenClaw plugin that selects the model per turn based on prompt difficulty (simple / default / complex)
Latest version: 1.0.4

# OpenClaw Difficulty Router

OpenClaw plugin that selects the **provider/model per turn** based on prompt difficulty. It implements the `before_model_resolve` hook and returns `providerOverride` / `modelOverride` so simple prompts can use a small model and complex prompts a larger one.

- **Automatic mode**: No config (or empty config). No overrides; OpenClaw uses its default model. Behavior is predictable.
- **Single config**: Configure tiers (and optional heuristic tuning) in one place: either the plugin config block in OpenClaw config or one optional JSON file.

No changes to the OpenClaw core repo are required. Install into an existing OpenClaw installation and enable the plugin.

**Requirements:** Node.js >= 18, OpenClaw >= 2026.2.0.

## Installation

From the OpenClaw project or environment where the `openclaw` CLI is available:

```bash
openclaw plugin install @ncdlabs/openclaw-difficulty-router
```

OpenClaw may also support installing from GitHub; see [OpenClaw plugin docs](https://docs.openclaw.ai/tools/plugin) for current options.

After install, enable the plugin (if not auto-enabled) and optionally add config:

```bash
openclaw plugins enable difficulty-router
```

## Configuration

All user-facing configuration is either:

- **Automatic**: No file, no plugin config. The plugin does not override; OpenClaw’s default model is used every turn.
- **Plugin config block**: In your main OpenClaw config (`openclaw.yaml` or `openclaw.json`), under `plugins.entries.difficulty-router.config`.
- **Single JSON file (optional)**: Set `configFile` in the plugin config to a path (e.g. `~/.openclaw/difficulty-router.json`). That file can define `tiers` and `heuristic`; values there override the plugin config block.

### Tier keys

Tiers are: `simple`, `default`, `complex`. Each value is a **model ref** in the same format OpenClaw uses: `provider/model-id` (e.g. `ollama/qwen2.5-coder:3b`, `openai/gpt-4o-mini`).

- **simple**: Very short prompts and no sign of multi-step work (see heuristic below).
- **default**: Everything that is neither simple nor complex.
- **complex**: Long prompts or clearly multi-part / step-by-step prompts.

You can set only the tiers you care about. If a tier is missing, that turn is not overridden and OpenClaw’s default applies.

### Heuristic (tunable)

When tiers are configured, difficulty is computed as follows (thresholds are configurable):

- **simple**: Prompt length ≤ `simpleMaxChars` (default **50**) and no multi-step indicators (e.g. “step 1”, “first, then”, bullet lists).
- **complex**: Prompt length ≥ `complexMinChars` (default **500**) or contains multi-step indicators.
- **default**: Everything else.

Prefer **default** when in doubt. Thresholds can be set under `heuristic` in the plugin config or in the optional JSON file.

### Example: plugin config only

In `openclaw.yaml` (or equivalent):

```yaml
plugins:
  entries:
    difficulty-router:
      enabled: true
      config:
        tiers:
          simple: "ollama/qwen2.5-coder:3b"
          default: "ollama/qwen2.5-coder:7b"
          complex: "ollama/qwen2.5-coder:32b"
        heuristic:
          simpleMaxChars: 80
          complexMinChars: 400
```

### Example: single JSON file

In OpenClaw config, point to one file:

```yaml
plugins:
  entries:
    difficulty-router:
      enabled: true
      config:
        configFile: "~/.openclaw/difficulty-router.json"
```

Then create `~/.openclaw/difficulty-router.json`:

```json
{
  "tiers": {
    "simple": "ollama/qwen2.5-coder:3b",
    "default": "ollama/qwen2.5-coder:7b",
    "complex": "ollama/qwen2.5-coder:32b"
  },
  "heuristic": {
    "simpleMaxChars": 50,
    "complexMinChars": 500
  }
}
```

### Behavior

- When **no tiers** are set (automatic or empty config): the plugin **never** overrides; OpenClaw’s default provider/model is used.
- When **tiers are set**: on each turn the plugin computes difficulty, picks the tier’s model ref, and returns `providerOverride` and `modelOverride`. OpenClaw then uses that model for that run. If the overridden model fails, OpenClaw’s existing fallback behavior applies.

### Heuristic validation

If `simpleMaxChars` is set greater than or equal to `complexMinChars`, the plugin automatically sets `complexMinChars` to `simpleMaxChars + 1` so the default band is never empty.

## Troubleshooting

- **Plugin does not override:** Ensure at least one tier is set under `tiers` (simple, default, or complex) and the plugin is enabled (`plugins.entries.difficulty-router.enabled: true`). Check gateway logs for `[difficulty-router] loaded with tiers` at startup.
- **configFile not found or invalid:** If you set `configFile`, the path is resolved via OpenClaw’s `resolvePath` (e.g. `~` expands to your home directory). The file must be valid JSON. You’ll see `[difficulty-router] configFile not found` or `configFile parse error` in logs if the file is missing or invalid.
- **Invalid tier model ref:** Each tier value must be `provider/model` (e.g. `ollama/qwen2.5-coder:3b`). If a ref is malformed, that tier is skipped for the run and no override is returned.
- **Hook errors:** If the hook throws (e.g. bug), the plugin catches, logs `[difficulty-router] before_model_resolve error: ...`, and returns no override so the run continues with the default model.

## Security / Scanning

This plugin has **zero runtime dependencies** (only a peer dependency on OpenClaw). That keeps the supply-chain surface small: no transitive packages from this plugin.

After installing (e.g. into `~/.openclaw/extensions/difficulty-router/`), you can run:

- **npm audit** – From the plugin directory: `npm audit`. Any reported vulnerabilities will be from OpenClaw’s dependency tree (installed as a peer), not from this package’s own dependencies.
- **Socket** – For a deeper scan, use [Socket CLI](https://docs.socket.dev/socket-cli/): `socket login` (once, with your API token), then `socket scan create` from the plugin directory or `socket package score npm @ncdlabs/openclaw-difficulty-router`.

See [SECURITY.md](SECURITY.md) for how to report vulnerabilities.

## Development

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

Build output is `dist/`. The OpenClaw plugin entry is `./dist/index.js` (see `openclaw.extensions` in `package.json`). Run `npm pkg fix` to normalize package.json if needed.

## License

MIT.