DeepSeek Harness Plugin Hub

Publish and manage complete Harness Profiles. Discover Plugins for your next setup.

Explore

PluginsPresetsDocsNews

Community

Publish a pluginContactReport an issue

Resources

Plugin Hub on GitHubDeepSeek HarnessSystem statusPrivacy notice
© 2026 DeepSeek Harness Plugin HubPowered byPaxTech

Independent and unofficial. Not affiliated with, authorized by, or endorsed by DeepSeek.

Round Inject — DSH Plugin for DeepSeek Harness
DeepSeek Harness Plugin Hub
ProfilesPluginsCategoriesNewsDocsSign inManage Profiles
ProfilesPluginsCategoriesNewsDocsSign in
← Plugins

dsh-round-inject

Round Inject

Periodic prompt injection for the DeepSeek Harness Web GUI: every N model invocations (conversation turns and tool-call steps both count) the plugin injects a user-configured prompt as a model-visible user message; the first injection happens at conversat

The plugin will be installed here. Keep web if you are unsure.

npx -y @deepseek-ai/dsh plugin --profile web add dsh-round-inject@0.1.14
READMECompatibilityVersions

Compatibility and provenance

Round Inject is published as dsh-round-inject and currently resolves to version 0.1.14. The Hub verifies its manifest and preserves the exact installation source for reproducible installs.

DSH compatibility
*
Runtime surfaces
web
Release source
npm
Registry updated
9/22/2026

Versions

0.1.14stable
9/4/2026
0.1.13stable
8/22/2026
0.1.12stable
8/22/2026
Show 12 more versionsCollapse versions
0.1.11stable
8/22/2026
0.1.10stable
8/22/2026
0.1.9stable
8/22/2026
0.1.8stable
8/22/2026
0.1.7stable
8/22/2026
0.1.6stable
8/22/2026
0.1.5stable
8/22/2026
0.1.4stable
8/22/2026
0.1.3stable
8/22/2026
0.1.2stable
8/22/2026
0.1.1stable
8/22/2026
0.1.0stable
8/22/2026
Latest
0.1.14
DSH
*
HMR
Process restart
Tree shaking
Safe tree shaking not declared
Unpacked size
43.5 kB
Files
7
Surface
web
License
MIT
Source
npm
GitHub
★ 0
Weekly downloads
41
Last push
9/4/2026
View source ↗Project homepage ↗
README badge

Click the badge to copy Markdown for your README.

Do you maintain this Plugin?Claim benefit · Priority security scan

Verify the GitHub repository declared in package.json to manage this listing. After you claim it, Hub will prioritize a security scan of the current version and publish the result when it passes.

Claim this Plugin →
Report an issue

README

dsh-round-inject

Periodic prompt injection for the DeepSeek Harness Web GUI.

Every N model invocations — conversation turns and tool-call steps each count as one — the plugin injects a user-configured prompt into the model context as a model-visible, source-attributed user message. The first injection happens at conversation start.

Hostagent/pre-step waterfall (counts every entering step, appends the injected message to that step's request)
Clientone Settings page with two prompt boxes + round interval (default 50)
Configround-inject settings namespace, persisted by the DSH settings provider

Features

  • Round counting — every model invocation counts once, including steps triggered by tool results (a tool call is followed by another model call = another step). Counting rides the durable sessionProjections seam (the same mechanism the built-in "N 轮 · M 步" stats line uses): the counter is a persisted projection per session, so compaction, paging, session resume and host restarts cannot reset it.
  • Periodic injection — when exactly interval completed model calls have elapsed since the previous injection, the periodic prompt is appended to that step's messages (default interval 50) — with the start prompt on, injected calls sit at steps 1, 1+interval, 1+2·interval, …; without one, at interval, 2·interval, 3·interval, …. The injected message carries source: { kind: 'plugin', plugin: 'round-inject' }, is persisted to the session log, and is visible to the model.
  • Two independent prompts — the conversation-start prompt (first input box) and the periodic prompt (second input box) are separate: the start injection uses only the start prompt, the periodic injection uses only the periodic prompt. Either can be left empty to disable that side.
  • Inject at conversation start — when enabled and the start prompt is non-empty, the very first model call of each conversation carries the start prompt; the periodic counter then restarts from that call.
  • Settings UI with Save button — Settings → 提示词注入: enable switch, interval (number input, default 50), conversation-start prompt (first textarea), periodic prompt (second textarea), and an "inject at conversation start" switch. All edits are draft-only; a Save button (bottom-right) commits the whole form to the settings namespace at once. Nothing is written until the user clicks Save. IME composition is protected (Chinese input never pollutes the form).
  • Safe by default — empty prompt ⇒ nothing is injected; disabled ⇒ no counting and no injection; a step that does not actually call the model is never counted.

Install

The package is a DSH plugin published to npm. From a DSH profile directory:

dsh plugin --profile web add dsh-round-inject

or add it manually to the profile's package.json dependencies and append "dsh-round-inject" to dsh.profile.bundles, then restart the profile.

Configuration

The composition row (also the settings namespace base layer):

- id: round-inject
  name: 'dsh-round-inject'
  config:
    enabled: true        # master switch
    interval: 50         # model invocations between two injections
    prompt: ''           # injected prompt text (empty ⇒ no injection)
    injectOnStart: true  # inject once at conversation start

All values can be changed live from Settings → 提示词注入 without a restart.

How it works

The host registers ONE durable fold on the sessionProjections seam and acts on it from the agent/pre-step waterfall:

  1. One fold for counting AND the bookmark — the round-inject projection is a pure fold over the session event stream. It consumes only built-in events — no custom event type is ever appended, so restoring a session can never fail on this plugin's vocabulary:
    • every step/end (one completed model call, the same event the built-in "N 轮 · M 步" line counts) increments totalSteps and — once the session has injected — sinceInject, the completed calls since the last injected message;
    • an injected user/message (identifiable by its source: {kind:'plugin', plugin:'round-inject'} marker, which the plugin stamps when appending) records lastInjectSeq and resets sinceInject to 0. The registry checkpoints the state into <root>/session_projcache/, so the count and the bookmark survive compaction, paging, session resume and host restarts. Keeping the bookmark in this derived state (instead of the settings namespace, which leaked across sessions in 0.1.11, or scanning session.events, which does not exist and crashed every turn in 0.1.13) makes the interval exact: one O(1) fold per event, never a per-step full-log scan.
  2. Injection (side effect) — the plugin listens to the agent/pre-step waterfall (one event per proposed step). After next() yields the loop's own decision, it:
    • ignores reject decisions and steps with an empty message set (those never call the model);
    • reads the latest config from the round-inject namespace;
    • reads the projected state (totalSteps, sinceInject, lastInjectSeq) and decides:
      • never injected yet + start prompt enabled → append the start prompt to the very first model call;
      • never injected yet + no start prompt → append the periodic prompt to the interval-th model call of the session;
      • otherwise sinceInject >= interval → append the periodic prompt to the next model call, exactly interval completed calls after the previous injection;
    • the whole decision is guarded: on any unexpected error it logs a warning and lets the step proceed uninjected, so the plugin can never take down an agent turn. The injected message is appended as createUserMessage({ content: [{ type: 'text', text: prompt }], source: { kind: 'plugin', plugin: 'round-inject' } }) and becomes part of the step's durable user messages — model-visible, audit-able in the session log, and it works with any model route.

Because the injected message becomes part of the step's durable user messages, it is model-visible, audit-able in the session log, and works with any model route.

KV cache note

An injection changes the request content at the injected step, so provider KV/prefix cache is invalidated from that request onward for one turn's worth of steps. With the default interval of 50 this is negligible; lowering the interval increases invalidation frequency.

IME input: pinyin/kana never pollute settings, Chinese typing works (0.1.8)

The settings inputs (prompt textarea, interval number) use a local draft plus a composition gate:

  • onChange always updates the local draft, so the controlled field keeps following the user's keystrokes — typing is never swallowed, committed Chinese characters stay on screen.
  • Settings writes are skipped while the IME is composing (onCompositionStart … onCompositionEnd, plus nativeEvent.isComposing), so uncommitted pinyin/kana never reach the settings namespace (the original "输入法拼音被记录" bug).
  • onCompositionEnd writes the final committed value (the DOM value at that moment, i.e. the selected hanzi/kana) once.

Version history:

  • 0.1.7 regressed: onChange was fully ignored during composition, which froze the React controlled value at the stale snapshot; the next render then reset the field and swallowed the committed Chinese characters ("选完字上不了屏").
  • 0.1.8 (current) fixes this with the local-draft approach above.

Related upstream DSH issue (chat composer): clicking the Send button while composing submitted the uncommitted pinyin — the Enter path already guarded, the button path did not. See docs/dsh-composer-ime-patch.md for the one-line upstream patch.

Changelog

  • 0.1.14 — fix "session.events is not iterable" (per-step turn failure): the bookmark scan used session.events, which is not an API of the session object (the public surface is session.snapshotEvents()). The bookmark now lives in the projection state (derived, O(1) per event, durable) and the decision is guarded, so an internal error can no longer kill a turn. Injection timing is exact: with the start prompt on, injected calls are the session's 1st, 1+interval-th, 1+2·interval-th, …; with it off, the interval-th, 2·interval-th, … (no more ±1 drift). Default interval lowered from 80 to 50.

Troubleshooting

DSH shared host packages are peerDependencies (0.1.6)

The plugin declares every DSH-provided runtime package (@deepseek-ai/cordis, @deepseek-ai/dsh-llm, @deepseek-ai/dsh-settings, @deepseek-ai/schemastery) as peerDependencies — not dependencies. DSH installs a shared host-package directory (~/.dsh/profiles/node_modules/@deepseek-ai/) with symlinks to the exact host versions, so plugins must resolve those packages through the host, never via a self-installed copy.

Before 0.1.6 the plugin shipped dsh-llm in dependencies, which made pnpm hoist a separate dsh-llm@0.1.0-rc.8 into the profile root. Node resolution then picked that copy over the host's shared symlink, so the plugin ran against a different dsh-llm instance than the host (host: 0.1.1-rc.2). The two versions had identical createUserMessage signatures, so it worked by luck — but any API drift would break silently. Symptom to look for: require.resolve('@deepseek-ai/dsh-llm/package.json') from the profile resolves to profiles/web/node_modules/... instead of the host install. After updating to 0.1.6, run pnpm install in the profile so the stale hoisted copy is pruned, then verify it resolves to the host:

cd ~/.dsh/profiles/web
pnpm add "dsh-round-inject@0.1.6"   # prunes the old hoisted dsh-llm copy
node -p "require.resolve('@deepseek-ai/dsh-llm/package.json')"  # → host path, not profiles/web/node_modules

"设置服务不可用" / settings inputs not editable / namespace missing

Symptom: the Settings page renders but shows "设置服务不可用,当前仅使用组合配置默认值", or the inputs are disabled/unfocusable, or settings.describe does not list the round-inject namespace.

Root cause (fixed in 0.1.5): the host plugin read its composition config via ctx.config. Cordis 4 guards property access on the context — reading ctx.config without declaring inject: ['config'] throws (cannot get property "config" without inject), so the host apply() failed on load. The client page still rendered independently (it is a separate bundle), which made the failure look like a settings-service issue. The fix reads config from the second apply(ctx, config) argument (the loader passes the resolved entry config there), and registers the settings namespace with that config as its base layer.

If you still see the symptom after updating to 0.1.5, verify:

# 1. the profile actually resolved 0.1.5 (pnpm autoInstallPeers=false can leave stale peers)
cd ~/.dsh/profiles/web && node -p "require('dsh-round-inject/package.json').version"
# 2. the namespace is registered (from the running instance)
#    settings.describe should include round-inject
# 3. restart the profile after the upgrade — host plugins load at startup

"loaded without registering "dsh-round-inject" via ModuleLoader.load"

The client bundle must register the exact npm package name (dsh-round-inject) as its module id — client-modules serves /plugins/<pkg>/client.js and verifies the bundle registers that exact id. Current client.js uses id: 'dsh-round-inject'. Reinstall and hard-refresh the page (the client bundle is cache-busted by a ?rev= query).

Development

├── index.js       # Host half (ESM; settings registration + session-start reset + pre-step counting/injection)
├── client.js      # Browser half (Settings page; __ModuleLoader__.load factory, no build step)
├── cordis.patch.yml
└── package.json

No build step — both halves are hand-authored ESM/browser factories (same pattern as dsh-strata). Publish with:

npm publish

License

MIT