@cmnyhh/dsh-mnemo 0.9.6 → 0.9.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -1
- package/index.js +29 -14
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -137,6 +137,13 @@ An exchange whose text fits in `segmentChars` is stored whole. A longer one is s
|
|
|
137
137
|
|
|
138
138
|
Turn-start turns, plugin-sourced messages, tool payloads, and the plugin's own injected block are excluded — recall must never feed on its own output, and a tool result quoted as memory is noise.
|
|
139
139
|
|
|
140
|
+
**Since 0.9.7 every exchange is recorded, not only the ones that mention a change.** That is `writeMode: 'log'`, the default, and it separates two products that used to share one switch:
|
|
141
|
+
|
|
142
|
+
- a **conversation log entry** — the turn's own words, composed by rule, no model call. It answers "what did we talk about", so its value comes from coverage and nothing filters it but an envelope check (a turn that is nothing but host scaffolding is not a conversation).
|
|
143
|
+
- **extracted facts** — only when the gate reports a signal (`explicit` / `change` / `repair`). This is where a model call is spent, and where admission applies.
|
|
144
|
+
|
|
145
|
+
Before this, a turn that stated something plainly ("我们用的是 PG18") matched no keyword, so it was never sent, never logged, and unanswerable later. `writeMode: 'signal'` restores that behaviour for hosts that want strict filtering; `writeGate: false` turns the judgement off entirely.
|
|
146
|
+
|
|
140
147
|
### When a block is injected
|
|
141
148
|
|
|
142
149
|
Only at step 1 of a turn, which is the one step that opens a turn's request. Later steps of the same turn already carry the block, and re-preparing step 1 after a failure injects again because that retry is the attempt that needs it.
|
|
@@ -150,7 +157,7 @@ With `serviceUrl` set the block is rendered by the service, so its wording and i
|
|
|
150
157
|
|
|
151
158
|
The `writeGate` is textual on purpose and it only recognises a "记住", a change, or a repair. A decision reached in ordinary discussion says none of those words, so the plugin also exposes **`memory_write`** (name configurable via `writeToolName`): one self-contained statement per call.
|
|
152
159
|
|
|
153
|
-
It is not a privileged path. The statement is
|
|
160
|
+
It is not a privileged path. The statement is written as a **direct item insert** (`sourceKind: 'tool'`, with the turn attached only so the service sees `trigger: 'explicit'`), and the service's write review still runs on it — an instruction smuggled into a "fact" is downgraded there rather than trusted because a model wrote it. Since 0.9.6 it no longer goes through extraction: re-running a model on a statement the model itself just decided to keep cost 5–8 seconds and could rewrite or drop it. In thin-client mode the call returns `queued: true`, since the write is delivered by the queue; the record becomes searchable a moment later.
|
|
154
161
|
|
|
155
162
|
|
|
156
163
|
### Corrections and the fact layer
|
package/index.js
CHANGED
|
@@ -1841,26 +1841,37 @@ var FIXED = /(根因|原因是|问题在于|解决的?办法|修好|修复|已
|
|
|
1841
1841
|
function join2(input) {
|
|
1842
1842
|
return [input.prompt, ...input.replies].join("\n").trim();
|
|
1843
1843
|
}
|
|
1844
|
+
function signalOf(input) {
|
|
1845
|
+
if (EXPLICIT.test(input.prompt)) return "explicit";
|
|
1846
|
+
const replies = input.replies.join("\n");
|
|
1847
|
+
if (PROBLEM.test(input.prompt) && FIXED.test(replies)) return "repair";
|
|
1848
|
+
if (CHANGE2.test(replies) || CHANGE2.test(input.prompt)) return "change";
|
|
1849
|
+
return "none";
|
|
1850
|
+
}
|
|
1844
1851
|
function decideCapture(input, options = {}) {
|
|
1845
1852
|
if (options.enabled === false) {
|
|
1846
|
-
return { capture: true, trigger: "
|
|
1853
|
+
return { capture: true, trigger: "change", reason: "\u95F8\u95E8\u5DF2\u5173\u95ED\uFF0C\u5168\u90E8\u5199\u5165" };
|
|
1847
1854
|
}
|
|
1848
1855
|
const minChars = options.minChars ?? 24;
|
|
1849
|
-
|
|
1850
|
-
return { capture: true, trigger: "explicit", reason: "\u7528\u6237\u663E\u5F0F\u8981\u6C42\u8BB0\u4F4F" };
|
|
1851
|
-
}
|
|
1856
|
+
const mode = options.mode ?? "log";
|
|
1852
1857
|
const text = join2(input);
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1858
|
+
if (text.length === 0) {
|
|
1859
|
+
return { capture: false, trigger: "none", reason: "\u7A7A\u8F6E\uFF0C\u65E0\u53EF\u5199\u5165\u5185\u5BB9" };
|
|
1860
|
+
}
|
|
1861
|
+
const trigger = signalOf(input);
|
|
1862
|
+
if (trigger === "explicit") {
|
|
1863
|
+
return { capture: true, trigger, reason: "\u7528\u6237\u663E\u5F0F\u8981\u6C42\u8BB0\u4F4F" };
|
|
1864
|
+
}
|
|
1865
|
+
if (text.length < minChars && trigger === "none") {
|
|
1866
|
+
return { capture: false, trigger, reason: `\u5185\u5BB9\u8FC7\u77ED\uFF08${String(text.length)} \u5B57\uFF09\u4E14\u65E0\u53D8\u66F4\u4FE1\u53F7\uFF0C\u4E0D\u8BB0` };
|
|
1856
1867
|
}
|
|
1857
|
-
if (
|
|
1858
|
-
return { capture:
|
|
1868
|
+
if (mode === "signal" && trigger === "none") {
|
|
1869
|
+
return { capture: false, trigger, reason: "\u65E2\u975E\u663E\u5F0F\u3001\u4E5F\u975E\u53D8\u66F4\u6216\u4FEE\u590D\uFF0C\u4E0D\u8BB0" };
|
|
1859
1870
|
}
|
|
1860
|
-
if (
|
|
1861
|
-
return { capture: true, trigger
|
|
1871
|
+
if (trigger === "none") {
|
|
1872
|
+
return { capture: true, trigger, reason: "\u8BB0\u5BF9\u8BDD\u65E5\u5FD7\uFF08\u4E0D\u62BD\u4E8B\u5B9E\uFF09" };
|
|
1862
1873
|
}
|
|
1863
|
-
return { capture:
|
|
1874
|
+
return { capture: true, trigger, reason: "\u672C\u8F6E\u6709\u4FE1\u53F7\uFF0C\u8BB0\u65E5\u5FD7\u5E76\u62BD\u4E8B\u5B9E" };
|
|
1864
1875
|
}
|
|
1865
1876
|
|
|
1866
1877
|
// src/token.ts
|
|
@@ -1934,7 +1945,10 @@ var Config = Schema.object({
|
|
|
1934
1945
|
agentsMaxChars: Schema.number().default(2048),
|
|
1935
1946
|
agentsSyncMinutes: Schema.number().default(30),
|
|
1936
1947
|
writeGate: Schema.boolean().default(true),
|
|
1937
|
-
writeGateMinChars: Schema.number().default(24)
|
|
1948
|
+
writeGateMinChars: Schema.number().default(24),
|
|
1949
|
+
// 取值在下面按 `=== 'signal'` 判定,非法值自动落回 log——不必用 union/literal,
|
|
1950
|
+
// 这个宿主带的 schemastery 版本没有 Schema.literal。
|
|
1951
|
+
writeMode: Schema.string().default("log")
|
|
1938
1952
|
});
|
|
1939
1953
|
var SEARCH_PARAMETERS = {
|
|
1940
1954
|
query: {
|
|
@@ -2061,6 +2075,7 @@ function apply(ctx, config) {
|
|
|
2061
2075
|
if (writeToolName === toolName) throw new Error("memory-core: writeToolName must differ from toolName");
|
|
2062
2076
|
const writeGate = config.writeGate !== false;
|
|
2063
2077
|
const writeGateMinChars = requireInteger("writeGateMinChars", config.writeGateMinChars, 1);
|
|
2078
|
+
const writeMode = config.writeMode === "signal" ? "signal" : "log";
|
|
2064
2079
|
const t0WriteEnabled = config.t0WriteEnabled === true;
|
|
2065
2080
|
const agentsMaxChars = requireInteger("agentsMaxChars", config.agentsMaxChars, 256);
|
|
2066
2081
|
const agentsSyncMs = requireInteger("agentsSyncMinutes", config.agentsSyncMinutes, 1) * 6e4;
|
|
@@ -2155,7 +2170,7 @@ function apply(ctx, config) {
|
|
|
2155
2170
|
offset,
|
|
2156
2171
|
gate: decideCapture(
|
|
2157
2172
|
{ prompt: exchange.prompt, replies: exchange.replies },
|
|
2158
|
-
{ enabled: writeGate, minChars: writeGateMinChars }
|
|
2173
|
+
{ enabled: writeGate, minChars: writeGateMinChars, mode: writeMode }
|
|
2159
2174
|
)
|
|
2160
2175
|
}));
|
|
2161
2176
|
const kept = gated.filter((entry) => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cmnyhh/dsh-mnemo",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.7",
|
|
4
4
|
"description": "Long-term memory for dsh: capture finished turns, recall them into the first step of a later turn, and expose recall and write as tools. Ships a bundle layer and a settings panel for the service address and token.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|