dshcost
Verified@stuchenxj/dshcost · v1.0.5 · MIT · Web UI
Session cost readout for the DeepSeek Harness Web GUI: prices every model call at DeepSeek's official peak/off-peak rates and shows the running session cost under the composer.
Install
dsh plugin add @stuchenxj/dshcost Confirm the layer applied with dsh --profile default --dump-config — see the install guide.
Source
Tags
Creators
Readme
dshcost
A publishable Cordis plugin for the DeepSeek Harness Web GUI that records and displays the current session's model consumption and estimated cost in real time, right under the composer.
It prices every model call at DeepSeek's official peak/off-peak rates and shows a compact readout like:
💰 本会话费用 ¥0.0123 · 模型 deepseek-v4-flash · 输入 12.3K · 缓存 20.1K · 输出 1.2K · 6 次调用
With the UI set to English the readout reads:
💰 Session cost:¥0.0123 model:deepseek-v4-flash input:12.3K cache:20.1K output:1.2K 6 calls
Hovering the readout shows the per-model breakdown and the full token usage.
Localization
The readout follows the DSH UI language through the client locale service (@deepseek-ai/dsh-client-locale): zh → 中文, en → English, and only those two are shipped — any other locale falls back to Chinese. Switching DSH's language (Settings → General → Language) updates the readout instantly without a reload. If the locale service is absent from the composition, the client falls back to the Chinese dictionary.
How it works
- Host half (
lib/index.js) registers a session projection unitsessionCostwithctx.sessionProjections. It replays the session log's provider-usage records (assistant/chunkusage samples plus the finalassistant/messageusage per step), tracks the model fromrequest/header/ message source, and estimates cost from:- token buckets (input + cache-write billed as input, cache-read, output),
- the model's price table,
- the call time in Beijing to pick peak vs. off-peak pricing.
- Client half (
lib/client.js) is a web module that registers a read-only cell in theconversation.composer.dockslot and reads the projection reactively via the slot's standarduseProjection('sessionCost')prop — no polling, no Client→Host RPC.
Because the data lives in a durable session projection, the readout survives process restarts: after a restart the projection refolds from the session log (or a checkpoint), so history is not lost.
Pricing
Prices in CNY per million tokens (DeepSeek official peak/off-peak pricing, effective 2026-08-17):
| Model | input peak / off | cache read peak / off | output peak / off |
|---|---|---|---|
| deepseek-v4-flash | 3.0 / 1.5 | 0.1 / 0.05 | 9.0 / 4.5 |
| deepseek-v4-pro | 9.0 / 4.5 | 0.3 / 0.15 | 27.0 / 13.5 |
Peak hours = Beijing 09:00–12:00 and 14:00–18:00; the rest is off-peak (half price). Cache writes are billed as input. Model ids with a version suffix (deepseek-v4-flash-0731) resolve to the base model price. Calls from models not in the table are counted as unknownCalls and shown as "价格未知".
These are estimates for display, not billing records.
Install & mount
The package is published on npm as @stuchenxj/dshcost and is also a profile bundle (its manifest declares dsh.bundle.patch).
[!WARNING] Do NOT run
npm installdirectly inside$DSH_HOME/profiles/node_modules— that directory has nopackage.json/lockfile, so npm treats the whole runtime dependency tree as extraneous and prunes it (this has wiped 500+ packages in practice). Install into a temp dir and copy the package in:tmp=$(mktemp -d) && cd "$tmp" && npm i @stuchenxj/dshcost # then copy "$tmp/node_modules/@stuchenxj/dshcost" into $DSH_HOME/profiles/node_modules/
Option A — as a bundle (add to a profile's dsh.profile.bundles):
// $DSH_HOME/profiles/web/package.json
{
"dsh": {
"profile": {
"bundles": ["@deepseek-ai/dsh-base", "@deepseek-ai/dsh-web-app", "@stuchenxj/dshcost"]
}
}
}
Option B — as a plugin row in the profile patch:
# $DSH_HOME/profiles/web/cordis.patch.yml
- insert:
- id: dshcost
name: '@stuchenxj/dshcost'
[!IMPORTANT] The client bundle registers via
__ModuleLoader__.load({ id: "dshcost" }). That string must equal the composition rowid(the boot-graph entry name) exactly — no@scope. The rownameis only the npm package name used to resolve the package; the loader does NOT key off it. A mismatch (e.g. an old client.js registering@stuchenxj/dshcost) fails the whole plugin tree withclient-modules: bundle ... loaded without registering "dshcost". Keep the row asid: dshcost+name: '@stuchenxj/dshcost'and never rename theid.
Install the package where the profile can resolve it (its node_modules, or the flat $DSH_HOME/profiles/node_modules fallback), then restart (bundle) or let patch HMR apply it (row) and reload the page. Requires ctx.sessionProjections (present in the standard Web profile via @deepseek-ai/dsh-session-projection).
Development
lib/index.js— Host half: thesessionCostprojection unit (pure fold, plain ESM, depends only onzod).lib/client.js— Client half: theconversation.composer.dockreadout (plain JS,window.__ModuleLoader__format, requires onlyreact).
Edit lib/index.js / lib/client.js, no build step. Bump stateVersion in the projection unit if you change the fold state shape (stale checkpoints then refold).
License
MIT