dsh上modlens的自动GeminiAPI密钥轮换

Automatic Gemini API key rotation for modlens on DeepSeek Harness (dsh) — when one key hits its quota (HTTP 429), the read
automatically switches to the next key in the pool and retries, with zero
intervention. Works everywhere modlens reads an image: the dsh GUI paste flow,
the modlens_read_image tool, and the CLI.

⚠️ Unofficial: this patches the installed modlens package. The patch is
wiped by any modlens upgrade; patch.ps1 re-applies it in one command.
If modlens upstream ever ships native multi-key support, drop this project.

Why

modlens reads images through a single Gemini API key stored in ~/.modlens/config.json. Free-tier keys hit daily quota (429 RESOURCE_EXHAUSTED) / rate limits quickly, and modlens has no retry or
failover for that. This project adds:

  • a key pool (~/.modlens/api-keys.json) — list, add, rotate, inspect
  • an engine patch — 429 triggers an automatic switch to the next pool key,
    persisted to the config, then a retry of the same request (up to 8 rotations)
  • a CLI wrapper — 429 → rotate + retry; 5xx → backoff retry on the same key
  • a re-patch script — re-applies the engine patch after a modlens upgrade

Requirements

  • DeepSeek Harness (dsh) with the modlens plugin installed: npx -y @deepseek-ai/dsh plugin --profile web add @liustack/modlens@<version>
  • Node 22.19+ (modlens requirement)
  • PowerShell (Windows) — the scripts are .ps1

Install

Clone this repo (or copy scripts/), then:

1
2
3
4
5
6
7
8
9
# 1. copy scripts next to the modlens config
Copy-Item scripts\* "$env:USERPROFILE\.modlens\"
# or link: New-Item -ItemType SymbolicLink ... (per-file)

# 2. apply the engine patch (idempotent)
powershell -ExecutionPolicy Bypass -File "$env:USERPROFILE\.modlens\patch.ps1"

# 3. seed the key pool (one command per key)
powershell -ExecutionPolicy Bypass -File "$env:USERPROFILE\.modlens\rotate.ps1" add <GEMINI_API_KEY>

The active key is the one modlens uses: if you already configured a key via modlens config set gemini-api.apiKey, add it to the pool too so rotation can
cycle back to it.

Usage

1
2
3
4
5
6
7
8
# manage the pool
rotate.ps1 list # show pool, >> marks the active key
rotate.ps1 status # pool size + active key (masked)
rotate.ps1 rotate # switch to the next key (persists)
rotate.ps1 add <key> # add a key to the pool

# read an image with automatic rotation
ml.ps1 -Image <path-or-url>

The engine patch makes rotation automatic for every read path (GUI paste, modlens_read_image tool, CLI), so rotate.ps1 rotate is mainly for manual
override or diagnosis.

If you use a proxy

modlens itself supports it — no changes needed here:

1
modlens config set proxy http://127.0.0.1:<port>

Note: Google’s Gemini API is region-restricted. A proxy exit in an unsupported
region (e.g. mainland China, Thailand) fails with 400 User location is not supported for all keys — rotation cannot fix
that; switch the proxy node instead.

After a modlens upgrade

1
powershell -ExecutionPolicy Bypass -File "$env:USERPROFILE\.modlens\patch.ps1"

It detects whether the patch is still present; if a new version changed the
targeted code and the hunks no longer match, it reports which hunk failed and
tells you to file a new patch.

How it works

modlens ships two components in one package:

  • dsh/index.js — the dsh plugin shell: registers modlens_read_image,
    handles paste-to-path. It contains no image-reading logic; it spawns a
    child process running the CLI engine.
  • dist/main.js — the CLI engine: reads the image, calls Gemini
    (executeGeminiApi), parses structured JSON. Every read path funnels
    through this file.

The patch lives in executeGeminiApi: a single request becomes a loop that
rotates the pool on 429. See PATCH.md for the exact change.

Security

  • Keys are stored in plain text at ~/.modlens/api-keys.json (same trust
    level as modlens’s own config.json, which also stores the key in plain
    text). Do not share your home directory.
  • This repo contains no keys, no credentials, no machine-specific paths
    all paths derive from $env:USERPROFILE.

Credits & license

  • modlens by Leon Liu (liustack) — the vision engine this project wraps and patches. MIT licensed
    (Copyright © 2026 Leon Liu), see LICENSE.modlens.
    The patch hunks in this repo are a derivative modification of modlens
    source and carry its MIT notice as required.
  • This project is not endorsed by upstream — it is an independent utility
    that depends on modlens.
  • Our own scripts and docs: MIT (see LICENSE).
  • Full attribution: ACKNOWLEDGMENTS.md — please star
    the upstream project, the real work lives there.