Skip to content
dsh.fish
Bundle

dsh-token-live

DeepSeek Harness composer readouts: CJK-weighted draft tokens, live CNY spend at official peak/idle rates, context occupancy, and the same usage priced on the costliest other model. Client-only, no host half.

Source
woodfood111
License
MIT
Updated
Updated 6 hours ago

Readme

# dsh-token-live

Live readings under the DeepSeek Harness composer: how big the draft is, what
this session has cost, and how full the context is.

![The dsh-token-live readout row under the composer](assets/screenshot-1.png)

## What it shows

| Reading | Source | Moves when |
| --- | --- | --- |
| **Draft** `≈ N tok · M chars` | the session-scoped `input` hook (`InputState.draft`) | every keystroke |
| **Cost** `¥0.42 · ¥1.8/h` | the `tokenUsage` projection × DeepSeek's published price list | each request settles |
| **Compare** `v4-pro ¥3.81` | the same buckets × the other model's prices | each request settles |
| **Context** `used / window` + bar | the `contextPressure` projection | a provider reports usage |
| **Session** `N tok · X% cached` | the `tokenUsage` projection | each request settles |

The plugin adds one entry to the composer dock (`conversation.composer.dock`).
It does not replace the harness's own stats pill.

## Install

```sh
dsh plugin --profile web add dsh-token-live
```

Then reload the page. The browser bundle reloads on its own when a client bundle
changes; the server-side row needs the plugin tree to re-compose, which the
profile's `patchReload: live` does on save, or a `dsh web` restart.

## The reading nothing else shows

**What this session would have cost on the other model.**

The `对照` / `vs` pill prices your exact token buckets — the same cache hits, the
same cache misses, the same output — on the costliest other model in the price
list, at the same billing tier. Hovering it lists every model in the table
against your session, with the current one marked.

Why it earns its place: every other cost plugin answers *what did I spend*, and
that question already has a dozen good answers. Choosing a model is a different
question — *what would the expensive route have cost me for this exact work* —
and it is the one a price list exists to answer. On this session, flash has cost
¥1.44 and v4-pro would have cost ¥3.81 for the same tokens; that is the number
worth knowing before switching, and it costs nothing to compute from data the
browser already has.

A survey of the 197 entries in the awesome-dsh-plugin **Usage & Billing**
category (2026-09-12) found **zero** that report a cross-model counterfactual for
the session in view. Several compare old and new *list prices* after a rate
change; none compare *your* usage across models.

Rendered only when both models are priced: an unpriced model shows no
comparison rather than a made-up one.

## The session tooltip explains the big number

`会话 30.7M tok` looks alarming next to a 327K context. It is not 30M tokens of
content — it is the same context sent again on every step. The session tooltip
says so, dividing cumulative billed input by the newest provider-reported prompt
size: *"cumulative billed input is about 94x the current context"*. Only one of
the 197 entries says anything comparable.

## Why the draft counter is the interesting part

The harness reports tokens after the fact. Two things in particular are not
available anywhere in it:

- **What the composer currently holds.** During streaming the client's
  `PartialAccumulator.push()` returns `false` for usage chunks, so no live token
  figure reaches the UI at all.
- **What it will cost.** Nothing in the harness carries money: the token meter's
  "pricing" is image-token pricing, unrelated to billing.

The harness's own estimator is a flat four characters per token
(`dsh-token-meter`'s `CHARS_PER_TOKEN`). That underprices CJK text by two to
three times, so the draft estimate here weights dense scripts separately: about
`0.7 token/character` for CJK/Kana/Hangul/fullwidth, about `4 characters/token`
for everything else.

## Cost model

Official prices, CNY per million tokens, at **peak** hours
([source](https://api-docs.deepseek.com/zh-cn/quick_start/pricing/), effective
2026-09-10):

| Model | Cached input | Uncached input | Output |
| --- | --- | --- | --- |
| `deepseek-flash` | 0.04 | 2 | 8 |
| `deepseek-v4-pro` | 0.30 | 9 | 27 |

**Idle hours bill at exactly half.** Peak is Beijing time (UTC+8), Monday
through Friday, 09:00–12:00 and 14:00–18:00; everything else is idle. The
plugin computes the tier from the wall clock, independent of the browser's own
time zone.

Details:

- The model comes from the `modelSelection` projection's `lastUsed` — the model
  that actually produced the recorded usage, not `next`.
- Cache **writes** are priced at the uncached rate, because the first send of a
  prefix is a cache miss.
- A model that is not in the table renders as `未定价` / `unpriced` rather than a
  guessed number. A wrong money figure is worse than none.
- Cumulative usage is priced at the **current** tier, so a single long session
  spanning a tier change can be off by up to 2×. The tooltip says so.
- `¥/h` is a page-local burn rate (up to 15 minutes of history); it resets on
  reload.
- Prices change. The table is a constant in `lib/client.js` with the source and
  effective date next to it.

## Design: this plugin has no host half

Everything lives in one browser bundle. `lib/index.js` is an empty Cordis plugin
that exists only so the loader row has something to resolve — it injects no
service, holds no state, registers no route, writes no file, and makes no network
call.

The consequence worth stating plainly: **this plugin never reads your API key.**
It cannot, because it has no host half to read it with and no way to send it
anywhere. It reads four client-visible things — three projections and the
composer draft — and nothing else.

That is a deliberate choice, not minimalism for its own sake. On the harness
version this was developed against (0.1.5-rc.1), routes registered by a plugin on
the web server are **not** behind the session-cookie fence: a bare
`GET /dsh-market/installed` answers `200` with no cookie at all, while `/` and
`/api/` answer `401`. So a plugin that fetches a balance on the host and serves
it over its own route exposes that response to any local process that can reach
the port — and to anything else if the server is ever bound beyond loopback.
Having no host half removes that class of exposure entirely.

If you want account balance and are happy with a host half that holds your key,
several plugins on the awesome-dsh-plugin list do exactly that. This one
deliberately does not.

## Accuracy and limits

- The draft figure is an estimate; cost, context and session are not.
- The draft estimate reads high on symbol-dense content (code, JSON) and is
  closest on prose. It is a pre-send sanity check, not billing.
- The context reading is absent until a provider reports usage for the session.
- Nothing here renders a live per-token count *during* generation. Doing that
  honestly needs the streaming usage path in `dsh-client-ui-chat`, which
  discards usage chunks by design.

## Development

```sh
npm test     # offline suite: estimator, price table, tier rule, render, slot registration
npm run check  # the release guard `npm publish` runs automatically
```

`npm test` executes the real `lib/client.js` under a stub `window.__ModuleLoader__`
and a stub `react`, so it needs no browser and no DSH install. It pins:

- the CJK-weighted estimator, including where it differs from the harness's own
- the price table and the peak/idle boundary at every edge (08:59, 09:00, 11:59,
  12:00, 13:00, 14:00, 18:00, weekend)
- the counterfactual: which model is picked as the alternative, that an alias
  resolves before picking, and that an unpriced model renders no comparison
- that the session re-read multiple is omitted rather than divided by zero when
  no provider-reported prompt size exists yet
- that a partial cache hit never rounds up to a full one
- that an unpriced model says so instead of inventing a number

The browser bundle is hand-written in the client module format
(`window.__ModuleLoader__.load`), so there is no build step: `lib/client.js` in
the repository is the file that ships and the file that runs.

## License

MIT

Install

dsh plugin --profile web add github:woodfood111/dsh-token-live

Profile: web

  • This source has no pinned commit, so a later push upstream changes what installs. Prefer pinning a commit.
Source