@dzhechkov/memory 0.2.6 → 0.2.9
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/dist/dreaming.d.ts +13 -3
- package/dist/dreaming.d.ts.map +1 -1
- package/dist/dreaming.js +93 -13
- package/dist/dreaming.js.map +1 -1
- package/package.json +1 -1
- package/src/dreaming.ts +105 -12
package/dist/dreaming.d.ts
CHANGED
|
@@ -35,12 +35,19 @@ export interface DreamOptions {
|
|
|
35
35
|
*/
|
|
36
36
|
export declare function isSystemWrapper(text: string): boolean;
|
|
37
37
|
/**
|
|
38
|
-
* True for insights
|
|
39
|
-
*
|
|
38
|
+
* True for insights that are NOISE rather than reusable learnings, so both the
|
|
39
|
+
* ingest gate and the retro-prune step can drop them:
|
|
40
40
|
*
|
|
41
41
|
* - `Tool mcp__* invoked during session` (telemetry, no longer harvested)
|
|
42
42
|
* - `User responded: "<system wrapper…"` for every wrapper prefix recognized
|
|
43
43
|
* by {@link isSystemWrapper}, including session-continuation forms.
|
|
44
|
+
* - `User responded: "<bare approval>"` — a checkpoint approval echoed as a
|
|
45
|
+
* pattern (e.g. `продолжай`, `ok`, `да`). These are REWARD signal (which
|
|
46
|
+
* phase was approved), captured separately; as a recallable "pattern" they
|
|
47
|
+
* carry zero reusable insight and clutter `dz recall`. Gated by EXACT match
|
|
48
|
+
* (after {@link normalizeCheckpointText}) against {@link EXCELLENT_RESPONSES},
|
|
49
|
+
* so a SUBSTANTIVE response ("продолжай, но добавь X") is NOT flagged and is
|
|
50
|
+
* preserved — it may carry real signal.
|
|
44
51
|
*
|
|
45
52
|
* This predicate is the shared contract for the prune step.
|
|
46
53
|
*/
|
|
@@ -55,7 +62,10 @@ export declare function isNoiseInsight(text: string): boolean;
|
|
|
55
62
|
* NOISE GATE (a real-store audit found ~85 of 91 records were junk):
|
|
56
63
|
* - Tool invocations are NOT harvested — a `tool_use` is telemetry, not a learning.
|
|
57
64
|
* - System wrappers arriving as user messages ({@link isSystemWrapper}) are skipped.
|
|
58
|
-
* -
|
|
65
|
+
* - Verdict classification only fires on checkpoint-like messages (≤ 200 chars,
|
|
66
|
+
* ≤ 100 for failed) and only on ANCHORED standalone words/phrases, never bare
|
|
67
|
+
* substrings — "в stop hook" and "не изобретать заново" are live-store
|
|
68
|
+
* misfires that bare substrings produced.
|
|
59
69
|
*/
|
|
60
70
|
export declare function harvestDreamPatterns(options: DreamOptions): DreamPattern[];
|
|
61
71
|
/** Convert a DreamPattern to a MemoryRecord for storage via any MemoryBackend. */
|
package/dist/dreaming.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dreaming.d.ts","sourceRoot":"","sources":["../src/dreaming.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAEjD,qDAAqD;AACrD,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM,GAAG,YAAY,GAAG,QAAQ,CAAC;IACjE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAED,uCAAuC;AACvC,MAAM,WAAW,YAAY;IAC3B,0DAA0D;IAC1D,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,2DAA2D;IAC3D,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CACzB;AAqBD;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAOrD;
|
|
1
|
+
{"version":3,"file":"dreaming.d.ts","sourceRoot":"","sources":["../src/dreaming.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAEjD,qDAAqD;AACrD,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM,GAAG,YAAY,GAAG,QAAQ,CAAC;IACjE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAED,uCAAuC;AACvC,MAAM,WAAW,YAAY;IAC3B,0DAA0D;IAC1D,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,2DAA2D;IAC3D,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CACzB;AAqBD;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAOrD;AAyGD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAcpD;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,YAAY,GAAG,YAAY,EAAE,CAyE1E;AAaD,kFAAkF;AAClF,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,YAAY,GAAG,YAAY,CAWxE"}
|
package/dist/dreaming.js
CHANGED
|
@@ -61,21 +61,87 @@ const EXCELLENT_RESPONSES = new Set([
|
|
|
61
61
|
]);
|
|
62
62
|
/**
|
|
63
63
|
* Only messages this short are considered checkpoint-like for the
|
|
64
|
-
* needs_work/failed
|
|
64
|
+
* needs_work/failed verdict checks. Longer messages routinely QUOTE words
|
|
65
65
|
* like 'stop' or 'переделай' without meaning them as verdicts.
|
|
66
66
|
*/
|
|
67
67
|
const CHECKPOINT_MAX_LENGTH = 200;
|
|
68
|
+
/**
|
|
69
|
+
* A `failed@0.0` verdict poisons the reward store, so it demands the tightest
|
|
70
|
+
* gate: real rejections ("стоп", "stop — wrong direction") are terse. Anything
|
|
71
|
+
* longer than this is an instruction that happens to contain a rejection word.
|
|
72
|
+
*/
|
|
73
|
+
const FAILED_MAX_LENGTH = 100;
|
|
68
74
|
/** Normalize a checkpoint response: trim, lowercase, strip trailing punctuation. */
|
|
69
75
|
function normalizeCheckpointText(text) {
|
|
70
76
|
return text.trim().toLowerCase().replace(/[\s.!…]+$/u, '');
|
|
71
77
|
}
|
|
78
|
+
/** Escape a literal string for embedding in a RegExp source. */
|
|
79
|
+
function escapeRegExp(literal) {
|
|
80
|
+
return literal.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Unicode-aware "standalone word" boundary, as lookarounds.
|
|
84
|
+
*
|
|
85
|
+
* CRITICAL: JS `\b` is ASCII-only — `\bпеределай\b` NEVER matches Cyrillic
|
|
86
|
+
* text because Cyrillic letters are non-word characters for `\b` (both sides
|
|
87
|
+
* of the "boundary" are non-word, so there is no boundary). Every RU/EN
|
|
88
|
+
* keyword must go through these lookarounds instead; no raw `\b` anywhere.
|
|
89
|
+
*
|
|
90
|
+
* The hyphen is treated as a joiner so glued/compound forms do not match:
|
|
91
|
+
* "напеределай", "stopwatch", "restop", "стоп-кран", "wrong-таки".
|
|
92
|
+
*/
|
|
93
|
+
const WORD_BEFORE = '(?<![\\p{L}\\p{N}-])';
|
|
94
|
+
const WORD_AFTER = '(?![\\p{L}\\p{N}-])';
|
|
95
|
+
/** True when `word` occurs in `text` as a standalone word (Unicode-aware). */
|
|
96
|
+
function hasStandaloneWord(text, word) {
|
|
97
|
+
const re = new RegExp(`${WORD_BEFORE}${escapeRegExp(word)}${WORD_AFTER}`, 'iu');
|
|
98
|
+
return re.test(text);
|
|
99
|
+
}
|
|
72
100
|
/**
|
|
73
|
-
*
|
|
74
|
-
*
|
|
101
|
+
* failed@0.0 — only when rejection is the ESSENCE of the message: the
|
|
102
|
+
* normalized text STARTS with a standalone rejection anchor. Mid-sentence
|
|
103
|
+
* mentions ("можешь добавить в stop hook…", "wrong-таки было") must NOT fire —
|
|
104
|
+
* a real misfire from the live store classified a normal instruction about a
|
|
105
|
+
* "stop hook" as failed@0.0.
|
|
106
|
+
*
|
|
107
|
+
* Documented choice: "стоп машина" starts with standalone "стоп" and DOES
|
|
108
|
+
* classify as failed — leading "стоп" as a word is accepted as a halt order.
|
|
109
|
+
*
|
|
110
|
+
* Applied to the normalized (trimmed, lowercased, punctuation-stripped) text.
|
|
111
|
+
*/
|
|
112
|
+
const FAILED_LEADING_RE = new RegExp(`^(?:стоп|stop|wrong|(?:это\\s+|вс[её]\\s+)?неправильно)${WORD_AFTER}`, 'u');
|
|
113
|
+
/**
|
|
114
|
+
* needs_work@0.3 — only ANCHORED imperative rework phrases, never bare
|
|
115
|
+
* keywords. Standalone-word matches anywhere in the message.
|
|
116
|
+
*/
|
|
117
|
+
const NEEDS_WORK_WORDS = [
|
|
118
|
+
'переделай',
|
|
119
|
+
'переделать',
|
|
120
|
+
'redo',
|
|
121
|
+
'rework',
|
|
122
|
+
'start over',
|
|
123
|
+
];
|
|
124
|
+
/**
|
|
125
|
+
* 'заново' fires ONLY inside imperative collocations ("сделай всё заново",
|
|
126
|
+
* "начни заново"). Bare 'заново' — and especially the idiom "не изобретать
|
|
127
|
+
* заново" (don't reinvent the wheel; a real misfire from the live store) —
|
|
128
|
+
* must NOT fire.
|
|
129
|
+
*/
|
|
130
|
+
const ZANOVO_IMPERATIVE_RE = new RegExp(`${WORD_BEFORE}(?:сделай|сделать|начни|начать|давай|начн[её]м)\\s+(?:вс[её]\\s+)?заново${WORD_AFTER}`, 'iu');
|
|
131
|
+
/**
|
|
132
|
+
* True for insights that are NOISE rather than reusable learnings, so both the
|
|
133
|
+
* ingest gate and the retro-prune step can drop them:
|
|
75
134
|
*
|
|
76
135
|
* - `Tool mcp__* invoked during session` (telemetry, no longer harvested)
|
|
77
136
|
* - `User responded: "<system wrapper…"` for every wrapper prefix recognized
|
|
78
137
|
* by {@link isSystemWrapper}, including session-continuation forms.
|
|
138
|
+
* - `User responded: "<bare approval>"` — a checkpoint approval echoed as a
|
|
139
|
+
* pattern (e.g. `продолжай`, `ok`, `да`). These are REWARD signal (which
|
|
140
|
+
* phase was approved), captured separately; as a recallable "pattern" they
|
|
141
|
+
* carry zero reusable insight and clutter `dz recall`. Gated by EXACT match
|
|
142
|
+
* (after {@link normalizeCheckpointText}) against {@link EXCELLENT_RESPONSES},
|
|
143
|
+
* so a SUBSTANTIVE response ("продолжай, но добавь X") is NOT flagged and is
|
|
144
|
+
* preserved — it may carry real signal.
|
|
79
145
|
*
|
|
80
146
|
* This predicate is the shared contract for the prune step.
|
|
81
147
|
*/
|
|
@@ -84,7 +150,16 @@ export function isNoiseInsight(text) {
|
|
|
84
150
|
return true;
|
|
85
151
|
const userPrefix = 'User responded: "';
|
|
86
152
|
if (text.startsWith(userPrefix)) {
|
|
87
|
-
|
|
153
|
+
const inner = text.slice(userPrefix.length);
|
|
154
|
+
if (isSystemWrapper(inner))
|
|
155
|
+
return true;
|
|
156
|
+
// Strip the trailing quote of the `User responded: "…"` wrapper, then
|
|
157
|
+
// normalize and require an EXACT match — reuses the existing approval
|
|
158
|
+
// vocabulary instead of duplicating it.
|
|
159
|
+
const approval = inner.replace(/"$/u, '');
|
|
160
|
+
if (EXCELLENT_RESPONSES.has(normalizeCheckpointText(approval)))
|
|
161
|
+
return true;
|
|
162
|
+
return false;
|
|
88
163
|
}
|
|
89
164
|
return false;
|
|
90
165
|
}
|
|
@@ -98,7 +173,10 @@ export function isNoiseInsight(text) {
|
|
|
98
173
|
* NOISE GATE (a real-store audit found ~85 of 91 records were junk):
|
|
99
174
|
* - Tool invocations are NOT harvested — a `tool_use` is telemetry, not a learning.
|
|
100
175
|
* - System wrappers arriving as user messages ({@link isSystemWrapper}) are skipped.
|
|
101
|
-
* -
|
|
176
|
+
* - Verdict classification only fires on checkpoint-like messages (≤ 200 chars,
|
|
177
|
+
* ≤ 100 for failed) and only on ANCHORED standalone words/phrases, never bare
|
|
178
|
+
* substrings — "в stop hook" and "не изобретать заново" are live-store
|
|
179
|
+
* misfires that bare substrings produced.
|
|
102
180
|
*/
|
|
103
181
|
export function harvestDreamPatterns(options) {
|
|
104
182
|
const { sessionsDir, since } = options;
|
|
@@ -135,17 +213,19 @@ export function harvestDreamPatterns(options) {
|
|
|
135
213
|
score = 1.0;
|
|
136
214
|
}
|
|
137
215
|
else if (trimmed.length <= CHECKPOINT_MAX_LENGTH) {
|
|
138
|
-
//
|
|
139
|
-
//
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
score = 0.3;
|
|
144
|
-
}
|
|
145
|
-
else if (text.includes('стоп') || text.includes('stop') || text.includes('wrong')) {
|
|
216
|
+
// Anchored verdicts only on checkpoint-like (short) messages.
|
|
217
|
+
// PRECISION over recall: a missed downgrade costs nothing (the
|
|
218
|
+
// 'good' outcome is not recorded), a false failed@0.0 poisons the
|
|
219
|
+
// reward store. When in doubt, do not classify.
|
|
220
|
+
if (trimmed.length <= FAILED_MAX_LENGTH && FAILED_LEADING_RE.test(normalized)) {
|
|
146
221
|
outcome = 'failed';
|
|
147
222
|
score = 0.0;
|
|
148
223
|
}
|
|
224
|
+
else if (NEEDS_WORK_WORDS.some((word) => hasStandaloneWord(trimmed, word)) ||
|
|
225
|
+
ZANOVO_IMPERATIVE_RE.test(trimmed)) {
|
|
226
|
+
outcome = 'needs_work';
|
|
227
|
+
score = 0.3;
|
|
228
|
+
}
|
|
149
229
|
}
|
|
150
230
|
if (outcome !== 'good') {
|
|
151
231
|
patterns.push({
|
package/dist/dreaming.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dreaming.js","sourceRoot":"","sources":["../src/dreaming.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAChE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAsBjC;;;;GAIG;AACH,MAAM,uBAAuB,GAAsB;IACjD,oBAAoB;IACpB,kBAAkB;IAClB,uBAAuB;IACvB,eAAe;IACf,aAAa;IACb,cAAc;IACd,sBAAsB;IACtB,sBAAsB;CACvB,CAAC;AAEF,0EAA0E;AAC1E,MAAM,uBAAuB,GAAG,mCAAmC,CAAC;AAEpE;;;;;;;;GAQG;AACH,MAAM,UAAU,eAAe,CAAC,IAAY;IAC1C,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;IAC5B,MAAM,KAAK,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IACpC,OAAO,CACL,uBAAuB,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;QAClE,uBAAuB,CAAC,IAAI,CAAC,OAAO,CAAC,CACtC,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,mBAAmB,GAAwB,IAAI,GAAG,CAAC;IACvD,IAAI;IACJ,IAAI;IACJ,MAAM;IACN,WAAW;IACX,IAAI;IACJ,QAAQ;IACR,SAAS;IACT,QAAQ;IACR,SAAS;IACT,MAAM;IACN,MAAM;IACN,eAAe;CAChB,CAAC,CAAC;AAEH;;;;GAIG;AACH,MAAM,qBAAqB,GAAG,GAAG,CAAC;AAElC,oFAAoF;AACpF,SAAS,uBAAuB,CAAC,IAAY;IAC3C,OAAO,IAAI,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC;AAC7D,CAAC;AAED
|
|
1
|
+
{"version":3,"file":"dreaming.js","sourceRoot":"","sources":["../src/dreaming.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/src/dreaming.ts
CHANGED
|
@@ -89,23 +89,102 @@ const EXCELLENT_RESPONSES: ReadonlySet<string> = new Set([
|
|
|
89
89
|
|
|
90
90
|
/**
|
|
91
91
|
* Only messages this short are considered checkpoint-like for the
|
|
92
|
-
* needs_work/failed
|
|
92
|
+
* needs_work/failed verdict checks. Longer messages routinely QUOTE words
|
|
93
93
|
* like 'stop' or 'переделай' without meaning them as verdicts.
|
|
94
94
|
*/
|
|
95
95
|
const CHECKPOINT_MAX_LENGTH = 200;
|
|
96
96
|
|
|
97
|
+
/**
|
|
98
|
+
* A `failed@0.0` verdict poisons the reward store, so it demands the tightest
|
|
99
|
+
* gate: real rejections ("стоп", "stop — wrong direction") are terse. Anything
|
|
100
|
+
* longer than this is an instruction that happens to contain a rejection word.
|
|
101
|
+
*/
|
|
102
|
+
const FAILED_MAX_LENGTH = 100;
|
|
103
|
+
|
|
97
104
|
/** Normalize a checkpoint response: trim, lowercase, strip trailing punctuation. */
|
|
98
105
|
function normalizeCheckpointText(text: string): string {
|
|
99
106
|
return text.trim().toLowerCase().replace(/[\s.!…]+$/u, '');
|
|
100
107
|
}
|
|
101
108
|
|
|
109
|
+
/** Escape a literal string for embedding in a RegExp source. */
|
|
110
|
+
function escapeRegExp(literal: string): string {
|
|
111
|
+
return literal.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Unicode-aware "standalone word" boundary, as lookarounds.
|
|
116
|
+
*
|
|
117
|
+
* CRITICAL: JS `\b` is ASCII-only — `\bпеределай\b` NEVER matches Cyrillic
|
|
118
|
+
* text because Cyrillic letters are non-word characters for `\b` (both sides
|
|
119
|
+
* of the "boundary" are non-word, so there is no boundary). Every RU/EN
|
|
120
|
+
* keyword must go through these lookarounds instead; no raw `\b` anywhere.
|
|
121
|
+
*
|
|
122
|
+
* The hyphen is treated as a joiner so glued/compound forms do not match:
|
|
123
|
+
* "напеределай", "stopwatch", "restop", "стоп-кран", "wrong-таки".
|
|
124
|
+
*/
|
|
125
|
+
const WORD_BEFORE = '(?<![\\p{L}\\p{N}-])';
|
|
126
|
+
const WORD_AFTER = '(?![\\p{L}\\p{N}-])';
|
|
127
|
+
|
|
128
|
+
/** True when `word` occurs in `text` as a standalone word (Unicode-aware). */
|
|
129
|
+
function hasStandaloneWord(text: string, word: string): boolean {
|
|
130
|
+
const re = new RegExp(`${WORD_BEFORE}${escapeRegExp(word)}${WORD_AFTER}`, 'iu');
|
|
131
|
+
return re.test(text);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* failed@0.0 — only when rejection is the ESSENCE of the message: the
|
|
136
|
+
* normalized text STARTS with a standalone rejection anchor. Mid-sentence
|
|
137
|
+
* mentions ("можешь добавить в stop hook…", "wrong-таки было") must NOT fire —
|
|
138
|
+
* a real misfire from the live store classified a normal instruction about a
|
|
139
|
+
* "stop hook" as failed@0.0.
|
|
140
|
+
*
|
|
141
|
+
* Documented choice: "стоп машина" starts with standalone "стоп" and DOES
|
|
142
|
+
* classify as failed — leading "стоп" as a word is accepted as a halt order.
|
|
143
|
+
*
|
|
144
|
+
* Applied to the normalized (trimmed, lowercased, punctuation-stripped) text.
|
|
145
|
+
*/
|
|
146
|
+
const FAILED_LEADING_RE = new RegExp(
|
|
147
|
+
`^(?:стоп|stop|wrong|(?:это\\s+|вс[её]\\s+)?неправильно)${WORD_AFTER}`,
|
|
148
|
+
'u',
|
|
149
|
+
);
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* needs_work@0.3 — only ANCHORED imperative rework phrases, never bare
|
|
153
|
+
* keywords. Standalone-word matches anywhere in the message.
|
|
154
|
+
*/
|
|
155
|
+
const NEEDS_WORK_WORDS: readonly string[] = [
|
|
156
|
+
'переделай',
|
|
157
|
+
'переделать',
|
|
158
|
+
'redo',
|
|
159
|
+
'rework',
|
|
160
|
+
'start over',
|
|
161
|
+
];
|
|
162
|
+
|
|
102
163
|
/**
|
|
103
|
-
*
|
|
104
|
-
*
|
|
164
|
+
* 'заново' fires ONLY inside imperative collocations ("сделай всё заново",
|
|
165
|
+
* "начни заново"). Bare 'заново' — and especially the idiom "не изобретать
|
|
166
|
+
* заново" (don't reinvent the wheel; a real misfire from the live store) —
|
|
167
|
+
* must NOT fire.
|
|
168
|
+
*/
|
|
169
|
+
const ZANOVO_IMPERATIVE_RE = new RegExp(
|
|
170
|
+
`${WORD_BEFORE}(?:сделай|сделать|начни|начать|давай|начн[её]м)\\s+(?:вс[её]\\s+)?заново${WORD_AFTER}`,
|
|
171
|
+
'iu',
|
|
172
|
+
);
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* True for insights that are NOISE rather than reusable learnings, so both the
|
|
176
|
+
* ingest gate and the retro-prune step can drop them:
|
|
105
177
|
*
|
|
106
178
|
* - `Tool mcp__* invoked during session` (telemetry, no longer harvested)
|
|
107
179
|
* - `User responded: "<system wrapper…"` for every wrapper prefix recognized
|
|
108
180
|
* by {@link isSystemWrapper}, including session-continuation forms.
|
|
181
|
+
* - `User responded: "<bare approval>"` — a checkpoint approval echoed as a
|
|
182
|
+
* pattern (e.g. `продолжай`, `ok`, `да`). These are REWARD signal (which
|
|
183
|
+
* phase was approved), captured separately; as a recallable "pattern" they
|
|
184
|
+
* carry zero reusable insight and clutter `dz recall`. Gated by EXACT match
|
|
185
|
+
* (after {@link normalizeCheckpointText}) against {@link EXCELLENT_RESPONSES},
|
|
186
|
+
* so a SUBSTANTIVE response ("продолжай, но добавь X") is NOT flagged and is
|
|
187
|
+
* preserved — it may carry real signal.
|
|
109
188
|
*
|
|
110
189
|
* This predicate is the shared contract for the prune step.
|
|
111
190
|
*/
|
|
@@ -113,7 +192,14 @@ export function isNoiseInsight(text: string): boolean {
|
|
|
113
192
|
if (/^Tool mcp__.+ invoked during session$/.test(text)) return true;
|
|
114
193
|
const userPrefix = 'User responded: "';
|
|
115
194
|
if (text.startsWith(userPrefix)) {
|
|
116
|
-
|
|
195
|
+
const inner = text.slice(userPrefix.length);
|
|
196
|
+
if (isSystemWrapper(inner)) return true;
|
|
197
|
+
// Strip the trailing quote of the `User responded: "…"` wrapper, then
|
|
198
|
+
// normalize and require an EXACT match — reuses the existing approval
|
|
199
|
+
// vocabulary instead of duplicating it.
|
|
200
|
+
const approval = inner.replace(/"$/u, '');
|
|
201
|
+
if (EXCELLENT_RESPONSES.has(normalizeCheckpointText(approval))) return true;
|
|
202
|
+
return false;
|
|
117
203
|
}
|
|
118
204
|
return false;
|
|
119
205
|
}
|
|
@@ -128,7 +214,10 @@ export function isNoiseInsight(text: string): boolean {
|
|
|
128
214
|
* NOISE GATE (a real-store audit found ~85 of 91 records were junk):
|
|
129
215
|
* - Tool invocations are NOT harvested — a `tool_use` is telemetry, not a learning.
|
|
130
216
|
* - System wrappers arriving as user messages ({@link isSystemWrapper}) are skipped.
|
|
131
|
-
* -
|
|
217
|
+
* - Verdict classification only fires on checkpoint-like messages (≤ 200 chars,
|
|
218
|
+
* ≤ 100 for failed) and only on ANCHORED standalone words/phrases, never bare
|
|
219
|
+
* substrings — "в stop hook" and "не изобретать заново" are live-store
|
|
220
|
+
* misfires that bare substrings produced.
|
|
132
221
|
*/
|
|
133
222
|
export function harvestDreamPatterns(options: DreamOptions): DreamPattern[] {
|
|
134
223
|
const { sessionsDir, since } = options;
|
|
@@ -169,15 +258,19 @@ export function harvestDreamPatterns(options: DreamOptions): DreamPattern[] {
|
|
|
169
258
|
outcome = 'excellent';
|
|
170
259
|
score = 1.0;
|
|
171
260
|
} else if (trimmed.length <= CHECKPOINT_MAX_LENGTH) {
|
|
172
|
-
//
|
|
173
|
-
//
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
score = 0.3;
|
|
178
|
-
} else if (text.includes('стоп') || text.includes('stop') || text.includes('wrong')) {
|
|
261
|
+
// Anchored verdicts only on checkpoint-like (short) messages.
|
|
262
|
+
// PRECISION over recall: a missed downgrade costs nothing (the
|
|
263
|
+
// 'good' outcome is not recorded), a false failed@0.0 poisons the
|
|
264
|
+
// reward store. When in doubt, do not classify.
|
|
265
|
+
if (trimmed.length <= FAILED_MAX_LENGTH && FAILED_LEADING_RE.test(normalized)) {
|
|
179
266
|
outcome = 'failed';
|
|
180
267
|
score = 0.0;
|
|
268
|
+
} else if (
|
|
269
|
+
NEEDS_WORK_WORDS.some((word) => hasStandaloneWord(trimmed, word)) ||
|
|
270
|
+
ZANOVO_IMPERATIVE_RE.test(trimmed)
|
|
271
|
+
) {
|
|
272
|
+
outcome = 'needs_work';
|
|
273
|
+
score = 0.3;
|
|
181
274
|
}
|
|
182
275
|
}
|
|
183
276
|
|