dsh-web
zhu1090093659
DeepSeek Harness (DSH) Web 插件聚合生态 · 万物皆插件,通过创意工坊分发||DeepSeek Harness (DSH) Web Plugin Aggregation Ecosystem · Everything is a plugin, distributed via the Creative Workshop
fishOfOUC/dsh-price-monitor
Session cost monitor for DeepSeek Harness — a dsh-better-sidebar tab (that sidebar is required; this package ships no UI of its own) showing per-turn, per-attempt token cost priced by official or manual plans
PROJECT TOPICS
INSTALL REFERENCE
dsh plugin --profile web add github:fishOfOUC/dsh-price-monitor
该命令指向仓库当前默认分支;尚无绑定当前 commit 的完整验证结果。
PROJECT README
Session cost monitoring for DeepSeek Harness: a host-side session projection folds the durable log into a per-attempt token ledger, and a dsh-better-sidebar tab prices that ledger with an official or hand-entered plan.
This plugin has no user interface of its own. It renders entirely as a tab of dsh-better-sidebar, which must be installed and mounted first. Without it:
dsh-price-monitor requires Better Sidebar features: pluginSettings, stateSubscription),
rather than loading a half-working panel.| Requirement | Why |
|---|---|
DeepSeek Harness with the web profile |
the plugin ships a Host half (a session projection and an HTTP route) and a browser half |
| dsh-better-sidebar ≥ 0.18.0, mounted and enabled | the tab, the settings panel, the plan catalog's storage, and the projection read all come from its service API (ctx.betterSidebar, stateSubscription, pluginSettings) — see Install |
| A plan for the rates you want to see | the selected plan prices the session; without one, every request is listed as unpriced rather than guessed |
The host half (the token ledger) works without the sidebar, but nothing reads it: the ledger has no UI besides that tab.
host priceMonitorUsage session projection ← the only fact source
└─ one row per (turn, step, attempt): startedAt/settledAt, provider,
model, the four DSH token buckets, completeness
client price tab (dsh-better-sidebar)
├─ reads the projection through ctx.sessions.binding(id)
├─ prices it with decimal.js under pluginSettings['price-monitor']
└─ official refresh: POST /price-monitor/api/official-pricing
Three properties follow from that split, and each is covered by tests:
deriveTurnTokenUsage and is cross-checked against it for every complete
turn.DSH's TokenUsage buckets are disjoint: inputTokens is uncached input
only, and DeepSeek's adapter subtracts cache hits out of prompt_tokens
before writing it. Pricing therefore multiplies each bucket by its own rate and
never computes prompt_tokens - cacheReadTokens. outputTokens already
includes reasoning tokens, so reasoning is never billed twice.
Rates are per million tokens, stored as decimal strings; every product and sum
stays a Decimal until display.
| Plan source | Editable | Created by |
|---|---|---|
official |
no — duplicate it first | an official refresh (the fetched era) |
manual |
yes | the settings panel, or the bundled history below |
The bundled catalog is the flash model's published price history — one plan per era, all in CNY, with the era in force selected:
| Plan | Rates per 1M tokens (off-peak, peak) |
|---|---|
| 涨价前(8-17 前) | ¥0.02 / ¥1 / ¥2, one flat price |
| 涨价后(8-17 起) | ¥0.05 / ¥1.5 / ¥4.5, peak ¥0.1 / ¥3 / ¥9 |
| 降价后(现行官方价) | flash ¥0.02 / ¥1 / ¥4 and peak ¥0.04 / ¥2 / ¥8; pro ¥0.15 / ¥4.5 / ¥13.5 and peak ¥0.3 / ¥9 / ¥27 |
A refresh replaces the official plan with the era the page currently
describes: one plan carrying one rate table per model the page lists, so a
retired model billed at its successor's rates is expressed as a group naming
both ids.
Official pricing is CNY by default: both the bundled snapshot and the
refresh route read DeepSeek's Chinese pricing page, which prints the primary
published numbers in yuan. The English page prints the same rates as a rounded
USD conversion of them (1 USD ≈ 6.818 CNY on the 2026-09-10 snapshot: flash is
¥0.02 / ¥1 / ¥4 in Chinese against $0.003 / $0.15 / $0.6 in English), and
this plugin never converts between the two.
A plan therefore carries the currency its publisher printed — CNY for the
official plans, and whichever currency a manual plan was saved in — and an
amount always reads in the currency of the plan that produced it. $0.15 and
¥1 are never silently added together. The same rule governs the comparison
list: rows of different currencies still list their totals, but no percentage is
shown between them, because a ratio across currencies would be meaningless.
Add a manual plan in USD if you account in dollars, and copy an official plan
into a manual one to restate it in the other currency. A plan's modelIds never
affects an amount, so a USD plan prices any session just as a CNY one does.
DeepSeek changes these rates over time, so the same session can be compared
across phases by saving one plan per phase and switching between them; the
comparison list then shows every phase's total for the very same tokens. Record
when each phase applied in its rate period (effectiveFrom / effectiveTo) —
that period is a label for the plan card and never gates pricing, so the
selected plan prices the whole session whatever dates its attempts fall on.
A superseded phase knows when it ended without knowing when it began, so either end of the period may be filled in on its own.
The selected plan is the whole pricing basis, and a plan is an era: the rates one provider charged for a set of models over a window. Switching a plan moves the hero total, the three-bucket breakdown, the per-turn rows, and the comparison list together — the reason to switch is exactly "what would these tokens cost under another era", and a session that switched models mid-way is still priced model by model.
Within a plan, each attempt is priced by the group its own model belongs to:
priced as <model> so the
substitution is visible rather than silent.Nothing about a provider gates an amount either: a request that ran on another gateway is priced the same way. Only the token facts can leave an attempt out of the money.
Only the token facts can leave an attempt out of the money: usage that never arrived or failed validation, cache buckets that cannot be separated, and cache-write tokens a plan has no rate for. Their tokens are still counted, and the hero switches to "known cost" with the reason tally, so an unknown amount never becomes a zero.
A plan's declared rate period (effectiveFrom / effectiveTo) is a label for
the plan card — when those rates applied — and never a gate: the selected plan
prices the whole session whatever dates its attempts fall on. The bundled
snapshot omits a start deliberately, because a fetch observes today's rates
rather than learning when they began.
Peak/off-peak uses each attempt's UTC start time: Monday–Friday, 01:00–04:00 and
06:00–10:00 UTC are peak (left-closed, right-open), and a plan without a peak
band prices everything at its single rate. The bundled snapshot is dated
2026-09-10 and shows its source link in the UI; it prices the two models the
page lists — the flash model and the pro model — with one flash price covering
the ids that model has been listed or reported under (deepseek-flash,
deepseek-v4-flash, deepseek-v4-flash-vision-exp).
Stored settings carry a schemaVersion. A readable version 1 blob — which also
held a calculation mode and a model-alias map — is upgraded in place, keeping
the user's plans and selection; both fields are gone because neither can change
an amount under a single pricing basis.
The client never fetches the upstream page. It POSTs to the plugin's host route, which:
cross-site and mismatched Origin are
refused) and POST only;https://api-docs.deepseek.com/zh-cn/quick_start/pricing/) — a client
payload cannot change the target, redirects must stay HTTPS on that one host,
and the body is capped at 256 KiB and must be HTML;Install and mount dsh-better-sidebar first — this plugin's tab appears in
that sidebar's + menu, and its plan settings appear in that sidebar's
Side card settings page. Then install this plugin:
# 1. the sidebar this plugin renders inside (skip if you already have it)
dsh plugin --profile web add dsh-better-sidebar
# 2. this plugin
dsh plugin --profile web add dsh-price-monitor
Both commands append a bundle to the profile and restart-time mount; restart
DSH after installing (the Host halves changed), then open the sidebar's +
menu and pick Session cost.
cd dsh-price-monitor
pnpm install
pnpm run build # tsc emits lib/types, tsdown emits lib/index.js + lib/client.js
Then point the profile's sidebar plugin at the built package:
# ~/.dsh/profiles/web/package.json
"dependencies": {
"dsh-price-monitor": "link:E:/Code/my_code/dsh_price_monitor/dsh-price-monitor"
}
cd ~/.dsh/profiles/web && pnpm install
The package's own cordis.patch.yml (dsh.bundle.patch) mounts the host half
once the bundle is in dsh.profile.bundles; for a link: install add the
bundle name there as well:
"dsh": { "profile": { "bundles": [ "...", "dsh-price-monitor" ] } }
Then restart DSH and hard-refresh the browser. The tab appears in the sidebar's + menu as Session cost; its gear opens the plan settings.
Restart the host after any rebuild, including client-only edits: the client
artifact is served from /plugins/<package>/client.js with a revision derived
from its bytes, and a link:ed package outside the loader's watched workspace
is not re-read while the host runs — a rebuilt lib/client.js keeps being
served from the host's in-memory copy until it restarts.
dsh plugin --profile web add dsh-price-monitor
The same sidebar-first rule applies: with no mounted dsh-better-sidebar the client half throws at activation instead of silently doing nothing, so check that the sidebar itself is working before filing a bug here.
pluginSettings['price-monitor'].catalog), i.e. alongside the user's other
sidebar settings; the plugin writes nothing into session logs.No cordis.yml configuration: the plan catalog is user data, edited in the
settings panel. The bundled official snapshot is the offline default.
pnpm run typecheck, pnpm run test, pnpm run build.lib/ is committed, so a git install (dsh plugin add github:<owner>/dsh-price-monitor)
needs no build step. Rerun pnpm run build and commit lib/ together with any
source change.format: 'cjs' wrapped in
window.__ModuleLoader__.load), because the harness evaluates it as a classic
script at /plugins/dsh-price-monitor/client.js; only the harness's browser
module table may stay external, so zod and decimal.js are inlined.<style> element from src/client/styles.ts
rather than a *.module.css import: tsdown does not compile CSS modules
without an extra plugin, and every class carries a dpm- prefix so one
global sheet cannot collide. Colors come only from DSH theme tokens.pluginSettings patch its client sends, serialized through one
promise chain so two quick edits cannot interleave.| File | Covers |
|---|---|
tests/usage-ledger.spec.ts |
the fold: attempt lifecycle, retries, validation, contradictions, a usage sample that never reported a cache-write bucket, reference stability, cold/live parity, and cross-checks against the harness's deriveTurnTokenUsage |
tests/pricing-engine.spec.ts |
peak boundaries, the selected era as the sole basis with a table per model group, the headline-group fallback for an unlisted model, switching plans repricing every layer, token facts under partial pricing, decimal exactness, schema rejection, and the generation-1/2 upgrades |
tests/official-pricing.spec.ts |
both saved page fixtures (three-column and the renamed two-model layout) parse exactly; changed amounts, categories, headers, malformed ids, or footnote windows fail |
tests/trust-fence.spec.ts |
loopback/trusted hosts pass; cross-site, opaque, and mismatched origins fail |
tests/client.spec.tsx |
activation and the feature gate, catalog reads (including the v1 upgrade), the hero total equal to the sum of the turn rows, and a plan switch repricing hero, breakdown, and rows |
tests/client-interaction.spec.tsx |
expanding a turn numbers each request by its step and marks a retry; clicking a plan writes the catalog and reprices the rendered tab; the plan form edits one rate table per model group; a failed write surfaces |
tests/built-artifacts.spec.ts |
the built entry points exist and behave; the client bundle is a valid loader factory; the route over real HTTP refuses GET/cross-site/foreign redirects and returns a candidate plus diff |
CLASSIFICATION EVIDENCE
系统优先读取 GitHub Topics,再与站内分类词典和词根规则比对。当前命中: cost-monitor、dsh-better-sidebar。