DeepSeek Harness plugin

dsh-web-billing

RMB/USD token-billing plugin for DSH web: official-policy auto pricing (incl. peak/off-peak), per-message ledger, account balance, locale-driven currency display

Jump to install

Source facts

Repository
bpc-oss/dsh-web-billing
Latest update
Aug 22, 2026
Category
Usage & Billing
GitHub stars
11
Format
plugin
Catalog evidence
Upstream dsh.bundle evidence
Evidence path
package.json#dsh.bundle
Checked against
0.1.0-rc.8
Upstream check date
2026-08-20

This evidence comes from the upstream catalog. This site has not installed, run, or security-reviewed the plugin.

Install

Start with a prompt that asks an agent to review the GitHub repository and source. Switch to the command if you want to install it yourself.

Copy this prompt into DSH, Codex, or another agent and ask it to review the GitHub repository and source first.

Do not install or run any commands yet. Read this plugin's GitHub repository, README, and relevant source code. Then answer the questions below clearly and directly so I can decide whether it fits my needs:

1. What is this plugin, and what problem does it solve?
2. Who is it for, and what are its typical use cases?
3. How is it used after installation? Include one minimal example.
4. What known limitations or privacy, security, compatibility, or maintenance risks does it have?
5. Give a clear recommendation: recommend, conditionally recommend, or do not recommend, with reasons.

Distinguish statements documented by the repository, inferences from source code, and unknowns. If evidence is insufficient, say so explicitly. Do not guess or simply repeat the README.

GitHub: https://github.com/bpc-oss/dsh-web-billing
Plugin: dsh-web-billing
Author: bpc-oss

Check the source files

Read the README and other files from this plugin directory before installing.

File explorer4 files
README.en.mdSource · read only
README language

dsh-web-billing

简体中文 · English

![License: MIT](LICENSE) ![GitHub stars](https://github.com/bpc-oss/dsh-web-billing/stargazers) ![GitHub release](https://github.com/bpc-oss/dsh-web-billing/releases) ![dsh-plugin](https://github.com/topics/dsh-plugin)

A RMB/USD token-billing plugin for DeepSeek Harness (dsh web / desktop). Bills every LLM call automatically against the official DeepSeek pricing policy schedule (including peak/off-peak pricing effective 2026-08-17), persists a ledger, shows the account balance, and renders live cost badges in the browser — displaying USD when the UI language is English.

In one line: make your AI spend visible, itemized, and optimizable — official prices auto-follow, local/subscription/free-ride are classified precisely, history re-prices on demand, budget and balance are always visible.

> ⚠️ Token and cost figures are a local DSH ledger: only completed > assistant/message events captured in this $DSH_HOME after the plugin was > installed. They are not the official DeepSeek account invoice. The balance > comes from /user/balance; reconcile usage across API keys and applications > with the DeepSeek console Usage export.

---

📸 Screenshots

Session header badge (hover for this-session details)Settings → Cost page (English UI, current layout)
![Session badge](docs/screenshots/badge-session-en.png)![Cost page](docs/screenshots/settings-en-current.png)

> Screenshots above are from the English UI; the Chinese-UI equivalents are > in README.md (the shared settings-*.png captures are > Chinese-UI screenshots).

---

✨ Key features

1. Official policy auto-pricing (peak/off-peak)

lib/pricing.js ships a curated official policy schedule (OFFICIAL_PRICING_POLICIES):

Effective (Beijing)PolicyModel prices (¥/1M; cache-hit / cache-miss / output)
2025-02-09deepseek-chat / deepseek-reasoner standard0.5/2/8 · 1/4/16
2026-05-22V4 series 75% cut made permanentv4-flash 0.02/1/2 · v4-pro 0.025/3/6
2026-08-17Peak/off-peak (peak 09:00-12:00 / 14:00-18:00 Beijing; off-peak = half)see below

Peak/off-peak prices (¥/1M):

ModelOff-peak (cache-hit / miss / output)Peak (cache-hit / miss / output)
deepseek-v4-flash0.05 / 1.5 / 4.50.10 / 3.0 / 9.0
deepseek-v4-pro0.15 / 4.5 / 13.50.30 / 9.0 / 27.0

Semantics:

  • Priced by message time: each message is billed with the policy and phase

active at its completion time; new policies apply automatically.

  • Policy-chain inheritance: a model not named by a newer policy keeps its

last named price (historical bills stay consistent with the platform).

  • Self-healing: when the schedule or config changes, the ledger is re-priced

on restart using each record's stored token counts.

  • User overrides: exact model entries in prices override the official

table; * only fills models the official table never named. officialPricing: off uses only the user table.

  • Extensible: append future official price changes via policyOverrides

config — no code change needed (PRs to lib/pricing.js welcome).

> The schedule is curated from official announcements > (DeepSeek API Docs); > verify against the official page and send a PR if you spot drift.

2. Coding-plan billing (full DSH preset coverage)

Besides the DeepSeek official API, you can connect various coding plans (subscription coding bundles) in DSH, such as opencode-go / opencode / kimi-coding, plus qwen / xiaomi / z.ai token subscription packs. This plugin ships the official USD prices for every model on these platforms (sourced from the DeepSeek Harness official pi-ai catalog, see lib/coding-plans.js), and prices by provider routing:

  • Official platform prices (opencode-go / opencode / kimi-coding): each

model's USD price ($/1M) is published by the platform. The RMB display value = official USD price × codingUsdCnyRate (default reference rate 7.2; display conversion only — DeepSeek's own prices have official CNY and never use this rate).

  • Subscription token packs (qwen-token-plan (incl. -cn) /

xiaomi-token-plan (incl. -ams/-cn/-sgp) / zai-coding-cn): no per-token price is published; calls are within the subscription allowance and are billed at 0.

  • Routing rule: a message takes the coding-plan route only when both

(provider, model) match that platform's table; anything else keeps the DeepSeek official policy chain (including peak/off-peak). The same model name (e.g. glm-5.2) is billed at opencode's official price under opencode-go and at each platform's own price under a direct API — never cross-priced.

  • Follows official automatically: regenerate the price table any time from

your local DSH catalog with node scripts/sync-coding-plans.mjs; the source version (pi-ai version + generated time) is part of the pricing fingerprint, so a table change re-prices history on restart.

> Unlike the DeepSeek official prices, coding plans have only official USD > prices — the RMB figures are a reference conversion at > codingUsdCnyRate (configurable); the USD figures are always the official > truth.

3. Provider metering (billing model)

Each provider can have its own billing model (Settings → Cost → Provider metering, takes effect immediately — no restart):

ModeMeaning
usagePay-per-use: billed at the official/platform price
usage-freeUsage + free ride: pay-per-use, but models on the free-model list are billed at 0
subscriptionSubscription: fixed monthly fee (monthly), calls billed at 0, nominal value shown as "recovered"
freePromo-free: calls billed at 0 (genuinely free)
localSelf-hosted: calls billed at 0 (you save the API cost)
  • Free-ride picks: the settings page lists every free model from the

pi-ai catalog (openrouter 17 / nvidia 16 / opencode 7 / google 2 / huggingface 1 / mistral 1 / vercel-ai-gateway 3 …; see lib/promo-models.js, generated by scripts/sync-promo-models.mjs) as a compact hint; rerun the script after DSH upgrades to refresh the promo data.

  • History re-pricing: switching a billing model **immediately re-prices all

history** (free/subscription/local records drop to 0 cost and become nominal savings) — no restart.

  • Recovery view: subscription monthly fee vs cumulative recovered amount,

visible in source groups and the header panel.

4. Cost page (Settings → Cost)

The browser-side summary page (read-only plus a few immediate settings):

  • Time-range filter: today / this week / this month / last 30 days / all /

custom start-end; every module (overview / sources / models / sessions / history) follows the range; defaults to this month.

  • Overview & source breakdown: range card (cost + gold saved total +

source strip), today / total / Token / balance cards.

  • Token stats: total tokens split into input (miss) / cache-hit / output —

cache-hit rate at a glance.

  • Source groups: local-saved / subscription-recovered / free-ride / usage,

each with a semantic accent bar and detail rows (pure savings tinted by source; real paid calls stay neutral).

  • Monthly budget: set a ¥ monthly budget; progress bar green→amber→red with

red over-budget highlight; budget stays locked to the current month.

  • Header balance toggle: controls whether the session-header badge shows the

balance; the settings page always shows it.

  • Data integrity: ledger view-consistency self-check (integrity) plus

explicit historical-trimming gaps (bdpGap / repriceGap) — gaps are visible and reconcilable, never silently shrink the ledger.

  • Export: CSV (UTF-8 BOM) / JSON one-click download.
  • Session titles: session list shows titles instead of UUIDs.
  • Version & updates: at the bottom — checks GitHub Releases for a newer

version and links to it.

> Aggregation note: range details come from the recent-ledger window > (maxRecent, default 100000 records); older data is aggregate-level only > (day totals are always full).

5. Session-header badge (top-right)

  • This session's today / cumulative cost + savings (savings total is

gold, distinct from per-source colors).

  • Per-model stats: cumulative amount per model + Input / cache-hit-rate /

Output; provider tags tinted by source (local green / free-ride sky / recovered purple / usage gray).

  • Per-model gap hint: when historical migration/trimming leaves the per-model

total below the session total, the panel shows an amber hint (Model split gap (trimmed history not in per-model rows) ¥X) — the money is NOT lost (it stays in the totals), it just can no longer be attributed to a specific model row; new data never shows this hint.

  • Balance row (toggleable): official account balance.
  • DeepSeek peak/off-peak hint: shows the current phase when the session

uses DeepSeek-family models.

  • Panel UX: rendered via React portal (never covered by the sidebar),

anchored to the badge, opaque themed background, hover auto-open/close.

6. Account balance

Reuses the provider's API key to call the official GET /user/balance (60s refresh, 5s timeout); CNY/USD both reported with the billing state. A transient failure (timeout / network hiccup) does NOT erase the last proven balance — the stale value is kept (the settings page subtitle reads "Balance from the last successful query (current query failed; retrying automatically)") while periodic refreshes retry; only a never-succeeded query shows "Unavailable". The runtime toggle controls the header display (balance.enabled or the settings toggle; turning it off stops polling and stops using the API key).

7. Pricing intel (current unit prices & next transition)

/billing/state exposes pricing intel for the client and external tools:

  • currentUnitPrices: the currently effective official unit prices

(dual currency + peak/off-peak mode);

  • nextTransitionAt: the next peak/off-peak or policy switch (epoch ms;

probed within 72h, null beyond — cannot actually happen since peak/off-peak switches daily), computed by nextPricingTransition in lib/pricing.js (hour probing then binary search to the second — crosses future policy boundaries);

  • observedAt / refreshIntervalMs: observation time and suggested refresh

interval (1h);

  • source: the official pricing page the schedule is curated from.

Install

The plugin is a standard DSH bundle (dsh.bundle.patch → its own cordis.patch.yml), following the official packaging guide:

# From GitHub
dsh plugin --profile web add github:<owner>/dsh-web-billing
# Or from npm (once published)
dsh plugin --profile web add dsh-web-billing
# Or link a local checkout (no copy; edits take effect on restart)
powershell -ExecutionPolicy Bypass -File scripts/install.ps1 -Profile web

> On git installs, pnpm >=10 may ask for a build authorization: add the > prompted package key to pnpm-workspace.yaml allowBuilds in the profile > and retry (this package has no prepare build, so authorization is > usually not needed).

Restart dsh web afterwards. Run only one instance per `$DSH_HOME (multiple instances would contend for the same ledger file). To override defaults, rewrite the plugin config row in $DSH_HOME/profiles/web/cordis.patch.yml` — the patch replaces the whole row's config, so restate every key you keep:

Configuration

KeyDefaultMeaning
currencyCNYCurrency identifier
symbol¥RMB display symbol
symbolUsd$USD display symbol
displayCurrencyautoauto=follow UI language; CNY/USD forces one
timezoneAsia/ShanghaiIANA timezone for peak/off-peak windows
peakWindows[[9,12],[14,18]]Peak hours (local, [start,end))
officialPricingautoauto=official auto-pricing; off=use only prices
prices{}User price table (override/fallback, ¥/1M)
usdPrices{}Optional USD overrides ($/1M)
localProviders[]Self-hosted providers: official value, actual cost at localCostPerM, difference = savings
localCostPerM0Actual local cost (¥/1M, uniform; 0 = free)
codingUsdCnyRate7.2Reference $→¥ rate for coding-plan USD prices (display only)
policyOverrides[]Extra official policy entries (since required; prices or peak+offPeak)
persistPath~/.dsh/storages/web-billing.jsonLedger file path (core aggregates, high-frequency writes)
maxRecent100000Recent-ledger window (range details)
maxMessagesPerSession2000Per-session message detail cap
detailWriteIntervalMs30000Detail-file (session messages + recent, separate -detail.json) debounce interval; raise to cut write frequency (loses ≤interval of details on power loss, aggregates untouched)
loopbackOnlytrue/billing endpoints loopback-only
balance.enabledtrueInitial header-balance enabled state
balance.endpointhttps://api.deepseek.com/user/balanceBalance endpoint (prefixed with DEEPSEEK_BASE_URL when set)
balance.apiKeyEnvDEEPSEEK_API_KEYCredential reference for the API key
balance.refreshMs60000Balance refresh interval
balance.timeoutMs5000Balance request timeout
metering{}Static billing-model table: { provider: { mode, monthly?, freeModels? } } (runtime edits persist to web-billing-metering.json)

Unit fields: input=cache-miss input, cacheRead=cache-hit input, output=output (¥ per million tokens).

Ledger correctness

  • Idempotent: keyed by (sessionId, messageId); replayed/duplicate events are skipped entirely (first write wins — global counts, session aggregates and details all recognize the first write only). Restarts do NOT replay history (dsh-session constructor seeds do not emit events); idempotency covers in-run duplicate delivery within the retained message window.
  • Local timezone for "today / this month".
  • Durability (split persistence, v2.3.2): the ledger is split into core aggregates (web-billing.json, ~0.2MB, 1s debounce high-frequency) and details (web-billing-detail.json, session messages + recent, default 30s debounce + flush on exit) — a large ledger no longer serializes tens of MB on every session event (which froze the event loop). Power loss loses at most one detail interval of details; aggregate statistics never lose data (missing detail file is tolerated; reprice is guarded against zeroing out). The detail interval is configurable via detailWriteIntervalMs. A corrupt/unreadable ledger starts empty with a warning; oversized detail (>20MB) warns (lower maxRecent / maxMessagesPerSession).
  • Audit fields: unitPrice and pricing mode (flat / peak / offPeak) per message.
  • Reprice gap: history revaluation (after price/metering changes) is bounded by the retained per-message records (session details ∪ recent window); messages trimmed from both cannot be repriced and their old-price contribution is lost on revaluation. The gap is surfaced explicitly as repriceGap in /billing/state and flagged on the cost page — never silently shrinks the ledger.
  • Per-model gap: the per-model aggregates (bySessionModel) may total less than the session total on migrated ledgers (messages trimmed from both retained windows cannot be backfilled); the difference is returned as modelGap in /billing/session/<id> and flagged in the panel — money is not lost, only its per-model attribution.
  • Balance read-only: only the official read endpoint; the key never reaches the browser.

Security

  • /billing endpoints loopback-only by default; loopbackOnly: false for LAN (no auth).
  • State-changing POSTs (metering / budget / balance) additionally require a

same-origin check: browser cross-site simple requests (text/plain POST) carry an Origin; it must match the Host. Requests without an Origin (local tools such as curl) are allowed (the loopback guard already restricts the source address).

  • Reads session/event and serves read-only endpoints only - never mutates session data.
  • Ledger stays local ($DSH_HOME/storages/), no message content, never uploaded.

Develop

npm run check   # syntax checks
npm test        # pricing / balance / ledger unit tests (node:test, zero deps)
node scripts/sync-coding-plans.mjs   # regenerate coding-plan prices from your DSH pi-ai catalog

Layout: lib/pricing.js (pricing engine incl. coding-plan route + metering), lib/coding-plans.js (generated coding-plan prices), lib/promo-models.js (generated free-model catalog), lib/balance.js, lib/index.js (host: ledger, balance, metering/budget/balance toggle, /billing routes), lib/client.js (browser: session badge, message chip, Settings→Cost page; handwritten bundle, no build step), test/, scripts/. The browser bundle is a handwritten module (same format as official DSH client plugins): client changes take effect after a page refresh + dsh web restart; host-side changes need a restart.

Contributing / 贡献

PRs and issues are welcome (English or Chinese). This repository is maintained bilingually: doc changes must update both README.md (Chinese) and README.en.md (English), and config comments are bilingual. Full rules in [CONTRIBUTING.md](CONTRIBUTING.md).

License

MIT