# dsh-memory ๐Ÿง  Cross-session memory plugin for [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) (dsh). YAML-backed `remember` / `recall` / `view` / `list` / `forget` / `pin` tools with **embedding search**, **title-first injection**, and **two-level (session/auto) automatic injection** โ€” the agent "naturally carries" memory without having to remember to call a tool. English | [ไธญๆ–‡](README.md) ### ๐ŸŽฏ Injection Strategy: Precise, Conservative, Cache-Friendly | Design Principle | Description | |---|---| | **Inject once, reuse forever** | Fixed memories inject on the **session's FIRST step** only, then ride the history โ€” no per-round re-render | | **Title-first, expand on demand** | Injects concise titles (with id); full details expand via `view` tool โ€” compact prompts | | **Dynamic memories independent from fixed set** | `auto` memories retrieved by topic, **never pollute the fixed injection set** | | **Preserves prefix cache** | After injection, memories enter history; system prompt + history prefix stays identical โ€” **LLM KV cache hit rate unaffected** | | **Provenance isolation** | Injected memories prefixed with `Retrieved memories from the memory store (not conversation history)` โ€” model never mistakes them for dialogue | ### ๐Ÿ“Š Comparison with Alternatives | Approach | Per-round injection | Cache impact | Token cost | |---|---|---|---| | Full injection every round | โŒ Repeats each round | โŒ Breaks cache | High | | This plugin | โœ… Once at start | โœ… Zero impact | Low | ## โœจ Features | Feature | Description | |---|---| | **remember / recall / view / list / forget / pin** | Write, semantic search, expand-by-id, list (titles), soft-delete, force-inject pinning | | **Title-first injection** | Memories inject as **summary titles** (with id), not full text โ€” compact prompts; details expand via the `view` tool | | **Two-level injection** | `injectLevel: session` memories are resident (injected once at session start); `auto` memories arrive via topic retrieval | | **Once-per-session injection** | Fixed memories inject on the session's FIRST step, then ride the history (no per-round re-render โ€” token + prefix-cache friendly) | | **Embedding search** | HybridSearch (keyword 2-gram + local embedding via ollama, RRF fusion) โ€” catches paraphrases keyword search misses | | **Tuned matching** | Generic-word downweighting (ๆ–‡ไปถ/ๆต‹่ฏ•/ๆ–‡ๆกฃโ€ฆ), โ‰ฅ2-token keyword hits, retrieval gate skips test-chatter ("ๅˆซ็ฎก/ๅชๆ˜ฏๆต‹่ฏ•") | | **Provenance labeling** | Injected memories are prefixed "โ€ฆfrom the memory store (not conversation history)" so the model never mistakes them for dialogue | | **Data safety** | Serialized write queue (no lost updates), corrupt-file quarantine + backup, atomic writes, mtime cache invalidation | ## ๐Ÿ“ฆ Install ```sh # From source (inside a dsh checkout) pnpm install pnpm run build # Register in your profile patch (e.g. ~/.dsh/profiles/web/cordis.patch.yml) - insert: - id: dsh-memory name: '@towzai/dsh-memory' config: file: /path/to/memory.yaml injectLimit: 8 ``` Requires a local [ollama](https://ollama.com) instance with an embedding model (default `qwen3-embedding:0.6b`; override via `DSH_MEMORY_EMBED_MODEL`). ## ๐Ÿ”จ Build (from source) Requires the dsh checkout's dependencies (the plugin's peer deps live there). On Windows you can junction them instead of reinstalling: ```powershell # in the plugin repo cmd /c mklink /J node_modules \node_modules npm run build # outputs lib/index.js ``` ## ๐Ÿ› ๏ธ Tools | Tool | Purpose | |---|---| | `remember` | Save a memory (content / title / category / tags / importance / forceInject / injectLevel / source) | | `recall` | Hybrid search (keyword + embedding) top-N | | `view` | Expand ONE memory's full content by id (title-first injection's detail entry) | | `list` | List memories as titles (category/tag/importance filters, `full` for content) | | `forget` | Soft-delete (marks `retired`, keeps history) | | `pin` | Toggle `forceInject` โ€” pinned memories always appear at session start | ## ๐Ÿ—‚๏ธ Storage Single YAML file (default `memory.yaml`). Each entry: ```yaml - id: MEM-20260814-001 title: "Summary title (auto-derived if absent)" # injected as title content: "..." category: preference | project | lesson | fact tags: [tag1, tag2] importance: high | normal | low created: 2026-08-14 updated: 2026-08-14 source: user | agent | conversation retired: false forceInject: false # full behavioural rules, always resident injectLevel: session | auto # resident vs on-demand vector: [...] # 1024-dim embedding, auto-computed on write ``` ## ๐Ÿ”ง Architecture ``` src/ โ”œโ”€โ”€ index.ts # plugin entry: tools + session-first injection + pre-step listener โ”œโ”€โ”€ storage.ts # Storage interface + YamlStorage (queue, mtime cache, quarantine) โ”œโ”€โ”€ search.ts # KeywordSearch / EmbeddingSearch / HybridSearch (RRF) / OllamaEmbedder โ”œโ”€โ”€ inject.ts # selectForInjection / renderSection (title-first) / deriveTitle / entryTitle โ”œโ”€โ”€ dynamic.ts # DynamicInjector (per-session dedup + retrieval gate + fixed-set exclusion) โ””โ”€โ”€ types.ts # data model (+ reserved fields: vector/scope/weight for future) ``` Architecture: [`docs/architecture.md`](docs/architecture.md) ยท Changelog: [`CHANGELOG.md`](CHANGELOG.md). ## ๐Ÿ—บ๏ธ Planned Ideas on the horizon (not yet implemented): | Feature | Description | |---|---| | **Feedback scoring** (`weight`) | Learn from implicit signals (usage, dismissals, agent feedback) and rank memories by usefulness instead of static importance | | **Multi-scope isolation** (`scope`) | Keep separate memory namespaces per project/workspace, so one agent's context never bleeds into another's | | **Auto-learning** | Distill session insights into new memories automatically (with human confirmation), instead of relying on explicit `remember` calls | | **More backends** | SQLite / JSON storage behind the existing `Storage` interface | | **Web UI** | Browse, edit and manage memories from the dsh WebUI (view only exists as an agent tool today) | | **Test suite** | Expand automated coverage for storage, search and injection logic | ## โš ๏ธ Notes - Embedding model change invalidates stored vectors (dimension mismatch is detected and logged) - The plugin is developed against dsh `v0.1.0-rc.5`; peer dependency ranges may need bumping ## ๐Ÿ”— References This plugin is part of the [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) (dsh) plugin ecosystem. - **Official repo**: [deepseek-ai/deepseek-harness](https://github.com/deepseek-ai/deepseek-harness) - **Plugin docs**: [docs/user/develop](https://github.com/deepseek-ai/deepseek-harness/tree/main/docs/user/develop) โ€” plugin lifecycle, config, and publish guide - **Ecosystem topic**: [`dsh-plugin`](https://github.com/topics/dsh-plugin) ## ๐Ÿ“„ License MIT