dsh-ctx-meter
English | 中文
A context-occupancy readout for DSH sessions: /ctx prints the numbers on demand (zero model tokens), and occupancy crossing 25% / 50% / 75% posts one short report per band. Host-only plugin — no client.js, so it occupies no UI slot.
Repository: https://github.com/ecbob/dsh-ctx-meter · changes: CHANGELOG.md / CHANGELOG.zh-CN.md (kept together) Compatible with
dsh >= 0.2.1-rc.2(tested against 0.2.1-rc.3)
What you get
/ctx
上下文占用 50.8% · 133,170 / 262,144 tokens · 剩余 128,974
档位:已越过 25% / 50% · 下一个 75%(还差 63,438 tokens)
构成(启发式):system 34,120 · tools 2,880 · messages 96,170
计费累计:输入(未缓存) 210,110 · 输出 8,120 · 缓存读 1,020,000 · 缓存写 40,000
数字与界面右上角的占用计同源;本命令不写入会话日志之外的东西,也不消耗模型 token。
(command output is in the session's language — the readout above is what a Chinese session prints; the band report reads the same way)
📊 上下文越过 50%:现在 50.0% · 131,197/262,144 tokens · 剩余 130,947 tokens
At the top band the report appends · 需要时可在步骤安全点 compact_now ("compact at the next safe point"); switch it off with hint: false.
Two surfaces, neither of them costs anything
| surface | trigger | model-token cost |
|---|---|---|
/ctx readout |
you type it in the composer | 0 — command discovery, execution and UI output never become model messages, and no tool schema is added to the system prompt |
| band report | occupancy crosses a percentage in bands |
~35–45 tokens: one form: 'notice' host aside (collapsed in the UI, visible to the model, so it can decide to compact) |
The report does not wake the agent — that is the point. agent.followup() would burn a whole model call; a notice is charged only when the next step is actually admitted, so it stays 0 as long as you keep silent.
Where the numbers come from
Straight from dsh's own session projections (contextPressure / contextBreakdown / tokenUsage, registered by @deepseek-ai/dsh-token-meter) — the same source as the occupancy meter in the web UI:
- numerator = the newest provider usage sample on the prompt side, adjusted by the surface's signed movement since that sample (token-meter's own
projectedTokensformula), because a usage sample alone cannot see a compaction; - denominator = the
contextWindowof the newestrequest/context, i.e. the limit of the model this session is actually routed to — no model or window size is hardcoded; - with no usage sample yet it degrades to a surface estimate, and both the readout and the report say so (
估算= estimated).
Subscription goes through ctx.sessionProjections.onChanged, reads through stateOf() / snapshot(): O(1) table lookups, nothing polled, tokenMeter.measure() never called.
How a band fires
- Only on an upward crossing, once per band; further growth does not repeat it.
- 2 percentage points of hysteresis: a band re-arms only once occupancy falls below
band - 2, so after a compaction you get a fresh 25 / 50 / 75 round automatically. - Several bands crossed in one jump merge into a single report.
- Mounting the plugin only takes a baseline — it never replays history that happened before.
- Band state lives in an in-process
WeakMap, decided per session; after a restart it starts from a new baseline.
Configuration
The bundle ships config: {}. Override it under the same id in the profile's own cordis.patch.yml (an override replaces config wholesale):
- id: ctx-meter
name: 'dsh-ctx-meter'
config:
bands: [30, 60, 90] # percentages to report, 0 < b <= 100, de-duplicated and sorted
notice: true # false: nothing is written to the session log at all — 0 tokens, /ctx only
hint: false # omit the compact_now hint on the top band
With notice: false the plugin's only user-facing surface is /ctx (v0.1 ships no UI component).
Install
Pack it:
npm pack→dsh-ctx-meter-0.1.1.tgz, drop it in<DSH_HOME>\.plugin-sources\.Add it to the profile:
pnpm --dir <DSH_HOME>\profiles\<profile> add file:..\..\.plugin-sources\dsh-ctx-meter-0.1.1.tgzAdd
"dsh-ctx-meter"todsh.profile.bundlesin the profile'spackage.json— pnpm writesdependencies, thebundleslist is a hand edit; both are required.Restart the app. The slash command registers with the bundle as soon as it activates (in practice: after editing
bundlesthe running session mounted the bundle immediately and fired its first report); if/ctxis not in the/menu yet, refresh the page or restart.
The only runtime dependency is the host-provided @deepseek-ai/dsh-llm (for createUserMessage); peerDependencies are declarations only and are never installed. Do not add new runtime dependencies to the profile: with autoInstallPeers: false an unresolvable runtime dependency takes Cordis down and the whole profile fails to boot.
Self-test
node scripts/selftest.mjs # or: npm test
Look for ALL PASS on the last line (38 assertions). They run against a fake ctx and fake sessions: band-by-band crossings, hysteresis, re-arming after a compaction, multi-band merging, per-session independence, notice: false, invalid bands falling back to 25/50/75, disposers unregistering command and subscription, plus every /ctx error path (extra argument, no agent, missing projection, no known window). When the real host package cannot be resolved (a bare clone, or running the script straight out of an installed copy), the test falls back to the committed stand-in scripts/fixtures/dsh-llm.mjs — so it runs offline and never touches a real profile.
Relation to smart-compaction
smart-compaction provides the model-side context_status and compact_now tools plus automatic compaction at safe points; this plugin adds the user-side free readout and the "let me say something when you cross a band" report. Both read the same projection, so the numbers agree. Adding yet another tool would put roughly 150 tokens permanently into the system prompt and break the prefix cache at that point — hence /ctx as a command rather than a tool.
Limits
- A session without a live agent has nothing to read;
/ctxsays so plainly. - Reports are written into the session log (
user/message+surfaceOp: append), so they count towards occupancy: ~35–45 tokens each. - v0.1 has no UI component: with
notice: falsenothing stays visible on screen — for a persistent chip usedsh-plugin-usage-meteror the built-in occupancy meter.
License
MIT © ecbob
No comments yet. Be the first to write one.