DeepSeek Harness Plugin Hub

发布与管理完整 Harness Profiles,发现适合你的插件。

探索

插件目录环境预设文档中心动态

社区

发布插件联系我们报告问题

相关链接

Plugin Hub GitHubDeepSeek Harness 官方项目系统状态隐私说明
© 2026 DeepSeek Harness Plugin HubPowered byPaxTech

独立、非官方社区项目,与 DeepSeek 官方无隶属、授权或背书关系。

Toolong Warning — DeepSeek Harness 插件(DSH Plugin)
DeepSeek Harness Plugin Hub
ProfilesPlugins分类动态文档登录管理 Profiles
ProfilesPlugins分类动态文档登录
← Plugins
T

@hjdd14/dsh-toolong-warning

Toolong Warning

DSH 插件:统计每个会话中已完成的压缩次数,并提供双语界面的浮动提醒;仅在多次压缩且额外消耗大量 token 后触发。

插件会安装到这里;不确定时保持 web。

npx -y @deepseek-ai/dsh plugin --profile web add github:Hjdd14/dsh-toolong-warning#37282b237fca1dfb9f598dfb6bf795d68537586b
README兼容性版本

兼容性与来源证明

Toolong Warning 以 @hjdd14/dsh-toolong-warning 发布,当前版本为 0.3.0。Plugin Hub 会校验它的 manifest,并保存精确安装来源,便于复现安装结果。

DSH 兼容范围
*
运行环境
web
发布来源
github
Registry 更新时间
2026/9/29

版本

0.3.0stable
2026/9/29

相关插件

正在加载相关插件…

最新版
0.3.0
DSH
*
HMR
重启进程
Tree shaking
未声明可安全裁剪
解包体积
未提供
文件数
未提供
Surface
web
许可证
MIT
发布源
github
GitHub
★ 1
周下载
0
最近提交
2026/9/29
查看源码 ↗
README Badge

点击下方 Badge 复制 Markdown,粘贴到 README 即可。

这是你的 Plugin?认领权益 · 优先安全扫描

验证 package.json 声明的 GitHub 仓库,即可管理这个公开页面。认领后,Hub 会优先安排当前版本的安全扫描,并在通过后公开展示结果。

认领这个 Plugin →
报告问题

相关插件

继续浏览 models-usage 分类下经过校验的插件。

Whale Widgetdsh-whale-widgetDSH Web 界面右下角的 DeepSeek 余额小鲸鱼挂件:余额/今日已用/峰谷定价、自定义泡泡点击序列(文本/余额/今日/峰谷/图片/随机语句与并列加权选择)、逐行样式与字体、悬浮快捷编辑、音效与每轮消耗、自定义角色/动图/音效、吸附与翻转自定义Usage@linxin666/dsh-usage用于 dsh Web GUI 的使用统计插件:检测各提供商的余额和编程套餐配额,并实时记录令牌使用情况;侧边栏 Settings 行上方显示紧凑的价格概览卡片Client Ui Model Capabilities@linxin666/dsh-client-ui-model-capabilities为自定义 pi-ai 提供商声明每个模型的能力(图像输入和推理力度),可直接在 Models 设置卡片中编辑;写入官方 llm-pi-ai 设置命名空间,不更改 DSH 源代码。Codex Subscriptiondsh-codex-subscription通过 OAuth 在 DeepSeek Harness 中使用 ChatGPT 和 Codex 订阅,支持配额管理、安全重置、网页搜索、图像和快速模式

README

dsh-toolong-warning

English | 中文

A DeepSeek Harness (dsh) plugin that warns when a conversation has become too long to be worth continuing — and stays quiet otherwise.

It counts how many times each conversation has been compacted, shows that count in a floating window at all times, and adds a warning only when compaction has happened repeatedly and the conversation has since burned a lot of extra tokens.

The point of this plugin is what it does not say. A reminder that cries wolf gets ignored, so every rule below is written to prefer silence whenever the data to justify a warning is missing.

The floating reminder window

Table of contents

  • What you see
  • When does it warn?
  • Install
  • Settings
  • How it works
  • Diagnostics
  • Requirements
  • License

What you see

A self-owned floating window in the top-right corner. It uses the shell.overlay seat and falls back to its own fixed container, so it never competes with another plugin for a slot:

┌──────────────────────────────┐
│ Long-conversation reminder – │
│ This conversation compacted  │
│ 3 time(s)                    │
└──────────────────────────────┘
┌──────────────────────────────┐
│ ⚠ This conversation is       │
│   getting long — consider    │
│   starting a new one         │
│ context occupancy has        │
│ reached 62%; about 310k      │
│ tokens were spent since the  │
│ last compaction              │
│ Compacted 3 time(s) so far   │
│ (threshold 3); current       │
│ context occupancy 62%        │
│ [Got it]  [Adjust thresholds]│
└──────────────────────────────┘
  • The counter is always shown; the warning card appears only when the rule is met.
  • Got it hides the current reminder only — the counter keeps updating.
  • Adjust thresholds jumps to this plugin's section on the Settings page.
  • The window is draggable: press anywhere on the card and move it, so it does not have to sit over the page's own top-right controls. Where you leave it is remembered in this browser, it is kept inside the viewport (and pulled back after a resize), and the Settings section offers a reset row once it has been moved.
  • Nothing is shown when the plugin is disabled or no conversation is open.
  • The whole UI is bilingual (中文 / English), switchable from the plugin's own settings section — see Settings.

When does it warn?

All three conditions must hold. If any input is missing, the plugin stays silent.

#ConditionDefault
1Completed compactions — only a compaction/start paired with a compaction/end that carries no error. Failed compactions, in-progress compactions, and pure pruning (compaction/prune) never count.≥ 3
2Extra spend since the last compaction — billed tokens (uncachedInput + cacheRead + cacheWrite + output), accumulated from the usage samples the session log carries.≥ 200,000
3Either context occupancy (the next request's expected prompt ÷ the model's context window) or double the spend threshold — the second is the fallback for routes that declare no context window, which is why it is twice as hard to reach.≥ 50% or ≥ 400,000

Cases where it deliberately stays silent

SituationResult
A very long, very expensive conversation that has never been compactedsilent — only the counter shows (0)
Two compactions only (default threshold is 3)silent
Three compactions, but the window is roomy and nothing extra was spentsilent
Three compactions, 250k extra spend, low occupancy — past the threshold but not past the doubled onesilent
No usage data at all (even at 95% occupancy)silent
The route declares no context window and the extra spend is lowsilent

A documented example: a session with 2,100+ events, ~87M tokens spent and ~60% occupancy reported no warning at all, because it had never been compacted (gate: "compactions").

Install

Requirements

  • dsh >= 0.1.7-rc.1 (@deepseek-ai/dsh)
  • Node >= 22.19
  • A profile with a browser client: web, or desktop for the Electron app (this plugin has a browser half; it is a no-op on surfaces without one)

1. From npm

dsh plugin --profile web add @hjdd14/dsh-toolong-warning

2. From the Git repository

dsh plugin --profile web add "git+https://github.com/Hjdd14/dsh-toolong-warning.git"

This plugin ships hand-written JavaScript with no build step, so pnpm has no prepare/postinstall script to approve and the install does not stop for a build prompt. If a dsh version reports a pending build script, add the key it prints under allowBuilds in <DSH_HOME>/profiles/web/pnpm-workspace.yaml and re-run.

3. From a clone (development)

git clone https://github.com/Hjdd14/dsh-toolong-warning.git
dsh plugin --profile web add "link:<absolute path to the clone>"

Editing client.js reloads the plugin in the browser within ~500 ms. Editing host-side files (index.js, src/*.js) requires a new dsh web process — see Diagnostics.

4. By editing the profile by hand (when the CLI is unavailable)

In <DSH_HOME>/profiles/web/package.json:

{
  "dsh": {
    "profile": {
      "bundles": ["...", "@hjdd14/dsh-toolong-warning"]
    }
  },
  "dependencies": {
    "@hjdd14/dsh-toolong-warning": "^0.3.0"
  }
}

Then run pnpm install inside <DSH_HOME>/profiles/web and restart dsh web.

5. Desktop (the Electron app)

The DSH Desktop app is another surface over the same installation, with its own profile (desktop) and the same Web UI served from the app's own origin. It consumes client plugins that declare platform: "web" — which is exactly what this package declares — so nothing about the manifest changes; the package is simply installed into the desktop profile:

  1. Open the app and add @hjdd14/dsh-toolong-warning from its Plugins page.
  2. Or by hand: add the package to <DSH_HOME>/profiles/desktop/package.json under both dsh.profile.bundles and dependencies, run pnpm install in that directory, then restart the app.

dsh plugin --profile desktop add … is refused on purpose: an application-owned profile is written through the app's own in-process plugin manager rather than the CLI. The floating window knows the shell owns the window chrome — see Desktop placement.

Install a prebuilt tarball

npm pack                       # produces hjdd14-dsh-toolong-warning-0.3.0.tgz
dsh plugin --profile web add "file:<path to the tgz>"

Uninstall

dsh plugin --profile web remove @hjdd14/dsh-toolong-warning

Or disable it from the dsh web sidebar's Plugins page.

Settings

The plugin's section on the Settings page holds the language switch and every threshold. Values are written into the profile's cordis patch and take effect immediately.

FieldDefaultRangeMeaning
enabledtruetoggleWhen off, no state route is registered and no window appears
compactCountMin31–20Completed compactions required before a warning is possible
occupancyPercentMin5010–95Context occupancy above which the conversation counts as expensive
tokensSinceCompactionMin20000010000–5000000Billed tokens spent after the last compaction before it counts as heavy waste; at twice this value the warning fires even without an occupancy figure
statsIntervalMs150005000–120000How often the window refreshes (polling pauses while the page is hidden)
dismissibletruetoggleWhether Got it may hide the current reminder
historyReadTtlMs300005000–600000How long a history read for a session the host has not loaded is reused
historyReadTimeoutMs50001000–30000Time limit for one history read; on timeout the window reports that the session cannot be read yet

The lower part of the section shows the current session's measured values (compactions, billed tokens, spend since the last compaction, occupancy) and why the reminder is or is not firing — which is what calibrating the thresholds needs.

Language

A 中文 / English selector in the same section. The choice is stored in the browser, applies to the floating window and the settings section immediately (no reload), and is also pushed to the harness' shared locale service when that service is writable — so on most deployments the rest of the UI follows too. The global language control DSH itself ships lives in Settings → General.

Window position

Drag the floating window anywhere; the position is stored in this browser, next to the language choice and the threshold override, and is deliberately not a profile setting — it describes one person's screen, not the conversation. It stays inside the viewport (a moved window is pulled back after a resize or when the warning card makes it taller), and a Reset window position row appears in this section as soon as the window has been moved.

Desktop placement

A desktop shell owns the window chrome, and the floating window is aware of it:

  • The shell's reserved band is never usable space. The window's default top and the smallest top it can be dragged to both come from the frame's own --dsh-frame-overlay-top variable, minus whatever the shell has already reserved by moving its content viewport down. A shell that layers its chrome over the content and one that moves the content below the chrome therefore each get the right answer, and neither is compensated twice. On a plain browser page no such variable is published, so every value stays what it was.
  • The space it is clamped against is measured, not assumed. A shell whose content viewport starts below its command bar would otherwise both mis-clamp the window and displace it a little on every drag; an inert probe spanning the containing block measures it exactly. On a browser page the probe measures the viewport itself, so the Web behaviour is unchanged.
  • It stays out of the shell's app-region computation, so the window's own drag strips keep working (macOS and Windows Electron both mark the document; a plain page never does).

One consequence worth knowing: browser storage is per origin, so the desktop app and a page at http://127.0.0.1:3080 keep separate language choices, window positions and browser-local threshold overrides. That was already true before this adaptation and is not changed by it.

Two scopes of edit — and why

DSH fixes settings writes to read-only on a non-loopback page (persistence = ctx.remote.$host.isLoopback ? 'host' : 'memory'), and that applies to every plugin's configuration form, not just this one. Rather than showing dead controls, this plugin degrades honestly:

Page opened atThe three decision thresholdsenabled / dismissible
http://127.0.0.1:3080 or http://localhost:3080 (loopback)written to the profile configuration — applies to every sessioneditable, written to the profile
anything else (IP, hostname, tunnel)still editable, stored in this browser, applied to this page onlyread-only (they decide whether the host registers the route)

Browser-local values ride each state request as query parameters, are re-validated and clamped by the host on every request, and are never persisted. Out-of-range or non-integer values are ignored and reported back. The decision always happens on the host, so a page cannot force a warning.

How it works

browser (client.js)                        host (index.js + src/*)
────────────────────                       ─────────────────────────
floating window                            ctx.on('session/event')  ── incremental fold (live)
  ├─ session catalog → main-view session     └─ first ask seeds that session's whole log
  ├─ poll /api/.../state every 15 s      ctx.sessionProjections
  └─ counter line + warning card            └─ tokenUsage / contextPressure
settings section                           ctx.sessionQuery.readSession(id)  ── history (cold)
  ├─ language switch                          └─ sessions the host has not loaded
  └─ ctx.configForms('toolong-warning')   two loopback-only, read-only routes
      8 volatile fields                       /api/dsh-toolong-warning/state   (per session)
                                              /api/dsh-toolong-warning/health  (probes)

Three data sources, degrading in order

#ConditionResponseNotes
1The session is live in this processsource: "live"Full live metrics, including occupancy from the meter
2Not loaded, but its log is readablesource: "history"Count and spend folded from the log — this is why switching conversations shows a number without a page reload
3Neitherknown: false + reasonsession-not-loaded or history-unavailable; never warns
  • The browser cannot see a session's event log (the client side only has the session catalog), so every measurement happens host-side and is served over a same-origin route.
  • Both sources share the same folding and decision functions, so they must agree; ?selftest=1 makes the running process prove that on real sessions.
  • The history source uses the supported read-only service and never reads private storage paths ($DSH_HOME/storages/**, session log files). It never inserts a session into the live tracker, is cached with a TTL, and is bounded by a timeout.
  • The browser half is plain JavaScript registered through dsh.client + exports["./client"]; React comes from the shell's module table. It is deliberately self-contained: DSH serves client bundles from an exact combo URL out of an in-memory response map, so a sibling module can never be fetched and the dictionaries are inlined.
  • The host half imports no @deepseek-ai/* runtime package except @deepseek-ai/schemastery, which the Settings form requires to be a real schema; it is loaded from an explicit candidate path and degrades to a structurally equivalent descriptor when unavailable.

Diagnostics

Both routes are loopback-only (socket address and Host header and same-origin markers) and always send cache-control: no-store.

# Is it loaded, which generation is running, what are the effective thresholds?
curl.exe -s "http://127.0.0.1:3080/api/dsh-toolong-warning/health"

# Drive the real routes in the running process and compare against expected values.
# Runs two self-checks: a synthetic session through the whole decision chain, and a
# live-vs-history count comparison on real sessions.
curl.exe -s "http://127.0.0.1:3080/api/dsh-toolong-warning/health?selftest=1"

# One session's decision and raw numbers. debug=1 adds event-type statistics and the
# compaction lifecycle — never message content.
curl.exe -s "http://127.0.0.1:3080/api/dsh-toolong-warning/state?sessionId=<session id>&debug=1"

state fields: known, source (live / history), count, lastCompactionSeq, tokensSinceCompaction, billedTokens, occupancyRatio / projectedTokens / contextWindow, shouldWarn, reasons, gate, thresholds, thresholdsSource, configVersion, sampledEvents, droppedEvents, coldReads.

moduleGeneration is load-bearing. Host-side changes only load in a new dsh web process — dsh hot-reloads client bundles only. The generation counter exists so the running process can report which code it is serving, rather than that being a matter of inference.

Requirements

dsh>= 0.1.7-rc.1
Surfacethe web profile, and the Desktop app's desktop profile (the browser half is a no-op elsewhere)
Optional@deepseek-ai/dsh-session-query — enables the history source. Without it, sessions the host has not loaded simply stay unmeasured
Host dependency@deepseek-ai/schemastery ~3.18.4 for the Settings form. The bare schemastery reachable from a profile is 3.18.0 and has no .volatile(), which silently makes the form unavailable

License

MIT © 2026 Hjdd14