DeepSeek Harness Plugin Hub

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

探索

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

社区

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

相关链接

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

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

DeepSeek Harness Plugin Hub
ProfilesPlugins分类动态文档登录管理 Profiles
ProfilesPlugins分类动态文档登录
← Plugins

dsh-warm

Warm

DeepSeek Harness 主机插件:提示缓存预热器。当会话的代理循环在工具执行(bash、wait_agent、job_output,…)中阻塞时,每隔一段时间通过 llm waterfall 以 max_tokens=1 重新调度会话的上一次对话请求,从而保持提供商的提示缓存前缀处于热状态;绝不会预热空闲会话或用户输入工具。

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

npx -y @deepseek-ai/dsh plugin --profile web add dsh-warm@0.2.0
README兼容性版本

说明

DeepSeek Harness 主机插件:提示缓存预热器。当会话的代理循环在工具执行(bash、wait_agent、job_output,…)中阻塞时,每隔一段时间通过 llm waterfall 以 max_tokens=1 重新调度会话的上一次对话请求,从而保持提供商的提示缓存前缀处于热状态;绝不会预热空闲会话或用户输入工具。日志与预算位于 $DSH_HOME/storages/dsh-warm/。

兼容性与来源证明

Warm 以 dsh-warm 发布,当前版本为 0.2.0。Plugin Hub 会校验它的 manifest,并保存精确安装来源,便于复现安装结果。

DSH 兼容范围
*
运行环境
web
发布来源
npm
Registry 更新时间
2026/10/20

版本

0.2.0stable
2026/10/20
0.1.0stable
2026/10/18

相关插件

正在加载相关插件…

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

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

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

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

认领这个 Plugin →
报告问题

相关插件

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

Experimental Cot Translation Bundle@deepseek-ai/dsh-experimental-cot-translation-bundle扩展推理的实验性机器翻译Our Free Model@ebony-vinyl/dsh-our-free-modelOur Free Model — 在 dsh 里装上这个插件即可,无需登录、注册或填 API Key,就能使用包括 DeepSeek V4.1 Flash、Kimi K3 在内的前沿模型,桌面端另有 EAC 协付渠道;2.0 起接入 LobsterAI、Qoder、TRAE、Cline、Loomy、Raccoon、MiniMax、ZCode、Gemini 十个账号渠道(原有匿名免费通道保留)(登录、账号池、积分领取、本地 OpenAI 网关与局域网转发、数据看板与运行日志),六页毛玻璃界面统一呈现。Usage@linxin666/dsh-usage用于 dsh Web GUI 的使用统计插件:检测各提供商的余额和编程套餐配额,并实时记录令牌使用情况;侧边栏 Settings 行上方显示紧凑的价格概览卡片Connect Workbuddydsh-connect-workbuddy把本机登录的 WorkBuddy 模型(国内版与国际版)接入 DeepSeek Harness:每次刷新按上游目录自动读取每个模型的积分倍率,支持逐模型图片输入开关、多账号切换与账号池自动换号,并提供每日签到、卡片与输入框里的胶囊积分读数等只读积分概览。

README

dsh-warm

Prompt-cache warmer for DeepSeek Harness, a host plugin. It keeps a session's provider prompt-cache prefix warm while, and only while, the session's agent loop is blocked inside a tool execution (long bash, job_output, wait_agent on teammates, and similar waits).

It re-dispatches the session's last conversation request through the host llm/stream waterfall with maxTokens: 1 on a fixed interval, then discards the 1-token response. The tool's result lands on the still-warm prefix, so the next real request bills cache-hit input instead of re-prefilling ~90k tokens at miss price and paying the full TTFT again.

Why only tool blocks

Measured on this setup (2026-10-17, live probe against api.mistral.ai, zai-glm-5-3; 50 days of ledgers, 350 sessions):

  • TTL is provider-specific. Mistral's lasts 5 to 7 min here (hit at 302 s, miss at 424 s, and hits refresh the TTL), which is why the interval table is per provider.
  • Tool and teammate waits resume for sure, since the loop continues the moment the tool settles. Over 50 days that nets +$7.15 and about 1 h of TTFT recovered, with zero tail risk.
  • Idle sessions mostly never come back. 344 of 350 sessions were never resumed, and naive OpenCode-style idle warming nets −$6.91 / 50 days. So idle sessions and user-input tools (ask_user_question) are never warmed here.

A cache hit bills at a 90 % discount on this provider ($1.40/M miss, $0.14/M hit). Each ping costs about $0.014 per 100k-token prefix and saves a ~$0.126 re-prefill plus 25 to 40 s of TTFT when the block outlasts the TTL.

How the replay stays byte-identical

The loop-built request arrives at the llm/stream waterfall deep-frozen, a pure function of the session log. The warmer captures that exact object and later sends a fresh shallow copy that shares the frozen fields, changing only:

  • maxTokens: 1, a sampling field that is not part of the cached input prefix,
  • signal, the captured call's signal chained (AbortSignal.any) with the ping timeout, so a user interrupt aborts an in-flight ping too.

The same adapter that served the real call serializes the ping, so the input prefix is byte-identical and the provider serves it from cache. This is the same cache-reusing auxiliary-call pattern the harness itself uses for compaction summarization. The ping is a hand-built call (the loop's markAgentLoopRequest WeakSet identity does not carry over to the copy) and it traverses the full waterfall, so routing adapters behave identically and dsh-cost-meter bills its usage like any other call. The ledger stays honest.

Install

dsh plugin --profile web add dsh-warm                      # from npm
dsh plugin --profile web add github:JanEickholt/dsh-warm  # from GitHub, no npm needed

Or as a local plugin (link protocol):

  1. profiles/<profile>/package.json: add "dsh-warm": "link:/absolute/path/to/dsh-warm" to dependencies and "dsh-warm" to dsh.profile.bundles.
  2. pnpm install inside the profile directory.
  3. Restart the harness from a terminal (e.g. systemctl --user restart <your-dsh-unit>). A restart kills the host process; never trigger it from inside a session.

The plugin's dsh.bundle.patch (cordis.patch.yml) inserts the loader row automatically; no cordis.patch.yml edit needed.

Configuration

$DSH_HOME/storages/dsh-warm/config.json (written with defaults on first load; edit + restart). The ping interval is per provider, because the interval must sit under that provider's own prompt-cache TTL:

{
  "enabled": true,
  "dryRun": false,
  "maxPings": 5,
  "providers": {
    "mistral":   { "intervalMs": 240000, "ttlMs": 302000 },
    "openai":    { "intervalMs": 240000, "ttlMs": 300000 },
    "anthropic": { "intervalMs": 240000, "ttlMs": 300000 }
  },
  "excludeTools": ["ask_user_question"],
  "minPrefixChars": 12000,
  "maxConcurrentPings": 2,
  "dailyPingBudget": 300,
  "pingTimeoutMs": 90000,
  "stats": { "enabled": true }
}
fielddefaultmeaning
enabledtruemaster switch
dryRunfalsejournal would-be pings, dispatch nothing. Watch mode for a first deploy.
providerssee abovepresence in the table = warm this provider; each entry needs its own intervalMs and may override maxPings and ttlMs
maxPings5ping cap per tool block when a provider entry doesn't override it (the prefix is stale past maxPings × intervalMs anyway)
excludeTools["ask_user_question"]user-idle-like waits with uncertain resume
minPrefixChars12000skip tiny prefixes (≈chars/4 tokens); preventing a miss on them is not worth a ping
maxConcurrentPings2global in-flight guard; over-cap pings retry in 5 s without consuming a slot
dailyPingBudget300hard stop per UTC day, counted over real dispatch attempts (expected need ≈30/day)
pingTimeoutMs90000abort a stalled ping stream
providers.*.ttlMsadopted per known providerthe provider's cache TTL floor, used by stats classification; intervalMs when a provider has no measured value. Warns when ttlMs <= intervalMs (the grid can never bridge the TTL)
stats.enabledtruestats counting + stats.json + the /api/dsh-warm/stats route's snapshot

Why these three providers

Interval defaults are tied to each provider's own cache behavior. Measure before adding more:

  • mistral was measured on this setup (2026-10-17 live probe, zai-glm-5-3): hit at 302 s, miss at 424 s, so 240 s leaves about a minute of headroom.
  • openai documents its cache as lasting "generally between 5 minutes and up to an hour"; 240 s stays under the short end.
  • anthropic documents a 5-minute TTL, refreshed on use; 240 s fits.
  • deepseek is deliberately absent. Its automatic disk cache outlives any sane ping grid (reports range from minutes to hours, and DeepSeek publishes no TTL), so a ping there every 4 minutes is pure waste. Add an entry only after measuring an actual TTL on your account.
  • opencode-go / other proxies are absent because their TTL is unmeasured. Probe first, then add e.g. "opencode-go": { "intervalMs": 120000 }".

A pre-table config (warmProviders + intervalMs) migrates automatically into the per-provider table with a console warning.

Stats

dsh-warm keeps its own ledger of what warming bought and what it wasted, independent of any other plugin. It shows up in three places: a stats.json file, a documented HTTP route, and a small client bundle.

Counters (kept per UTC day and all-time; failed is all-time only):

countermeaning
warmspings dispatched
needlesswasted: the follow-up request arrived within the provider TTL anyway, so the prefix was still warm without the ping
noFollowupwasted: the tool block ended with no follow-up request at all (the turn went idle, or the session was disposed)
expiredwasted: the follow-up needed the warm prefix but came more than TTL after the last successful ping, so the cache had already dropped
failedpings that errored (counted separately, never as waste)
savedCacheTokenscache-read tokens of the last successful ping in a block whose follow-up was necessary and arrived within TTL, i.e. what warming verifiably bought

Approximations, by design: classification compares request/ping timestamps against the configured ttlMs, not provider-side cache state. A ping that reported a miss (cacheReadTokens 0) is never credited. After a crash (no clean dispose) the boot reseeds warms/failed from warm.jsonl but leaves outcome counters at zero, because outcomes need the follow-up request that happened after the journal line. Stats are written to storages/dsh-warm/stats.json (atomic rename, UTC-day buckets).

Toggle: "stats": { "enabled": true }, on by default. Off means no counting, no stats.json, and the route below serves "statsEnabled": false, "stats": null so consumers can render the state instead of guessing.

GET /api/dsh-warm/stats serves a stable schema for third-party consumers (say a dsh-context-insights card; both plugins stay fully independent, this route is the only coupling, and it fails open when dsh-warm is absent). The shape changes only behind a schema bump:

{
  "schema": 1,
  "statsEnabled": true,
  "stats": {
    "today":   { "day": "2026-10-20", "warms": 3, "needless": 0, "noFollowup": 1, "expired": 0, "savedCacheTokens": 1152 },
    "allTime": { "warms": 12, "needless": 1, "noFollowup": 2, "expired": 1, "savedCacheTokens": 4608 },
    "byDay":   { "2026-10-20": { "warms": 3, "needless": 0, "noFollowup": 1, "expired": 0, "savedCacheTokens": 1152 } },
    "failed": 0
  },
  "config": {
    "providers": { "mistral": { "intervalMs": 240000, "ttlMs": 302000 } },
    "budget": { "dailyPingBudget": 300, "maxPingsPerBlock": 5 },
    "dryRun": false
  }
}

The route sits behind the harness's authenticated /api fence (no separate auth; same fence as the harness's own routes) and exists whenever the plugin is enabled, also when stats are off, so the toggle state is visible.

Client bundle: the package ships a web client (dsh.client, a plain CJS factory, no build step). A "Warm" row in the sidebar footer opens a detail panel with today and all-time counters, the provider grid, and the budget; it polls while open. A dsh-warm card on the Plugins page shows the same data. Both surfaces only read the route; nothing is stored client-side.

Observability

  • storages/dsh-warm/warm.jsonl holds one line per ping: provider usage (cacheReadTokens > 0 means a hit), latency, errors, dry-run markers. It rolls at 5 MB, and the budget counter boots from today's lines.
  • storages/dsh-warm/stats.json holds the stats counters above (see Stats), atomic-written, resilient to crashes.
  • Host console: a load banner with the resolved config, plus rate-limited failure warnings.
  • dsh-cost-meter's ledger includes every ping (session-attributed via sessionId), so the economics stay verifiable against reality.

Known limitations

  • Provider scope: only providers with an entry in the providers table are warmed, and each needs a measured or documented TTL floor. deepseek and opencode-go are absent by default for that reason (see the configuration section).
  • The re-dispatch goes through the profile's main llm service; a provider adapter registered only on an isolated service would serialize differently (none exist in this profile today).
  • The 302 s TTL floor is a Mistral measurement for zai-glm-5-3; other providers need their own probe before being added to the providers table.