Introduction¶
When developing daily with DSH (DeepSeek Harness), sessions are isolated from each other: if you bring up the same topic discussed last week in a new session today, the agent won’t remember the details; if you switch topics in the same session and come back, the key information in between has already slipped out of context. Existing remedial measures each have their limitations — dsh-session-query provides a passive query API that requires someone to call it; dsh-session-reference requires the user to explicitly @ reference; dsh-agent-instructions only loads static instruction files. None of them actively return memory at the opportune moment.
DSH’s philosophy is “everything is a plugin,” and capabilities like cross-session memory can be supplemented by community plugins. The concept behind dsh-cue-bank is to mimic human brain episodic memory: humans can switch between tasks anytime because they create multi-dimensional trigger points (keywords, perspectives, triggers) for each event; once the current situation activates these trigger points, they retrieve the event details from long-term memory. This plugin brings the same mechanism to DSH.
What is this¶
dsh-cue-bank is a cross-session “Event Trigger Memory” plugin, maintained by itr-del, currently version 0.1.0, under the MIT license. It builds a persistent event trigger library (keywords + user idioms) for DeepSeek Harness and reawakens and injects relevant memory details when topic switching is detected.
Summarize its behavior in two sentences:
- At the end of each turn, automatically extract keywords and user idioms from the text and write them into the global trigger library;
- When the overlap between a new message and keywords from the previous turn is below a threshold, it is judged as a topic switch, and relevant memories are recalled from the library and injected with the request.
How it Works¶
Write Side: Automatic Library Creation on Turn End¶
The plugin listens for agent/status=idle, reads the text of the current turn when each turn ends, extracts three types of triggers, and upserts them into the global trigger library (atomic write JSON):
- Conversation-level triggers: Keywords from the current turn (2-4 character Chinese n-grams + English words);
- Task-level triggers: Aggregated keywords from the session, merged and updated;
- User idioms: High-frequency personal words within the recent N-turn window, recorded separately as a second type of trigger.
Each time a trigger is hit, lastTouchedAt is updated and keywords are merged; memory is progressively perfected with use.
Awake Side: Injection on Topic Switch¶
The plugin registers dynamic context via systemPrompt.context(). Every time a prompt is assembled, it extracts keywords from the new message and calculates overlap with the previous turn’s keywords. If below the threshold (default 0.25), it is judged as a topic switch, triggering a trigger library scan. After hitting top-N, it injects a <system-reminder> memory awake block. The injected content includes source markers (conversation / task), hit triggers, recent mention time, and detail summaries; if a user idiom is hit, a “User Idiom” hint line is appended.
Two notable designs:
- The injected content is a runtime-context snapshot with sources, sent with the request, but not written to persistent session history. It is not injected when the topic hasn’t switched, keeping the context clean. This is a key difference from
dsh-agent-instructions(persistent injection). - The plugin is generic: it listens for the global
agent/createdevent, mounting awake/write hooks for all agents, not limited to Feishu.userIdis extracted from the session ID (e.g.,feishu:ou_xxx→ou_xxx), and storage is sharded by user.
Matching Algorithm and Cost¶
Matching supports three modes:
| Mode | Description |
|---|---|
keyword |
TF-weighted exhaustive search, purely local, accurate literal overlap, weak semantics, zero external cost |
vector |
Vector cosine, strong semantic matching, uses OpenAI-compatible embedding interface |
auto (default) |
Uses vectors if key exists, auto-downgrades to keywords if none |
The vector mode defaults to SiliconFlow’s BAAI/bge-m3. The README specifically notes that the DeepSeek official API does not provide an embedding endpoint (citing deepseek-ai/DeepSeek-V3 issue #806), so the vector mode uses the OpenAI-compatible interface.
Regarding cost, library vectors are pre-calculated and cached during write, so only 1 query is encoded during awakening, avoiding double billing. Based on bge-m3 / SiliconFlow’s August 2026 rates, a single awakening costs about ¥0.000025, or about ¥0.25 for every 10,000 topic switches; the keyword mode has zero external cost.
Installation and Activation¶
One-click install (recommended). The installer resolves the plugin via the dsh.bundle manifest in package.json (cordis.patch.yml) and mounts it to the specified profile:
dsh plugin --profile web add github:itr-del/dsh-cue-bank
Can also install from npm (README states it has been published to npmjs.com/package/dsh-cue-bank):
dsh plugin --profile web add dsh-cue-bank
If you want to mount manually, first add the dependency in the profile’s package.json:
"dependencies": {
"dsh-cue-bank": "^0.1.0"
}
Then insert the configuration block for id: cue-bank into the profile’s cordis.patch.yml (containing default configs for storageRoot, matchMode, embedding, topic, inject, etc.; see README for the full YAML).
Then install dependencies and restart:
cd ~/.dsh/profiles/web && pnpm install
It takes effect after restarting dsh web; the plugin loads on startup.
To enable vector mode, just set an environment variable (or configure embedding.apiKey), no code changes needed:
export SILICONFLOW_API_KEY=...
If no key is set, matchMode: auto will automatically downgrade to pure keyword local matching; you can also change embedding.baseURL to a self-hosted endpoint to achieve completely local operation.
Configuration¶
Commonly adjustable items (default values):
| Key | Default | Description |
|---|---|---|
storageRoot |
'' |
Empty = $DSH_HOME/storages/cue-bank |
matchMode |
auto |
auto / keyword / vector |
topic.switchThreshold |
0.25 |
Topic switch is judged if keyword overlap is below this value |
topic.scanEveryTurn |
false |
Scan every turn (sensitive but high overhead) |
inject.maxCues |
3 |
Maximum number of memories to inject |
inject.maxDetailChars |
400 |
Truncation length for single detail |
extract.userIdiomWindowTurns |
10 |
Idiom statistics window (turns) |
dbg |
false |
Debug logs |
The trigger library is stored by default at $DSH_HOME/storages/cue-bank/users/<userId>.json, shared across profiles and sessions. The per-user trigger limit is 200 items (LRU eviction), and idiom limit is 50 items. See README for the full configuration table.
Testing and Verification¶
The repository comes with four test suites, results given in README:
node test/keywords.test.js # 22/22 passed
node test/store.test.js # 16/16 passed
node test/embedding.test.js # 18/18 passed (no network requests)
node test/integration.test.js # 13/13 passed
Covers library creation on write, awakening on topic switch, same-topic suppression, irrelevant topic suppression, idiom extraction and participation in awakening. It has also been verified in a real dsh process (headless profile): no errors on plugin load, automatic writing to global trigger library on turn end. For vector mode without a real key, code paths were verified using a local mock OpenAI-compatible server, including API call contracts, cosine similarity judgment, auto-downgrade without a key, and timeout abort.
Differences from Official Plugins¶
The README describes core capabilities that hardly overlap with DSH official plugins (dsh-session-query, dsh-session-reference, dsh-compaction, dsh-agent-instructions, dsh-spill), estimated overlap of 10-15%, opposite direction: official plugins are “passive query,” while cue-bank is “automatic memory + active awakening.”
Unique capabilities not found in the official list include: automatic library creation on turn end, threshold-triggered topic switching, dynamic injection without user mention, user word profiling, and structured global storage.
Use Cases and Considerations¶
Suitable for users: those who use DSH long-term, work across multiple sessions, and often switch topics back and forth, hoping the agent remembers “what was discussed before” and “what expressions they typically use.” Without configuring an embedding key, it runs purely locally with very low maintenance cost.
Notes before use:
- The plugin runs with the permissions of the current dsh process; it is recommended to read the source code and license before installing (this project is MIT);
- Vector mode (
matchMode: autowithSILICONFLOW_API_KEYset) encodes dialogue text and sends it tohttps://api.siliconflow.cn/v1(default third-party OpenAI-compatible endpoint), and library vectors are also pre-calculated via this endpoint during writing. If you mind data leaving the local machine, do not set this key, or switch to a self-hosted endpoint; - The trigger library has a capacity limit (200 triggers with LRU eviction, 50 idioms), so it is not suitable for use as a full archive.
Conclusion¶
dsh-cue-bank turns “passive history querying” into “actively sending memory back at the moment of topic switching,” complementing the direction of official plugins. Vector mode costs about ¥0.000025 per awakening and can also run completely locally.
Project homepage: https://github.com/itr-del/dsh-cue-bank; Community directory page: https://www.skillhub.cn/plugins/itr-del/dsh-cue-bank (this directory is an independent community site, with no official affiliation to DeepSeek / Hypersphere).