DeepSeek Harness (DSH) ‘s default auto-compaction is based on a window ratio, making it difficult to meet the need for precise control over absolute token counts (such as 400k). dsh-oha-whale-compress is a plugin that solves this pain point: it takes over compaction threshold evaluation, supports absolute-value settings, and provides quick-action entry points in the sidebar and below the input box.
Core Features¶
The plugin mainly provides the following capabilities:
- Sidebar Entry: Provides a full configuration panel at the bottom of the sidebar, where you can view session size (node count / token count) and compaction status.
- Persistent Input Box Button: Provides a persistent “Compact” button below the input box. Clicking it invokes the simplified (halved) panel.
- Auto-Compaction Control: Supports enabling/disabling auto-compaction and customizing the trigger threshold (default 409600 tokens).
- Manual Compaction: One-click compaction triggering via the sidebar or the input box button.
Installation¶
Install via the official CLI:
dsh plugin --profile web add dsh-oha-whale-compress
Configuration and Usage¶
The configuration file is located under the user root directory:
~/.dsh/storages/dsh-oha-whale-compress/config.
Set the following fields in this file:
autoCompress: Controls the master switch for auto-compaction.autoThresholdTokens: The absolute token threshold that triggers compaction (default 409600).dockButton: Controls the visibility of the button below the input box.
There are two ways to trigger compaction:
- Click the button in the full panel at the bottom of the sidebar.
- Use the persistent button below the input box (which invokes the halved panel).
Manual compaction must go through the framework command: ctx.get('commands').execute(agent, '/compact', [], signal).
Engine Injection and Activation¶
To make auto-compaction work according to this plugin’s absolute threshold, replace the injected preset engine name with dsh-oha-whale-compress/engine.
According to official documentation, the authoritative runtime source is the profile’s cordis.patch.yml, not ~/.dsh/.agent-presets/<id>/agent.cordis.yml. If batch replacement is needed, you can use the provided injection script:
cd /root/dsha-oha-whale-compress && node --input-type=module -e "
const { injectPreset } = await import('file:///root/dsha-oha-whale-compress/src/injector.js')
const r = await injectPreset({
presetPath: '/root/.dsh/profiles/web/cordis.patch.yml',
userRoot: '/root/.dsh/profiles',
mode: 'inject',
expectedCount: 4
})
console.log(r)"
Conditions for changes to take effect:
* Modify src/* (host side): a dsh restart is required.
* Modify client/client.js: refresh the page.
* Modify the preset engine line: a dsh restart is required (the loader does not watch preset files).
Technical Details and Caveats¶
- Lazy-Loading Design: The plugin only hard-injects
webServer; all other services are lazily retrieved at runtime viactx.get(). If retrieval fails, it gracefully returns 503 and never blocks plugin activation. - Service Isolation: The
compactionservice is isolated (the compaction group isisolate), so profile plugins cannot call it directly; it can only be triggered through commands. - Dependency Declaration: The
exportsfield inpackage.jsonmust declare./engine; otherwise loading will throw an error. - Asynchronous Loading Pitfall: Do not pass asynchronously loaded values directly to toggles; otherwise, opening the panel will trigger replay animations every time. Use the already loaded value from the module-level config store as the initial value.
- Store Field Differences: The
sessionsstore does not have acurrentfield; it only hasbyIdandlist. The panel should obtain the current session viauiSession.current, or find the session inbyIdwhereretainedBy.mainView > 0. - UI Rendering Pitfalls: Inverting a boolean condition can cause the UI to silently fail to render. For example, writing the
if (full)condition inverted will cause all fields in the full panel, such as toggles and thresholds, not to display. After fixing the condition, verify each field individually. - Slot Props: When the host renders
shell.overlayandconversation.composer.dock, it passes empty objects. Related props (such asuseSessions) are allundefinedand must be obtained manually from sources such asctx.get('uiSession').current.