<p align="right"> <strong>English</strong> · <a href="./README_ZH.md">简体中文</a> </p>
<p align="center"> <a href="https://www.npmjs.com/package/dsh-provider-usage"><img src="https://img.shields.io/npm/v/dsh-provider-usage.svg?cacheSeconds=300" alt="npm version"></a> <a href="./LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="MIT license"></a> <img src="https://img.shields.io/badge/DeepSeek%20Harness-plugin-202724" alt="DeepSeek Harness plugin"> </p>
dsh-provider-usage
Every provider's balance, one glance away. A DeepSeek Harness plugin that floats a small draggable usage ball over the Web GUI — no more logging into each provider console to check whether you are about to run out of credit mid-session.
Features
- Auto-detection — enumerates the provider routes registered in the current profile (
ctx.llm); zero configuration for well-known routes. - Per-kind wire adapters — routes with no public balance/quota API (Google, Mistral, Groq, Bedrock, Azure, Qwen Token Plan, …) are listed as
unsupportedinstead of being silently dropped:
| kind | routes | query | shows | |
|---|---|---|---|---|
| --- | --- | --- | --- | |
deepseek | deepseek-official, deepseek | GET {baseURL}/user/balance | total / granted / topped-up balance | |
moonshot | moonshotai-cn, moonshotai | GET {baseURL}/users/me/balance | available / voucher / cash balance | |
kimi-coding | kimi-coding | GET {baseURL}/v1/usages | weekly quota + rate-limit windows, reset countdown | |
openrouter | openrouter | GET {origin}/api/v1/credits | credits used / total | |
github-copilot | github-copilot | GET api.github.com/copilot_internal/user | plan quota snapshots (paid) or monthly quotas (free) | |
openai-codex | openai-codex | GET {baseURL}/wham/usage | ChatGPT subscription 5h / weekly windows + credits | |
openai | openai | GET {origin}/v1/organization/costs | current-month spend (admin key required; a regular key fails with 403) | |
anthropic | anthropic | GET {baseURL}/v1/organizations/cost_report | current-month spend (admin key required, x-api-key auth) | |
minimax | minimax, minimax-cn | GET {origin}/v1/api/openplatform/coding_plan/remains | Coding Plan 5h / weekly remaining % | |
zai | zai, zai-coding-cn | GET {origin}/api/monitor/usage/quota/limit | GLM Coding Plan windows (raw key in Authorization, no Bearer) | |
opencode | opencode, opencode-go | GET {baseURL}/usage | Zen Go rolling / weekly / monthly windows | |
vercel-ai-gateway | vercel-ai-gateway | GET {baseURL}/v1/credits | team credit balance | |
xai | xai | GET {baseURL}/billing/credits | prepaid balance (USD) |
- Credentials stay safe — API keys are resolved per request through the harness credentials service (environment variables /
~/.dsh/.credentials.yaml); never cached, never written to disk. - Floating ball widget — a draggable floating ball opens the usage panel. Drop it anywhere in the viewport (position persisted); it docks by default at the bottom-left of the chat area with equal margins, and the panel-header home button sends it back. The halo around the ball encodes provider health: green all good, amber some quota below 30% left, red on query failure / missing key / usage ≥90%.
- Version badge — the panel header shows the running plugin version next to the title, so it is obvious which release is loaded.
- Bilingual panel — built-in Chinese/English UI; follows the harness language by default, with a one-click toggle in the panel header (persisted in localStorage).
- Configurable refresh — adjustable in the panel (15s–30min, persisted in localStorage); the default comes from the plugin config.
- Manual providers — add arbitrary gateways (e.g. a self-hosted DeepSeek-compatible endpoint) via config.
Screenshots
The floating ball (bottom-left, with the green healthy halo) and the open usage panel:

Install
> [!NOTE] > Requires an existing DeepSeek Harness installation.
npm
dsh plugin --profile web add dsh-provider-usage@latestBuild from source
git clone https://github.com/lizhouai/dsh-provider-usage.git
cd dsh-provider-usage
pnpm install
pnpm build
pnpm pack # produces dsh-provider-usage-<version>.tgz
dsh plugin --profile web add ./dsh-provider-usage-<version>.tgzInstall the tarball, not the repo directory: dsh plugin add . links the repo, whose own node_modules then shadows the harness's shared @deepseek-ai/cordis instance and the host half never registers (RPC 404). The link form is still handy for client-only UI iteration — the browser bundle is self-contained, so a rebuild + page refresh picks it up — but switch to the tarball (or the npm release) whenever you need the host half. If pnpm fails with EPERM ... symlink while replacing a linked install, delete the stale node_modules/dsh-provider-usage junction in the profile directory and retry.
Restart dsh web after changing the plugin set (a plugin add/remove requires a restart; afterwards, code changes only need a rebuild + re-add + page refresh).
Upgrade
dsh plugin --profile web add dsh-provider-usage@latestThen restart dsh web and refresh the page. If the release you want was published very recently, your profile's supply-chain cooldown (minimumReleaseAge) may silently keep the older version — pin the exact version instead (dsh plugin --profile web add dsh-provider-usage@0.3.1) and dsh will exempt it automatically. The version badge in the panel header confirms which release is actually loaded.
Configuration
Defaults work out of the box: the plugin auto-detects every provider route of the active profile. A trusted profile can tune behavior in ~/.dsh/profiles/web/cordis.patch.yml — override the bundle's row by id (the package's own bundle patch already inserts it; a second insert of the same id fails the boot with duplicate loader entry id):
- id: provider-usage
name: dsh-provider-usage
config:
refreshSeconds: 60 # suggested panel refresh interval (5–86400)
autoDetect: true # enumerate provider routes from the llm registry
providers: [] # manual specs; an id matching a detected route overrides it| Field | Type | Default | Description |
|---|---|---|---|
refreshSeconds | number | 60 | Suggested widget refresh interval in seconds (5–86400) |
autoDetect | boolean | true | Enumerate live provider routes from the llm registry |
providers | array | [] | Manual provider specs: {id, kind, baseURL, apiKeyEnv, displayName?, enabled?}; kind is one of the adapter table above |
The same fields can be hot-updated under the provider-usage: namespace in ~/.dsh/settings.yaml.
Adding a manual provider
config:
providers:
- id: my-deepseek-gateway
kind: deepseek
baseURL: https://my-gateway.example.com
apiKeyEnv: MY_GATEWAY_KEY
displayName: My GatewayHow it works
- Host half (
src/index.ts):UsageService extends TypertRemoteServiceexposesusage/listvia@Remote('list')(SRC mode, no codegen). Config is declared with schemastery, andinstallSettingsSectionenables hot updates from settings. - Client half (
src/client/): awindow.__ModuleLoader__.load({id, factory})bundle (built by tsdown) mounts through thesidebar.footer.actionslot (used purely as a mount point — the trigger itself is a floating ball portaled todocument.body) and pollsusage/listthroughctx.connection.rpc.call('/api', 'usage/list', {args:{}})on its own interval. The service stays stateless — every poll fetches live values.
License
[MIT](./LICENSE)