DSH HUB
HomePlugin StorePlugin PacksCommunityRankingsResourcesPublish Guide
Plugin source
Back to catalog

thezavtrak-a11y /

thezavtrak-a11y/dsh-cost-stats

Verified

Money on the screen for the DeepSeek Harness web GUI: per-turn USD cost in the chat, a Cost tab with charts, ratings and an interactive spend timeline, and a local price table you control.

★ 0 Stars0 Forks0 IssuesN/A Community rating0 Confirmed installs
View on GitHub
READMESource: main@7d6c0013

dsh-cost-stats

Money on the screen for the DeepSeek Harness web GUI: a cost pill under every completed turn, and a Cost tab next to the chat and trajectory views with charts, ratings and an interactive timeline. DSH reports tokens and never a monetary amount, so this plugin does the arithmetic against a local price table — the numbers are an estimate, not a bill.

Nothing upstream is patched: the plugin registers into the official slot, session-source and locale registries, so it survives DSH upgrades and uninstalls by removing one row.

What you get

In the chat — a flat, right-aligned pill in the message action row, styled like the shipped Used N tokens item next to it:

≈ $.6217   ⚙$.4698   🧠$.0430   👁$.1519

The icons are the categories, the numbers are what each kind of action cost (see below). Click it for the full breakdown: bucket table (uncached input, cached input, cache write, output, of which reasoning), model, turn number, wall time, TTFT and tok/s.

Under the composer — the same four numbers for the whole session, sitting right after the shipped stats strip (steps, tok/s, tokens, cache hit).

The Cost tab (order: 20, so it lands right after the action graph) contains:

  • KPI cards: cost of the loaded turns, whole session, requests and average cost per request, reasoning share, cache hit %, tok/s, TTFT, turn wall time;
  • per-turn token and cost columns, a spend-composition donut, time split and context composition;
  • what each action costs — tools / reasoning / reading and analysis, with request counts, tokens, money and share;
  • ratings: most expensive turns, tools by calls and time, most expensive requests with their model, models by cost;
  • an interactive timeline (see below);
  • the price table the whole thing is computed with.

What each action costs

Every model request is attributed to exactly one category by what that request did:

Category Icon Condition
Tools gear the request called at least one tool outside the read list
Reasoning the shell's own "think" glyph the request called no tool at all
Reading & analysis browse/data every tool it called is on the read list

A request's cost lands in one category, so the shares always add up to the total. The read list lives in READ_TOOLS at the top of lib/client.js — MCP names are normalised, so mcp__some-server__Snapshot counts as snapshot.

The interactive timeline

Metric Shows
$ per minute spend rate over time
Requests per minute how often the model was called
Tokens per minute token throughput
Cumulative cost how the money accumulated from the window start

Wheel zooms around the cursor, dragging pans, double click (or the Reset button) returns to the full range. A step selector offers 10 s / 1 min / 5 min / 15 min; rates are always normalised to a minute, so the unit never changes. Hovering any step shows its own numbers. The line above the plot summarises the visible window: range, requests, window cost, average rate, peak rate and how many requests fall outside it.

Geometry is one SVG with preserveAspectRatio="none" and all readable text lives in HTML layers on top — text inside a stretched SVG would be distorted. The wheel listener is attached natively with { passive: false }, because React's own onWheel is passive and preventDefault there is ignored (the page would scroll instead of the chart zooming).

Pricing

PRICES at the top of lib/client.js is four numbers per model, in USD per million tokens:

miss  — uncached prompt input
hit   — prompt input served from the provider cache
write — prompt input written into the provider cache
out   — completion output (reasoning tokens are a SUBSET of out, so they are not added twice)

The table ships with published DeepSeek rates on the prompt/output sides and hit at zero. That zero is deliberate: auditing a real, long-lived DSH corpus (tools/audit-usage.mjs) showed ~99.4 % of all prompt tokens arriving as cache hits, and pricing those at a published cache rate overshot the provider's own bill by an order of magnitude — cached input is evidently not charged on that plan. If yours is, put the real number in hit and every total moves with it.

Install

The plugin is a normal DSH client package. Put it anywhere, then add it to a web profile:

// ~/.dsh/profiles/web/package.json
{
  "dependencies": { "dsh-cost-stats": "file:<path to this checkout>" },
  "dsh": { "profile": { "bundles": ["@deepseek-ai/dsh-base", "@deepseek-ai/dsh-web-app", "dsh-cost-stats"] } }
}

dsh plugin --profile web add "file:<path>" does the same thing and needs pnpm on PATH. A bundle list is composed at boot, so a newly added bundle shows up after a restart; edits to lib/client.js afterwards are picked up by dsh-client-hmr (it polls the bundle's mtime and size) without any restart.

If you would rather not touch the bundle list, mount the row from the profile's own live-reloaded patch layer instead — it composes at boot all the same, and reloads live:

# ~/.dsh/profiles/web/cordis.patch.yml
- insert:
    - id: cost-stats
      name: dsh-cost-stats

Tools

node tools/smoke.mjs         # 96 assertions: folding, pricing, attribution, rendering, hooks
node tools/audit-usage.mjs   # independent audit straight out of the durable session logs

smoke.mjs renders the plugin against a miniature React and mock shell services, so it runs with no browser: it covers the cost folds, the category attribution, the money formatting, both seats the pill can render into, and — because both have already bitten once — that no component changes its hook count between data states.

audit-usage.mjs is the ground truth check. It reads $DSH_HOME/sessions/*/session.v3.jsonl.zstd (each file is a stream of independent zstd frames), sums the provider-reported usage, prices it with the same table, and reports per model, per session and in total. Useful flags:

node tools/audit-usage.mjs --session <id-prefix>   # one session
node tools/audit-usage.mjs --target <bill>         # solve the implied $/M, and print a ready table
node tools/audit-usage.mjs --root <dsh-home>       # read another DSH home

It makes no model calls — it only reads logs and does arithmetic, so running it costs nothing.

Limitations

  • An estimate, not an invoice. Token counts come from the provider; the money comes from the local table.
  • Money is only shown where the cost is actually known: an exact per-turn accounting, or a turn rebuilt from its own requests (marked ≈). Otherwise nothing is rendered rather than a made-up number.
  • The report covers the loaded history window; the "whole session" figures come from the host's own token projection, priced with the effective tariff of the loaded turns.
  • Timestamps are the request start times from the log, so a long request is attributed to the minute it began.

Notes for plugin authors

NOTES.md collects what was learned writing this against DSH's client-plugin API: the module format, the four slot kinds (and why chain is not a list), how session-scoped hooks reach a component, which conversation targets carry usage, and the React/scroll traps that only appear after a page reload.

License

MIT — see LICENSE.

—/ 5

No ratings yet

Verified DSH bundle

Commit 7d6c0013cb45

Community comments

No comments yet. Be the first to write one.

DSH HUB

A community index for DSH plugins. Not an official GitHub or DeepSeek AI product.

CommunityResourcesAPIAbout