dsh-layered-memory 0.7.1 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.en.md +115 -68
- package/README.md +128 -100
- package/assets/img/EmbeddingSource.png +0 -0
- package/assets/img/MemoryTools.png +0 -0
- package/assets/img/ToolTrajectory.png +0 -0
- package/dist/client.js +11 -2
- package/dist/config.d.ts +26 -1
- package/dist/config.js +9 -3
- package/dist/hooks/recall.d.ts +11 -8
- package/dist/hooks/recall.js +70 -51
- package/dist/index.d.ts +16 -0
- package/dist/index.js +5 -1
- package/dist/llm.d.ts +13 -0
- package/dist/llm.js +17 -0
- package/dist/pipeline/l1.js +5 -4
- package/dist/pipeline/l2.js +7 -2
- package/dist/pipeline/l3.js +7 -2
- package/dist/pipeline/runner.d.ts +36 -5
- package/dist/pipeline/runner.js +148 -35
- package/dist/pipeline/trigger.d.ts +38 -0
- package/dist/pipeline/trigger.js +64 -0
- package/dist/store/bm25.js +2 -1
- package/dist/store/embedding.d.ts +12 -6
- package/dist/store/embedding.js +10 -7
- package/dist/store/l0.d.ts +2 -0
- package/dist/store/l0.js +4 -0
- package/dist/store/l1.d.ts +2 -0
- package/dist/store/l1.js +2 -2
- package/dist/store/pending.d.ts +27 -6
- package/dist/store/pending.js +49 -9
- package/dist/store/search-utils.js +3 -2
- package/dist/store/session-modes.d.ts +4 -0
- package/dist/store/session-modes.js +16 -0
- package/dist/store/sqlite.d.ts +12 -0
- package/dist/store/sqlite.js +103 -5
- package/dist/util/recall-budget.d.ts +32 -0
- package/dist/util/recall-budget.js +85 -0
- package/dist/util/text.d.ts +8 -3
- package/dist/util/text.js +41 -15
- package/dist/util/tokenizer.d.ts +14 -0
- package/dist/util/tokenizer.js +53 -0
- package/package.json +2 -1
package/README.en.md
CHANGED
|
@@ -1,56 +1,19 @@
|
|
|
1
|
-
|
|
1
|
+
<div align="center">
|
|
2
2
|
|
|
3
|
-
<
|
|
4
|
-
|
|
5
|
-
alt="DeepSeek Harness hero banner: conversations distilled into layered memories and recalled before every model step — chat bubbles dissolve into three progressively brighter light layers flowing into a frosted-glass capsule with a glowing orb and gradient track (tick labels: 日常·工作·智能·关闭), with light threads looping back to suggest recall">
|
|
6
|
-
</p>
|
|
3
|
+
<img src="./assets/img/Hero.png" width="100%"
|
|
4
|
+
alt="DeepSeek Harness hero banner: conversations distilled into layered memories and recalled before every model step — chat bubbles dissolve into three progressively brighter light layers flowing into a frosted-glass capsule with a glowing orb and gradient track (tick labels: 日常·工作·智能·关闭), with light threads looping back to suggest recall">
|
|
7
5
|
|
|
8
6
|
# dsh-layered-memory
|
|
9
7
|
|
|
10
|
-
A
|
|
11
|
-
plugin): conversations are processed in the background through L0 capture → L1 atomic
|
|
12
|
-
memories → L2 scene consolidation → L3 persona distillation, and relevant memories are
|
|
13
|
-
automatically injected into context before every model step — neither the user nor the
|
|
14
|
-
model needs to do anything.
|
|
8
|
+
**A layered distillation memory plugin for DeepSeek Harness: conversations are processed in the background through L0 capture → L1 atomic memories → L2 scene consolidation → L3 persona distillation, and relevant memories are automatically injected into context before every model step — neither the user nor the model needs to do anything.**
|
|
15
9
|
|
|
16
|
-
|
|
17
|
-
> prompts, and dual-write storage design) are modeled after **MemoryCore** from
|
|
18
|
-
> [TencentDB-Agent-Memory](https://github.com/TencentCloud/TencentDB-Agent-Memory):
|
|
19
|
-
> prompts are kept as-is; only the L2/L3 "LLM manipulates files" flow is adapted to
|
|
20
|
-
> "LLM outputs, engineering side executes".
|
|
10
|
+
[简体中文](README.md) · [Latest release](https://github.com/JunNanLYS/dsh-layered-memory/releases/latest) · [Report issues](https://github.com/JunNanLYS/dsh-layered-memory/issues)
|
|
21
11
|
|
|
22
|
-
|
|
12
|
+
[](https://github.com/JunNanLYS/dsh-layered-memory/tree/main)
|
|
13
|
+
[](https://github.com/deepseek-ai/deepseek-harness)
|
|
14
|
+
[](LICENSE)
|
|
23
15
|
|
|
24
|
-
|
|
25
|
-
<img src="./assets/readme/flow.svg" width="100%"
|
|
26
|
-
alt="Runtime data flow: session events from User and Assistant (left) flow into the plugin (L0 capture, L1–L3 distillation, retrieval, memory tools), which injects relevant memories into the DeepSeek Harness core (right) at agent/pre-step; distillation reuses the core's ctx.llm and data is dual-written to ~/.dsh/memory/">
|
|
27
|
-
</p>
|
|
28
|
-
|
|
29
|
-
The plugin attaches to DSH-native event seams (`session/event` for capture,
|
|
30
|
-
`agent/pre-step` for injection), reuses the host's `ctx.llm` for distillation, and stays
|
|
31
|
-
fully transparent to both user and model. It also registers three model-callable memory
|
|
32
|
-
tools: `memory_search` / `conversation_search` / `memory_read_scene`.
|
|
33
|
-
|
|
34
|
-
## Layered Memory (L0–L3)
|
|
35
|
-
|
|
36
|
-
<p align="center">
|
|
37
|
-
<img src="./assets/img/Layers.png" width="100%"
|
|
38
|
-
alt="Four memory layers refining from top-left to bottom-right: L0 raw conversation (chat bubbles) → L1 atomic memories (glowing fact particles) → L2 scene blocks (glass document slabs) → L3 core persona (radiant crystal core); stages connected by LLM extract/consolidate/distill light beams, shrinking width shows progressive refinement">
|
|
39
|
-
</p>
|
|
40
|
-
|
|
41
|
-
## Per-Session Memory Modes
|
|
42
|
-
|
|
43
|
-
<p align="center">
|
|
44
|
-
<img src="./assets/img/Modes.png" width="100%"
|
|
45
|
-
alt="Per-session memory modes: a glass capsule track with four stops (日常 · 工作 · 智能 · 关闭), the glowing orb resting on 智能 (default); a vignette above each — personal chat bubbles for 日常, code/document panes for 工作, two streams merging brightest for 智能, a dim dashed ghost bubble for 关闭">
|
|
46
|
-
</p>
|
|
47
|
-
|
|
48
|
-
- **Control**: the pill next to the mode selector in the input bar (`Memory · Auto`);
|
|
49
|
-
clicking opens a macOS-style sliding picker above — release to snap to the nearest
|
|
50
|
-
mode; adapts to light/dark themes;
|
|
51
|
-
- Each session's choice is persisted by sessionId to `session-modes.json`, surviving
|
|
52
|
-
restarts/session restore; stacks with the global switches (global is the master gate);
|
|
53
|
-
L2/L3 are fully family-isolated — content never leaks across families.
|
|
16
|
+
</div>
|
|
54
17
|
|
|
55
18
|
## Getting Started
|
|
56
19
|
|
|
@@ -58,7 +21,7 @@ Requires Node ≥ 22.16. Two invocation styles — the `npx` prefix can replace
|
|
|
58
21
|
any command below:
|
|
59
22
|
|
|
60
23
|
```bash
|
|
61
|
-
# Option 1: run the official CLI directly via npx (no pre-installed dsh; version can be pinned, e.g. dsh-layered-memory@0.
|
|
24
|
+
# Option 1: run the official CLI directly via npx (no pre-installed dsh; version can be pinned, e.g. dsh-layered-memory@0.7.1)
|
|
62
25
|
npx -y @deepseek-ai/dsh plugin --profile web add dsh-layered-memory
|
|
63
26
|
|
|
64
27
|
# Option 2: with the dsh CLI installed (dsh is a pnpm forwarder; npm i -g pnpm first if missing)
|
|
@@ -69,6 +32,24 @@ dsh plugin --profile web add https://github.com/JunNanLYS/dsh-layered-memory
|
|
|
69
32
|
dsh plugin --profile web add /path/to/dsh-layered-memory
|
|
70
33
|
```
|
|
71
34
|
|
|
35
|
+
### Install via an AI Agent (Recommended)
|
|
36
|
+
|
|
37
|
+
If your current agent can run terminal commands, send it this message as-is:
|
|
38
|
+
|
|
39
|
+
```text
|
|
40
|
+
Please install the dsh-layered-memory plugin for the web profile of DeepSeek Harness.
|
|
41
|
+
|
|
42
|
+
Run only the two commands below and do not modify any other profile:
|
|
43
|
+
dsh plugin --profile web add dsh-layered-memory
|
|
44
|
+
dsh --profile web --dump-config
|
|
45
|
+
|
|
46
|
+
Confirm that dsh-layered-memory appears in the output, then report the result to me.
|
|
47
|
+
Do not close or restart my running DSH yourself; after installation, remind me to manually restart the DSH Web Host.
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
The agent should report the installation result and explicitly tell you whether
|
|
51
|
+
`dsh-layered-memory` has appeared in the configuration.
|
|
52
|
+
|
|
72
53
|
This package declares a `dsh.bundle` composition layer (`cordis.patch.yml`); after
|
|
73
54
|
installation the **plugin entry is mounted automatically** — no need to hand-edit
|
|
74
55
|
`$DSH_HOME/profiles/web/cordis.patch.yml`. Then restart DeepSeek Harness and verify:
|
|
@@ -95,6 +76,63 @@ npm run smoke # smoke test (rebuild first: see command b
|
|
|
95
76
|
npx tsc src/smoke.ts --outDir dist-smoke --module nodenext --moduleResolution nodenext --target es2022 --strict --skipLibCheck --esModuleInterop
|
|
96
77
|
```
|
|
97
78
|
|
|
79
|
+
## Runtime Data Flow
|
|
80
|
+
|
|
81
|
+
<p align="center">
|
|
82
|
+
<img src="./assets/readme/flow.svg" width="100%"
|
|
83
|
+
alt="Runtime data flow: session events from User and Assistant (left) flow into the plugin (L0 capture, L1–L3 distillation, retrieval, memory tools), which injects relevant memories into the DeepSeek Harness core (right) at agent/pre-step; distillation reuses the core's ctx.llm and data is dual-written to ~/.dsh/memory/">
|
|
84
|
+
</p>
|
|
85
|
+
|
|
86
|
+
The plugin attaches to DSH-native event seams (`session/event` for capture,
|
|
87
|
+
`agent/pre-step` for injection) and reuses the host's `ctx.llm` for distillation. Recall
|
|
88
|
+
is presented as **message-side injection**: relevant memories enter the conversation as a
|
|
89
|
+
synthetic message placed right before the user's new message, rendered as a
|
|
90
|
+
**"Context injection · memory"** row in the chat flow (expand to see the hits) — so you
|
|
91
|
+
can see "memory at work" directly. Injected content is bounded by length and
|
|
92
|
+
time budgets — oversized lines are truncated (pointing the model at the memory tools for
|
|
93
|
+
the full text) and a timed-out recall silently skips that turn, never slowing the chat. It
|
|
94
|
+
also registers three model-callable memory tools: `memory_search` /
|
|
95
|
+
`conversation_search` / `memory_read_scene`.
|
|
96
|
+
|
|
97
|
+
In action: the "Context injection · memory" row surfaces relevant memories first, and
|
|
98
|
+
the model then calls `memory_read_scene` directly to read scene blocks before answering
|
|
99
|
+
from memory:
|
|
100
|
+
|
|
101
|
+
<p align="center">
|
|
102
|
+
<img src="./assets/img/MemoryTools.png" width="60%"
|
|
103
|
+
alt="Real conversation UI (light theme): a "Context injection · memory" row sits above the user's message asking about recent plans; the assistant lists 4 memory_read_scene tool calls (with scene-block .md filenames as arguments) before answering from memory">
|
|
104
|
+
</p>
|
|
105
|
+
|
|
106
|
+
In restricted sessions where only the code-execution entry point is available, the model
|
|
107
|
+
reaches the memory tools indirectly through `run_code` (nested as SUBTOOL calls in the
|
|
108
|
+
trajectory view):
|
|
109
|
+
|
|
110
|
+
<p align="center">
|
|
111
|
+
<img src="./assets/img/ToolTrajectory.png" width="80%"
|
|
112
|
+
alt="Tool-call trajectory view: a colored timeline on top and a step list on the left (SYSTEM/CONTEXT/USER/ASSISTANT/TOOL/SUBTOOL tags); a run_code tool step nests 5 memory_read_scene sub-tool calls (SUBTOOL tags), with a detail panel for the selected step on the right">
|
|
113
|
+
</p>
|
|
114
|
+
|
|
115
|
+
## Layered Memory (L0–L3)
|
|
116
|
+
|
|
117
|
+
<p align="center">
|
|
118
|
+
<img src="./assets/img/Layers.png" width="100%"
|
|
119
|
+
alt="Four memory layers refining from top-left to bottom-right: L0 raw conversation (chat bubbles) → L1 atomic memories (glowing fact particles) → L2 scene blocks (glass document slabs) → L3 core persona (radiant crystal core); stages connected by LLM extract/consolidate/distill light beams, shrinking width shows progressive refinement">
|
|
120
|
+
</p>
|
|
121
|
+
|
|
122
|
+
## Per-Session Memory Modes
|
|
123
|
+
|
|
124
|
+
<p align="center">
|
|
125
|
+
<img src="./assets/img/Modes.png" width="100%"
|
|
126
|
+
alt="Per-session memory modes: a glass capsule track with four stops (日常 · 工作 · 智能 · 关闭), the glowing orb resting on 智能 (default); a vignette above each — personal chat bubbles for 日常, code/document panes for 工作, two streams merging brightest for 智能, a dim dashed ghost bubble for 关闭">
|
|
127
|
+
</p>
|
|
128
|
+
|
|
129
|
+
- **Control**: the pill next to the mode selector in the input bar (`Memory · Auto`);
|
|
130
|
+
clicking opens a macOS-style sliding picker above — release to snap to the nearest
|
|
131
|
+
mode; adapts to light/dark themes;
|
|
132
|
+
- Each session's choice is persisted by sessionId to `session-modes.json`, surviving
|
|
133
|
+
restarts/session restore; stacks with the global switches (global is the master gate);
|
|
134
|
+
L2/L3 are fully family-isolated — content never leaks across families.
|
|
135
|
+
|
|
98
136
|
## UI Preview
|
|
99
137
|
|
|
100
138
|
<p align="center">
|
|
@@ -128,8 +166,9 @@ the bundle layer appends and causes `duplicate loader entry id` startup failure)
|
|
|
128
166
|
| `capture.stripCodeBlocks` | `true` | Strip code blocks from assistant messages |
|
|
129
167
|
| `capture.maxMessageChars` | `4000` | Max characters per message |
|
|
130
168
|
| `extract.enabled` | `true` | L1 extraction |
|
|
131
|
-
| `extract.minMessages` | `
|
|
132
|
-
| `extract.
|
|
169
|
+
| `extract.minMessages` | `6` | Steady-state trigger threshold: run L1 extraction once a session accumulates N new messages. The effective threshold ramps up 1→2→4→…→N (first turn yields memories immediately, then batches to save calls) |
|
|
170
|
+
| `extract.idleSeconds` | `300` | Idle flush: distill a session's pending slice after N seconds of silence (catches "user left before reaching the threshold"); `0` disables |
|
|
171
|
+
| `extract.backgroundMessages` | `10` | Background messages attached to extraction (fetched per session from L0 — no cross-session contamination) |
|
|
133
172
|
| `extract.candidatePool` | `5` | Dedup candidate pool size |
|
|
134
173
|
| `l2.enabled` | `true` | L2 scene consolidation |
|
|
135
174
|
| `l2.minNewMemories` | `5` | New-memory threshold since last L2 consolidation |
|
|
@@ -138,9 +177,12 @@ the bundle layer appends and causes `duplicate loader entry id` startup failure)
|
|
|
138
177
|
| `l3.enabled` | `true` | L3 persona distillation |
|
|
139
178
|
| `l3.interval` | `20` | L3 distillation interval (new-memory count) |
|
|
140
179
|
| `recall.enabled` | `true` | Auto recall |
|
|
141
|
-
| `recall.maxResults` | `5` | L1 records injected
|
|
142
|
-
| `recall.
|
|
143
|
-
| `recall.
|
|
180
|
+
| `recall.maxResults` | `5` | Max L1 records injected before each new user message |
|
|
181
|
+
| `recall.maxCharsPerMemory` | `500` | Per-memory character cap for injected recall (overlong lines truncated with a hint to use the memory tools for the full text); `0` disables |
|
|
182
|
+
| `recall.maxTotalRecallChars` | `2000` | Total character cap per injected recall batch (lowest-ranked tail dropped first); `0` disables |
|
|
183
|
+
| `recall.timeoutMs` | `5000` | Overall recall budget (ms): a timed-out recall skips that turn without blocking the chat; `0` disables |
|
|
184
|
+
| `recall.includePersona` | `true` | Inject persona context into the system prompt (`<user-persona>`, stable zone) |
|
|
185
|
+
| `recall.includeSceneNav` | `true` | Inject scene navigation into the system prompt (`<scene-navigation>`, stable zone) |
|
|
144
186
|
| `recall.strategy` | `hybrid` | Retrieval strategy: `keyword` / `embedding` / `hybrid` |
|
|
145
187
|
| `recall.scoreThreshold` | `0.3` | Recall score threshold (below is not injected; applies to keyword/embedding only, not pre-fusion hybrid; tool path unfiltered) |
|
|
146
188
|
| `embedding.enabled` | `false` | Vector retrieval switch; off = pure FTS |
|
|
@@ -153,7 +195,7 @@ the bundle layer appends and causes `duplicate loader entry id` startup failure)
|
|
|
153
195
|
| `embedding.allowLocalModels` | `true` | Allow the local embedding tier (deployment ceiling; when off, no model downloads and no local tier in settings) |
|
|
154
196
|
| `embedding.mirror` | `https://hf-mirror.com` | Download mirror root for local models (can be changed back to `https://huggingface.co`) |
|
|
155
197
|
| `llm.provider/model` | empty | Distillation model override (defaults to current selection) |
|
|
156
|
-
| `llm.maxTokens` | `
|
|
198
|
+
| `llm.maxTokens` | `65536` | Fallback output cap for non-layered calls. Each distillation stage has its own budget (extraction 16k / dedup 8k / L2 32k / L3 16k; auto ×4 when reasoning effort is high/max, so thinking can't starve the text budget) |
|
|
157
199
|
| `llm.reasoningEffort` | `off` | Distillation reasoning-effort tier (deployment default): `off` / `high` / `max`; empty string = don't send (follow model default). Distillation is structured extraction, so thinking is off by default — a reasoning model (e.g. v4-flash) at its default `high` tier can consume the entire output budget on thinking, leaving 0 chars of text; set to empty string for models that don't recognize the effort parameter. Switchable at runtime in Settings → Memory → Overview ("follow config" falls back to this value) |
|
|
158
200
|
| `llm.temperature` | `0.3` | Distillation temperature |
|
|
159
201
|
| `llm.maxInputChars` | `700000` | Input character budget per distillation call (over-budget L1 inputs are chunked automatically) |
|
|
@@ -176,20 +218,17 @@ local), switchable at runtime in the settings page — see the next section.
|
|
|
176
218
|
Pick the embedding source in Settings → Memory → Overview → Semantic Retrieval;
|
|
177
219
|
it takes effect immediately, no config edit or restart:
|
|
178
220
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
| **Local** | Pick from a built-in model catalog, ONNX-quantized **CPU inference** — no API key, data never leaves the machine |
|
|
184
|
-
|
|
185
|
-
The local catalog is a built-in allowlist (each model pinned to a revision with
|
|
186
|
-
per-file sha256; arbitrary repos cannot be downloaded):
|
|
221
|
+
<p align="center">
|
|
222
|
+
<img src="./assets/img/EmbeddingSource.png" width="70%"
|
|
223
|
+
alt="Semantic retrieval (embedding source) panel in the settings page (light theme): a three-state selector (Off/Local/Remote, Local selected) showing the current source and the first-run runtime install hint; below it the local model catalog lists BGE small Chinese (in use/ready), EmbeddingGemma 300M (download 316MB) and BGE-M3 (download 560MB) with dims/context/size/notes and download buttons">
|
|
224
|
+
</p>
|
|
187
225
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
226
|
+
Three sources: **Off** (default; no vector embedding at all, pure BM25 keyword
|
|
227
|
+
retrieval), **Remote** (bring any OpenAI-compatible `/embeddings` service, selectable
|
|
228
|
+
only when the `embedding.*` quartet is configured), **Local** (pick from a built-in
|
|
229
|
+
model catalog, ONNX-quantized **CPU inference** — no API key, data never leaves the
|
|
230
|
+
machine). The local catalog is a built-in allowlist (each model pinned to a revision
|
|
231
|
+
with per-file sha256; arbitrary repos cannot be downloaded).
|
|
193
232
|
|
|
194
233
|
- **Download**: one click on the model card (default mirror `hf-mirror.com`, resumable
|
|
195
234
|
downloads + sha256 integrity checks); stored under `models/<id>/` in the data
|
|
@@ -221,8 +260,8 @@ of the raw model output; all failure warns carry the first stack frame.
|
|
|
221
260
|
|
|
222
261
|
- The full pipeline is embedded (no external Gateway); distillation reuses DSH's own LLM;
|
|
223
262
|
- L2/L3 changed from "LLM manipulates file tools" to "LLM outputs operation JSON / full documents, engineering side executes";
|
|
224
|
-
- Recall injection happens at `agent/pre-step`
|
|
225
|
-
- Storage/retrieval is a single-machine slimmed version of the official sqlite backend (drops multi-tenant isolation columns, TCVDB cloud backend, audit tables; tokenization uses
|
|
263
|
+
- Recall injection happens at `agent/pre-step` (message-side synthetic message, the official pre-step replacement semantics) plus agent-scoped `systemPrompt.context` (persona/navigation stable zone — DSH-native events/services);
|
|
264
|
+
- Storage/retrieval is a single-machine slimmed version of the official sqlite backend (drops multi-tenant isolation columns, TCVDB cloud backend, audit tables; tokenization uses jieba like the official one — @node-rs/jieba prebuilt binaries union CJK character bigrams: word tokens give BM25 exact-word hits while bigrams keep sub-word recall; on load failure it falls back to pure bigrams, and FTS indexes are rebuilt automatically via a tokenizer version stamp).
|
|
226
265
|
|
|
227
266
|
## Credits
|
|
228
267
|
|
|
@@ -231,6 +270,14 @@ dual-write storage architecture) are modeled after **MemoryCore** from
|
|
|
231
270
|
[TencentCloud/TencentDB-Agent-Memory](https://github.com/TencentCloud/TencentDB-Agent-Memory).
|
|
232
271
|
Thanks to the original project for open-sourcing its design and implementation.
|
|
233
272
|
|
|
273
|
+
## Roadmap
|
|
274
|
+
|
|
275
|
+
Features under planning — feedback and priorities welcome in the
|
|
276
|
+
[issue tracker](https://github.com/JunNanLYS/dsh-layered-memory/issues):
|
|
277
|
+
|
|
278
|
+
- [ ] **Git branch awareness**: associate memories with the current git branch; recall can filter/boost by branch (orthogonal to the existing memory modes)
|
|
279
|
+
- [ ] **Claude Code / Codex memory import**: one-click migration of existing memory assets (`CLAUDE.md`, Claude Code memory files, Codex `AGENTS.md`, etc.), fed into the layered distillation pipeline
|
|
280
|
+
|
|
234
281
|
## License
|
|
235
282
|
|
|
236
283
|
[MIT](LICENSE)
|
package/README.md
CHANGED
|
@@ -1,57 +1,26 @@
|
|
|
1
|
-
|
|
1
|
+
<div align="center">
|
|
2
2
|
|
|
3
|
-
<
|
|
4
|
-
|
|
5
|
-
alt="DeepSeek Harness hero 横幅:对话自动分层蒸馏成记忆,模型每步前自动召回注入——右侧对话气泡逐层溶解为三层渐亮光带,流入带发光圆球与渐变轨道的玻璃胶囊(下有 日常·工作·智能·关闭 四档刻度),光丝回流示意召回注入">
|
|
6
|
-
</p>
|
|
3
|
+
<img src="./assets/img/Hero.png" width="100%"
|
|
4
|
+
alt="DeepSeek Harness hero 横幅:对话自动分层蒸馏成记忆,模型每步前自动召回注入——右侧对话气泡逐层溶解为三层渐亮光带,流入带发光圆球与渐变轨道的玻璃胶囊(下有 日常·工作·智能·关闭 四档刻度),光丝回流示意召回注入">
|
|
7
5
|
|
|
8
6
|
# dsh-layered-memory
|
|
9
7
|
|
|
10
|
-
DeepSeek Harness
|
|
11
|
-
L0 捕获 → L1 原子记忆 → L2 场景整合 → L3 画像蒸馏,模型每一步前自动把相关记忆
|
|
12
|
-
注入上下文——用户与模型都不需要做任何操作。
|
|
13
|
-
|
|
14
|
-
> 本插件的记忆核心能力(L0–L3 分层蒸馏管线、Prompt 与双写存储设计)参考自
|
|
15
|
-
> [TencentDB-Agent-Memory](https://github.com/TencentCloud/TencentDB-Agent-Memory)
|
|
16
|
-
> 中的 **MemoryCore**:Prompt 原样保留,仅把"LLM 操作文件"的 L2/L3 流程适配为
|
|
17
|
-
> "LLM 输出、工程侧执行"。
|
|
18
|
-
|
|
19
|
-
## 运行时数据流
|
|
20
|
-
|
|
21
|
-
<p align="center">
|
|
22
|
-
<img src="./assets/readme/flow.svg" width="100%"
|
|
23
|
-
alt="dsh-layered-memory 运行时数据流:左侧 User 与 Assistant 的会话事件流入插件(L0 捕获、L1–L3 蒸馏、检索召回、记忆工具),插件经 agent/pre-step 把相关记忆注入右侧 DSH 核心;蒸馏复用核心的 ctx.llm,数据双写 ~/.dsh/memory/">
|
|
24
|
-
</p>
|
|
8
|
+
**DeepSeek Harness 的分层蒸馏记忆插件:对话在后台自动完成 L0 捕获 → L1 原子记忆 → L2 场景整合 → L3 画像蒸馏,模型每一步前自动把相关记忆注入上下文。**
|
|
25
9
|
|
|
26
|
-
|
|
27
|
-
蒸馏调用复用宿主 `ctx.llm`,全程对用户与模型透明。另注册三个模型可主动调用的
|
|
28
|
-
记忆工具:`memory_search` / `conversation_search` / `memory_read_scene`。
|
|
10
|
+
[English](README.en.md) · [最新发行版](https://github.com/JunNanLYS/dsh-layered-memory/releases/latest) · [反馈问题](https://github.com/JunNanLYS/dsh-layered-memory/issues)
|
|
29
11
|
|
|
30
|
-
|
|
12
|
+
[](https://github.com/JunNanLYS/dsh-layered-memory/tree/main)
|
|
13
|
+
[](https://github.com/deepseek-ai/deepseek-harness)
|
|
14
|
+
[](LICENSE)
|
|
31
15
|
|
|
32
|
-
|
|
33
|
-
<img src="./assets/img/Layers.png" width="100%"
|
|
34
|
-
alt="分层记忆四层(自左上向右下逐层精炼):L0 原始对话(对话气泡)→ L1 原子记忆(发光事实粒子)→ L2 场景块(玻璃文档板)→ L3 核心画像(发光晶核);层间由 LLM 提取/整合/蒸馏光束相连,宽度递减表示数据逐层精炼">
|
|
35
|
-
</p>
|
|
36
|
-
|
|
37
|
-
## 会话级记忆档位
|
|
38
|
-
|
|
39
|
-
<p align="center">
|
|
40
|
-
<img src="./assets/img/Modes.png" width="100%"
|
|
41
|
-
alt="会话级记忆档位:一条玻璃胶囊滑轨四个停点(日常·工作·智能·关闭),发光圆球停在智能(默认)档;各档上方微场景——日常为个人聊天气泡、工作为代码文档窗格、智能为双流合流最亮、关闭为暗淡虚线幽灵泡">
|
|
42
|
-
</p>
|
|
43
|
-
|
|
44
|
-
- **控件**:输入栏内、模式选择器右侧的 pill(`记忆·自动`),点击在上方浮出 macOS
|
|
45
|
-
风格滑动选择器——拖拽松手吸附最近档位;深浅主题自适应;
|
|
46
|
-
- 每会话的选择按 sessionId 持久化到 `session-modes.json`,重启/恢复会话不丢;
|
|
47
|
-
与全局开关叠加(全局是总闸);L2/L3 完全分族,跨族内容不渗透。
|
|
16
|
+
</div>
|
|
48
17
|
|
|
49
18
|
## 快速开始
|
|
50
19
|
|
|
51
20
|
需要 Node ≥ 22.16。两种调用方式任选(`npx` 前缀可替换下面任何 `dsh` 命令):
|
|
52
21
|
|
|
53
22
|
```bash
|
|
54
|
-
# 方式一:npx 直接跑官方 CLI(无需预装 dsh;可 pin 版本,如 dsh-layered-memory@0.
|
|
23
|
+
# 方式一:npx 直接跑官方 CLI(无需预装 dsh;可 pin 版本,如 dsh-layered-memory@0.7.1)
|
|
55
24
|
npx -y @deepseek-ai/dsh plugin --profile web add dsh-layered-memory
|
|
56
25
|
|
|
57
26
|
# 方式二:已装 dsh CLI(dsh 是 pnpm 转发器,未装 pnpm 时先 npm i -g pnpm)
|
|
@@ -62,14 +31,28 @@ dsh plugin --profile web add https://github.com/JunNanLYS/dsh-layered-memory
|
|
|
62
31
|
dsh plugin --profile web add /path/to/dsh-layered-memory
|
|
63
32
|
```
|
|
64
33
|
|
|
34
|
+
### 让 Agent 安装(推荐)
|
|
35
|
+
|
|
36
|
+
如果当前 Agent 可以执行终端命令,把下面这段话完整发送给它:
|
|
37
|
+
|
|
38
|
+
```text
|
|
39
|
+
请为 DeepSeek Harness 的 web Profile 安装 dsh-layered-memory 插件。
|
|
40
|
+
|
|
41
|
+
只执行下面两条命令,不要修改其他 Profile:
|
|
42
|
+
dsh plugin --profile web add dsh-layered-memory
|
|
43
|
+
dsh --profile web --dump-config
|
|
44
|
+
|
|
45
|
+
确认输出中出现 dsh-layered-memory 后告诉我安装结果。
|
|
46
|
+
不要替我关闭或重启正在运行的 DSH;安装完成后提醒我手动重启 DSH Web Host。
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Agent 应当返回安装结果,并明确告诉你配置中是否已经出现 `dsh-layered-memory`。
|
|
50
|
+
|
|
65
51
|
本包声明了 `dsh.bundle` 组合包层(`cordis.patch.yml`),安装后会**自动挂载插件行**——
|
|
66
52
|
不需要再手改 `$DSH_HOME/profiles/web/cordis.patch.yml`。然后重启 DeepSeek Harness,
|
|
67
53
|
验证:`~/.dsh/memory/` 下出现 `conversations/ records/ scenes/` 目录和 `memory.db`
|
|
68
54
|
即插件 apply 成功;设置页出现"记忆"页面、输入栏出现档位 pill 即 client 半边就绪。
|
|
69
55
|
|
|
70
|
-
> ⚠️ **安全提示**:安装插件 = 以你的权限运行第三方代码。本插件会读取会话内容、
|
|
71
|
-
> 在数据目录写文件、调用你配置的 LLM/embedding 服务;介意请先审查源码(`src/`)。
|
|
72
|
-
|
|
73
56
|
**卸载**:`dsh plugin --profile web remove dsh-layered-memory` + 重启。数据保留在
|
|
74
57
|
`~/.dsh/memory/`,不需要时手动删除整个目录即可。
|
|
75
58
|
|
|
@@ -84,6 +67,52 @@ npm run smoke # 冒烟测试(先重编:见下方命
|
|
|
84
67
|
npx tsc src/smoke.ts --outDir dist-smoke --module nodenext --moduleResolution nodenext --target es2022 --strict --skipLibCheck --esModuleInterop
|
|
85
68
|
```
|
|
86
69
|
|
|
70
|
+
## 运行时数据流
|
|
71
|
+
|
|
72
|
+
<p align="center">
|
|
73
|
+
<img src="./assets/readme/flow.svg" width="100%"
|
|
74
|
+
alt="dsh-layered-memory 运行时数据流:左侧 User 与 Assistant 的会话事件流入插件(L0 捕获、L1–L3 蒸馏、检索召回、记忆工具),插件经 agent/pre-step 把相关记忆注入右侧 DSH 核心;蒸馏复用核心的 ctx.llm,数据双写 ~/.dsh/memory/">
|
|
75
|
+
</p>
|
|
76
|
+
|
|
77
|
+
插件挂在 dsh 原生事件上(`session/event` 捕获、`agent/pre-step` 注入),蒸馏调用复用宿主 `ctx.llm`。召回以**消息侧注入**呈现:相关记忆作为一条合成消息排在用户新消息之前,会话流里显示为**"上下文注入 · memory"**行(点开看命中内容)——用户能直接看到"记忆生效了";注入内容有长度预算与时间预算,超限截断/超时跳过,绝不拖慢对话。
|
|
78
|
+
|
|
79
|
+
**记忆工具(3):**
|
|
80
|
+
- memory_search
|
|
81
|
+
- conversation_search
|
|
82
|
+
- memory_read_scene
|
|
83
|
+
|
|
84
|
+
真机实录:召回注入与工具调用在对话里的样子——"上下文注入 · memory"行先带出相关记忆,模型再按需调 `memory_read_scene` 读取场景块,凭记忆直接作答:
|
|
85
|
+
|
|
86
|
+
<p align="center">
|
|
87
|
+
<img src="./assets/img/MemoryTools.png" width="60%"
|
|
88
|
+
alt="对话界面实录(浅色主题):用户消息"我们最近要干什么?"上方可见"上下文注入 · memory"行;助手回答前列出 4 次 memory_read_scene 工具调用(参数为 scenes 场景块的 .md 文件名),随后凭记忆梳理近期目标与推进路线">
|
|
89
|
+
</p>
|
|
90
|
+
|
|
91
|
+
在只开放代码执行入口的受限会话中,模型经由 `run_code` 间接调用记忆工具(轨迹视图中的 SUBTOOL 嵌套):
|
|
92
|
+
|
|
93
|
+
<p align="center">
|
|
94
|
+
<img src="./assets/img/ToolTrajectory.png" width="80%"
|
|
95
|
+
alt="工具调用轨迹视图:顶部彩色时间线与左侧步骤列表(SYSTEM/CONTEXT/USER/ASSISTANT/TOOL/SUBTOOL 彩色标签),run_code 工具步骤内嵌套 5 次 memory_read_scene 子工具调用(SUBTOOL 标记),右侧为所选步骤的详情面板">
|
|
96
|
+
</p>
|
|
97
|
+
|
|
98
|
+
## 分层记忆(L0–L3)
|
|
99
|
+
|
|
100
|
+
<p align="center">
|
|
101
|
+
<img src="./assets/img/Layers.png" width="100%"
|
|
102
|
+
alt="分层记忆四层(自左上向右下逐层精炼):L0 原始对话(对话气泡)→ L1 原子记忆(发光事实粒子)→ L2 场景块(玻璃文档板)→ L3 核心画像(发光晶核);层间由 LLM 提取/整合/蒸馏光束相连,宽度递减表示数据逐层精炼">
|
|
103
|
+
</p>
|
|
104
|
+
|
|
105
|
+
## 会话级记忆档位
|
|
106
|
+
|
|
107
|
+
<p align="center">
|
|
108
|
+
<img src="./assets/img/Modes.png" width="100%"
|
|
109
|
+
alt="会话级记忆档位:一条玻璃胶囊滑轨四个停点(日常·工作·智能·关闭),发光圆球停在智能(默认)档;各档上方微场景——日常为个人聊天气泡、工作为代码文档窗格、智能为双流合流最亮、关闭为暗淡虚线幽灵泡">
|
|
110
|
+
</p>
|
|
111
|
+
|
|
112
|
+
- **控件**:输入栏内、模式选择器右侧的 pill(`记忆·自动`),点击在上方浮出档位滑块深浅主题自适应;
|
|
113
|
+
- 每会话的选择按 sessionId 持久化到 `session-modes.json`,重启/恢复会话不丢;
|
|
114
|
+
与全局开关叠加(全局是总闸);L2/L3 完全分类,分类内容不渗透。
|
|
115
|
+
|
|
87
116
|
## 界面预览
|
|
88
117
|
|
|
89
118
|
<p align="center">
|
|
@@ -93,6 +122,40 @@ npx tsc src/smoke.ts --outDir dist-smoke --module nodenext --moduleResolution no
|
|
|
93
122
|
alt="浅色主题下的同一设置页记忆浏览器概览:同款布局与信息,浅色卡片底与同套强调色,主题切换无需重载">
|
|
94
123
|
</p>
|
|
95
124
|
|
|
125
|
+
## 存储布局
|
|
126
|
+
|
|
127
|
+
<p align="center">
|
|
128
|
+
<img src="./assets/readme/storage.svg" width="100%"
|
|
129
|
+
alt="存储布局:双写架构(JSONL 事实源只增不改 + memory.db 主检索库);文件形态含 conversations/records/scenes/persona/state/pending/session-modes/embedding-source/模型目录/推理运行时/日志与重建归档;检索三策略 keyword/embedding/hybrid(RRF k=60);降级链保证永不阻塞宿主">
|
|
130
|
+
</p>
|
|
131
|
+
|
|
132
|
+
向量能力默认关闭(纯 FTS)。DSH 的 `ctx.llm` 无 embeddings 端点,语义检索由
|
|
133
|
+
**三态嵌入源**提供(关闭 / 远程 / 本地),设置页可运行时切换——见下节。
|
|
134
|
+
|
|
135
|
+
## 语义检索(嵌入源)
|
|
136
|
+
|
|
137
|
+
设置页(记忆 → 概览 → 语义检索)选择嵌入源,即时生效、无需改配置重启:
|
|
138
|
+
|
|
139
|
+
<p align="center">
|
|
140
|
+
<img src="./assets/img/EmbeddingSource.png" width="70%"
|
|
141
|
+
alt="设置页语义检索(嵌入源)面板(浅色主题):三态选择器(关闭/本地/远程,本地选中)显示当前嵌入源与首次启用自动安装运行时提示;下方本地模型目录列出 BGE small 中文(使用中/已就绪)、EmbeddingGemma 300M(下载 316MB)、BGE-M3(下载 560MB)三款模型的维度/上下文/体积/特点与下载入口">
|
|
142
|
+
</p>
|
|
143
|
+
|
|
144
|
+
三种嵌入源:**关闭**(默认,纯 BM25 关键词检索)、**远程**(自备任意 OpenAI 兼容
|
|
145
|
+
`/embeddings` 服务,`embedding.*` 四件套配齐才可选)、**本地**(内置模型目录选一款,
|
|
146
|
+
ONNX 量化 **CPU 推理**——无需 API Key,数据不出本机)。本地模型目录是插件内置
|
|
147
|
+
白名单(每款锁定 revision + 每文件 sha256,不可下载任意仓库)。
|
|
148
|
+
|
|
149
|
+
- **下载**:模型卡一键下载(默认镜像 `hf-mirror.com`,断点续传 + sha256 完整性
|
|
150
|
+
校验),落盘数据目录 `models/<id>/`,不用了随时在设置页删除;
|
|
151
|
+
- **按需运行时**:首次切换本地档才安装推理运行时(transformers.js,约 100~200MB,
|
|
152
|
+
装进数据目录 `runtime/`——不进插件依赖树,不碰插件安装目录);
|
|
153
|
+
- **活切换**:一键换源——自动后台全量重嵌(进度可见、可取消,期间检索自动降级
|
|
154
|
+
关键词,不影响对话;维度变化时向量表按新维度重建);切换失败保持旧源,重启仍按原源运行;
|
|
155
|
+
- **生效规则 = 部署上限 AND 运行时选择**:`embedding.allowLocalModels=false` 可整体
|
|
156
|
+
禁用本地档、未配 `embedding.*` 四件套则远程档不可选(企业部署可收口),状态持久
|
|
157
|
+
化在 `embedding-source.json`。
|
|
158
|
+
|
|
96
159
|
## 配置
|
|
97
160
|
|
|
98
161
|
覆盖配置写在 profile 自己的 `cordis.patch.yml`,用**顶层裸 patch 条目**(直接 `id:`,
|
|
@@ -117,8 +180,9 @@ npx tsc src/smoke.ts --outDir dist-smoke --module nodenext --moduleResolution no
|
|
|
117
180
|
| `capture.stripCodeBlocks` | `true` | 助手消息剥离代码块 |
|
|
118
181
|
| `capture.maxMessageChars` | `4000` | 单条消息最大字符数 |
|
|
119
182
|
| `extract.enabled` | `true` | L1 抽取 |
|
|
120
|
-
| `extract.minMessages` | `
|
|
121
|
-
| `extract.
|
|
183
|
+
| `extract.minMessages` | `6` | 稳态触发阈值:单会话攒够 N 条新消息跑一次 L1 抽取。起步阶段生效阈值从 1 翻倍爬坡到此值(首轮即出记忆,随后自动攒批省调用) |
|
|
184
|
+
| `extract.idleSeconds` | `300` | 闲置兜底:会话静默 N 秒后把未蒸馏切片落袋(接住"没攒够阈值用户就离开");`0` 关闭 |
|
|
185
|
+
| `extract.backgroundMessages` | `10` | 抽取时附带的背景消息条数(按会话从 L0 现查,会话间互不污染) |
|
|
122
186
|
| `extract.candidatePool` | `5` | 去重候选池大小 |
|
|
123
187
|
| `l2.enabled` | `true` | L2 场景整合 |
|
|
124
188
|
| `l2.minNewMemories` | `5` | 距上次 L2 整合的新记忆阈值 |
|
|
@@ -127,9 +191,12 @@ npx tsc src/smoke.ts --outDir dist-smoke --module nodenext --moduleResolution no
|
|
|
127
191
|
| `l3.enabled` | `true` | L3 画像蒸馏 |
|
|
128
192
|
| `l3.interval` | `20` | L3 蒸馏间隔(新记忆条数) |
|
|
129
193
|
| `recall.enabled` | `true` | 自动召回 |
|
|
130
|
-
| `recall.maxResults` | `5` |
|
|
131
|
-
| `recall.
|
|
132
|
-
| `recall.
|
|
194
|
+
| `recall.maxResults` | `5` | 每条新用户消息前注入的 L1 条数上限 |
|
|
195
|
+
| `recall.maxCharsPerMemory` | `500` | 单条注入记忆的字符上限(超限截断并提示用记忆工具查全文);`0` 不限 |
|
|
196
|
+
| `recall.maxTotalRecallChars` | `2000` | 整轮注入总字符上限(超限按相关性丢尾部);`0` 不限 |
|
|
197
|
+
| `recall.timeoutMs` | `5000` | 召回总预算(ms):超时跳过本轮注入、不阻塞对话;`0` 不限时 |
|
|
198
|
+
| `recall.includePersona` | `true` | 系统提示注入画像上下文(`<user-persona>`,稳定区) |
|
|
199
|
+
| `recall.includeSceneNav` | `true` | 系统提示注入场景导航(`<scene-navigation>`,稳定区) |
|
|
133
200
|
| `recall.strategy` | `hybrid` | 检索策略:`keyword` / `embedding` / `hybrid` |
|
|
134
201
|
| `recall.scoreThreshold` | `0.3` | 召回分数阈值(低于不注入;仅 keyword/embedding 策略生效,hybrid 融合前不过滤;工具路径不过滤) |
|
|
135
202
|
| `embedding.enabled` | `false` | 向量检索开关;关闭即纯 FTS 运行 |
|
|
@@ -142,68 +209,29 @@ npx tsc src/smoke.ts --outDir dist-smoke --module nodenext --moduleResolution no
|
|
|
142
209
|
| `embedding.allowLocalModels` | `true` | 允许本地嵌入档(部署上限:关闭后设置页不能下载模型、不能切本地档) |
|
|
143
210
|
| `embedding.mirror` | `https://hf-mirror.com` | 本地模型下载镜像根地址(可改回官方 `https://huggingface.co`) |
|
|
144
211
|
| `llm.provider/model` | 空 | 蒸馏模型覆盖(默认用当前默认选择) |
|
|
145
|
-
| `llm.maxTokens` | `
|
|
212
|
+
| `llm.maxTokens` | `65536` | 未分层调用的兜底输出总闸。各蒸馏层有独立预算(抽取 16k / 去重 8k / L2 32k / L3 16k;思考档 high/max 时自动 ×4,防 reasoning 吃光预算) |
|
|
146
213
|
| `llm.reasoningEffort` | `off` | 蒸馏思考档位(部署默认):`off` / `high` / `max`,空串不传(跟随模型默认)。蒸馏是结构化抽取任务,默认关思考——推理模型(如 v4-flash)默认 high 档的思考可把任意输出预算全部吃光导致正文 0 字符;非推理模型不认识 effort 时需设为空串。运行时可在设置页 → 记忆 → 概览临时切换(选"跟随配置"即回退本值) |
|
|
147
214
|
| `llm.temperature` | `0.3` | 蒸馏温度 |
|
|
148
215
|
| `llm.maxInputChars` | `700000` | 单次蒸馏输入字符预算(超限的 L1 输入自动分块抽取) |
|
|
149
216
|
| `llm.timeoutMs` | `120000` | 单次蒸馏调用超时(ms) |
|
|
150
217
|
| `tools` | `true` | 是否注册模型可调用的记忆工具 |
|
|
151
218
|
|
|
152
|
-
## 存储布局
|
|
153
|
-
|
|
154
|
-
<p align="center">
|
|
155
|
-
<img src="./assets/readme/storage.svg" width="100%"
|
|
156
|
-
alt="存储布局:双写架构(JSONL 事实源只增不改 + memory.db 主检索库);文件形态含 conversations/records/scenes/persona/state/pending/session-modes/embedding-source/模型目录/推理运行时/日志与重建归档;检索三策略 keyword/embedding/hybrid(RRF k=60);降级链保证永不阻塞宿主">
|
|
157
|
-
</p>
|
|
158
|
-
|
|
159
|
-
向量能力默认关闭(纯 FTS)。DSH 的 `ctx.llm` 无 embeddings 端点,语义检索由
|
|
160
|
-
**三态嵌入源**提供(关闭 / 远程 / 本地),设置页可运行时切换——见下节。
|
|
161
|
-
|
|
162
|
-
## 语义检索(嵌入源)
|
|
163
|
-
|
|
164
|
-
设置页(记忆 → 概览 → 语义检索)选择嵌入源,即时生效、无需改配置重启:
|
|
165
|
-
|
|
166
|
-
| 嵌入源 | 说明 |
|
|
167
|
-
| --- | --- |
|
|
168
|
-
| **关闭**(默认) | 不做任何向量嵌入,纯 BM25 关键词检索 |
|
|
169
|
-
| **远程** | 自备任意 OpenAI 兼容 `/embeddings` 服务(`embedding.*` 四件套配齐才可选) |
|
|
170
|
-
| **本地** | 内置模型目录选一款,ONNX 量化 **CPU 推理**——无需 API Key,数据不出本机 |
|
|
171
|
-
|
|
172
|
-
本地模型目录是插件内置白名单(每款锁定 revision + 每文件 sha256,不可下载任意仓库):
|
|
173
|
-
|
|
174
|
-
| 模型 | 维度 | 上下文 | 体积 | 特点 |
|
|
175
|
-
| --- | --- | --- | --- | --- |
|
|
176
|
-
| BGE small 中文 | 512 | 512 | ~25MB | CPU 嵌入最快,适合先体验语义检索 |
|
|
177
|
-
| EmbeddingGemma 300M | 768 | 2048 | ~330MB | 100+ 语言含中文,质量与开销均衡(上游 MemoryCore 同款) |
|
|
178
|
-
| BGE-M3 | 1024 | 8192 | ~590MB | 中文质量最强,单条嵌入可达秒级 |
|
|
179
|
-
|
|
180
|
-
- **下载**:模型卡一键下载(默认镜像 `hf-mirror.com`,断点续传 + sha256 完整性
|
|
181
|
-
校验),落盘数据目录 `models/<id>/`,不用了随时在设置页删除;
|
|
182
|
-
- **按需运行时**:首次切换本地档才安装推理运行时(transformers.js,约 100~200MB,
|
|
183
|
-
装进数据目录 `runtime/`——不进插件依赖树,不碰插件安装目录);
|
|
184
|
-
- **活切换**:一键换源——自动后台全量重嵌(进度可见、可取消,期间检索自动降级
|
|
185
|
-
关键词,不影响对话;维度变化时向量表按新维度重建);切换失败保持旧源,重启仍
|
|
186
|
-
按原源运行;
|
|
187
|
-
- **生效规则 = 部署上限 AND 运行时选择**:`embedding.allowLocalModels=false` 可整体
|
|
188
|
-
禁用本地档、未配 `embedding.*` 四件套则远程档不可选(企业部署可收口),状态持久
|
|
189
|
-
化在 `embedding-source.json`。
|
|
190
|
-
|
|
191
|
-
## 日志与排查
|
|
192
|
-
|
|
193
|
-
dsh 宿主把插件日志打到控制台,插件将 info 及以上镜像到数据目录 `memory.log`。一轮
|
|
194
|
-
对话的典型日志路径:`L0 捕获` → `L0 落盘` → `蒸馏管线开始` → `LLM 调用(输入/输出
|
|
195
|
-
字符数、耗时)` → `L1 抽取完成` → `蒸馏管线结束`;下一轮有 `召回命中 N 条 L1`。
|
|
196
|
-
LLM 空输出带完整诊断(finish 原因 / token 计数 / reasoning 摘录),JSON 解析失败
|
|
197
|
-
附模型原始输出前 400 字符,失败 warn 均带堆栈首帧。
|
|
198
|
-
|
|
199
219
|
## 与 MemoryCore 的差异
|
|
200
220
|
|
|
201
221
|
- 内嵌完整管线(不依赖外部 Gateway),蒸馏复用 DSH 自己的 LLM;
|
|
202
222
|
- L2/L3 由"LLM 操作文件工具"改为"LLM 输出操作 JSON / 完整文档,工程侧执行";
|
|
203
|
-
- 召回注入点在 `agent/pre-step
|
|
223
|
+
- 召回注入点在 `agent/pre-step`(消息侧合成消息,官方 pre-step 替换语义)+ agent 作用域 `systemPrompt.context`(画像/导航稳定区,DSH 原生事件/服务);
|
|
204
224
|
- 存储/检索即官方 sqlite 后端的单机裁剪版(裁掉多租户隔离列、TCVDB 云后端、审计表;
|
|
205
|
-
|
|
206
|
-
|
|
225
|
+
分词与官方一致用 jieba——@node-rs/jieba 预编译二进制 + CJK 二元组并集,
|
|
226
|
+
词元供 BM25 精确整词命中、二元组保子词召回;加载失败自动回退纯二元组,
|
|
227
|
+
FTS 索引按分词器版本戳自动重建)。
|
|
228
|
+
|
|
229
|
+
## 路线图
|
|
230
|
+
|
|
231
|
+
以下为规划中的功能,欢迎在 [Issues](https://github.com/JunNanLYS/dsh-layered-memory/issues) 反馈需求与优先级:
|
|
232
|
+
|
|
233
|
+
- [ ] **Git 分支感知**:记忆与当前 git 分支关联,召回可按分支过滤/加权(与现有记忆档位正交)
|
|
234
|
+
- [ ] **Claude Code / Codex 记忆导入**:一键迁移既有记忆资产(`CLAUDE.md`、Claude Code 记忆文件、Codex `AGENTS.md` 等),导入后进入分层蒸馏管线
|
|
207
235
|
|
|
208
236
|
## 致谢
|
|
209
237
|
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/dist/client.js
CHANGED
|
@@ -1500,11 +1500,20 @@ window.__ModuleLoader__.load({
|
|
|
1500
1500
|
if (!settingsData) return;
|
|
1501
1501
|
// 乐观更新:立即翻 UI,失败回滚
|
|
1502
1502
|
var prev = settingsData;
|
|
1503
|
+
var patch = (function () { var o = {}; o[key] = value; return o; })();
|
|
1503
1504
|
var next = Object.assign({}, prev, {
|
|
1504
|
-
settings: Object.assign({}, prev.settings,
|
|
1505
|
+
settings: Object.assign({}, prev.settings, patch),
|
|
1505
1506
|
});
|
|
1507
|
+
// 蒸馏思考选择器读 effort.current(非 settings 键):乐观更新须同步该视图字段,
|
|
1508
|
+
// 否则点击后选择器在下一个 5s 轮询前"弹回"旧值,看起来没生效
|
|
1509
|
+
if (key === "reasoningEffort" && next.effort) {
|
|
1510
|
+
next.effort = Object.assign({}, prev.effort, {
|
|
1511
|
+
current: value,
|
|
1512
|
+
effective: value || prev.effort.fallback,
|
|
1513
|
+
});
|
|
1514
|
+
}
|
|
1506
1515
|
setSettingsData(next);
|
|
1507
|
-
rpc("dsh-memory/settings-set",
|
|
1516
|
+
rpc("dsh-memory/settings-set", patch)
|
|
1508
1517
|
.then(function (r) {
|
|
1509
1518
|
if (!r || !r.ok) {
|
|
1510
1519
|
setSettingsData(prev);
|