Skip to content

About

A DSH plugin that turns one provider API key into a managed pool + more built-in LLM Providers

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Latest commit

 

History

477 Commits

Folders and files

Repository files navigation

DSH Keys Manager

npm downloads License: MIT Node DSH

English | 简体中文

A DeepSeek Harness plugin that turns one provider API key into a managed pool. It extends the Models page rather than replacing it: providers, models, and the model picker stay where they are; only the API-key source moves behind the manager.

What it does

Pool and routing

  • Several keys per provider, each with an alias and a health state.
  • One key pinned to a session, round-robin for new sessions; a failing request is retried on its key, then moved to another key.
  • Exponential cooldown recovery, capped at seven days.

Accounts and sign-in

  • Seven pi-ai OAuth providers can join the pool as an account instead of a pasted key.
  • Two more sign in through the plugin's own bundled clients: Kilo and Z.AI Coding Plan.
  • Seven companion transport routes for providers the vendored pi-ai cannot speak: Cursor, Devin, the two Google routes, Factory Droid, and the two GitLab Duo routes.

Interface

  • A search-driven Keys Manager page on the plugin's own detail page.
  • A "managed by Keys Manager" badge inside the existing Models provider cards.
  • Extra built-in providers installed as ordinary llm-pi-ai routes — 35 of them, listed under Provider coverage.

Quick start

Install

In the Desktop or Web app, open Plugins → Add plugin, enter dsh-keys-manager, click Install, then Enable now. This installs the same published package as the CLI path, already carrying its built bundle.

dsh plugin --profile web add dsh-keys-manager

One install yields both bundles, dsh-keys-manager and llm-omp-transports; enable both — the manager owns credentials and routing, the transport the seven routes' wire protocols. Refresh the Web page afterwards for the browser half.

Install from a local checkout
git clone https://github.com/btspoony/dsh-keys-manager
cd dsh-keys-manager
pnpm i
dsh plugin --profile web link .

add installs the published tarball with its built lib/ and client bundle; link . builds them via prepare during pnpm i, as does prepack when packing.

Use it

Take over a provider and add keys

  1. Search for a provider. Open Plugins → Keys Manager → View (Plugins → 密钥管理 → 查看 in the Chinese locale); the manager renders on the plugin's detail page. Existing DSH providers appear first; the plugin also ships the curated extra catalog described under Provider coverage.
  2. Adopt a provider. For an existing provider the manager imports the currently resolved credential, writes a broker reference into the provider profile, and leaves the original key in the credential store so release can restore it.
  3. Add more keys with an alias. Every key is stored in the Harness credential store under its own reference; the manager state document never contains a key literal.
  4. Manage a key from the three-dot menu: rename, pause/resume, delete. A key row shows status, last use, and the recovery time while cooling.
  5. Tune retry count (1–3), base cooldown, and recovery grace in the settings card.

Accounts and sign-in

Providers that ship a native OAuth sign-in offer two ways to join the pool: Add key stores a static API key, while Add account runs the provider's OAuth sign-in flow and stores the result as an account row in the same pool. Nine routes join as an account: seven through pi-ai's own flows, kilo and zai through the plugin's bundled clients (device code, pasted zcode:// redirect), which mint a static credential renewed only by Sign in again.

Route group How it joins Refresh / renew
9 OAuth accounts Add account — seven pi-ai flows, two plugin clients provider-managed for the seven; Sign in again for the two static credentials
7 transport routes Transport accounts — one grant per route see Transport routes

API keys form the selection ring — sticky sessions, round-robin, retry failover and cooldowns operate across the provider's keys — while one projected OAuth grant serves its provider, and an account row's counters reflect only that account's own successes and failures. Per-account ranking is future work. When the projected grant fails, the account cools down and the pool falls back to its keys, or stops serving on an OAuth-only route until a manual re-login.

muse-code needs no transport or account row of its own: the vendored pi-ai meta route (openai-responses on https://api.meta.ai/v1) serves it, the agreement check was static, and the first live call is a manual smoke check per Known limits.

Transport routes

Providers the vendored pi-ai cannot speak are served by the companion dsh-llm-omp-transports component:

  • One grant per route, at llm-omp-transports/<route> — no key pool and no per-account rotation. Sign-in happens in the Transport accounts section of the Keys Manager page.
  • Models are generated from the pinned @oh-my-pi/pi-catalog@18.12.3 table when the transport is built, and the clients are unofficial: read the transports package docs and its known limits before relying on them.
Route Sign-in Refresh Model rows
cursor browser page + poll on the credential seam 123
devin paste the landed callback URL none — sign in again 2
google-gemini-cli loopback 8085 + paste fallback on the credential seam 7
google-antigravity loopback 51121 + paste fallback on the credential seam 22
factory-droid WorkOS device code (URL + user code) one refresh in a 60 s window, keeps orgId/region 62
gitlab-duo PKCE loopback localhost:8080/callback, no port fallback, paste fallback one refresh in a 60 s window 16
gitlab-duo-agent paste the vscode:// URL one refresh, echoes the vscode redirect 1
Per-route notes
  • Cursor — streams text and reasoning and hands tool calls to DSH's tool loop; images are refused with a typed error. The client presents Cursor's vendor-internal OAuth identity.
  • Devin — no refresh: a static bearer whose expiry is derived from the token (JWT exp minus five minutes, else one year), and without a readable expiry the row shows active with a blank countdown column.
  • Google routes — both share one generated lib/omp/google.mjs artifact yet keep separate grants, account rows and catalogs. The grant is {access, refresh, expires, projectId, email?}; sign-in resolves the Cloud project the route bills, and a legacy-tier or paid account whose project cannot be discovered fails AUTH_FAILED until GOOGLE_CLOUD_PROJECT (or GOOGLE_CLOUD_PROJECT_ID) is set.
  • Factory Droid — four wires behind one proxy, chosen by model id inside the artifact; rows carry no base URL and the account's residency (orgId/region) survives refresh.
  • GitLab Duo pair — gitlab-duo's direct-access token cache is keyed on the GitLab token, so a rotated token misses it; gitlab-duo-agent re-seeds a workflow per request and replays the transcript rather than resuming a socket.

Selection and failure policy

Mechanism Behaviour
Sticky session The first request of a session selects a key and binds it for that session/provider pair. Later requests reuse it.
Round robin A new session advances the provider cursor and takes the next healthy key.
Retry A failing request is retried on the same key retryCount times. Request-shaped failures such as CONTEXT_WINDOW_EXCEEDED and cancellation never cool a key.
Switch After the retry budget is spent, the failing key is marked cooling, and the session is rebound to another healthy key. When no alternate key exists, the manager delegates to the composition's normal retry/fallback policy.
Cooldown The first failure cools a key for baseCooldownMs. A failure while cooling, or within recoveryGraceMs after recovery, doubles the next cooldown; a long healthy gap resets the escalation. The hard cap is seven days.
Recovery The key is automatically selectable again when its cooldown expires; no manual reset is required.

Configuration & data

Manager metadata lives at:

$DSH_HOME/keys-manager/state.json

with owner-only permissions. It contains aliases, credential references, health counters, session bindings, and provider adoption facts. API key literals live only in the Harness credential store; an account row follows the same rule behind its grantRef, with only non-sensitive metadata (email, account id, expiry) in the state. The file is written atomically through a temporary file and a rename.

Each managed provider profile points its apiKeyEnv at a broker reference such as KEYSMGR_ZAI_CODING_CN_3FA2C1. The Host credential layer answers that reference per request with the session's selected key. The Models page sees the profile as configured; writing directly to the broker reference is refused with a pointer to the manager.

OAuth2 extension point

The state shape already distinguishes kind: "api-key" from kind: "oauth" and keeps a nullable oauth object beside the credential reference. A future account flow can add records under keys-manager/<provider>/<key> without rewriting existing rows. Providers whose only authentication is OAuth are reported as unsupported in this version rather than being treated as API-key providers.

Provider coverage

Four groups, one pool:

  • DSH built-in — routes from the shipped DSH pi-ai catalog. The set follows your installed DSH version, so the Models page is the authoritative list; four of them are outside single-key pooling (below).
  • Plugin extra built-in — 35 routes this plugin adds as ordinary llm-pi-ai routes.
  • OAuth accounts — 9 routes that join as an account instead of a pasted key: seven use pi-ai's own flows, kilo and zai are signed in by the plugin's bundled clients.
  • Transport routes — 7 routes the vendored pi-ai cannot speak, served by dsh-llm-omp-transports.
Supported — every plugin extra, OAuth account and transport route

Plugin extra built-in — 35 — from oh-my-pi's provider catalog (MIT):

Provider Route id API key env
DeepInfra deepinfra DEEPINFRA_API_KEY
Novita novita NOVITA_API_KEY
StepFun stepfun STEPFUN_API_KEY
SambaNova sambanova SAMBANOVA_API_KEY
Qianfan qianfan QIANFAN_API_KEY
GMI Cloud gmi-cloud GMI_API_KEY
Synthetic synthetic SYNTHETIC_API_KEY
ZenMux zenmux ZENMUX_API_KEY
Kilo Gateway kilo KILO_API_KEY
NanoGPT nanogpt NANO_GPT_API_KEY
Venice AI venice VENICE_API_KEY
AIML API aimlapi AIMLAPI_API_KEY
AI& aiand AIAND_API_KEY
Helmcode helmcode HELMCODE_API_KEY
Alibaba Coding Plan alibaba-coding-plan ALIBABA_CODING_PLAN_API_KEY
MiniMax Coding (Global) minimax-code MINIMAX_CODE_API_KEY
MiniMax Coding (CN) minimax-code-cn MINIMAX_CODE_CN_API_KEY
Umans AI Coding Plan umans UMANS_AI_CODING_PLAN_API_KEY
Sakana AI sakana SAKANA_API_KEY
CoralBricks coralbricks CORAL_API_KEY
Wafer Serverless wafer-serverless WAFER_SERVERLESS_API_KEY
Alibaba Token Plan alibaba-token-plan ALIBABA_TOKEN_PLAN_API_KEY
Alibaba Token Plan (CN) alibaba-token-plan-cn BAILIAN_TOKEN_PLAN_API_KEY
Charm Hyper charm-hyper CHARM_HYPER_API_KEY, HYPER_API_KEY
LiteLLM Proxy litellm LITELLM_API_KEY
SiliconFlow siliconflow SILICONFLOW_API_KEY
SiliconFlow (CN) siliconflow-cn SILICONFLOW_CN_API_KEY
Zhipu Coding Plan zhipu-coding-plan ZHIPU_API_KEY
Abliteration abliteration ABLITERATION_API_KEY, ABLIT_KEY
ClinePass cline-pass CLINE_API_KEY
Command Code commandcode COMMAND_CODE_API_KEY, COMMANDCODE_API_KEY
CoreWeave Serverless Inference coreweave COREWEAVE_API_KEY
Fire Pass firepass FIREPASS_API_KEY
Ollama Cloud ollama-cloud OLLAMA_CLOUD_API_KEY
Yolo Auto yolo-auto YOLO_AUTO_API_KEY

Where two variables are listed, either is accepted; the first is the primary. CoreWeave Serverless Inference also needs COREWEAVE_PROJECT=<team>/<project> in the DSH process environment before it is added.

OAuth accounts — 9

Provider Route Sign-in client
Anthropic anthropic pi-ai
GitHub Copilot github-copilot pi-ai
Kimi Coding kimi-coding pi-ai
OpenAI Codex openai-codex pi-ai
OpenRouter openrouter pi-ai
Radius radius pi-ai
xAI xai pi-ai
Kilo kilo plugin bundled client — device code + poll
Z.AI Coding Plan zai plugin bundled client — pasted zcode:// redirect

The two plugin-signed credentials are static, tagged signin:kilo / signin:zai-coding-plan, and nothing is written to llm-pi-ai/<provider>; the seven pi-ai rows are the provider's own grants. kilo is listed twice on purpose: the same route takes an API key as an extra built-in and an account through its bundled client.

Transport routes — 7 — cursor, devin, google-gemini-cli, google-antigravity, factory-droid, gitlab-duo, gitlab-duo-agent; sign-in, refresh and model detail live in Transport routes.

Not pooled — 4 DSH built-ins
Provider Why
amazon-bedrock AWS credential chain (profile, IAM keys, ECS/IRSA/EC2), not one API key
cloudflare-ai-gateway API key plus a Cloudflare account ID and gateway ID
cloudflare-workers-ai API key plus a Cloudflare account ID
openai-codex ChatGPT OAuth sign-in only; no API-key credential — usable as an OAuth account instead of a key

Every other DSH catalog route exposes an API-key credential; a route you declare yourself in the profile (自定义 / Custom) is pooled like any built-in.

Documentation

Doc Content
Development build and dev workflow, repository layout
Release CI checks and the npm release flow
Known limits current design boundaries, including the seven transport routes
Transports package Transport routes: support status, risks, build/test, release

Chinese: README.zh-CN.md · 开发 · 发布 · 已知限制.

License

Released under the MIT License.

About

A DSH plugin that turns one provider API key into a managed pool + more built-in LLM Providers

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Contributors

Languages