dsh-ctm
Verifieddsh-ctm Β· v1.0.2 Β· MIT Β· Web UI
Context Transparency Manager: the model context as a visible, editable, effectiveness-scored surface (self-contained dsh bundle plugin)
Install
dsh plugin add dsh-ctm Confirm the layer applied with dsh --profile default --dump-config β see the install guide.
Source
Tags
Creators
Readme
dsh-ctm β Context Transparency Manager
English | δΈζ
Turns the model's context into a visible, editable, effectiveness-scored first-class object, published as a self-contained bundle plugin for DeepSeek Harness.

Features
- Full visibility: a turn β segment flow view colored by role / tokens / cache status / effectiveness, with markdown rendering and paging.
- Token accounting (provider-measured): the KPI strip uses MECE buckets β uncached input / cache hit / output (cache write appears separately only when > 0) β plus a derived cache hit rate (hit Γ· bucket sum; hidden when the denominator is 0) and the model. All figures are whole-session cumulative, read preferentially from the
tokenUsagesession projection, falling back to a full-log event fold when the projection is unavailable (the summary'susageSourcemarks which path was taken). Turn headers show the sum of that turn's step requests; step headers show that single request's measured usage (tooltips state the exact semantics); the latest request's prompt size and context-window occupancy (when thecontextPressureprojection is readable) sit in the KPI tooltip. Segment-level token counts remain local heuristic estimates and are explicitly labeled as estimates. - Live refresh: event-driven (reactive
useSessionsubscription) β new messages, tool results and turn boundaries update immediately; no polling. - System prompt: Session V3 compatible. CTM treats the newest
system/messageon the current surface as the editable effective system prompt and displays it under the stable segment-0 identity; migrated historical sessions use the same path. - Editable: replace, delete, rollback, snapshot restore, undo, effectiveness override (manual), and copy segment content (to re-send a rolled-back message, copy the original into the host input box β the host chat UI does not expose its input box to plugins). The initial system prompt is replaceable; all other system-injected content (runtime context etc.), tool results, and CTM placeholder markers are read-only in the UI.
- Effectiveness engine: automatic
effective/redundant/stale/injectedverdicts with manual override. The 2-gram similarity sets are LRU-cached (500-entry cap), never rebuilt from scratch per request. - Apply for real (off by default): when enabled, replace / delete / rollback no longer intercept requests β they are written into the session log as surface
replaceevents atagent/pre-step(same timing, same mechanism as official compaction), honoring DSH's model-visible βΊ logged invariant: replay / fork / token accounting always match what the model actually saw. Edits are badged "pending" until logged. Deletes and rollbacks are carried by placeholderuser/messagenodes (grouped under "User input" in the UI, read-only protected β not classified as system injections); assistant revisions are carried as user messages by role demotion; tool-call/result pairs are never split (deletion always shadows a minimal balanced range: deleting a tool result absorbs the assistant message carrying its tool-call, so the model never sees a dangling call). Undo = a queued (not yet logged) edit is simply dequeued; an already-logged edit is reversed by a counter-replace with the original content (only the most recent operation is undoable); undoing a rollback or a multi-node delete uses a restore group: the placeholder node is replaced by the first shadowed item and the rest append to the tail in original order, all demoted to user messages (an append-only log cannot re-add assistant/tool roles), and a restore group is itself undoable (undoing it re-shadows the run). Logging failures are recorded and surfaced at the top of the view. Mutations carryingexpectedVersionare checked optimistically β a version mismatch rejects the request with zero side effects. - System prompt editing: a replacement of segment 0 is stored as an override and swapped into the section list by the
system-prompt/assemblewaterfall at the next prompt assembly; the agent loop logs the validsystem/messagereplacement. - i18n: Chinese / English UI.
- Zero coupling: hostβclient runs over plain HTTP
POST /ctmβ no Typert@Remote/dsh-api-remotes; zero runtime dependencies (the tool-pair balance check is re-implemented locally instead of depending on@deepseek-ai/dsh-compaction).
Architecture
src/
βββ contract.ts # shared contract: TS types + Zod runtime validation (single source of truth)
βββ host.ts # host half: POST /ctm route + the agent/pre-step & system-prompt/assemble waterfalls
βββ usage.ts # MECE bucket conversion / summation / full-log fold for usage (pure logic, unit-tested)
βββ surface-edits.ts # edit logging layer: replace-event construction, tool-pair balancing, edit-queue application (pure logic, unit-tested)
βββ bigrams.ts # 2-gram sets + LRU cache for the effectiveness engine (pure logic, unit-tested)
βββ client/ # browser half: conversation.view tab + fetch('/ctm')
contract.ts: the host validates requests with it, the client validates responses with it. Types are inferred from Zod schemas, and runtime validation provides cross-version tolerance β the key to a community plugin shipping on its own cadence. New fields are always.optional()(e.g. segmentpending,usage; stateapplyError); the single exception was the summary usage rework (oldinputTokens/cachedTokens/...β MECEtotal/lastRequest/usageSource) β host and client ship in one package, so that one breaking change was made directly.host.ts: registersPOST /ctmviawebServer; injectssessionQuery/sessions/tokenMeter. Reads Session V3 surface events fromreadSurface, marks the newestsystem/messageas the stable system-prompt segment 0, reads full logs throughsnapshotEvents(), and resolves individual events througheventAt(). Usage has two channels: assistant segments carry the provider-measured usage of a single request from theassistant/messageevent; session-level totals prefersessionProjections.snapshot()(an optional service captured through anctx.injectchild context β cordis throws on any read of a service not declared ininject, optional chaining does not help) for thetokenUsage/contextPressureprojections β the projection folds the complete log, immune to compaction/shadowing β falling back to summing the full log event by event (correct but O(log) per read), with the summary'susageSourcemarking the channel actually used. With apply for real on, edits enter a per-session queue and are appended group by group in theagent/pre-stepwaterfall (the turn is open and the request not yet built, so edits take effect in that very request; edits to an idle session queue up and land on the next step). The system-prompt override swaps the whole section list in thesystem-prompt/assemblewaterfall. Memory is bounded: session store LRU capped at 50, 20 snapshots per session, 50 trash entries per session.client/: registers a "Context" tab inconversation.view; every operation round-trips throughfetch('/ctm')with responses validated byctmResponseSchema; refresh is triggered reactively viauseSession. A "pending" badge distinguishes queued-but-unlogged edits from applied ones.
Wire protocol
POST /ctm; the body is an op-discriminated union (JSON), and every request carries a sessionId:
| op | extra fields |
|---|---|
getState |
β |
replace |
segmentId, content (UI allows replacing only the initial system prompt and non-system-injected segments; queued for logging when apply for real is on) |
delete |
segmentId |
rollback |
turnIndex |
restore |
snapshotId |
reset |
β |
undo |
β |
override |
segmentId, value (string | null) |
setRealtime |
enabled |
Response: { ok: true, state: CtmState } | { ok: false, error: string }.
Every op may additionally carry an optional expectedVersion (the version of the last state the client applied): the host compares it before any side effect and rejects mismatches with a stale_version error notice (optimistic concurrency against multi-client / stale-page races).
Known limitation: undoing a rollback or a delete involving tool pairs restores the removed content as user messages (the first item replaces the placeholder node, the rest append to the tail) β an append-only log cannot re-add assistant/tool roles. This is the same role-demotion scheme as assistant edits.
The bundled client does not currently send expectedVersion; the host check is available to callers that supply it, not a guarantee for every UI edit. The transcript view belongs to the host and may still show shadowed messages. Compatibility with a newer DeepSeek Harness revision should be checked against the host APIs used by this plugin.
Install / uninstall
# Install the prebuilt package from npm (desktop app: Plugins β Add plugin β enter dsh-ctm)
dsh plugin --profile <name> add dsh-ctm
dsh plugin --profile <name> remove dsh-ctm
# Or install from GitHub: git installs pull source only, so the package's prepare
# script builds it at install time. On first install pnpm refuses to run it until
# you add the key it prints to allowBuilds in the profile's pnpm-workspace.yaml.
dsh plugin --profile <name> add github:ac0033/dsh-ctm#v1.0.2
add automatically writes the package into the profile's dependencies + dsh.profile.bundles (because it declares dsh.bundle) β no manual cordis.patch.yml edits; remove cleans up the dependency, the bundle layer and node_modules together.
Local development
pnpm install
pnpm build # produces dsh/index.js (host) + dsh/client.js (client)
Publishing
- Run
pnpm buildbefore publishing (e.g. a"prepublishOnly": "pnpm build"script); community users then receive the prebuiltdsh/index.js+dsh/client.jswith zero build steps. - Zero runtime dependencies:
zodis inlined into both bundles;reactresolves from the shell's module table. - When moving to your own scope, update both
nameinpackage.jsonand thename:row incordis.patch.yml.
License
MIT Β© YuanLumen