Bundle
dsh-cost-dashboard
Cost dashboard for DeepSeek Harness - model spend, tokens and cache usage across all sessions (settings section). DSH 费用看板:汇总全部会话的模型输入/输出/缓存 token 用量并按价格表计费。
- Source
- mike-lee0120
- stars
- 4 stars
- License
- MIT
- Updated
- Updated 3 days ago
Readme
# dsh-cost-dashboard
English | [中文](README.zh.md)
A cost-dashboard plugin for [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) (dsh): aggregates model input / output / cache token usage across **all local sessions**, prices it with a built-in table (including DeepSeek peak/off-peak time-of-day pricing), and renders a dashboard under **Settings -> Cost Dashboard**.
## What you get
- **Two entry points**: Settings -> Cost Dashboard (the settings nav icons are hardcoded by the dsh settings shell, so plugins cannot customize them), plus a **sidebar footer icon button** (data-grid style) that opens the same dashboard in an anchored panel
- **Currency switch**: displays in **USD by default** with a one-click CNY toggle; converts between CNY- and USD-listed prices at the configurable `fx.cnyPerUsd` rate (default 6.79)
- **Summary cards**: total cost, today's cost, input (cache-miss) / cache-read / cache-write / output tokens, session count
- **Daily trend chart**: ECharts smooth line charts (gradient area fill and hover tooltips); cost mode is a single unified-currency series, tokens mode splits into "input / cache write / output" and "cache read" charts on independent scales; selectable **1W / 1M / 3M** ranges (default 1W)
- **By-model table**: tokens, cost, share per model
- **By-session table**: sorted by cost, **one row per session-model pair** (a session that used several models appears on several rows, each with its own model, tokens and cost), with title, project directory, subagent badge
- **Pricing editor**: edit the pricing JSON (including the FX rate) in-page; saves to `~/.dsh/cost-dashboard.json`, effective immediately
- **Auto-synced catalog**: fills in models missing from builtin/overrides from the LiteLLM price JSON (24h TTL + disk cache, degrades on network failure); never overrides builtin or hand-written prices
- **Actual billing (optional)**: with read-only provider keys configured, shows DeepSeek/OpenRouter real balances and OpenAI/Anthropic real spend next to the estimate; domestic cloud vendors (Volcengine/Alibaba/Tencent) are not integrated - prices come from the config file
- **Auto refresh**: polls every 15s while open; the host re-reads only changed log files (mtime + size validated)
<p align="center">
<img src="assets/screenshot-en-1.png" alt="Cost dashboard - trend & summary" width="49%" />
<img src="assets/screenshot-en-2.png" alt="Cost dashboard - model & session breakdown" width="49%" />
</p>
## Install
```sh
dsh plugin --profile web add <spec>
```
`<spec>` may be a local path, an npm name, or a GitHub repo:
```sh
dsh plugin --profile web add /path/to/dsh-cost-dashboard
dsh plugin --profile web add github:mike-lee0120/dsh-cost-dashboard
```
`dsh plugin add` runs pnpm in the profile directory and **automatically** appends any `dsh.bundle`-declaring package to `dsh.profile.bundles`. Restart `dsh web` and refresh the page, then open **Settings -> Cost Dashboard**.
Remove with `dsh plugin --profile web remove dsh-cost-dashboard`.
Requires dsh `0.1.0-rc.7`+ and Node >= 22.15 (the `node:zlib` zstd API the host itself relies on for session logs).
## Data source and accounting
- Read-only scan of `$DSH_HOME/sessions/*/*/session.jsonl.zstd` (or plaintext `.jsonl`); nothing is written, no projection touched.
- Accounting mirrors the official `@deepseek-ai/dsh-token-meter` `tokenUsage` projection:
- `assistant/chunk {type:'usage'}` is an early sample that survives a later request failure;
- `assistant/message` usage is the final sample for the same `(turn, step)` and **replaces** it instead of double counting;
- four disjoint buckets: uncached input (DeepSeek `prompt_tokens` with cache hits subtracted), cache read, cache write, output.
- Model attribution: `assistant/message` carries `message.source.provider/model`; a bare usage chunk (failed request) is attributed to the latest `request/header` model.
- Mid-session model switches are split correctly.
- Run `node scripts/verify-totals.mjs` to reconcile against the official `session_projcache.json` (verified session-by-session in development; an actively-writing session may drift by a live-write race, which is expected).
## Pricing
Built-in pricing for 21 mainstream models (per 1M tokens, checked 2026-08-18; "hit" = cache-read rate, "write" = cache-write rate, defaults to the cache-miss input rate when unset):
**CNY-listed models**
| Model | Input (miss) | Input (hit) | Output | Notes |
|---|---|---|---|---|
| deepseek-v4-pro | 4.5 | 0.15 | 13.5 | peak doubles: 9 / 0.30 / 27 (09-12, 14-18) |
| deepseek-v4-flash | 1.5 | 0.05 | 4.5 | peak doubles: 3 / 0.10 / 9.0 |
| kimi-k3 | 20 | 2 | 100 | Moonshot China list price |
| qwen3.8-max | 12 | 1.5 | 36 | Alibaba Bailian China price |
| doubao-seed-2.1-pro | 6 | - | 30 | Volcengine Ark |
| hy3 | 1 | 0.25 | 4 | Tencent Hunyuan |
| minimax-m3 | 3.15 | 0.63 | 12.6 | ≤512K input, half-price list rate |
**USD-listed models**
| Model | Input (miss) | Input (hit) | Cache write | Output | Notes |
|---|---|---|---|---|---|
| gpt-5.6-sol | 5 | 0.5 | - | 30 | |
| gpt-5.6-terra | 2 | 0.2 | - | 12 | |
| gpt-5.6-luna | 0.20 | 0.02 | - | 1.20 | |
| gpt-5.5 | 5 | 0.5 | - | 30 | |
| gpt-5.4 | 2.5 | 0.25 | - | 15 | |
| gpt-5.1 | 1.25 | 0.125 | - | 10 | |
| claude-opus-5 | 5 | 0.5 | 6.25 | 25 | |
| claude-sonnet-5 | 2 | 0.2 | 2.5 | 10 | temporary rate through 2026-08-31, then $3/$15 |
| claude-fable-5 | 10 | 1 | 12.5 | 50 | |
| gemini-3.6-flash | 1.5 | - | - | 7.5 | |
| gemini-3.5-flash-lite | 0.3 | - | - | 2.5 | |
| grok-4.6 | 2 | - | - | 6 | |
| grok-4.6-fast | 4 | 1 | - | 12 | |
| glm-5.3 | 1.40 | - | - | 4.40 | Z.ai list price; override for the volcengine route |
- DeepSeek V4 peak/off-peak pricing effective 2026-08-17 (off-peak is half of peak; peak hours 09:00-12:00 and 14:00-18:00). Every usage record is timestamped, so the dashboard prices each sample by the host-local clock hour.
- Unpriced models count tokens only.
### Overrides
The in-dashboard **Pricing config** editor saves `~/.dsh/cost-dashboard.json` (per-model whole-entry overrides plus the FX rate):
```json
{
"fx": { "cnyPerUsd": 6.79 },
"models": {
"glm-5.3": { "currency": "USD", "input": 1.4, "inputHit": 0.14, "output": 4.4 },
"my-local-model": { "currency": "CNY", "input": 2, "output": 6,
"peak": { "input": 4, "output": 12 }, "peakHours": [[9, 12], [14, 18]] }
}
}
```
Fields: `fx.cnyPerUsd` (USD->CNY, default 6.79, used for cross-currency display); per model `currency` (CNY|USD), `input` (cache-miss), `inputHit` (defaults to input), `cacheWrite` (defaults to input), `output`; optional `peak` and `peakHours` (host-local hours; peak hours use peak rates, unset peak fields fall back to flat). The dashboard displays USD by default and converts CNY-listed prices at the FX rate; switching to CNY converts USD-listed prices the other way.
### Auto-synced catalog
- Beyond the builtin table, the dashboard fills missing models from the [LiteLLM price JSON](https://github.com/BerriAI/litellm/blob/main/model_prices_and_context_window.json) (USD rates, converted for display via `fx`).
- Priority: **user override > builtin > catalog** — the catalog only fills gaps and never overrides builtin peak pricing or your hand-written config.
- Refreshed every 24h and cached at `~/.dsh/storages/cost-dashboard-catalog.json`; on network failure it degrades to the cache, the status is visible in the dashboard footer, and a "Refresh prices" button retries manually.
### Actual billing (optional)
- Expand the **Actual billing** section and configure read-only provider keys to show real balances and spend alongside the estimate.
- Supported: **DeepSeek** `/user/balance` (balance), **OpenRouter** `/api/v1/key` (credits), **OpenAI** Cost API (daily spend), **Anthropic** Cost Report (daily spend).
- Credentials are stored at `~/.dsh/cost-dashboard-credentials.json` (mode 0600):
```json
{
"providers": {
"deepseek": { "apiKey": "sk-..." },
"openrouter": { "apiKey": "sk-or-..." },
"openai": { "adminKey": "sk-admin-..." },
"anthropic": { "adminKey": "sk-ant-admin-..." }
}
}
```
- Use read-only/billing-scoped keys only; remove an entry to stop fetching it. Domestic cloud vendors (Volcengine/Alibaba/Tencent) are not integrated - their prices live in the pricing config.
## Development
Plain `.mjs`, zero build step (host uses only Node builtins; the client is a hand-written module-loader bundle; charts use the vendored ECharts 5 build, Apache-2.0, served locally from `/cost-dashboard/vendor/echarts` - no CDN). Restart `dsh web` and refresh the page after any change.
## Security
- GET routes expose the same surface as other plugins' own routes (local data, no credentials).
- The pricing write (POST) accepts same-origin requests only (Origin==Host).
- Nothing is uploaded; the scan is read-only.
## Known limitations
- Costs are list-price estimates; no plans, discounts, or vouchers; peak hours use the host-local clock.
- Deleting session logs removes their history (statistics are entirely log-derived).
- Very large log corpora slow the cold scan; incremental caching keeps everyday refreshes fast.
Install
dsh plugin --profile web add github:mike-lee0120/dsh-cost-dashboard
Profile: web
With the hub plugin installed, ask your agent to install it by name — it resolves the same plan shown here.
dsh plugin --profile web add github:stvlynn/dsh.fish#path:packages/dsh-plugin-hub
install dsh-cost-dashboard from the hub
- This source has no pinned commit, so a later push upstream changes what installs. Prefer pinning a commit.