返回目录
部署运维 基础设施

dsh-cost-stats

thezavtrak-a11y/dsh-cost-stats

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.

Stars
0
Forks
0
Issues
0
更新
9 天前

PROJECT TOPICS

项目标签

PROJECT README

README

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.

CLASSIFICATION EVIDENCE

分类依据

项目类型基础设施
功能分类部署运维
规则置信度

系统优先读取 GitHub Topics,再与站内分类词典和词根规则比对。当前命中: observability、cost-tracking。