Перейти к основному содержимому
V

dsh-deepseek-balance

vincibeans/dsh-deepseek-balance

DeepSeek account balance monitor for DSH: polls GET /user/balance every 5s and shows the balance in the web UI (session header pill + settings card).

Установка

dsh plugin --profile web add github:vincibeans/dsh-deepseek-balance

README

dsh-deepseek-balance

A DSH (DeepSeek Harness) plugin that polls the account balance of your DeepSeek API key every 5 seconds and shows it in the web UI.

  • a compact pill in the session header — total balance per currency, with a heartbeat dot (green = live data, amber = last poll failed and it is retrying, red = low balance or no balance available)
  • a settings card (Settings → Plugins → Configurable) with the balance details (granted / topped up / availability / last update) and the plugin configuration

中文 | English

Compatibility

Targets DSH v0.1.2-rc.1 and v0.1.3-alpha.2 (the latter verified against the alpha.2 checkout at 72fde8ccca). Both were verified end-to-end with scripts/compat-probe.mjs (11/11 checks: boot graph, bundle form, status endpoint, auth fence, pill render, card fold flow, clean console).

The contract surface this plugin consumes — everything else is local code or the platform seed table:

seamuse
dsh.bundle.patch row + dsh.client declarationhost load + browser bundle discovery
/plugins/??<pkg>/client.js module-table closure (window.__ModuleLoader__.load)browser half delivery
ctx.slots.inject/registerconversation.session.header.actions (pill), settings.plugin.item (card)
ctx.connection.fetch.registerhost status endpoint on the shared /api carrier, which applies the deployment's Host/Origin fence and browser authentication
browser fetch('/api/deepseek-balance')same-origin status read; no DSH client service involved
ctx.settings.installSection / ctx.settingsScope.bindconfiguration persistence
ctx.locale.registerzh/en copy
ctx.credentials.resolve (optional)DEEPSEEK_API_KEY; falls back to the process environment
platform seed rows react, react/jsx-runtime, @deepseek-ai/dsh-client-ui-primitivesbrowser bundle externals

Deliberately not used: connection.rpc.handle. Its route registration resolves the owner context through a cordis shadow and throws cannot get property "webServer" without inject for out-of-repo plugins on 0.1.3+ (no in-repo production code uses it). The exact Fetch route reaches the same carrier with the same auth and no such coupling.

Not supported: 0.1.1-rc.2 and earlier — that generation runs a different client-runtime contract.

Verify any DSH build yourself against a running instance (from a source checkout; the probe is not shipped in the npm tarball):

node scripts/compat-probe.mjs http://127.0.0.1:3080 <boot-token> --browser

Notable packaging fact: the 0.1.2-rc.1/0.1.3-alpha.* package line is not published to npm yet, so the plugin carries no runtime @deepseek-ai/* dependency — the host half bundles @deepseek-ai/schemastery (validation only) and everything else resolves from the DSH install; @deepseek-ai/* types are hand-written shims, never imports.

Install

The plugin does not store an API key: it resolves the same DEEPSEEK_API_KEY credential reference the model adapter uses (through DSH's credentials service, then the environment), so a key stored or rotated on the web Models page reaches the next poll. The key never leaves the host process — the browser only receives the balance snapshot.

From source (current)

npm install && npm run build          # build host + browser bundles
dsh plugin --profile <name> add ./dsh-deepseek-balance
dsh --profile <name>

Or as a git dependency once the repo has the prepare build (pnpm runs it after a git install; allow it if pnpm asks):

dsh plugin --profile <name> add github:VinciBeans/dsh-deepseek-balance

From npm (after the first release)

dsh plugin --profile <name> add @wenqi_bian/dsh-deepseek-balance

The npm package ships prebuilt lib/ bundles, so no build step is needed on install.

Quickstart

npm install
npm run build                            # lib/index.js (host) + lib/client.js (browser)
dsh plugin --profile <name> add .
dsh --profile <name> --dump-config       # a "== @wenqi_bian/dsh-deepseek-balance" layer appears
# restart dsh web, open a conversation — the balance pill sits in the session header

What you see

The pill shows CNY 100.00 next to the session title. Hover for the breakdown (granted / topped up / availability / last update / last error); click to refresh immediately.

statemeaning
green dotlast poll succeeded (ticked on each poll)
amber dotlast poll failed; it keeps retrying with the backoff below
red pillbalance below the threshold, or is_available is false
No keyno API key resolved

Configuration

Settings card

Settings → Plugins → Configurable → DeepSeek Balance:

fielddefaultmeaning
Poll interval (ms)5000query cadence; minimum 1000
Low-balance threshold10per currency; below it the pill turns red
API key environment variableDEEPSEEK_API_KEYcredential reference name
API base URLhttps://api.deepseek.comorigin for GET /user/balance

cordis.patch.yml

The same values as the entry row's config (the base layer; the settings card overrides them):

- insert:
    - id: deepseek-balance
      name: '@wenqi_bian/dsh-deepseek-balance'
      config:
        intervalMs: 5000
        lowBalanceThreshold: 10
        apiKeyEnv: DEEPSEEK_API_KEY
        baseUrl: https://api.deepseek.com

Failure behavior

Consecutive failures delay the next poll: failure 1 → max(2×interval, 10s), failure 2 → max(3×interval, 20s), failure 3 → max(4×interval, 30s), no further escalation. Any success resets the counter. The pill keeps the last successful value (amber dot) and the tooltip explains the reason; without a first success it shows a placeholder. A 401 is reported as an invalid key. While the browser tab is hidden the timer pauses; showing it again polls immediately.

Development

npm install
npm run build        # esbuild: lib/index.js (host) + lib/client.js (browser)
npm run typecheck
npm test             # node --test tests/

Load into a DSH source checkout without publishing — the entry row may point at the source file directly:

# dev.cordis.yml
- insert:
    - id: deepseek-balance
      name: 'file:///E:/path/to/dsh-deepseek-balance/src/index.ts'

On Windows the entry name must be a file:// URL (as above); on POSIX an absolute path works.

pnpm dsh web --patch ./dev.cordis.yml   # from the DSH checkout

The host half runs from TSX; build the browser half (npm run build) after client edits and refresh the page (or run the DSH client bundle watcher for no-refresh updates). Verify the composed tree with pnpm dsh --profile <name> --dump-config.

How it works

  • Host half (src/index.ts): registers the deepseek-balance settings section, then a private RPC channel /deepseek-balance (connection.rpc.handle — registered through a deferred inject because the connection service activates only after the web server binds). Each status call resolves the key from the credential seam and fetches GET {baseUrl}/user/balance; failures come back as typed codes (no-key, unauthorized, network, api, invalid-response).
  • Browser half (src/client/): one reference-counted poller drives both surfaces over connection.rpc.call('/deepseek-balance', 'status'); the pill (BalancePill.tsx) and the settings card (BalanceCard.tsx) render with DSW design tokens, and the copy follows the UI language (ctx.locale, zh/en, en fallback).

Design decisions are recorded in docs/adr; the domain glossary is in CONTEXT.md.

License

MIT — see LICENSE.

Похожие плагины