@modusensus/dsh-mneme 0.8.13 → 0.8.15
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/LICENSE +21 -21
- package/README.md +655 -626
- package/assets/icon.svg +3 -3
- package/bin/cli.mjs +689 -689
- package/bin/dsh-mneme-mcp.mjs +510 -510
- package/bin/dsh-mneme-serve.mjs +151 -0
- package/cordis.patch.yml +21 -21
- package/docs/CONFIGURATION.md +263 -0
- package/docs/CONTINUITY.md +124 -0
- package/docs/DAEMON.md +46 -0
- package/docs/ENTITIES.md +245 -0
- package/docs/LOCAL_MODEL.md +222 -0
- package/docs/SEMANTIC.md +256 -0
- package/docs/SLEEP.md +164 -0
- package/docs/STORAGE.md +89 -0
- package/lib/api-standalone.js +673 -572
- package/lib/api.js +1437 -1433
- package/lib/bootstrap.js +211 -211
- package/lib/client.js +5444 -5295
- package/lib/commands.js +95 -95
- package/lib/config.js +880 -836
- package/lib/content-hash.js +54 -54
- package/lib/continuity.js +220 -220
- package/lib/document-index.js +94 -94
- package/lib/document.js +303 -303
- package/lib/dream/clustering.js +118 -118
- package/lib/dream/decisions.js +674 -674
- package/lib/dream/narratives.js +44 -44
- package/lib/dream/sleep.js +819 -819
- package/lib/dream.js +1501 -1501
- package/lib/embedding.js +177 -177
- package/lib/entities/extractor.js +252 -252
- package/lib/graph/anchoring.js +179 -179
- package/lib/guide.js +74 -74
- package/lib/heat.js +144 -144
- package/lib/hot-memory.js +46 -46
- package/lib/index.js +535 -671
- package/lib/inject.js +464 -450
- package/lib/lang.js +248 -229
- package/lib/local-embedder.js +358 -358
- package/lib/maintenance.js +142 -142
- package/lib/mirror.js +330 -330
- package/lib/organize.js +450 -450
- package/lib/peak-hours.js +117 -117
- package/lib/placement.js +13 -0
- package/lib/pre-inject-gate.js +340 -0
- package/lib/quality-filter.js +126 -126
- package/lib/recall-stats.js +175 -175
- package/lib/reranker.js +269 -269
- package/lib/runtime/adopt.js +176 -176
- package/lib/runtime/closure.js +172 -172
- package/lib/runtime/download.js +247 -247
- package/lib/runtime/layout.js +265 -265
- package/lib/runtime/loader.js +252 -252
- package/lib/runtime/model-fetch.js +361 -361
- package/lib/runtime/provision.js +237 -237
- package/lib/runtime/tarball.js +130 -130
- package/lib/runtime/verify.js +223 -204
- package/lib/scope.js +146 -146
- package/lib/search/adaptive.js +60 -60
- package/lib/search/bm25.js +96 -96
- package/lib/semantic.js +229 -0
- package/lib/sensitive-scan.js +209 -209
- package/lib/serve.js +215 -0
- package/lib/service.js +2663 -2596
- package/lib/settings.js +517 -509
- package/lib/store.js +3007 -3007
- package/lib/summarize.js +891 -856
- package/lib/tools.js +743 -737
- package/lib/vector-index.js +110 -110
- package/lib/version-check.js +122 -122
- package/lib/write-admission.js +402 -402
- package/locale/en.json +6 -6
- package/locale/zh.json +6 -6
- package/package.json +8 -4
- package/runtime-manifest.json +526 -526
- package/scripts/benchmark-embed.js +201 -201
- package/scripts/benchmark-recall.js +249 -249
- package/scripts/benchmark-rerank.js +166 -166
- package/scripts/build-runtime-manifest.mjs +224 -224
- package/scripts/changelog-prep.mjs +36 -0
- package/scripts/check-sync.js +42 -42
- package/scripts/e2e-dsh.js +220 -220
- package/scripts/mneme-runtime.mjs +277 -277
- package/scripts/stress-dsh.js +255 -255
- package/scripts/sync-lib.js +47 -47
- package/scripts/sync-test-badge.mjs +69 -69
- package/scripts/test-count-sync.mjs +44 -44
- package/src/api-standalone.js +673 -572
- package/src/api.js +1437 -1433
- package/src/bootstrap.js +211 -211
- package/src/commands.js +95 -95
- package/src/config.js +880 -836
- package/src/content-hash.js +54 -54
- package/src/continuity.js +220 -220
- package/src/document-index.js +94 -94
- package/src/document.js +303 -303
- package/src/dream/clustering.js +118 -118
- package/src/dream/decisions.js +674 -674
- package/src/dream/narratives.js +44 -44
- package/src/dream/sleep.js +819 -819
- package/src/dream.js +1501 -1501
- package/src/embedding.js +177 -177
- package/src/entities/extractor.js +252 -252
- package/src/graph/anchoring.js +179 -179
- package/src/guide.js +74 -74
- package/src/heat.js +144 -144
- package/src/hot-memory.js +46 -46
- package/src/index.js +535 -671
- package/src/inject.js +464 -450
- package/src/lang.js +248 -229
- package/src/local-embedder.js +358 -358
- package/src/maintenance.js +142 -142
- package/src/mirror.js +330 -330
- package/src/organize.js +450 -450
- package/src/peak-hours.js +117 -117
- package/src/placement.js +13 -0
- package/src/pre-inject-gate.js +340 -0
- package/src/quality-filter.js +126 -126
- package/src/recall-stats.js +175 -175
- package/src/reranker.js +269 -269
- package/src/runtime/adopt.js +176 -176
- package/src/runtime/closure.js +172 -172
- package/src/runtime/download.js +247 -247
- package/src/runtime/layout.js +265 -265
- package/src/runtime/loader.js +252 -252
- package/src/runtime/model-fetch.js +361 -361
- package/src/runtime/provision.js +237 -237
- package/src/runtime/tarball.js +130 -130
- package/src/runtime/verify.js +223 -204
- package/src/scope.js +146 -146
- package/src/search/adaptive.js +60 -60
- package/src/search/bm25.js +96 -96
- package/src/semantic.js +229 -0
- package/src/sensitive-scan.js +209 -209
- package/src/serve.js +215 -0
- package/src/service.js +2663 -2596
- package/src/settings.js +517 -509
- package/src/store.js +3007 -3007
- package/src/summarize.js +891 -856
- package/src/tools.js +743 -737
- package/src/vector-index.js +110 -110
- package/src/version-check.js +122 -122
- package/src/write-admission.js +402 -402
- package/test/adaptive-inject-budget.test.js +85 -85
- package/test/api-routes-gaps.test.js +218 -218
- package/test/api.test.js +1702 -1688
- package/test/audit.test.js +448 -448
- package/test/baseline-persist.test.js +248 -248
- package/test/benchmark.test.js +94 -94
- package/test/bootstrap.test.js +220 -220
- package/test/changelog-prep.test.js +60 -0
- package/test/client.test.js +1230 -1169
- package/test/clustering.test.js +100 -100
- package/test/commands.test.js +106 -106
- package/test/config.test.js +66 -66
- package/test/conflict-freeze.test.js +300 -300
- package/test/content-hash.test.js +204 -204
- package/test/continuity.test.js +333 -333
- package/test/document-dir.test.js +233 -233
- package/test/document.test.js +671 -671
- package/test/dream-archive-guardrail.test.js +116 -116
- package/test/dream-candidate-hybrid.test.js +281 -281
- package/test/dream-coverage-degrade.test.js +86 -86
- package/test/dream-failure-backoff.test.js +173 -173
- package/test/dream-peak-hours.test.js +194 -194
- package/test/dream.test.js +1385 -1383
- package/test/embedding-ready.test.js +196 -196
- package/test/entities.test.js +627 -547
- package/test/entity-recall.test.js +179 -179
- package/test/epistemic.test.js +325 -325
- package/test/fnew-0112.test.js +311 -311
- package/test/fnew-03.test.js +422 -422
- package/test/graph-anchoring.test.js +184 -184
- package/test/graph-api.test.js +175 -175
- package/test/graph-inject-budget.test.js +103 -103
- package/test/graph-passive-confirm.test.js +91 -91
- package/test/graph-weight-evolution.test.js +104 -104
- package/test/heat.test.js +175 -175
- package/test/helpers/dream-mock.js +82 -82
- package/test/helpers/peer-worker.mjs +25 -25
- package/test/helpers/runtime-source.js +60 -60
- package/test/helpers/tar-builder.js +80 -80
- package/test/helpers/write-admission-samples.js +308 -308
- package/test/hot-memory.test.js +145 -145
- package/test/inject-content-cap.test.js +91 -91
- package/test/inject-first-round-bm25.test.js +89 -89
- package/test/inject-heat.test.js +77 -61
- package/test/inject-parent-gate.test.js +106 -106
- package/test/inject-pools.test.js +194 -194
- package/test/inject-recall.test.js +105 -105
- package/test/inject-rotation.test.js +161 -161
- package/test/inject.test.js +420 -420
- package/test/lang.test.js +87 -87
- package/test/lastrunat-persist.test.js +101 -101
- package/test/lib-smoke.test.js +96 -96
- package/test/llm-audit.test.js +598 -598
- package/test/llm-message-source.test.js +207 -207
- package/test/local-embedder.test.js +292 -292
- package/test/maintenance.test.js +391 -391
- package/test/mcp-stdio.test.js +385 -385
- package/test/mirror-dirty.test.js +424 -424
- package/test/mirror-edit-digest.test.js +187 -187
- package/test/mirror-generation.test.js +499 -499
- package/test/mirror-types.test.js +208 -208
- package/test/mirror.test.js +249 -249
- package/test/narrative-bars.test.js +162 -162
- package/test/organize.test.js +418 -418
- package/test/peer-blockers.test.js +193 -193
- package/test/placement.test.js +36 -0
- package/test/policy-epoch.test.js +259 -259
- package/test/pre-inject-gate.test.js +434 -0
- package/test/quality-filter.test.js +186 -186
- package/test/reasoning-effort.test.js +752 -752
- package/test/recall-anti-update.test.js +82 -82
- package/test/recall-evals.test.js +253 -253
- package/test/recall-layer.test.js +326 -326
- package/test/recall-stats.test.js +189 -189
- package/test/receipt-chain.test.js +451 -451
- package/test/reflection.test.js +226 -226
- package/test/reindex-backfill.test.js +62 -62
- package/test/reranker-single-logit.test.js +73 -73
- package/test/reranker.test.js +197 -197
- package/test/resident-status.test.js +83 -83
- package/test/runtime-adopt.test.js +206 -206
- package/test/runtime-cli.test.js +89 -89
- package/test/runtime-closure.test.js +193 -193
- package/test/runtime-download.test.js +302 -302
- package/test/runtime-layout.test.js +163 -163
- package/test/runtime-loader.test.js +255 -255
- package/test/runtime-manifest.test.js +159 -159
- package/test/runtime-model-fetch.test.js +348 -348
- package/test/runtime-provision.test.js +101 -101
- package/test/runtime-tarball.test.js +81 -81
- package/test/runtime-verify.test.js +319 -279
- package/test/scope-candidates.test.js +239 -239
- package/test/scope-explicit.test.js +452 -452
- package/test/scope-inject-soft.test.js +106 -106
- package/test/scope-retrieval.test.js +197 -197
- package/test/scope-storage.test.js +255 -255
- package/test/scope-strict.test.js +367 -343
- package/test/search-fusion.test.js +90 -90
- package/test/semantic.test.js +124 -124
- package/test/sensitive-scan.test.js +207 -207
- package/test/serve-bin.test.js +121 -0
- package/test/serve.test.js +196 -0
- package/test/service-search.test.js +174 -174
- package/test/service.test.js +405 -405
- package/test/settings.test.js +261 -261
- package/test/skip-invalid-restore.test.js +262 -262
- package/test/sleep-action-set.test.js +422 -422
- package/test/sleep-heat.test.js +126 -126
- package/test/sleep-scheduler-rearm.test.js +89 -89
- package/test/sleep.test.js +527 -527
- package/test/standalone-api.test.js +751 -544
- package/test/store-vector-cache.test.js +98 -98
- package/test/store.test.js +396 -396
- package/test/stress.test.js +209 -209
- package/test/summarize-occurred-at.test.js +127 -0
- package/test/summarize-reasoning-effort.test.js +189 -189
- package/test/summarize.test.js +1465 -1465
- package/test/supersede-state-tracking.test.js +394 -0
- package/test/test-count-sync.test.js +60 -60
- package/test/tools-dto-schema-matrix.test.js +325 -325
- package/test/tools-memory-get-schema.test.js +65 -65
- package/test/tools.test.js +428 -374
- package/test/updated-at-semantics.test.js +113 -113
- package/test/vector-index.test.js +221 -221
- package/test/version-check.test.js +152 -152
- package/test/webServer-optional.test.js +82 -82
- package/test/write-admission.test.js +668 -668
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// bin/dsh-mneme-serve.mjs —— mneme 独立服务(daemon)入口。
|
|
3
|
+
//
|
|
4
|
+
// 为什么独立成 bin 而不是 cli.mjs 的子命令:CONTRIBUTING「The CLI is dependency-free
|
|
5
|
+
// by contract」禁止给 bin/cli.mjs 加 import,而 serve 必须挂载 lib/serve.js;命名循
|
|
6
|
+
// dsh-mneme-mcp 先例。数据面 = src/api-standalone.js 同一工厂,路由与鉴权零新面。
|
|
7
|
+
//
|
|
8
|
+
// 生命周期:bind 失败(含 strictPort 下端口被占)→ stderr 清错 + exit 1;
|
|
9
|
+
// SIGINT/SIGTERM → dispose + exit 0。Windows 下 kill() 是硬终止、handler 不跑:
|
|
10
|
+
// 已提交事务由 WAL 回放兜底(node:sqlite 未 finalize 语句的 close 抛错同理),不丢数据。
|
|
11
|
+
//
|
|
12
|
+
// 日志纪律:进度/错误全走 stderr;stdout 只在就绪时打一行机器可读的 listening 行
|
|
13
|
+
// (脚本/测试从中解析实际端口),其余时刻保持干净——serve 是常驻进程,stdout 常被
|
|
14
|
+
// 重定向进监控管道。
|
|
15
|
+
import { readFileSync } from "node:fs";
|
|
16
|
+
import { fileURLToPath } from "node:url";
|
|
17
|
+
import { dirname, join, resolve } from "node:path";
|
|
18
|
+
import { createServeRuntime } from "../lib/serve.js";
|
|
19
|
+
|
|
20
|
+
const BIN_NAME = "dsh-mneme-serve";
|
|
21
|
+
const PKG_ROOT = join(dirname(fileURLToPath(import.meta.url)), "..");
|
|
22
|
+
const PKG = JSON.parse(readFileSync(join(PKG_ROOT, "package.json"), "utf8"));
|
|
23
|
+
|
|
24
|
+
const USAGE = `${BIN_NAME} — run the mneme data plane as a standalone service (no DSH required)
|
|
25
|
+
|
|
26
|
+
Usage: dsh-mneme-serve [--memory-dir <dir>] [--port <n>] [--host <addr>] [--embed <provider>]
|
|
27
|
+
|
|
28
|
+
Options:
|
|
29
|
+
--memory-dir <dir> data directory (default: ~/.dsh/memory, same as the plugin)
|
|
30
|
+
--port <n> HTTP port (default: persisted external_api port, else 8790)
|
|
31
|
+
--host <addr> bind address (default: persisted external_api host, else 127.0.0.1)
|
|
32
|
+
--embed <provider> semantic retrieval: local (default, downloads the ONNX runtime
|
|
33
|
+
+ embedding model on first boot) | ollama | openai (uses the
|
|
34
|
+
vector-config saved by the DSH panel) | off (keyword + BM25 only)
|
|
35
|
+
-h, --help show this help
|
|
36
|
+
-V, --version print version
|
|
37
|
+
|
|
38
|
+
Auth: Bearer token is shared with the DSH panel / CLI (kv "external_api" in
|
|
39
|
+
memory.db); it is generated on first boot. A busy configured port is a hard
|
|
40
|
+
error — the DSH external API and this daemon must not share a port (pick one).
|
|
41
|
+
|
|
42
|
+
Environment (runtime provisioning, local provider only):
|
|
43
|
+
DSH_MNEME_MEMORY_DIR data directory override
|
|
44
|
+
DSH_MNEME_RUNTIME_DIR self-managed runtime dir (default ~/.dsh/mneme/runtime)
|
|
45
|
+
DSH_MNEME_RUNTIME_TARBALL_DIR offline .tgz dir preferred over the network
|
|
46
|
+
DSH_MNEME_RUNTIME_MIRROR npm registry mirror prefix (e.g. npmmirror)`;
|
|
47
|
+
|
|
48
|
+
/** 极简 argv 解析(--k=v / --k v / 旗标);够用即可,完整 CLI 在 bin/cli.mjs。 */
|
|
49
|
+
function parseArgv(argv) {
|
|
50
|
+
const out = {};
|
|
51
|
+
for (let i = 0; i < argv.length; i++) {
|
|
52
|
+
const a = argv[i];
|
|
53
|
+
if (a === "-h" || a === "--help") out.help = true;
|
|
54
|
+
else if (a === "-V" || a === "--version") out.version = true;
|
|
55
|
+
else if (a.startsWith("--")) {
|
|
56
|
+
const eq = a.indexOf("=");
|
|
57
|
+
if (eq > -1) out[a.slice(2, eq)] = a.slice(eq + 1);
|
|
58
|
+
else {
|
|
59
|
+
const v = argv[i + 1];
|
|
60
|
+
// 本 bin 的旗标全部取值(无泛用布尔旗标):值缺失或下一个 token 是旗标
|
|
61
|
+
// 都按「缺值」报错退出——不能落成 true(Number(true)=1 会把 --port 变成
|
|
62
|
+
// 绑端口 1,报 EACCES 让用户查错方向)。帮助/版本在上方分支已提前返回。
|
|
63
|
+
if (v !== undefined && !v.startsWith("-")) { out[a.slice(2)] = v; i++; }
|
|
64
|
+
else fail(`${a} 缺少参数值`);
|
|
65
|
+
}
|
|
66
|
+
} else {
|
|
67
|
+
fail(`未知参数: ${a}\n运行 \`${BIN_NAME} --help\` 查看用法。`);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return out;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function fail(msg) {
|
|
74
|
+
console.error(`[${BIN_NAME}] ${msg}`);
|
|
75
|
+
process.exit(1);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// api-standalone 的 logger 契约:info/warn/error 收单字符串。全走 stderr(见头部纪律)。
|
|
79
|
+
const logger = {
|
|
80
|
+
info: (msg) => console.error(`[dsh-mneme] ${msg}`),
|
|
81
|
+
warn: (msg) => console.error(`[dsh-mneme] warn: ${msg}`),
|
|
82
|
+
error: (msg) => console.error(`[dsh-mneme] error: ${msg}`)
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
async function main(argv) {
|
|
86
|
+
const args = parseArgv(argv);
|
|
87
|
+
if (args.help) { process.stdout.write(USAGE + "\n"); return; }
|
|
88
|
+
if (args.version) { console.log(PKG.version); return; }
|
|
89
|
+
|
|
90
|
+
// memoryDir:CLI > env > serve.js 缺省(~/.dsh/memory)。相对路径按 CWD 解;
|
|
91
|
+
// 前导 ~ 留给 serve.js 展开(与宿主 index.js:192-194 同一口径)。
|
|
92
|
+
const rawDir = typeof args["memory-dir"] === "string" ? args["memory-dir"]
|
|
93
|
+
: (typeof process.env.DSH_MNEME_MEMORY_DIR === "string" && process.env.DSH_MNEME_MEMORY_DIR ? process.env.DSH_MNEME_MEMORY_DIR : undefined);
|
|
94
|
+
const memoryDir = rawDir && !rawDir.startsWith("~") ? resolve(rawDir) : rawDir;
|
|
95
|
+
|
|
96
|
+
let port;
|
|
97
|
+
if (args.port !== undefined) {
|
|
98
|
+
port = Number(args.port);
|
|
99
|
+
if (!Number.isInteger(port) || port < 0 || port > 65535) {
|
|
100
|
+
fail(`--port 需要合法端口(0-65535),收到: ${args.port}`);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
const host = typeof args.host === "string" && args.host ? args.host : undefined;
|
|
104
|
+
|
|
105
|
+
let embed = "local";
|
|
106
|
+
if (args.embed !== undefined) {
|
|
107
|
+
if (typeof args.embed !== "string" || !["off", "local", "ollama", "openai"].includes(args.embed)) {
|
|
108
|
+
fail(`--embed 需要 off|local|ollama|openai,收到: ${String(args.embed)}`);
|
|
109
|
+
}
|
|
110
|
+
embed = args.embed;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
let rt;
|
|
114
|
+
try {
|
|
115
|
+
// 装配是异步的:embed=local 时可能要先取件 runtime(download 档,失败内部降级)
|
|
116
|
+
rt = await createServeRuntime({ memoryDir, port, host, logger, embed });
|
|
117
|
+
} catch (err) {
|
|
118
|
+
fail(`启动失败: ${err?.message ?? err}`);
|
|
119
|
+
}
|
|
120
|
+
try {
|
|
121
|
+
await rt.api.ready;
|
|
122
|
+
} catch (err) {
|
|
123
|
+
fail(`数据面启动失败: ${err?.message ?? err}\n` +
|
|
124
|
+
` 端口 ${rt.api.port} 被占通常意味着另一个 mneme 数据面正在运行` +
|
|
125
|
+
`(DSH 的「外部访问」或另一份 ${BIN_NAME})——二选一,或用 --port 换端口。`);
|
|
126
|
+
}
|
|
127
|
+
const addr = rt.api.server.address();
|
|
128
|
+
// stdout 唯一一行:机器可读就绪行(测试/脚本解析端口用)。
|
|
129
|
+
console.log(`${BIN_NAME} listening on http://${addr?.address ?? rt.api.host}:${addr?.port ?? rt.api.port} (pid ${process.pid})`);
|
|
130
|
+
if (!rt.tokenExisted) {
|
|
131
|
+
console.error(`[dsh-mneme] 首次启动已生成 Bearer token(已持久化,与 DSH 面板/CLI 共用):\n` +
|
|
132
|
+
` ${rt.api.token}`);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
let closing = false;
|
|
136
|
+
const shutdown = async (signal) => {
|
|
137
|
+
// 第二次信号 = 强制退出(dispose 里 server.close 等 in-flight 收尾,极端情况下会挂)
|
|
138
|
+
if (closing) process.exit(0);
|
|
139
|
+
closing = true;
|
|
140
|
+
console.error(`[dsh-mneme] ${signal} received, closing...`);
|
|
141
|
+
try { await rt.dispose(); } catch { /* dispose 各步自吞 */ }
|
|
142
|
+
process.exit(0);
|
|
143
|
+
};
|
|
144
|
+
process.on("SIGINT", () => shutdown("SIGINT"));
|
|
145
|
+
process.on("SIGTERM", () => shutdown("SIGTERM"));
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
main(process.argv.slice(2)).catch((err) => {
|
|
149
|
+
console.error(err?.stack ?? String(err));
|
|
150
|
+
process.exit(1);
|
|
151
|
+
});
|
package/cordis.patch.yml
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
# dsh-mneme bundle patch — the layer applied when a profile lists this bundle.
|
|
2
|
-
# Installed via: dsh plugin --profile <name> add @modusensus/dsh-mneme
|
|
3
|
-
- insert:
|
|
4
|
-
- id: dsh-mneme
|
|
5
|
-
name: '@modusensus/dsh-mneme'
|
|
6
|
-
config:
|
|
7
|
-
memoryDir: ~/.dsh/memory
|
|
8
|
-
autoInject: true
|
|
9
|
-
autoSummarize: true
|
|
10
|
-
maxInjectedItems: 5
|
|
11
|
-
importanceThreshold: 3
|
|
12
|
-
autoDream: true
|
|
13
|
-
dreamThresholdCount: 10
|
|
14
|
-
dreamThresholdChars: 5000
|
|
15
|
-
dreamDelayMs: 2000
|
|
16
|
-
# 巩固默认压低推理:思考型模型(如方舟 v4 系)会把 dreamMaxTokens
|
|
17
|
-
# 预算花在推理上、正文空体 → "no json array in llm output"。low 让
|
|
18
|
-
# provider 封顶推理;拒绝 effort 字段的 provider 由 runAuditedLlm
|
|
19
|
-
# 自动去掉重试,行为安全(v0.7.16 机制)。
|
|
20
|
-
dreamReasoningEffort: low
|
|
21
|
-
entityExtractionEnabled: true
|
|
1
|
+
# dsh-mneme bundle patch — the layer applied when a profile lists this bundle.
|
|
2
|
+
# Installed via: dsh plugin --profile <name> add @modusensus/dsh-mneme
|
|
3
|
+
- insert:
|
|
4
|
+
- id: dsh-mneme
|
|
5
|
+
name: '@modusensus/dsh-mneme'
|
|
6
|
+
config:
|
|
7
|
+
memoryDir: ~/.dsh/memory
|
|
8
|
+
autoInject: true
|
|
9
|
+
autoSummarize: true
|
|
10
|
+
maxInjectedItems: 5
|
|
11
|
+
importanceThreshold: 3
|
|
12
|
+
autoDream: true
|
|
13
|
+
dreamThresholdCount: 10
|
|
14
|
+
dreamThresholdChars: 5000
|
|
15
|
+
dreamDelayMs: 2000
|
|
16
|
+
# 巩固默认压低推理:思考型模型(如方舟 v4 系)会把 dreamMaxTokens
|
|
17
|
+
# 预算花在推理上、正文空体 → "no json array in llm output"。low 让
|
|
18
|
+
# provider 封顶推理;拒绝 effort 字段的 provider 由 runAuditedLlm
|
|
19
|
+
# 自动去掉重试,行为安全(v0.7.16 机制)。
|
|
20
|
+
dreamReasoningEffort: low
|
|
21
|
+
entityExtractionEnabled: true
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
# 配置说明(全键参考)
|
|
2
|
+
|
|
3
|
+
> 正本是 `src/config.js` 的 schema——本文与其同步维护,键名、默认值、取值范围以代码为准;
|
|
4
|
+
> 行为动机与踩坑出处在 schema 注释里(含 issue 编号),本文只保留「怎么配、配了会怎样」。
|
|
5
|
+
> 改 schema 时顺手更新对应行(新改动自查清单第 2 条)。
|
|
6
|
+
|
|
7
|
+
**怎么读这张表**
|
|
8
|
+
|
|
9
|
+
- 「默认」列即 `config.js` schema 的解析默认值;默认值本身 = 未配置时的行为。
|
|
10
|
+
- 标 **light** 的键会被 lightMode 预设强制关闭(文末附完整清单);lightMode 是预设不是
|
|
11
|
+
强制——用户显式写在 feature_flags 里的值优先于预设。
|
|
12
|
+
- 行为开关(布尔键)默认关的即 opt-in:不开 = 行为与该键存在之前逐字节一致。
|
|
13
|
+
- 绝大多数行为开关与部分阈值/路由键在 `settings.js` 的白名单里,可在面板「功能开关」
|
|
14
|
+
逐项启停(线上回滚开关);未入白名单的键(路径、词典、枚举外的杂项)只能改 bundle 配置。
|
|
15
|
+
|
|
16
|
+
## 全局与存储
|
|
17
|
+
|
|
18
|
+
| 键 | 默认 | 作用 | 开启后果 / 冲突 |
|
|
19
|
+
|---|---|---|---|
|
|
20
|
+
| `language` | `zh` | 记忆语言:生成条目、注入标题、后台提示词所用语言(`zh`/`en`) | 切换后重启生效 |
|
|
21
|
+
| `memoryDir` | `~/.dsh/memory` | SQLite 记忆库目录 | WAL + busy_timeout 已为多进程就绪;两个宿主共用库时 `externalApiEnabled` 与 `autoDream` 只能一边开 |
|
|
22
|
+
| `lightMode` | `false` | 轻量档总闸:一键关掉全部重型路径,保留核心循环(见文末清单) | 面板 `panel_mode=light` 等效为 `true` 且优先于 bundle 配置 |
|
|
23
|
+
|
|
24
|
+
## scope 隔离(issue #17)
|
|
25
|
+
|
|
26
|
+
| 键 | 默认 | 作用 | 开启后果 / 冲突 |
|
|
27
|
+
|---|---|---|---|
|
|
28
|
+
| `scopeEnabled` | `false` | 存储层总开关:写入标注 agent_scope / workspace_scope,去重键扩展;检索与注入排序按当前会话作用域加权(命中 ×1.25、他 scope ×0.5 保留可见,issue #339 补齐注入通道) | opt-in;关 = 写入不标注、行为与 A1 前逐字节一致 |
|
|
29
|
+
| `strictScope` | `false` | 硬过滤模式(A3):他 scope 完全不可见、未标注恒可见(fail-closed);硬过滤先于软加权执行 | 依赖 `scopeEnabled` 打开才有意义;关 = A2 软隔离(他 scope 降权保留可见,检索与注入同权重) |
|
|
30
|
+
|
|
31
|
+
## 审计
|
|
32
|
+
|
|
33
|
+
| 键 | 默认 | 作用 | 开启后果 / 冲突 |
|
|
34
|
+
|---|---|---|---|
|
|
35
|
+
| `llmAudit.enabled` | `true` | 后台 LLM 调用全量落 `llm_audit_logs`(tokens / 时长 / 状态 / 触发源) | 覆盖 autoDream / autoSummarize / sleep / entityExtract 与写入准入测量点;关 = 一行不写 |
|
|
36
|
+
| `llmAudit.retentionDays` | `90` | 审计表滚动清理保留天数(≤3650) | 启动时清理旧行 |
|
|
37
|
+
|
|
38
|
+
## 写入准入(#254)
|
|
39
|
+
|
|
40
|
+
写入前判定「这条该不该进库」,与 `memoryQualityFilter` 的分工是**时点**不是判据:那个是写入后打分归档(扣分可以错,只影响排序与归档),这个是写入前判定(硬拒不能错)。两个键都默认关,分层是为了把「先观察」和「开始拦」分成两次上线。
|
|
41
|
+
|
|
42
|
+
| 键 | 默认 | 作用 | 开启后果 / 冲突 |
|
|
43
|
+
|---|---|---|---|
|
|
44
|
+
| `writeAdmission.enabled` | `false` | 跑第 1 级确定性判据:空白 / 纯噪声 + 密钥 / PII(判据来源是 #164 A2,经 `sensitiveScan` 注入) | 关 = 不判定、不拒绝,`evaluate` 返回与只计量阶段逐字段一致。命中 → 审计行带 `metadata.deny` |
|
|
45
|
+
| `writeAdmission.enforce` | `false` | 命中时真的拒绝(`store.save` 之前返回) | 关 = 仅告警:判据照跑、审计照留、写入不拦(读审计时「`deny` 非空且 `decision=allow`」即这一档的指纹)。被拒写入不落库、不通知、不排嵌入,`memory_save` 返回 `action:"denied"` + `reason` |
|
|
46
|
+
|
|
47
|
+
第 1 级的判据面刻意收窄:**去重键命中不进第 1 级**(归 write-update 放行——同步近重复门跑在异步矛盾检测之前会把本该被裁决的矛盾直接拒掉),G1/G2 阈值也只是计量。两个键都走 feature_flags 白名单(面板可启停)。
|
|
48
|
+
|
|
49
|
+
## 注入前判定(#380)
|
|
50
|
+
|
|
51
|
+
每帧注入候选出池后、进入 system prompt 前,一次**池级** LLM 调用判出「会向本次请求注入意见/立场」的记忆(判定协议与 E12 实验同源;实验依据:D1 判定+过滤把谄媚率 26.9%→2.5%,判定+标记比过滤差 +17.6pp——判定结果**只给闸门用,绝不进模型上下文**)。两级语义与 writeAdmission 同构,落点在注入面而非写入面。
|
|
52
|
+
|
|
53
|
+
| 键 | 默认 | 作用 | 开启后果 / 冲突 |
|
|
54
|
+
|---|---|---|---|
|
|
55
|
+
| `preInjectGate.enabled` | `false` | 跑池级判定。判定 async prefetch + cache、渲染帧同步消费(宿主 systemPrompt 渲染是同步回调) | 关 = 注入行为与现状逐字节一致。**冷缓存首帧降级**:新查询的第一帧原样注入,下一轮同 key 渲染生效;判定完成落 `llm_audit_logs`(`trigger_source=preInjectGate`,真实 token 用量,`related_memory_ids`=被标记记忆)——先观察真实负载的意见占比分布 |
|
|
56
|
+
| `preInjectGate.enforce` | `false` | 缓存命中帧真的滤除被标记候选 | 关 = 仅观察:候选集不动。**enforce 无 enabled 时无效果**。pin 池(constraint/preference,#249 逐字保真)与 graphHint 线索行豁免——判定与过滤只作用于一般记忆槽 |
|
|
57
|
+
|
|
58
|
+
降级路径:判定失败/超时/不可解析 → 本帧原样注入 + 审计行 `degraded:true` 且不缓存(下一帧重试)——防线故障永不阻塞注入;连续失败 3 次熔断一个冷却期(判定器系统性坏掉时不再逐帧花钱,到期自动恢复)。**整池被标记**时放弃本帧 enforce(fail-open):记忆正文是判定模型的可影响输入,一条指令型记忆不该让整个记忆块静默失明——该形态在审计行里就是 `n_flagged == n_pool`(判定与审计按原样保留,只有滤除让位)。判定 LLM 走 `agentDefaultModel` 当前选择(entity adapter 同款装配,无独立 provider/model 键;审计行带实际模型与用量,无默认模型路由时 `model_id` 落 `unknown` 占位——判定生效就必有账;成本痛了再加覆盖键)。缓存键 = 查询 + 候选 `id:内容` 集,候选集变化(轮换/新记忆)或候选内容被就地修正(`updateMemory`)即重新判定,不吃旧判定;命中刷新序(LRU,容量 8)。`llmAudit.enabled=false` 时本闸不运行(无账目的判定不可见也不该花钱)。lightMode 强制关(LLM-per-turn 附加路径与低资源档互斥)。
|
|
59
|
+
|
|
60
|
+
## 蒸馏(会话 → 记忆)
|
|
61
|
+
|
|
62
|
+
| 键 | 默认 | 作用 | 开启后果 / 冲突 |
|
|
63
|
+
|---|---|---|---|
|
|
64
|
+
| `autoSummarize` | `true` | 会话/回合结束自动蒸馏记忆。E10 EdgeMem 考卷(#339)实测:对「未来才问的具体值」类细节,零 LLM 原样写入保真 100% 而蒸馏丢 17/120——蒸馏的归纳收益在别的口径,二者是并存关系而非替代(原样写入并存的产品化见讨论 #361) | 关 = 只剩工具与命令写入口 |
|
|
65
|
+
| `summarizeProvider` / `summarizeModel` | 空 | 蒸馏专用模型路由 | 两者都非空才生效;空 = 用会话当前模型 |
|
|
66
|
+
| `distillMaxChars` | `24000` | 喂给蒸馏 LLM 的完整转录上限(字符,1000–200000) | 调大更完整、更贵 |
|
|
67
|
+
| `summarizeMinIntervalMinutes` | `0` | 同会话两次蒸馏的最小间隔(分钟,≤10080) | 0 = 不限(#127 节流三键之一) |
|
|
68
|
+
| `summarizeMaxEntriesPerRun` | `0` | 单次蒸馏最多落库条数(≤50) | 0 = 不限 |
|
|
69
|
+
| `summarizeMinWindowChars` | `0` | 窗口可蒸馏文本下限(字符),不足直接跳过 LLM(#239) | 被挡窗口照常消费游标并留 skip 审计 |
|
|
70
|
+
| `summarizeMaxRunsPerSession` | `0` | 每会话蒸馏次数预算,只计真实发起的调用(≤1000) | 0 = 不限;进程内计数,重启清零 |
|
|
71
|
+
| `summarizePeakHours` | `""` | 高峰时段串(`"09:00-18:00"` / `"mon-fri 08:00-12:00,14:00-18:00"`,支持跨零点) | 命中高峰不调 LLM、顺延补跑;任一写法非法整串按未配置处理 |
|
|
72
|
+
| `summarizePeakMaxDeferMinutes` | `120` | 高峰顺延上限(分钟,≤1440) | 0 = 不设上限;到点仍处高峰照跑(bypassPeak) |
|
|
73
|
+
| `summarizeDedupeMode` | `off` | 落库前去重档位:`off` / `title`(拦完全同名)/ `vector`(同会话语义近邻) | `vector` 复用已有 embedding 列,无 LLM 调用 |
|
|
74
|
+
| `summarizeDedupeMinSim` | `0.92` | `vector` 档并入阈值(0.5–0.99) | 仅 `vector` 档生效 |
|
|
75
|
+
| `summarizeDedupeWindowHours` | `24` | `vector` 档回看窗口(小时,≤168) | 仅 `vector` 档生效 |
|
|
76
|
+
| `distillRateLimitIntervalMs` | `1000` | 蒸馏请求全局串行排队的相邻间隔(毫秒) | 0 = 关闭排队(默认开的 429 保护随之失效) |
|
|
77
|
+
| `distillRateLimitRetries` | `3` | 命中 429 的指数退避重试次数(≤10) | 重试全程对用户透明 |
|
|
78
|
+
| `distillRateLimitBaseDelayMs` | `1000` | 429 退避基数(毫秒,100–60000) | 1s→2s→4s… |
|
|
79
|
+
| `summarizeReasoningEffort` | `none` | 蒸馏 LLM 推理档位:`off`/`low`/`medium`/`high`/`none`(#315) | `none` = 不发字段用服务商默认;思考模型建议 `off`/`low` 防推理烧光输出预算 |
|
|
80
|
+
| `codingRetrospect` | `false` | 编码记忆蒸馏:rejected_solution / pitfall / constraint 三类 | opt-in;开启后蒸馏上下文为整轮完整对话 |
|
|
81
|
+
| `codingKeywords` | 内置词表 | 编码任务识别词表(读取侧门控) | 命中才注入编码记忆 |
|
|
82
|
+
| `codingBoostFactor` | `2` | 编码任务时编码记忆的 importance 加权系数(1–5) | — |
|
|
83
|
+
| `memoryQualityFilter.enabled` | `true` | 写入质量打分:≥60 正常 / 30–60 降权 / <30 归档打 low_quality 标 | 归档行仍可显式搜到 |
|
|
84
|
+
| `memoryQualityFilter.archiveThreshold` | `30` | 自动归档线 | 与 `exemptImportance` 联动 |
|
|
85
|
+
| `memoryQualityFilter.degradeThreshold` | `60` | 降权线(注入排序乘 quality_score) | — |
|
|
86
|
+
| `memoryQualityFilter.minContentLength` | `10` | 最短内容长度(字符) | — |
|
|
87
|
+
| `memoryQualityFilter.exemptImportance` | `4` | importance ≥ 此值豁免静默自动归档(#135) | 设 1 = 等效关自动归档 |
|
|
88
|
+
|
|
89
|
+
## 注入
|
|
90
|
+
|
|
91
|
+
| 键 | 默认 | 作用 | 开启后果 / 冲突 |
|
|
92
|
+
|---|---|---|---|
|
|
93
|
+
| `autoInject` | `true` | 每轮自动注入记忆块的父总闸 | 关 = 两个子开关一并失效(持久值保留,不重置) |
|
|
94
|
+
| `maxInjectedItems` | `5` | 注入条数上限(1–20) | — |
|
|
95
|
+
| `importanceThreshold` | `3` | 注入候选的 importance 下限(1–5) | 低于该值的记忆不进注入面 |
|
|
96
|
+
| `injectRotationTurns` | `0` | 跨轮轮换:最近 N 轮注入过的不再优先(#205) | opt-in;会话边界自动重置 |
|
|
97
|
+
| `injectContentMaxChars` | `300` | 单条正文截断上限(60–4000,#164①) | 截断带「上限/原长/全文指引」提示,不静默 |
|
|
98
|
+
| `injectUncertaintyAdaptive` | `false` | 确定性强的话题收缩注入条数(减半、下限 1,#239 第 5 项) | 只做单向收缩,绝不越过 `maxInjectedItems` |
|
|
99
|
+
| `injectGuidanceEnabled` **light** | `true` | 工具描述 + order 150 系统段讲「何时查/何时写」(#249) | `autoInject` 子开关;lightMode 强制关 |
|
|
100
|
+
| `continuityRescueEnabled` **light** | `false` | 压缩边缘双落点:连续性提案落库 + 追加注入(#249 N3) | opt-in(新注入表面);`autoInject` 子开关;订阅宿主压缩事件,无该时机则降级为持久规则 |
|
|
101
|
+
| `pinnedInjectBudget` | `0` | 约束/偏好 pin 池独立预算(0–5,#249 B1) | 0 = 关;pin 不占 `maxInjectedItems` 名额 |
|
|
102
|
+
| `hotMemoryEnabled` | `true` | 会话近期对话渲染在长期记忆块之前 | — |
|
|
103
|
+
| `hotMemoryRounds` | `5` | 热记忆覆盖最近几轮对话(≤50) | — |
|
|
104
|
+
| `hotMemoryMaxTokens` | `2000` | 热记忆块 token 上限(200–32000) | — |
|
|
105
|
+
| `escapePromptVariables` | `true` | 注入内容连续花括号转义(#162) | 关 = 原样透传(DSH interpolate 可能 throw) |
|
|
106
|
+
|
|
107
|
+
## 巩固(autoDream)
|
|
108
|
+
|
|
109
|
+
| 键 | 默认 | 作用 | 开启后果 / 冲突 |
|
|
110
|
+
|---|---|---|---|
|
|
111
|
+
| `autoDream` **light** | `true` | 阈值触发的后台巩固(LLM 合并/归档/降重) | lightMode 强制关;与 sleepMode 串行、不重叠 |
|
|
112
|
+
| `dreamThresholdCount` / `dreamThresholdChars` | `10` / `5000` | 触发阈值(新增条数 / 字符,双过才跑) | — |
|
|
113
|
+
| `dreamDelayMs` | `2000` | 触发后的延迟(毫秒) | — |
|
|
114
|
+
| `dreamMinIntervalMinutes` | `0` | 两次开跑最小间隔(分钟,≤10080,#89) | 失败/degraded run 也占用;0 = 不限 |
|
|
115
|
+
| `autoDreamFailureBackoff` | `false` | 连续失败指数退避:有效间隔 = 基数 × 2^连败,封顶 30 分钟(#292) | opt-in;基数取 `dreamMinIntervalMinutes`(0 = 无闸可翻倍);成功一次清零;重启归零 |
|
|
116
|
+
| `dreamPeakHours` | `""` | 巩固错峰,与 `summarizePeakHours` 同一份时段语法(#239) | 命中高峰不做梦、阈值继续累积、留 skip 审计;非法写法按未配置 |
|
|
117
|
+
| `dreamPeakMaxDeferMinutes` | `120` | 巩固顺延上限(分钟) | 0 = 不设上限;到点仍处高峰照跑 |
|
|
118
|
+
| `dreamProvider` / `dreamModel` | 空 | 巩固专用路由(settings「巩固模型」) | 建议非思考模型——思考模型易烧光预算返回空体(#135) |
|
|
119
|
+
| `dreamMaxTokens` | `131072` | 巩固输出预算(256–131072) | 流式计费按实际用量,调大不增加成本 |
|
|
120
|
+
| `dreamReasoningEffort` | 未配置 | 巩固推理档位(同 `summarizeReasoningEffort` 的枚举) | 未配置 = 自动取模型支持的最低档(#135);显式 `none` = 不发字段 |
|
|
121
|
+
| `dreamSummaryProvider` / `dreamSummaryModel` | 空 | 记忆总览(dream_summarize)专用路由(#258) | 空 = 回落巩固路由;总览输入为全库,建议大 ctx 非思考模型 |
|
|
122
|
+
| `dreamSummaryMaxInputs` | `0` | 总览输入条数硬上限(按 updated_at 倒序取最新 N 条) | 0 = 不设上限(库增长可能撑爆小 ctx 模型) |
|
|
123
|
+
| `dreamMaxSnapshotSize` | `200` | 滑动窗口:每次只巩固最近 N 条(≤1000) | 窗口外旧记忆不进快照 |
|
|
124
|
+
| `dreamCandidateMode` | `window` | 候选集构造:`window` / `hybrid`(并入向量高相似组,#125) | `hybrid` 让该合并的对能碰面;输入成本不随库增长 |
|
|
125
|
+
| `dreamCandidateMax` | `0` | `hybrid` 候选总量上限(≤5000) | 0 = 复用 `dreamMaxSnapshotSize` |
|
|
126
|
+
| `dreamCandidateMinSim` | `0.85` | `hybrid` 判「高相似」的阈值 | 与 sleep normal 档同一个定义 |
|
|
127
|
+
| `dreamMaxArchivePerRun` | `8` | 单轮 archive 决策上限(≤200,#104) | 超限整单拒绝,`dreamSkipInvalid` 不豁免 |
|
|
128
|
+
| `dreamImplicitKeep` | `true` | LLM 未提及的快照记忆自动补 keep | `false` = 恢复严格校验(未覆盖即拒绝整单) |
|
|
129
|
+
| `dreamMinExplicitCoverage` | `0.5` | 显式决策覆盖率下限(0–1) | 防截断输出被隐式 keep 洗白 |
|
|
130
|
+
| `dreamSkipInvalid` | `true` | 跳过单条非法决策、应用合法子集、run 记 degraded(#89) | `false` = 恢复整单拒绝 |
|
|
131
|
+
| `allowCrossTypeMerge` | `false` | 放宽跨类型合并检查 | opt-in;`dreamSkipInvalid` 关时跨类型 merge 直接整单拒绝 |
|
|
132
|
+
| `dreamMergeGuard` | `true` | guarded 类型 merge 护栏(#339/E8):合并对象命中长保留类型(与 archive 护栏同表:preference/pattern/rejected_solution/constraint/pitfall)的 merge 决策整条跳过——E8 实测巩固损耗里 10/26 条被丢约束已归位 guarded 类型仍被 merge 吃掉 | 默认开(同类压缩管线实测:安全规则被同速压缩后一轮只剩 53%、五轮只剩 10%,全程无报错);关闭 = guarded 类型的 merge 不再被跳过,「更精炼的摘要」重新成为约束失真的主通道。`dreamSkipInvalid`(默认开)时被跳条目进 `dream_runs.skipped`、run 记 degraded,关闭时整单拒绝 |
|
|
133
|
+
| `dreamNarrativeEnabled` **light** | `false` | dream 期间按共享 tag 聚类合成叙述条(#164 对齐) | opt-in;按需检索、不常驻注入 |
|
|
134
|
+
| `dreamNarrativeMinCluster` | `3` | 成簇门槛(共享同一 tag 的记忆数,2–20) | — |
|
|
135
|
+
| `documentMemoryEnabled` **light** | `false` | document 型记忆:长文档指针行,全文归 agent(#230) | opt-in;注册校验 + C2 去重 + supersede 记账 |
|
|
136
|
+
| `documentInjectBudget` | `2` | document 摘要行的注入预算(1–5) | 只约束注入,不约束检索 |
|
|
137
|
+
| `documentDir` | `""` | managed 落盘目录(#296) | 空 = `<memoryDir>/documents/`;目录之外只登记指针、正文零读零写 |
|
|
138
|
+
| `policyEpoch` | `0` | 裁决规则版本号 | bump 后旧 dream_runs 降为历史证据(receipt 不再驱动现行决策) |
|
|
139
|
+
|
|
140
|
+
## 睡眠模式(sleep,空闲深维护)
|
|
141
|
+
|
|
142
|
+
| 键 | 默认 | 作用 | 开启后果 / 冲突 |
|
|
143
|
+
|---|---|---|---|
|
|
144
|
+
| `sleepModeEnabled` **light** | `false` | 库静默后全库深维护:冲突消解/归档降级/模式发现/关系补全 | opt-in;可被用户活动中止,与 autoDream 串行 |
|
|
145
|
+
| `sleepIdleMinutes` | `5` | 静默多久触发(1–60 分钟) | — |
|
|
146
|
+
| `sleepMinIntervalHours` | `8` | 两次 run 最小间隔(小时,≤168) | — |
|
|
147
|
+
| `sleepConflictStrictness` | `normal` | 冲突裁决档:`gentle`(0.92) / `normal`(0.85) / `aggressive`(0.75) | — |
|
|
148
|
+
| `sleepActionSet` | `conflict` | 动作集:`conflict` / `full`(六分支,#126) | `full` 让互补型/演进型重复有正确出口 |
|
|
149
|
+
| `sleepArchiveDays` / `sleepCompressDays` | `30` / `90` | 归档降级分层(天):先缩为摘要、再彻底归档 | 实体关系保留 |
|
|
150
|
+
| `sleepPatternMinMemories` | `100` | 模式发现的扫描窗口(条) | — |
|
|
151
|
+
| `sleepPatternLookbackDays` | `30` | 属性变更回看(天) | — |
|
|
152
|
+
| `sleepMaxPatternPerRun` | `3` | 单轮模式条上限(0–10) | 0 = 关闭模式发现 |
|
|
153
|
+
| `sleepProvider` / `sleepModel` | 空 | sleep 专用路由 | 空 = 用巩固路由 / 当前模型 |
|
|
154
|
+
| `sleepReasoningEffort` | 未配置 | 同 `dreamReasoningEffort` | — |
|
|
155
|
+
| `sleepMaxTokens` | `8192` | 冲突/模式阶段输出预算(#257) | 原硬编码 2048 对 `full` 档必然截断 |
|
|
156
|
+
| `sleepHeatThreshold` | `0.05` | 降级联合判定的热度下限(heat < 值且 importance<5 才降) | `heatEnabled` 关时退回纯时间分层 |
|
|
157
|
+
|
|
158
|
+
## 反思与冲突(dream 配套)
|
|
159
|
+
|
|
160
|
+
| 键 | 默认 | 作用 | 开启后果 / 冲突 |
|
|
161
|
+
|---|---|---|---|
|
|
162
|
+
| `reflectionUpdateEnabled` | `true` | 检索后的反思更新既有记忆 | — |
|
|
163
|
+
| `reflectionFailureTracking` | `true` | 失败经验追踪 | — |
|
|
164
|
+
| `reflectionUpdateMaxPerRun` | `2` | 单轮 update 上限(0–5) | — |
|
|
165
|
+
| `reflectionUpdateMinAgeHours` | `24` | 可更新记忆的最短年龄(小时,≤168) | — |
|
|
166
|
+
| `conflictFreezeEnabled` | `false` | 冲突不自动合并、冻结待人工复核 | opt-in |
|
|
167
|
+
| `conflictFreezeMaxPending` | `100` | 冻结队列上限(≤1000) | — |
|
|
168
|
+
|
|
169
|
+
## 实体
|
|
170
|
+
|
|
171
|
+
| 键 | 默认 | 作用 | 开启后果 / 冲突 |
|
|
172
|
+
|---|---|---|---|
|
|
173
|
+
| `entityExtractionEnabled` **light** | `false` | 写入时 LLM 抽取实体/属性/关系 | opt-in;存储三表与 CRUD 恒可用,本键只闸抽取 |
|
|
174
|
+
| `entityExtractionProvider` / `entityExtractionModel` | 空 | 抽取专用路由 | 单边为空时回落调用方默认 |
|
|
175
|
+
| `entityExtractionReasoning` | `none` | 抽取推理档位(#109) | `none` = 不发字段;拒收自动去掉字段重试一次 |
|
|
176
|
+
| `entityExtractionMaxEntities` / `entityExtractionMaxAttrs` | `10` / `20` | 单次抽取的实体数 / 每实体属性数上限 | — |
|
|
177
|
+
| `entitySearchEnabled` | `true` | 实体名前缀/语义搜索(供召回) | — |
|
|
178
|
+
| `entityRecallEnabled` **light** | `false` | 图召回轴:查询命中实体名时并入融合池(#219) | opt-in;依赖实体抽取产出(lightMode 下抽取已关) |
|
|
179
|
+
|
|
180
|
+
## 检索
|
|
181
|
+
|
|
182
|
+
| 键 | 默认 | 作用 | 开启后果 / 冲突 |
|
|
183
|
+
|---|---|---|---|
|
|
184
|
+
| `embedProvider` | `openai` | 嵌入提供方:`openai`(外部 API)/ `local`(ONNX)/ `ollama` | — |
|
|
185
|
+
| `vectorSearchTopK` | `20` | 向量召回条数(≤100) | — |
|
|
186
|
+
| `vectorSearchThreshold` | `0.65` | 固定向量阈值 | `adaptiveThresholdEnabled` 开启时被动态阈值取代 |
|
|
187
|
+
| `adaptiveThresholdEnabled` | `true` | 查询感知动态阈值(实体前缀放宽、短查询收紧等) | 关 = 回到固定 0.65 |
|
|
188
|
+
| `bm25SearchEnabled` **light** | `true` | BM25 第三召回路径(标识符/代码碎片/混排) | — |
|
|
189
|
+
| `hybridSearchVectorWeight` / `hybridSearchKeywordWeight` | `0.6` / `0.4` | 混合检索加权 | — |
|
|
190
|
+
| `recallFusion` | `blend` | 融合配方:`blend`(现状)/ `rrf` / `minmax` | `rrf`/`minmax` 修「raw 余弦 + 关键词分直接相加」的量纲失配 |
|
|
191
|
+
| `signalTransparency` | `false` | 每条结果附带 `{keyword, vector, bm25, final}` 信号 | 只装饰返回行,不改排序 |
|
|
192
|
+
| `hybridInject` **light** | `true` | 注入前语义优先召回、规则序回填 | — |
|
|
193
|
+
| `selectiveInjectEnabled` **light** | `true` | 有查询向量时按相似度重排注入候选 | — |
|
|
194
|
+
| `searchSemanticDedup` **light** | `false` | 检索期语义去重(贪心剔除近重复) | opt-in 激进档:小嵌入模型易把不同条目坍缩 |
|
|
195
|
+
| `searchSemanticDedupThreshold` | `0.95` | 去重阈值 | — |
|
|
196
|
+
| `evalPersistTestResults` | `false` | 检索评测快照落 `recall_evals` | 生产检索恒只进 `recall_runs`,与此键无关 |
|
|
197
|
+
| `recallRecordDefault` | `true` | `recall_runs` 记录默认开 | 显式传 `false` 的调用方不受影响 |
|
|
198
|
+
| `recallRetentionDays` | `90` | `recall_runs` 滚动清理保留天数 | — |
|
|
199
|
+
| `trustEpistemicWeighting` | `false` | 来源可信度(observation/subjective/inferred)参与排序与标注 | opt-in;关时 epistemic_status 只是惰性数据 |
|
|
200
|
+
|
|
201
|
+
### 重排层
|
|
202
|
+
|
|
203
|
+
| 键 | 默认 | 作用 | 开启后果 / 冲突 |
|
|
204
|
+
|---|---|---|---|
|
|
205
|
+
| `rerankEnabled` **light** | `false` | 本地交叉编码器重排 | opt-in:显式 `true` + `local` 才拉起 onnxruntime |
|
|
206
|
+
| `rerankProvider` | `none` | `local` / `none` | — |
|
|
207
|
+
| `rerankModel` | `Xenova/bge-reranker-base` | 重排模型 | — |
|
|
208
|
+
| `rerankBatchSize` | `8` | 批大小(≤64) | — |
|
|
209
|
+
| `rerankMaxCandidates` | `30` | 参与重排的候选上限(5–100) | — |
|
|
210
|
+
| `rerankScoreThreshold` | `0.1` | 重排分数阈值 | — |
|
|
211
|
+
| `rerankDtype` | `q8` | 量化档(#188) | 非法值由 transformers 抛出 → 重排降级告警 |
|
|
212
|
+
|
|
213
|
+
## 热度
|
|
214
|
+
|
|
215
|
+
| 键 | 默认 | 作用 | 开启后果 / 冲突 |
|
|
216
|
+
|---|---|---|---|
|
|
217
|
+
| `heatEnabled` **light** | `false` | 热度曲线(遗忘):热度字段 / sleep 降级联判(#218) | opt-in;关 = sleep 退回纯时间分层 |
|
|
218
|
+
| `injectHeatEnabled` | `false` | 注入排序乘 heat(#218 / E5 考卷:heat 乘进注入排序在真实年龄混合下饿死老约束,拆独立开关默认关) | 依赖 `heatEnabled`;关 = 注入乘数恒 1(与 heat 关闭逐字节一致);开 = 恢复层内乘 heat 旧序 |
|
|
219
|
+
| `heatGlobalBeta` | `1.0` | 广义指数形状参数 β(0.5–2) | 专家调优项,不进面板白名单 |
|
|
220
|
+
| `heatTypeDecay` | 内置默认 | per-type 衰减 λ(键为 type 字符串) | λ=0 的类型免疫(热度恒 1、sleep 永不降级) |
|
|
221
|
+
|
|
222
|
+
## API 与工具面
|
|
223
|
+
|
|
224
|
+
| 键 | 默认 | 作用 | 开启后果 / 冲突 |
|
|
225
|
+
|---|---|---|---|
|
|
226
|
+
| `apiToken` | 空 | 宿主内 API 敏感端点的共享 token | 空 = 只读端点保持开放(DSH 绑 127.0.0.1 且无内建鉴权) |
|
|
227
|
+
| `externalApiEnabled` | `false` | 独立 `node:http` 数据面(生态集成用) | opt-in;双宿主共用库时只能一边开(端口冲突) |
|
|
228
|
+
| `externalApiPort` | `8790` | 端口 | — |
|
|
229
|
+
| `externalApiHost` | `127.0.0.1` | 绑定地址 | 改成非回环 = 把整个记忆库暴露给网络,自负其责 |
|
|
230
|
+
| `disableMemorySearch` | `false` | 对模型隐藏 `memory_search` 工具(v0.8.5) | 慢/轻量模型的工具往返节流;隐藏即不可调 |
|
|
231
|
+
| `disableMemoryArchive` | `false` | 对模型隐藏 `memory_archive` 工具 | 同上 |
|
|
232
|
+
|
|
233
|
+
## 运行时与本地模型
|
|
234
|
+
|
|
235
|
+
| 键 | 默认 | 作用 | 开启后果 / 冲突 |
|
|
236
|
+
|---|---|---|---|
|
|
237
|
+
| `localEmbedModel` | `Xenova/bge-small-zh-v1.5` | 本地嵌入模型(`embedProvider=local` 时) | — |
|
|
238
|
+
| `localEmbedDimension` | `512` | 向量维度 | — |
|
|
239
|
+
| `localEmbedDevice` | `cpu` | `cpu` / `gpu` | — |
|
|
240
|
+
| `localEmbedBatchSize` | `8` | 批大小(≤64) | — |
|
|
241
|
+
| `localEmbedPooling` | `auto` | 池化:`auto`(BGE→cls,其余→mean)/ `cls` / `mean` | 池化决定向量空间——改动会变 modelHash、触发既有索引重建 |
|
|
242
|
+
| `ollamaBaseUrl` | `http://localhost:11434` | Ollama 地址 | 只接受 http/https(SSRF 防线) |
|
|
243
|
+
| `ollamaModel` | `nomic-embed-text` | Ollama 嵌入模型 | — |
|
|
244
|
+
| `embedModelCacheDir` | `""` | 模型缓存目录 | 空 = `~/.dsh/mneme/models` |
|
|
245
|
+
| `embedModelMirror` | `https://hf-mirror.com` | 模型下载镜像 | — |
|
|
246
|
+
| `resilientModelDownload` | `true` | 模型下载断点续传 + 空闲看门狗(#194) | 关 = 恢复原生 fetch(线上回滚开关) |
|
|
247
|
+
| `runtimeDir` | `""` | 自管运行时目录(transformers + onnxruntime 闭包,#131) | 空 = `~/.dsh/mneme/runtime`;把重依赖挪出宿主 profile 的依赖图 |
|
|
248
|
+
| `runtimeTarballDir` | `""` | 本地 `.tgz` 离线取件目录 | 有货优先于联网(弱网下装 onnxruntime-node 用) |
|
|
249
|
+
| `runtimeMirror` | `""` | registry 镜像前缀(如 `https://npmmirror.com/mirrors/npm/`) | 空 = manifest 里的官方地址 |
|
|
250
|
+
|
|
251
|
+
## lightMode 强制关闭清单(`LIGHT_MODE_OFF`)
|
|
252
|
+
|
|
253
|
+
`lightMode: true`(或面板 `panel_mode=light`)时,以下键被预设强制为 `false`——都是
|
|
254
|
+
重型路径;核心循环(autoInject、autoSummarize、hotMemory*、质量过滤、关键词检索)不动:
|
|
255
|
+
|
|
256
|
+
`entityExtractionEnabled` · `autoDream` · `sleepModeEnabled` · `rerankEnabled` ·
|
|
257
|
+
`autoReindexOnBoot` · `hybridInject` · `injectGuidanceEnabled` · `searchSemanticDedup` ·
|
|
258
|
+
`selectiveInjectEnabled` · `bm25SearchEnabled` · `entityRecallEnabled` ·
|
|
259
|
+
`dreamNarrativeEnabled` · `documentMemoryEnabled` · `heatEnabled` · `continuityRescueEnabled` ·
|
|
260
|
+
`preInjectGate.enabled`(#380)
|
|
261
|
+
|
|
262
|
+
预设只是默认值而非强制:用户显式写进 feature_flags 的值在装配顺序上后展开、仍然生效
|
|
263
|
+
(「用户开关 > 轻量预设 > bundle 配置」)。
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
# dsh-mneme 压缩边缘抢救(issue #249 N3)
|
|
2
|
+
|
|
3
|
+
- **日期**:2026-09-24
|
|
4
|
+
- **状态**:✅ 已实现(opt-in,默认关)
|
|
5
|
+
- **范围**:上下文即将被宿主压缩前,抢救「正在做什么」,让它活过这次压缩
|
|
6
|
+
- **相关文档**:[存储与回收](STORAGE.md)(同批的 #275 第一批) · [语义增强](SEMANTIC.md)
|
|
7
|
+
|
|
8
|
+
## 1. 问题
|
|
9
|
+
|
|
10
|
+
宿主的压缩摘要器只看对话里的内容:压缩时它按固定字段模板重建对话(Current Work /
|
|
11
|
+
Next Step / Critical Context 等),**系统提示段里的东西不进这次重建**。所以任何"只放在
|
|
12
|
+
提示段里的工作状态",一过压缩就等于没写过。
|
|
13
|
+
|
|
14
|
+
## 2. 形态:必须双落点
|
|
15
|
+
|
|
16
|
+
| 落点 | 去处 | 为什么不能省 |
|
|
17
|
+
|---|---|---|
|
|
18
|
+
| ① 落提案 | `continuity_proposals` 表(`src/store.js`) | 脱离对话独立存活;注入失败/被跳过也不丢工作状态 |
|
|
19
|
+
| ② 追加消息 | 序列末尾一条 `user/message`(`source: {kind: "plugin", plugin: "dsh-mneme"}`) | 这是唯一能进宿主摘要器重建范围的落点 |
|
|
20
|
+
|
|
21
|
+
落库先于注入。落点顺序由宿主契约保证:压缩插件在自己那一步先压缩、再 `return next()`,
|
|
22
|
+
所以我们在 `agent/pre-step` 拿到 `next()` 结果时压缩事件已落库;而我们返回的
|
|
23
|
+
`decision.messages` 由宿主在本步末尾以 `surfaceOp: "append"` 追加,晚于压缩的
|
|
24
|
+
`surfaceOp: "replace"`——追加物天然在压缩之后、靠近序列末尾。
|
|
25
|
+
|
|
26
|
+
注入文本是**结构化快照**(统一前缀 + 三行固定字段,整条 ≤900 字符),不是 §6.3 那种
|
|
27
|
+
≤160B 的单行提醒——那条上限约束的是"一句话提醒",不约束固定字段的快照;字段内部的换行
|
|
28
|
+
仍会被压平成空格,保证它仍是一条消息。**判重按当前表面**(`session.surface.nodes`),
|
|
29
|
+
不按全量日志:被一次压缩折叠出表面的旧快照还在 append-only 日志里,照日志判重会让这次
|
|
30
|
+
该补的注入静默跳过。
|
|
31
|
+
|
|
32
|
+
## 3. 触发
|
|
33
|
+
|
|
34
|
+
**不自定阈值**,就是订阅宿主真的压缩:`compaction/start` / `compaction/summary` /
|
|
35
|
+
`compaction/end`(都在宿主的事件白名单里)。理由:「压缩边缘」由宿主定义,我们再校准
|
|
36
|
+
一份阈值参数只会与之漂移,还多一份没人维护的旋钮。
|
|
37
|
+
|
|
38
|
+
DSH 没有 in-memory 消息改写钩子,所以本机制一律是「注入 + 序号引用寻址」,**不改写
|
|
39
|
+
历史消息本体**。
|
|
40
|
+
|
|
41
|
+
## 4. 字段与抽取口径
|
|
42
|
+
|
|
43
|
+
固定三字段(不用自由散文),全程不调模型、纯确定性抽取(`src/continuity.js`):
|
|
44
|
+
|
|
45
|
+
| 字段 | 来源 | 截断 |
|
|
46
|
+
|---|---|---|
|
|
47
|
+
| `current_work` | 最近一条**真实** `user/message`(插件注入与子代理上报不算用户指令) | 头部 200 字符 |
|
|
48
|
+
| `next_step` | 最近一条 `assistant/message` | **尾部** 200 字符(下一步活在末尾那句里) |
|
|
49
|
+
| `open_questions` | 恒 `null` | —— |
|
|
50
|
+
|
|
51
|
+
「哪些问题还没解决」判不出就是判不出,硬猜会给出似是而非的字段;空字段在注入文本里
|
|
52
|
+
如实标 `(none)`。这个字段留给转正通道与人工补。
|
|
53
|
+
|
|
54
|
+
字段名以 #249 §6.2 为准(`current_work` / `next_step` / `open_questions`)。§4.4 里的
|
|
55
|
+
Current Work / Next Step / Critical Context 是**宿主压缩模板**的字段名,不是这张表的列名
|
|
56
|
+
(规格里两处用词不同,实现取 §6.2)。
|
|
57
|
+
|
|
58
|
+
## 5. 存储与生命周期
|
|
59
|
+
|
|
60
|
+
```
|
|
61
|
+
continuity_proposals(id, session_id, kind, current_work, next_step, open_questions,
|
|
62
|
+
status, edge_seq, created_at, updated_at)
|
|
63
|
+
UNIQUE (session_id, kind) -- 「同一会话同一类只留一条」:再次触发是刷新,不是新增
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
- `kind`:`compaction-edge`(一次会话里这一类只留一条)。
|
|
67
|
+
- `status`:`pending`(本批唯一写入态)→ 未来 `promoted` / `discarded`(转正通道与
|
|
68
|
+
#254 的二次确认共用一套,阶段二才打开)。
|
|
69
|
+
- **队列满则弃新**(`MAX_CONTINUITY_PENDING = 200`):达上限丢掉本次触发,而不是淘汰
|
|
70
|
+
旧行——旧行是别的会话还没转正的工作状态,用「更近的边缘」把它挤掉是反的。满队列
|
|
71
|
+
不影响已有行的刷新。
|
|
72
|
+
- 丢弃会**留痕**(`agent/pre-step` 监听器 `logger.warn`):弃新属于"静默失效",不报出来
|
|
73
|
+
的话 §8 的触发率口径会把它算成"没触发"。
|
|
74
|
+
- **本批没有回收路径**:`status` 只写 `pending`,`maintenance`/`reclaim` 不碰这张表,
|
|
75
|
+
所以 200 是上限——满了之后新会话不再落行,直到转正通道打开(阶段二)。判定是进程内的
|
|
76
|
+
(先查计数再写),两个宿主共用同一 `memoryDir` 时可能各自都看到未满,实际越过 200 条。
|
|
77
|
+
- `edge_seq` 记最近一次触发的压缩事件序号,是「实际触发率」的证据。
|
|
78
|
+
- 落库失败只告警、不抛:可选插件的故障不该把宿主的这一步变成失败,而注入那一半不依赖
|
|
79
|
+
库,照做。
|
|
80
|
+
|
|
81
|
+
指标口径(#249 §8 要求触发率/采纳率可统计):实际触发率 = 提案行数;采纳率 =
|
|
82
|
+
`promoted` / 全部。两者都是就地读表,不需要额外打点。
|
|
83
|
+
|
|
84
|
+
## 6. 开关
|
|
85
|
+
|
|
86
|
+
| 层级 | 键 | 默认 |
|
|
87
|
+
|---|---|---|
|
|
88
|
+
| 父 | `autoInject` | 开(既有总闸) |
|
|
89
|
+
| 子 | `continuityRescueEnabled` | **关**(引入新注入表面,按 #249 §10 判据独立成键) |
|
|
90
|
+
|
|
91
|
+
父关则子不生效(`injectChildEnabled`);轻量档默认置关(`applyLightModePreset`
|
|
92
|
+
把它算进 `LIGHT_MODE_OFF`),但那只是默认值——装配时按「用户开关 > 轻量预设 >
|
|
93
|
+
bundle 配置」合并,用户在面板里显式勾选仍然赢。面板落点在 `lib/client.js`
|
|
94
|
+
的 `FEATURE_CHILDREN` / `FEATURE_GROUPS`(该文件无 src 对应物),跨文件关系由
|
|
95
|
+
`test/inject-parent-gate.test.js` 逐个断言钉住。
|
|
96
|
+
|
|
97
|
+
## 7. 降级路径(不要求宿主加接口)
|
|
98
|
+
|
|
99
|
+
宿主若不提供可挂钩的压缩前时机,双落点里的 ② 就没有触发者。这时**不算失败**:把规则
|
|
100
|
+
写成持久规则交给 agent 自判(`src/guide.js` 的 `CONTINUITY_TOOL_RULE`,挂在
|
|
101
|
+
`memory_save` 的工具描述尾部——常驻文本、零注入成本,只在子开关开启时出现)。
|
|
102
|
+
|
|
103
|
+
本批**不做宿主能力探测**(没有可靠的探测口,宿主也没有暴露"有没有压缩前时机"这个事实),
|
|
104
|
+
所以子开关打开时这条规则就常驻,与 ② 并存——两者不是互斥的备选,而是同一个开关下的两层:
|
|
105
|
+
② 在宿主真的压缩时自动生效,持久规则在 agent 自己判断"上下文要炸了"时兜底。
|
|
106
|
+
|
|
107
|
+
## 8. 已知坑
|
|
108
|
+
|
|
109
|
+
- **判重只能做到「同一份文本不追加第二次」**。没有改写钩子,就不能删掉表面里已经存在
|
|
110
|
+
的那条旧快照;内容一变就是新的一份(旧的那份随宿主压缩自然消失)。这是形态上限,
|
|
111
|
+
不是实现偷懒。
|
|
112
|
+
- **注入物不得变成记忆**:追加消息用 `source.kind = "plugin"`,`summarize.js` 的
|
|
113
|
+
`collectMessages` 会跳过它——否则注入物会被下一轮蒸馏成记忆,形成自我强化。
|
|
114
|
+
- **`open_questions` 恒 null** 是刻意留白,不是没实现。
|
|
115
|
+
|
|
116
|
+
## 9. 验收锚点
|
|
117
|
+
|
|
118
|
+
`test/continuity.test.js` 逐条锁形态(不是锁文案):抽取口径(头/尾方向、插件消息跳过、
|
|
119
|
+
插件消息是最后一条 `user/message` 时仍被跳过)、渲染(统一前缀、单行、`none`、整条上限)、
|
|
120
|
+
唯一键刷新(`created_at` 不动、幂等 UPSERT)、队列满弃新且不影响刷新、丢弃留痕、
|
|
121
|
+
pre-step 双落点与一次性消费、同文本不重复追加(按当前表面)、被折叠出表面的旧注入要补、
|
|
122
|
+
落库失败不打断宿主的一步、`reject` 放行且不消费边缘、缺 session 不抛、dispose 后不再动作、
|
|
123
|
+
默认关 + 父关不生效 + 轻量档压掉 + 降级规则只在开启时进描述、门控不调模型(静态锁)、
|
|
124
|
+
存量库重开即建表。
|