Changelog

September 19, 2026 · View on GitHub

All notable changes to this project are documented here. The format follows Keep a Changelog and the project uses Semantic Versioning. 中文版见 CHANGELOG_ZH.md.

[1.1.6] - 2026-09-19

Fixed

  • Host pricing file source lifecycle (pricing.json override & change watcher)PR #10:
    • Fixed premature disposal of filePricingSource during plugin registration: ctx.effect(() => fileSource.dispose(), ...) called dispose() synchronously while building the fiber and registered undefined as the cleanup handler, aborting initial asynchronous file loading and disabling the file change watcher. Resolved by returning a disposer function: ctx.effect(() => () => fileSource.dispose(), ...).
    • Updated test mocks in tests/core.test.mjs, tests/pricing.test.mjs, and tests/rounds.test.mjs to properly track and execute Cordis effect disposers in after().
    • Added regression test covering the /pricing route with user pricing.json overrides enabled at startup.

[1.1.5] - 2026-09-12

Changed

  • DeepSeek official pricing update (2026-09-10) & deepseek-flash supportPR #8:
    • New deepseek-flash model pricing: Updated builtin pricing according to the official DeepSeek pricing table (verified 2026-09-10). The new deepseek-flash rates are:
      • Off-peak (Beijing Mon–Fri non-peak & weekends): CNY 1.0 / 0.02 / 4.0 per 1M tokens (cache-miss input / cache-hit input / output); USD 0.15 / 0.003 / 0.6 per 1M tokens.
      • Peak (Beijing Mon–Fri 09:00–12:00 & 14:00–18:00): CNY 2.0 / 0.04 / 8.0 per 1M tokens; USD 0.30 / 0.006 / 1.2 per 1M tokens.
    • Backward compatibility for legacy model names: deepseek-v4-flash and deepseek-v4-flash-vision-exp are mapped to deepseek-flash in BUILTIN_PRICING so historical session logs continue resolving without falling back to unknown-model estimates.
    • Fallback pricing: Default unlisted model fallback (FALLBACK_PRICING) now points to the new deepseek-flash pricing.
    • Docs & test synchronization: Updated custom pricing.json example in README.md and README_ZH.md (verifiedAt: 1788998400000), and aligned test cases across tests/core.test.mjs, tests/pricing.test.mjs, and tests/rounds.test.mjs (BUILTIN_VERIFIED_AT set to 2026-09-10T00:00:00Z).

[1.1.4] - 2026-09-08

Fixed

  • dsh-session >= 0.1.2-rc.1 compatibility (snapshotEvents())PR #7: dsh-session removed its public events property in 0.1.2-rc.1 (replaced by the snapshotEvents() method); the /usage route then threw TypeError: events is not iterable, which dsh-host-webserver wrapped as a bare 400 empty response, and the per-round chart disappeared (the client fell back to the empty observed-rounds path). Reproduced live on dsh-session 0.1.2-rc.1: /usage?session=<loaded> returned an empty 400 while /usage?session=<unknown> returned the plugin 404 JSON and folding the same log offline succeeded — confirming the crash was only the new runtime API shape. The host now reads events via capability detection — prefers session.snapshotEvents() when the function is present and falls back to the legacy session.events ?? [] (so a missing API can never crash the route again). The vendored SessionEventLike type adds the time field (Unix epoch ms) and a SessionHandle shape (optional events + optional snapshotEvents) so SessionStoreService.get()/list() stay valid across both API generations. Verified against the upstream deepseek-harness source: Session.events was removed from 0.1.2-alpha.4 onward (official architecture note 2026-08-21-session-log-read-intent); the installed 0.1.0-rc.6 still exposes events, so the fallback path remains covered.
  • Test coverage for the new snapshotEvents() access path: added tests/rounds.test.mjs/usage route prefers snapshotEvents() when the new API is present, mocking a session handle that exposes only snapshotEvents() (its get events() throws, proving the route never reads the removed property), asserts time is consumed (duration/peak billing) and that snapshotEvents() wins when both APIs are present.

[1.1.2] - 2026-08-26

Improved & Fixed

  • Compact 2-Column Hover Tooltip & Overflow Elimination:
    • Height Reduction: Redesigned .duc-chart-tooltip into a compact 2-column grid (2×2 token breakdown + 2-column metadata pairs), reducing card height from ~280px to ~120px (>55% reduction).
    • Top-Aligned Positioning: Adjusted placement from top: 20px to top: 2px (240px width), ensuring the hover card stays strictly within the 132px chart boundary and never expands container scroll height or triggers popover scrollbars.

[1.1.1] - 2026-08-26

Improved & Fixed

  • Compact Panel UI & Vertical Overflow Elimination:
    • Height Reduction: Tightened .duc-section vertical padding from 12px to 8px, compacted .duc-cell padding from 8px 9px to 5px 8px, reduced bar heights and line-heights. Overall panel height shrinks from ~800px to ~560px (~170px reduction), allowing the full dashboard to fit comfortably in viewport without vertical scrolling.
    • Removed Redundant Legend: Eliminated the duplicate 4-color legend row in the "Session Usage" section (values are already labeled in the 4 grid cards above; chart legend remains intact in the per-round section).
    • Lightweight Compaction Empty State: When no compaction has occurred, the placeholder row is omitted to save vertical space; compaction details are shown only when compactions exist.
    • SVG Chart Height Optimization: Reduced RoundBars baseline height from 96px to 76px (canvas height reduced from 166px to 132px), keeping all scroll arrows, duration lines, anomaly markers, and hover tooltips aligned and legible.
    • Robustness Defense: Added fallback defaults for missing currency parameter ('cny') and safe optional chaining on round.cost in RoundBars.

[1.1.0] - 2026-08-26

Milestone release: Context Explainability & Compaction Diagnostics. Turns "why context grows, which round got compacted, how many tokens were freed, and how much the summarize step cost" into an interpretable view (dock indicator + dedicated panel diagnostics section), alongside user/message input source attribution.

Added

  • Context & Compaction Diagnostics Section: added a dedicated diagnostics section in the panel showing System Prompt, Tools Schema, and Message History token counts and percentage breakdown, complete with a multi-segment color bar (system blue, tools amber, messages green) and an explicit heuristic-approximation note based on the official contextBreakdown projection.
  • Compaction Lifecycle Folding & Cost Accounting: host-side foldCompactions (src/usage/compactions.ts) parses compaction/start, compaction/summary, compaction/prune, and compaction/end events from session logs, tracking shadowed token count, shadowed range/seqs, round attribution, summarize model, and dual-currency summarize cost (peak/off-peak tier aware).
  • Compaction Timeline & Savings: the diagnostics section summarizes total freed tokens and total compaction occurrences, listing each compaction record (round, freed tokens, summarize cost).
  • Context Occupancy Recommendations: actionable recommendations based on contextPressure occupancy (≥75% suggests starting a new session or trimming large file injections; ≥90% warns of imminent context exhaustion).
  • Segmented Dock Pressure Bar: consumes official contextBreakdown projection to render system (blue), tools (amber), and messages (green) multi-segment bars on the composer dock indicator with detailed tooltip percentages, smoothly falling back to single-color bar when breakdown is unavailable.
  • Per-Round User Source Attribution: foldRounds captures userSource (human, agent.inject, continuation) from user/message events and displays the attribution badge in the chart tooltip explainer card.
  • New Exports: foldCompactions function and CompactionRecord type.

[1.0.2] - 2026-08-26

Fixed

  • Weekend off-peak tier rule: isPeakHour and tierAt now take day-of-week into account — peak hours strictly apply to Monday through Friday 09:00–12:00 and 14:00–18:00 (Beijing time / UTC+8); all hours on Saturday and Sunday are now correctly classified as off-peak (leisure/discount period).
  • Builtin pricing coverage: added deepseek-v4-flash-vision-exp to builtin pricing table (identical pricing to flash); updated BUILTIN_VERIFIED_AT to 2026-08-26.

[1.0.1] - 2026-08-17

Billing updated to the latest DeepSeek pricing (official pricing pages, fetched 2026-08-17): prices are now quoted in two currencies — CNY (Chinese page) and USD (English page) — per 1M tokens with peak / off-peak tiers — peak hours (Beijing time 09:00–12:00 and 14:00–18:00, i.e. UTC 01:00–04:00 and 06:00–10:00) are billed at 2× the off-peak rate.

Added

  • Peak/off-peak tiered billing: the builtin price table stores both peak and offPeak unit prices per model; each round's cost is billed with the tier of its start time (tierAt resolves Beijing time = UTC+8). Unknown timestamps fall back to the peak tier (conservative estimate).
  • Official dual-currency pricing: each tier carries both the official CNY quote and the official USD quote; costs are computed with the list price of the selected display currency — no FX conversion, consistent with the official bill. The CNY/USD toggle now drives the indicator, the panel, the chart cost view and the cost badge.
  • pricing.json now accepts the dual-currency tiered shape { "peak": { "cny": {…}, "usd": {…} }, "offPeak": {…} }; legacy shapes are still accepted (single-currency tiers or the flat shape are treated as CNY, with USD derived at the default rate 6.76).
  • New exports: costSplitAt, tierAt, isPeakHour, formatCny, and the CostCurrency / PriceTier / PriceTierId / BucketPrices types.
  • The cost note in the panel now shows both tiers: e.g. cache-miss input 1.5/3.0 (off-peak/peak) in the selected currency.
  • Live billing-tier tag: the panel's session-usage header shows a red (peak) / green (off-peak) tag for the current billing period (Beijing time, auto-flips at hour boundaries), and each round's tooltip shows its own billing tier.
  • Per-round cost always visible: in the cost chart view every bar shows its own cost value (not only the current round), and the observed-rounds fallback (no host history) now derives per-round cost client-side from the /pricing snapshot + per-turn model/start time, so the cost view works even without host history.

Changed

  • Builtin list price updated to the official prices (flash: CNY off-peak 1.5 / 0.05 / 4.5, peak 3.0 / 0.10 / 9.0; USD off-peak 0.22 / 0.007 / 0.66, peak 0.44 / 0.014 / 1.32; pro: CNY off-peak 4.5 / 0.15 / 13.5, peak 9.0 / 0.30 / 27.0; USD off-peak 0.66 / 0.022 / 1.98, peak 1.32 / 0.044 / 3.96 — miss input / hit input / output); BUILTIN_VERIFIED_AT updated to 2026-08-17.
  • Cost computation is now currency-parameterized: costSplit(usage, pricing, tier, currency) and costSplitAt(usage, pricing, timeMs, currency) return a currency-neutral CostSplit (input / cacheRead / output / total) in the requested currency. formatMoney / formatPricePerM drop the FX-rate parameter (amounts are already in the display currency); toDisplayAmount is removed. estimateCost keeps returning { cny, estimated } (official CNY prices).
  • foldRounds bills each round with the tier of its turn/start time (fallback: turn/end, then peak) and publishes both cny and usd cost splits in the /usage payload, so the client can switch currencies without re-deriving.
  • The FX rate (config.cnyPerUsd, /rate, "Refresh rate") is now informational only ("1 USD ≈ X CNY" note); costs never depend on it for official models.

Fixed

  • The old builtin table (single-currency USD, flat price) no longer matched the official tiered billing in either currency, so costs were stale; the whole pipeline now follows the current official pricing pages (CNY + USD).

[1.0.0] - 2026-08-15

First complete release — the in-session usage interpreter is feature-complete (per-round chart with full-history horizontal scroll + cost/timing/anomaly explainer + multi-currency costs with live rates + account balance).

Changed

  • Per-round chart no longer truncates to the latest 12 rounds: all rounds render into a horizontally scrollable area with a fixed slim bar width (30px), so bars stay constant-width and never look crowded. It auto-scrolls to the latest round, and arrow buttons + edge fades appear when content overflows; the scrollbar is slimmed down.
  • Per-bar value labels adapt to density: in scrollable (dense) mode only the current round keeps its top-of-bar value (details stay in the hover explainer card); otherwise overly long labels (e.g. $0.0013, 123.4K) are elided so neighbouring labels never overlap.
  • Chart minimum width adapts to the panel width: short histories fill/center without stretching bar widths; the tooltip follows the active bar across scrolling (content coordinate − scroll offset, clamped to the visible area).

Fixed

  • The tooltip could not be positioned correctly once the chart could scroll; it now tracks the bar precisely at any scroll position.
  • Short histories could overflow on narrow panels; the adaptive minimum width removes the needless scroll.
  • The balance no-key test now isolates $DEEPSEEK_API_KEY, so the suite passes on hosts that have the key in the environment; added coverage for the env fallback itself.

[0.3.0] - 2026-08-15

Added

  • Cost display currency: config.currency ('usd' | 'cny') and config.cnyPerUsd (default 6.76); costs render in the chosen currency.
  • USD/CNY toggle in the cost section; the choice is remembered in the browser (localStorage).
  • Rate-refresh button: fetches the latest USD→CNY rate through the new same-origin /dsh-usage-chart/rate proxy (config.fxUrl) and re-estimates immediately.
  • /dsh-usage-chart/meta route serving display-currency config to the client.

Changed

  • Per-model price notes follow the display currency and show the applied rate (e.g. CNY(1 USD ≈ 6.76 CNY)).

Fixed

  • Resilient rate refresh: falls back to a built-in FX source (frankfurter.dev) when the default (open.er-api.com) is unreachable or blocked; the last successful rate is persisted, so offline refreshes keep the previous rate instead of the fixed default.
  • Client slots register via ctx.slots.inject (wait for declaration), fixing slot "…" is not declared when loader order changes.

[0.2.0] - 2026-08-15## [0.2.0] - 2026-08-15

Added

  • Per-round cost explainability (v0.2, see docs/ROADMAP.md): the host fold (RoundFold, src/usage/rounds.ts) now derives per-round duration (turn/start → turn/end), TTFT (start → first usage sample), output throughput (tokens/s), model attribution (request/contextrequest/header → cross-round carry-forward), end reason, and a per-round cost split (input / cache-read / output × unit price).
  • Pricing governance: src/pricing.ts is split into a pure math module (pricing/calc.ts, bundled by both halves) and a host-only PricingSource seam (pricing/source.ts — builtin list with a verification date + user-override pricing.json file adapter with change watching) plus a PricingResolver (pricing/resolve.ts, priority file > builtin > fallback, unknown models explicitly marked). New /dsh-usage-chart/pricing route exposes the resolved snapshot — the client's only price input (ADR 2); the old bundled pricing constants no longer drift from host resolution.
  • /usage route now returns rounds (with cost/timing/model/endReason) instead of bare turns (foldTurnUsage kept as a v0.1-compatible wrapper).
  • RoundBars cost view: a third chart mode stacks bars by cost (bucket × unit price); a duration polyline overlays bar tops; anomalously expensive rounds (relative to the previous N rounds, src/client/diagnose/anomaly.ts) get a warning marker with attributed reason chips; a per-round cache-hit mini tick sits under the baseline; the tooltip became an explainer card (tokens + cost + model + duration + TTFT + TPS + cache hit + end reason + anomaly chips).
  • Cost badge: a dismissible ≈ \$0.00xx badge per assistant message (conversation.chat.assistant-actions slot, data from the host /usage history).
  • Dock context pressure bar: slim contextPressure bar in the indicator (green → amber → red as occupancy rises).
  • Tests: tests/rounds.test.mjs (fold timing/TTFT/TPS/model/cost + route), tests/pricing.test.mjs (resolver priority, file source with temp dir, unknown marking + route), tests/anomaly.test.mjs (spike flagging and attribution); 28 tests pass via npm run verify.
  • Configuration: optional config.pricingFile overrides the default $DSH_HOME/data/dsh-usage-chart/pricing.json (falls back to ~/.dsh/...).

Fixed

  • Cost estimates are now single-sourced: real-time indicator cost and panel cost both consume the /pricing snapshot; the price source, verification date, and unknown-model marker are shown in the panel.
  • Panel cost resolution now prefers the host fold's authoritative model attribution (ADR 1) over snapshot provenance, which can be absent for older sessions — the price source previously showed a spurious "fallback estimate" in that case.

Upgrade note

  • Restart dsh web after upgrading to 0.2.0. The Host process caches plugin code in memory (no hot reload): the new /dsh-usage-chart/pricing route and the rounds-shaped /dsh-usage-chart/usage response are only served after a restart. Until then the indicator silently omits the cost segment and the panel shows "Price snapshot unavailable".

[0.1.1] - 2026-08-14

Added

  • Balance queries now resolve the DeepSeek API key through the DSH credentials service (ctx.get('credentials')), so a key configured in the web UI (Settings → Models) or in .credentials.yaml works without an environment variable or plugin config.

Fixed

  • Install warning missing peer react@^18.2.0 (react is provided by the DSH web platform; the peer is now marked optional).
  • Docs: document uninstall/cleanup steps in the README.

[0.1.0] - 2026-08-14

Added

  • Composer usage indicator and expandable SVG dashboard.
  • Session token, cache, context-pressure, model, and estimated-cost views.
  • Per-turn usage chart with total/mix views, hover and keyboard tooltips, and a highlighted current-round band; host-side per-turn aggregation from the session log.
  • Host-side DeepSeek balance proxy.
  • Full zh/en localization: the indicator, dashboard, charts, and balance views follow the DSH in-app Language setting through the locale service (dictionaries registered under the dsh-usage-chart namespace; browser language only seeds the initial value).
  • Release metadata, bilingual documentation, CI, contribution/security policies, and portable visual probe scripts (scripts/*.mjs).
  • Privacy-safe README demo screenshot with fictional usage values and no account data.

Fixed

  • Light-mode readability: indicator, panel, and SVG charts now use DSH theme tokens (--dsw-alias-label-* / --dsw-alias-bg-*) and theme static palette colors, so text and chart segments stay legible in both light and dark appearances.

Security

  • Restrict Host JSON routes to same-origin GET requests.
  • Require HTTPS for custom API endpoints, except loopback HTTP proxies.
  • Validate token-usage samples before aggregation.