@modusensus/dsh-mneme 0.8.14 → 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 -654
- 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 -151
- 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 -673
- 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 -843
- 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 -503
- 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 -229
- package/lib/sensitive-scan.js +209 -209
- package/lib/serve.js +215 -215
- package/lib/service.js +2663 -2605
- package/lib/settings.js +517 -511
- 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 +118 -118
- 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 -36
- 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 -673
- package/src/api.js +1437 -1433
- package/src/bootstrap.js +211 -211
- package/src/commands.js +95 -95
- package/src/config.js +880 -843
- 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 -503
- 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 -229
- package/src/sensitive-scan.js +209 -209
- package/src/serve.js +215 -215
- package/src/service.js +2663 -2605
- package/src/settings.js +517 -511
- 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 -1690
- 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 -60
- 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 -77
- 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 -367
- 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 -121
- package/test/serve.test.js +196 -196
- 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 -751
- 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
package/bin/dsh-mneme-serve.mjs
CHANGED
|
@@ -1,151 +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
|
-
});
|
|
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 配置」)。
|