mem-os-python 1.6.27__py3-none-any.whl

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.
Files changed (253) hide show
  1. mem_os_python-1.6.27.dist-info/METADATA +1032 -0
  2. mem_os_python-1.6.27.dist-info/RECORD +253 -0
  3. mem_os_python-1.6.27.dist-info/WHEEL +4 -0
  4. mem_os_python-1.6.27.dist-info/entry_points.txt +2 -0
  5. mem_os_python-1.6.27.dist-info/licenses/LICENSE +21 -0
  6. memos/__init__.py +16 -0
  7. memos/_js/adapters/anthropic.d.ts +279 -0
  8. memos/_js/adapters/anthropic.d.ts.map +1 -0
  9. memos/_js/adapters/anthropic.js +348 -0
  10. memos/_js/adapters/anthropic.js.map +1 -0
  11. memos/_js/adapters/base.d.ts +10 -0
  12. memos/_js/adapters/base.d.ts.map +1 -0
  13. memos/_js/adapters/base.js +2 -0
  14. memos/_js/adapters/base.js.map +1 -0
  15. memos/_js/adapters/openai.d.ts +264 -0
  16. memos/_js/adapters/openai.d.ts.map +1 -0
  17. memos/_js/adapters/openai.js +342 -0
  18. memos/_js/adapters/openai.js.map +1 -0
  19. memos/_js/apps/explorer.d.ts +244 -0
  20. memos/_js/apps/explorer.d.ts.map +1 -0
  21. memos/_js/apps/explorer.js +738 -0
  22. memos/_js/apps/explorer.js.map +1 -0
  23. memos/_js/citations.d.ts +65 -0
  24. memos/_js/citations.d.ts.map +1 -0
  25. memos/_js/citations.js +143 -0
  26. memos/_js/citations.js.map +1 -0
  27. memos/_js/cli-browse.d.ts +3 -0
  28. memos/_js/cli-browse.d.ts.map +1 -0
  29. memos/_js/cli-browse.js +129 -0
  30. memos/_js/cli-browse.js.map +1 -0
  31. memos/_js/cli-completion.d.ts +31 -0
  32. memos/_js/cli-completion.d.ts.map +1 -0
  33. memos/_js/cli-completion.js +340 -0
  34. memos/_js/cli-completion.js.map +1 -0
  35. memos/_js/cli-help.d.ts +18 -0
  36. memos/_js/cli-help.d.ts.map +1 -0
  37. memos/_js/cli-help.js +357 -0
  38. memos/_js/cli-help.js.map +1 -0
  39. memos/_js/cli.d.ts +28 -0
  40. memos/_js/cli.d.ts.map +1 -0
  41. memos/_js/cli.js +2880 -0
  42. memos/_js/cli.js.map +1 -0
  43. memos/_js/compression.d.ts +25 -0
  44. memos/_js/compression.d.ts.map +1 -0
  45. memos/_js/compression.js +319 -0
  46. memos/_js/compression.js.map +1 -0
  47. memos/_js/confidence-machine.d.ts +99 -0
  48. memos/_js/confidence-machine.d.ts.map +1 -0
  49. memos/_js/confidence-machine.js +222 -0
  50. memos/_js/confidence-machine.js.map +1 -0
  51. memos/_js/context-pack.d.ts +506 -0
  52. memos/_js/context-pack.d.ts.map +1 -0
  53. memos/_js/context-pack.js +1435 -0
  54. memos/_js/context-pack.js.map +1 -0
  55. memos/_js/contradictions.d.ts +160 -0
  56. memos/_js/contradictions.d.ts.map +1 -0
  57. memos/_js/contradictions.js +255 -0
  58. memos/_js/contradictions.js.map +1 -0
  59. memos/_js/dashboard.d.ts +30 -0
  60. memos/_js/dashboard.d.ts.map +1 -0
  61. memos/_js/dashboard.js +302 -0
  62. memos/_js/dashboard.js.map +1 -0
  63. memos/_js/ebbinghaus.d.ts +29 -0
  64. memos/_js/ebbinghaus.d.ts.map +1 -0
  65. memos/_js/ebbinghaus.js +32 -0
  66. memos/_js/ebbinghaus.js.map +1 -0
  67. memos/_js/embedding-queue.d.ts +190 -0
  68. memos/_js/embedding-queue.d.ts.map +1 -0
  69. memos/_js/embedding-queue.js +316 -0
  70. memos/_js/embedding-queue.js.map +1 -0
  71. memos/_js/embeddings.d.ts +187 -0
  72. memos/_js/embeddings.d.ts.map +1 -0
  73. memos/_js/embeddings.js +633 -0
  74. memos/_js/embeddings.js.map +1 -0
  75. memos/_js/entity-extraction.d.ts +54 -0
  76. memos/_js/entity-extraction.d.ts.map +1 -0
  77. memos/_js/entity-extraction.js +325 -0
  78. memos/_js/entity-extraction.js.map +1 -0
  79. memos/_js/entity-index.d.ts +93 -0
  80. memos/_js/entity-index.d.ts.map +1 -0
  81. memos/_js/entity-index.js +165 -0
  82. memos/_js/entity-index.js.map +1 -0
  83. memos/_js/event-memory.d.ts +147 -0
  84. memos/_js/event-memory.d.ts.map +1 -0
  85. memos/_js/event-memory.js +290 -0
  86. memos/_js/event-memory.js.map +1 -0
  87. memos/_js/external-import.d.ts +98 -0
  88. memos/_js/external-import.d.ts.map +1 -0
  89. memos/_js/external-import.js +669 -0
  90. memos/_js/external-import.js.map +1 -0
  91. memos/_js/fidelity.d.ts +367 -0
  92. memos/_js/fidelity.d.ts.map +1 -0
  93. memos/_js/fidelity.js +911 -0
  94. memos/_js/fidelity.js.map +1 -0
  95. memos/_js/graph-expansion.d.ts +119 -0
  96. memos/_js/graph-expansion.d.ts.map +1 -0
  97. memos/_js/graph-expansion.js +213 -0
  98. memos/_js/graph-expansion.js.map +1 -0
  99. memos/_js/graph-mermaid.d.ts +13 -0
  100. memos/_js/graph-mermaid.d.ts.map +1 -0
  101. memos/_js/graph-mermaid.js +32 -0
  102. memos/_js/graph-mermaid.js.map +1 -0
  103. memos/_js/graph.d.ts +170 -0
  104. memos/_js/graph.d.ts.map +1 -0
  105. memos/_js/graph.js +482 -0
  106. memos/_js/graph.js.map +1 -0
  107. memos/_js/harness.d.ts +63 -0
  108. memos/_js/harness.d.ts.map +1 -0
  109. memos/_js/harness.js +93 -0
  110. memos/_js/harness.js.map +1 -0
  111. memos/_js/importance.d.ts +118 -0
  112. memos/_js/importance.d.ts.map +1 -0
  113. memos/_js/importance.js +144 -0
  114. memos/_js/importance.js.map +1 -0
  115. memos/_js/index.d.ts +51 -0
  116. memos/_js/index.d.ts.map +1 -0
  117. memos/_js/index.js +53 -0
  118. memos/_js/index.js.map +1 -0
  119. memos/_js/mcp.d.ts +58 -0
  120. memos/_js/mcp.d.ts.map +1 -0
  121. memos/_js/mcp.js +1853 -0
  122. memos/_js/mcp.js.map +1 -0
  123. memos/_js/memory.d.ts +1762 -0
  124. memos/_js/memory.d.ts.map +1 -0
  125. memos/_js/memory.js +6283 -0
  126. memos/_js/memory.js.map +1 -0
  127. memos/_js/procedural.d.ts +74 -0
  128. memos/_js/procedural.d.ts.map +1 -0
  129. memos/_js/procedural.js +125 -0
  130. memos/_js/procedural.js.map +1 -0
  131. memos/_js/project-config.d.ts +68 -0
  132. memos/_js/project-config.d.ts.map +1 -0
  133. memos/_js/project-config.js +59 -0
  134. memos/_js/project-config.js.map +1 -0
  135. memos/_js/proof-of-forgetting.d.ts +57 -0
  136. memos/_js/proof-of-forgetting.d.ts.map +1 -0
  137. memos/_js/proof-of-forgetting.js +80 -0
  138. memos/_js/proof-of-forgetting.js.map +1 -0
  139. memos/_js/provenance.d.ts +122 -0
  140. memos/_js/provenance.d.ts.map +1 -0
  141. memos/_js/provenance.js +182 -0
  142. memos/_js/provenance.js.map +1 -0
  143. memos/_js/quarantine-commands.d.ts +23 -0
  144. memos/_js/quarantine-commands.d.ts.map +1 -0
  145. memos/_js/quarantine-commands.js +42 -0
  146. memos/_js/quarantine-commands.js.map +1 -0
  147. memos/_js/quarantine.d.ts +120 -0
  148. memos/_js/quarantine.d.ts.map +1 -0
  149. memos/_js/quarantine.js +873 -0
  150. memos/_js/quarantine.js.map +1 -0
  151. memos/_js/redact.d.ts +12 -0
  152. memos/_js/redact.d.ts.map +1 -0
  153. memos/_js/redact.js +26 -0
  154. memos/_js/redact.js.map +1 -0
  155. memos/_js/repl.d.ts +57 -0
  156. memos/_js/repl.d.ts.map +1 -0
  157. memos/_js/repl.js +295 -0
  158. memos/_js/repl.js.map +1 -0
  159. memos/_js/rerank-local.d.ts +61 -0
  160. memos/_js/rerank-local.d.ts.map +1 -0
  161. memos/_js/rerank-local.js +210 -0
  162. memos/_js/rerank-local.js.map +1 -0
  163. memos/_js/retain-filter.d.ts +98 -0
  164. memos/_js/retain-filter.d.ts.map +1 -0
  165. memos/_js/retain-filter.js +232 -0
  166. memos/_js/retain-filter.js.map +1 -0
  167. memos/_js/retrieval.d.ts +265 -0
  168. memos/_js/retrieval.d.ts.map +1 -0
  169. memos/_js/retrieval.js +1018 -0
  170. memos/_js/retrieval.js.map +1 -0
  171. memos/_js/revert.d.ts +77 -0
  172. memos/_js/revert.d.ts.map +1 -0
  173. memos/_js/revert.js +252 -0
  174. memos/_js/revert.js.map +1 -0
  175. memos/_js/scope.d.ts +30 -0
  176. memos/_js/scope.d.ts.map +1 -0
  177. memos/_js/scope.js +71 -0
  178. memos/_js/scope.js.map +1 -0
  179. memos/_js/semantic-screen.d.ts +152 -0
  180. memos/_js/semantic-screen.d.ts.map +1 -0
  181. memos/_js/semantic-screen.js +290 -0
  182. memos/_js/semantic-screen.js.map +1 -0
  183. memos/_js/session-hooks.d.ts +127 -0
  184. memos/_js/session-hooks.d.ts.map +1 -0
  185. memos/_js/session-hooks.js +482 -0
  186. memos/_js/session-hooks.js.map +1 -0
  187. memos/_js/storage/sqlite.d.ts +427 -0
  188. memos/_js/storage/sqlite.d.ts.map +1 -0
  189. memos/_js/storage/sqlite.js +2428 -0
  190. memos/_js/storage/sqlite.js.map +1 -0
  191. memos/_js/sync.d.ts +213 -0
  192. memos/_js/sync.d.ts.map +1 -0
  193. memos/_js/sync.js +389 -0
  194. memos/_js/sync.js.map +1 -0
  195. memos/_js/tamper-log.d.ts +98 -0
  196. memos/_js/tamper-log.d.ts.map +1 -0
  197. memos/_js/tamper-log.js +327 -0
  198. memos/_js/tamper-log.js.map +1 -0
  199. memos/_js/temporal.d.ts +92 -0
  200. memos/_js/temporal.d.ts.map +1 -0
  201. memos/_js/temporal.js +536 -0
  202. memos/_js/temporal.js.map +1 -0
  203. memos/_js/time-travel.d.ts +38 -0
  204. memos/_js/time-travel.d.ts.map +1 -0
  205. memos/_js/time-travel.js +46 -0
  206. memos/_js/time-travel.js.map +1 -0
  207. memos/_js/timestamp-format.d.ts +18 -0
  208. memos/_js/timestamp-format.d.ts.map +1 -0
  209. memos/_js/timestamp-format.js +52 -0
  210. memos/_js/timestamp-format.js.map +1 -0
  211. memos/_js/triple-extraction.d.ts +31 -0
  212. memos/_js/triple-extraction.d.ts.map +1 -0
  213. memos/_js/triple-extraction.js +116 -0
  214. memos/_js/triple-extraction.js.map +1 -0
  215. memos/_js/types.d.ts +2474 -0
  216. memos/_js/types.d.ts.map +1 -0
  217. memos/_js/types.js +20 -0
  218. memos/_js/types.js.map +1 -0
  219. memos/_js/updater.d.ts +95 -0
  220. memos/_js/updater.d.ts.map +1 -0
  221. memos/_js/updater.js +268 -0
  222. memos/_js/updater.js.map +1 -0
  223. memos/_js/version.d.ts +17 -0
  224. memos/_js/version.d.ts.map +1 -0
  225. memos/_js/version.js +34 -0
  226. memos/_js/version.js.map +1 -0
  227. memos/_js/vision/clip-query-cache.d.ts +58 -0
  228. memos/_js/vision/clip-query-cache.d.ts.map +1 -0
  229. memos/_js/vision/clip-query-cache.js +79 -0
  230. memos/_js/vision/clip-query-cache.js.map +1 -0
  231. memos/_js/vision/clip.d.ts +113 -0
  232. memos/_js/vision/clip.d.ts.map +1 -0
  233. memos/_js/vision/clip.js +224 -0
  234. memos/_js/vision/clip.js.map +1 -0
  235. memos/_js/vision/fake-clip.d.ts +55 -0
  236. memos/_js/vision/fake-clip.d.ts.map +1 -0
  237. memos/_js/vision/fake-clip.js +122 -0
  238. memos/_js/vision/fake-clip.js.map +1 -0
  239. memos/_js/vision/index.d.ts +15 -0
  240. memos/_js/vision/index.d.ts.map +1 -0
  241. memos/_js/vision/index.js +13 -0
  242. memos/_js/vision/index.js.map +1 -0
  243. memos/_js/vision/store.d.ts +137 -0
  244. memos/_js/vision/store.d.ts.map +1 -0
  245. memos/_js/vision/store.js +383 -0
  246. memos/_js/vision/store.js.map +1 -0
  247. memos/adapters/__init__.py +0 -0
  248. memos/adapters/crewai.py +385 -0
  249. memos/adapters/langchain.py +301 -0
  250. memos/adapters/ollama.py +396 -0
  251. memos/server/__init__.py +0 -0
  252. memos/server/main.py +547 -0
  253. memos/server/routes.py +360 -0
@@ -0,0 +1,210 @@
1
+ /**
2
+ * ─── Local cross-encoder reranking ──────────────────────────────────────────
3
+ *
4
+ * In-process alternative to the HTTP `/rerank` endpoint path in
5
+ * `MemOS.applyRerank`. Loads a sequence-classification cross-encoder
6
+ * (default `Xenova/bge-reranker-base`, ~280 MB) through
7
+ * `@huggingface/transformers` (falling back to `@xenova/transformers`),
8
+ * scores `[query, document]` pairs, and returns sigmoid-squashed relevance
9
+ * scores in [0,1].
10
+ *
11
+ * Design rules (same as the endpoint path):
12
+ * - Opt-in only: nothing here runs unless `experimental.rerank` selects the
13
+ * local provider (or `MEMOS_RERANK_LOCAL=1`).
14
+ * - Any failure — missing package, model download failure, inference
15
+ * error — returns `null` so the caller keeps the fused ranking. A broken
16
+ * reranker degrades quality, never availability.
17
+ * - The model is loaded once per (model, dtype) and reused; the download
18
+ * happens on first use, so the first reranked query pays for it.
19
+ */
20
+ import { createRequire } from "node:module";
21
+ export const DEFAULT_LOCAL_RERANK_MODEL = "Xenova/bge-reranker-base";
22
+ /** Default quantization for local rerank inference. q8 is ~4x faster on CPU. */
23
+ export const DEFAULT_LOCAL_RERANK_DTYPE = "q8";
24
+ // ─── test seam ──────────────────────────────────────────────────────────────
25
+ let testLoader = null;
26
+ /** Test-only override for the model loader (stubbed inference, no download). */
27
+ export function __setLocalRerankLoaderForTests(loader) {
28
+ testLoader = loader;
29
+ }
30
+ const modelCache = new Map();
31
+ let warnedMissingPackage = false;
32
+ /**
33
+ * Tokenize (query, doc) pairs for the cross-encoder. Tries the fast batched
34
+ * path first; some tokenizers (XLM-R family in transformers.js v4) throw on
35
+ * batched pair input (`text.replace is not a function`), in which case we
36
+ * fall back to per-pair tokenization with manual padding. Exported for tests.
37
+ */
38
+ export async function tokenizePairsForRerank(tokenizer, pairs, maxLength) {
39
+ try {
40
+ return await tokenizer(pairs, {
41
+ padding: true,
42
+ truncation: true,
43
+ max_length: maxLength,
44
+ });
45
+ }
46
+ catch {
47
+ const allIds = [];
48
+ const allMasks = [];
49
+ for (const [q, d] of pairs) {
50
+ const t = await tokenizer(q, {
51
+ text_pair: d,
52
+ truncation: true,
53
+ max_length: maxLength,
54
+ });
55
+ allIds.push(Array.from(t["input_ids"].data));
56
+ allMasks.push(Array.from(t["attention_mask"].data));
57
+ }
58
+ const ml = Math.max(...allIds.map((a) => a.length));
59
+ const B = pairs.length;
60
+ const padId = BigInt(tokenizer.pad_token_id ?? 1);
61
+ const inputIds = new BigInt64Array(B * ml);
62
+ const attnMask = new BigInt64Array(B * ml);
63
+ allIds.forEach((arr, i) => {
64
+ for (let j = 0; j < ml; j++) {
65
+ inputIds[i * ml + j] = j < arr.length ? BigInt(arr[j]) : padId;
66
+ attnMask[i * ml + j] = j < arr.length ? BigInt(allMasks[i][j]) : 0n;
67
+ }
68
+ });
69
+ return {
70
+ input_ids: { type: "int64", data: inputIds, dims: [B, ml] },
71
+ attention_mask: { type: "int64", data: attnMask, dims: [B, ml] },
72
+ };
73
+ }
74
+ }
75
+ async function defaultLoader(model, dtype, maxLength) {
76
+ const key = `${model}::${dtype}::${maxLength}`;
77
+ let cached = modelCache.get(key);
78
+ if (!cached) {
79
+ cached = (async () => {
80
+ // Both packages are optional peer deps. We load them with
81
+ // `createRequire` (not dynamic `import()`): the ESM entry of
82
+ // `@huggingface/transformers` v4 does a named import from the CJS
83
+ // `onnxruntime-common` that Node's ESM loader rejects, while the
84
+ // CJS build loads fine.
85
+ const require = createRequire(import.meta.url);
86
+ let spec = null;
87
+ let resolved = null;
88
+ for (const candidate of [
89
+ "@huggingface/transformers",
90
+ "@xenova/transformers",
91
+ ]) {
92
+ try {
93
+ resolved = require(candidate);
94
+ spec = candidate;
95
+ break;
96
+ }
97
+ catch {
98
+ // try the next package
99
+ }
100
+ }
101
+ if (!resolved || !spec) {
102
+ if (!warnedMissingPackage) {
103
+ warnedMissingPackage = true;
104
+ console.warn("[memos] local rerank unavailable: neither @huggingface/transformers " +
105
+ "nor @xenova/transformers is installed — keeping fused ranking. " +
106
+ "Install one of them to enable local reranking.");
107
+ }
108
+ return null;
109
+ }
110
+ try {
111
+ const tokenizer = await resolved.AutoTokenizer.from_pretrained(model);
112
+ const mdl = await resolved.AutoModelForSequenceClassification.from_pretrained(model, { dtype });
113
+ // Raw InferenceSession: transformers.js v4 wraps input tensors in a
114
+ // way the installed onnxruntime-native binding rejects
115
+ // ("Tensor.location must be a string" — version skew between the
116
+ // wrapper and onnxruntime-node 1.30). Driving the session directly
117
+ // with tensors built from the package's OWN onnxruntime copy avoids
118
+ // the skew entirely.
119
+ const session = mdl.sessions?.["model"] ?? mdl.session;
120
+ if (!session) {
121
+ throw new Error("no inference session exposed on the loaded model");
122
+ }
123
+ const ortRequire = createRequire(require.resolve(spec));
124
+ const ort = ortRequire("onnxruntime-node");
125
+ const inputNames = session.inputNames;
126
+ return {
127
+ async scorePairs(pairs) {
128
+ const batch = await tokenizePairsForRerank(tokenizer, pairs, maxLength);
129
+ const feeds = {};
130
+ const batchDims = batch["input_ids"]?.dims;
131
+ for (const name of inputNames) {
132
+ let t = batch[name];
133
+ if (!t && name === "token_type_ids" && batchDims) {
134
+ // BERT-style models expect segment ids; tokenizers for
135
+ // single-pair cross-encoders sometimes omit them (all zeros
136
+ // is correct for [query, doc] pairs).
137
+ const size = batchDims.reduce((a, b) => a * b, 1);
138
+ t = {
139
+ type: "int64",
140
+ data: new BigInt64Array(size),
141
+ dims: [...batchDims],
142
+ };
143
+ }
144
+ if (!t)
145
+ continue;
146
+ feeds[name] = new ort.Tensor(t.type, t.data, t.dims);
147
+ }
148
+ const out = await session.run(feeds);
149
+ const logits = out["logits"] ?? out[Object.keys(out)[0]];
150
+ if (!logits)
151
+ throw new Error("model returned no outputs");
152
+ const data = logits.data;
153
+ const rowSize = logits.dims.length >= 2
154
+ ? logits.dims[logits.dims.length - 1]
155
+ : 1;
156
+ const result = [];
157
+ for (let i = 0; i < pairs.length; i += 1) {
158
+ result.push(Number(data[i * rowSize]));
159
+ }
160
+ return result;
161
+ },
162
+ };
163
+ }
164
+ catch (err) {
165
+ console.error("[memos] local rerank model failed to load " +
166
+ `("${model}", dtype "${dtype}") — keeping fused ranking:`, err instanceof Error ? err.message : String(err));
167
+ return null;
168
+ }
169
+ })();
170
+ modelCache.set(key, cached);
171
+ }
172
+ return cached;
173
+ }
174
+ function sigmoid(x) {
175
+ return 1 / (1 + Math.exp(-x));
176
+ }
177
+ /**
178
+ * Score each document against the query with the local cross-encoder.
179
+ * Returns sigmoid-squashed scores in input order, or `null` when the
180
+ * reranker is unavailable — the caller must keep the fused ranking.
181
+ */
182
+ export async function scorePairsLocal(query, docs, opts = {}) {
183
+ if (docs.length === 0)
184
+ return [];
185
+ const model = opts.model ?? DEFAULT_LOCAL_RERANK_MODEL;
186
+ const dtype = opts.dtype ?? DEFAULT_LOCAL_RERANK_DTYPE;
187
+ const maxLength = opts.maxLength ?? 512;
188
+ const loader = testLoader ?? defaultLoader;
189
+ let loaded;
190
+ try {
191
+ loaded = await loader(model, dtype, maxLength);
192
+ }
193
+ catch {
194
+ return null;
195
+ }
196
+ if (!loaded)
197
+ return null;
198
+ try {
199
+ const pairs = docs.map((doc) => [query, doc]);
200
+ const logits = await loaded.scorePairs(pairs);
201
+ if (logits.length !== docs.length)
202
+ return null;
203
+ return logits.map(sigmoid);
204
+ }
205
+ catch (err) {
206
+ console.error("[memos] local rerank inference failed — keeping fused ranking:", err instanceof Error ? err.message : String(err));
207
+ return null;
208
+ }
209
+ }
210
+ //# sourceMappingURL=rerank-local.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rerank-local.js","sourceRoot":"","sources":["../src/rerank-local.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,98 @@
1
+ /**
2
+ * Retain pre-filter for MemOS memory writes (v1.6.26).
3
+ *
4
+ * Hermes-style signal gate (cf. NousResearch/hermes-agent #16834): a cheap
5
+ * local classifier that decides whether a piece of content is worth storing in
6
+ * long-term memory before the write happens. Without this, every turn —
7
+ * including low-signal acknowledgements, chit-chat, and retries — enters
8
+ * memory and later bloats context-packs, costing retrieval tokens and diluting
9
+ * relevance ranking.
10
+ *
11
+ * Default mode is a ZERO-LLM-CALL local classifier (keeps MemOS fast and
12
+ * local). The *decision* is conservative-first: a write is skipped only
13
+ * on positive evidence of noise (empty content, pure acknowledgements,
14
+ * fragments, near-duplicates of existing same-scope memories) — when in
15
+ * doubt the memory is kept, because a false skip silently loses user
16
+ * data. The *score* (0–1) separately estimates signal density from
17
+ * length, entity/code presence, action verbs, and novelty, and is
18
+ * reported for debugging/telemetry. An optional custom classifier can
19
+ * be injected via `setRetainClassifier()`.
20
+ *
21
+ * @module @mem-os/sdk/retain-filter
22
+ */
23
+ /** Inputs the retain gate uses to make its decision. */
24
+ export interface RetainInput {
25
+ /** The content proposed for storage. */
26
+ content: string;
27
+ /**
28
+ * Existing memory content in the same namespace (for novelty detection).
29
+ * Optional; when absent, novelty is assumed maximal.
30
+ */
31
+ existingContent?: string[];
32
+ }
33
+ /** The gate's verdict plus the score that drove it. */
34
+ export interface RetainDecision {
35
+ /** True = store the content. */
36
+ retain: boolean;
37
+ /** Signal-density score in [0, 1]. Higher = more worth storing. */
38
+ score: number;
39
+ /** Human-readable reason for the decision (for debugging). */
40
+ reason: string;
41
+ }
42
+ /** Score at or above which content is retained. */
43
+ declare const RETAIN_THRESHOLD = 0.3;
44
+ /**
45
+ * Does this content read as a correction of something already stored?
46
+ *
47
+ * The gate's near-duplicate rule exists to stop *identical restatements*
48
+ * from re-entering memory. A negation/retraction ("user no longer lives in
49
+ * Berlin", "switched from vim to neovim") is deliberately NOT a duplicate —
50
+ * it is the update the confidence lifecycle exists to process, and it
51
+ * arrives sharing most of its tokens with the memory it retracts (a
52
+ * retraction necessarily names the same subject). Dropping it as a
53
+ * "near-duplicate" is how a retraction silently never reaches the
54
+ * confidence machine, leaving the old belief in place at full weight.
55
+ * This check reuses the SAME signal list as `classifyEvidence` so the gate
56
+ * and the state machine cannot drift apart.
57
+ */
58
+ export declare function carriesContradictionSignal(content: string): boolean;
59
+ /**
60
+ * Max token overlap of `content` against any entry of `existingContent`
61
+ * (0–1). Tokens are lowercase alphanumeric words longer than 2 chars.
62
+ */
63
+ export declare function maxTokenOverlap(content: string, existingContent: string[]): number;
64
+ /**
65
+ * Default local classifier: scores content on signal density (0-1).
66
+ *
67
+ * Components:
68
+ * - Length floor: tiny content scores ~0.
69
+ * - Signal density: entities / code refs / numbers per 100 chars.
70
+ * - Action / preference verbs: factual statements score higher.
71
+ * - Low-signal penalty: pure acknowledgements score ~0.
72
+ * - Novelty: down-weight content that duplicates existing memory.
73
+ *
74
+ * No LLM call, no I/O — runs in well under 1ms.
75
+ */
76
+ export declare function scoreRetain(input: RetainInput): number;
77
+ /**
78
+ * Decide whether to retain (store) content. Default uses the local
79
+ * classifier; callers can inject a custom classifier via
80
+ * `setRetainClassifier()`.
81
+ *
82
+ * Conservative-first contract (the accuracy gate): a write is skipped
83
+ * ONLY on positive evidence of noise —
84
+ * 1. empty content,
85
+ * 2. a pure acknowledgement ("ok", "thanks", "ok ok ok", …),
86
+ * 3. a fragment with almost no alphanumeric content ("...", "k"),
87
+ * 4. a near-duplicate of an existing same-scope memory.
88
+ * Everything else is retained. When in doubt, keep the memory — a
89
+ * false skip silently loses user data, while a false keep only costs a
90
+ * little storage. `score` still reports the signal-density estimate
91
+ * from `scoreRetain` for debugging/telemetry.
92
+ */
93
+ export declare function shouldRetain(input: RetainInput): RetainDecision;
94
+ export declare function setRetainClassifier(classifier?: (input: RetainInput) => RetainDecision): void;
95
+ /** Decide whether to retain, using the custom classifier if installed. */
96
+ export declare function decideRetain(input: RetainInput): RetainDecision;
97
+ export { RETAIN_THRESHOLD };
98
+ //# sourceMappingURL=retain-filter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retain-filter.d.ts","sourceRoot":"","sources":["../src/retain-filter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAIH,wDAAwD;AACxD,MAAM,WAAW,WAAW;IAC1B,wCAAwC;IACxC,OAAO,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;CAC5B;AAED,uDAAuD;AACvD,MAAM,WAAW,cAAc;IAC7B,gCAAgC;IAChC,MAAM,EAAE,OAAO,CAAC;IAChB,mEAAmE;IACnE,KAAK,EAAE,MAAM,CAAC;IACd,8DAA8D;IAC9D,MAAM,EAAE,MAAM,CAAC;CAChB;AAID,mDAAmD;AACnD,QAAA,MAAM,gBAAgB,MAAM,CAAC;AA+C7B;;;;;;;;;;;;;GAaG;AACH,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAGnE;AAKD;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,OAAO,EAAE,MAAM,EACf,eAAe,EAAE,MAAM,EAAE,GACxB,MAAM,CAqBR;AAeD;;;;;;;;;;;GAWG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CAmCtD;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,WAAW,GAAG,cAAc,CA0C/D;AAQD,wBAAgB,mBAAmB,CACjC,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,cAAc,GAClD,IAAI,CAEN;AAED,0EAA0E;AAC1E,wBAAgB,YAAY,CAAC,KAAK,EAAE,WAAW,GAAG,cAAc,CAG/D;AAED,OAAO,EAAE,gBAAgB,EAAE,CAAC"}
@@ -0,0 +1,232 @@
1
+ /**
2
+ * Retain pre-filter for MemOS memory writes (v1.6.26).
3
+ *
4
+ * Hermes-style signal gate (cf. NousResearch/hermes-agent #16834): a cheap
5
+ * local classifier that decides whether a piece of content is worth storing in
6
+ * long-term memory before the write happens. Without this, every turn —
7
+ * including low-signal acknowledgements, chit-chat, and retries — enters
8
+ * memory and later bloats context-packs, costing retrieval tokens and diluting
9
+ * relevance ranking.
10
+ *
11
+ * Default mode is a ZERO-LLM-CALL local classifier (keeps MemOS fast and
12
+ * local). The *decision* is conservative-first: a write is skipped only
13
+ * on positive evidence of noise (empty content, pure acknowledgements,
14
+ * fragments, near-duplicates of existing same-scope memories) — when in
15
+ * doubt the memory is kept, because a false skip silently loses user
16
+ * data. The *score* (0–1) separately estimates signal density from
17
+ * length, entity/code presence, action verbs, and novelty, and is
18
+ * reported for debugging/telemetry. An optional custom classifier can
19
+ * be injected via `setRetainClassifier()`.
20
+ *
21
+ * @module @mem-os/sdk/retain-filter
22
+ */
23
+ import { CONTRADICTION_SIGNALS } from "./confidence-machine.js";
24
+ /** Minimum content length (in chars) to consider storing. */
25
+ const MIN_LENGTH = 15;
26
+ /** Score at or above which content is retained. */
27
+ const RETAIN_THRESHOLD = 0.3;
28
+ // Action / signal verbs — presence pushes the score up.
29
+ const ACTION_VERBS = /\b(?:prefers?|wants?|needs?|likes?|dislikes?|uses?|chose|chooses|set|configured?|created?|added?|removed?|updated?|installed?|deployed?|named|called|works?|lives?|located?|built|built with|wrote|fixed|decided|chose|switched|migrated|adopted|disabled|enabled|changed|replaced)\b/gi;
30
+ const ENTITY_SIGNALS = [
31
+ /`[^`]+`/g, // code refs
32
+ /(?:[\w./-]+\.(?:ts|tsx|js|jsx|py|go|rs|md|json|yaml|yml|toml))/g, // file paths
33
+ /https?:\/\/[^\s,)]+/g, // urls
34
+ /\b[A-Z][a-z]+(?:\s+[A-Z][a-z]+)+\b/g, // proper nouns / concepts
35
+ /\b\d+(?:\.\d+)?(?:%|ms|s|usd|\$|x)\b/gi, // numbers with units
36
+ ];
37
+ // Low-signal acknowledgement phrases — pure noise, not worth storing.
38
+ // Anchored: the whole content must be an acknowledgement.
39
+ const LOW_SIGNAL_PATTERNS = /^(?:ok|okay|sure|got it|understood|done|will do|sure thing|sounds good|great|perfect|thanks|thank you|yep|yup|no problem|of course|absolutely|right|correct|exactly|yes|no|maybe|sure|hi|hello|hey|lol|haha|k|kk|cool|nice|wow)[.!?]?$/i;
40
+ // Individual acknowledgement words — used to catch repeated acks
41
+ // ("ok ok ok", "thanks thanks") that the anchored phrase pattern misses.
42
+ const ACK_WORDS = /^(?:ok|okay|sure|got|it|understood|done|will|do|thing|sounds|good|great|perfect|thanks|thank|you|yep|yup|no|problem|of|course|absolutely|right|correct|exactly|yes|maybe|hi|hello|hey|lol|haha|k|kk|cool|nice|wow)$/i;
43
+ /**
44
+ * Strip trailing sentence punctuation.
45
+ *
46
+ * Hand-rolled rather than `/[.!?]+$/g`: that pattern is UNANCHORED, so the
47
+ * engine retries it at every offset in a long punctuation run, each retry
48
+ * backtracking through the rest of the run — quadratic on input like
49
+ * `"!!!!!…!x"` (CodeQL js/polynomial-redos). A single left-to-right scan
50
+ * is linear and behaves identically.
51
+ */
52
+ function stripTrailingPunctuation(s, alsoComma = false) {
53
+ let end = s.length;
54
+ while (end > 0) {
55
+ const c = s.charCodeAt(end - 1);
56
+ // "." (46), "!" (33), "?" (63), "," (44 when alsoComma)
57
+ if (c !== 46 && c !== 33 && c !== 63 && !(alsoComma && c === 44))
58
+ break;
59
+ end--;
60
+ }
61
+ return end === s.length ? s : s.slice(0, end);
62
+ }
63
+ /** Near-duplicate threshold: token overlap at/above this is a duplicate. */
64
+ const DUPLICATE_OVERLAP = 0.85;
65
+ /**
66
+ * Does this content read as a correction of something already stored?
67
+ *
68
+ * The gate's near-duplicate rule exists to stop *identical restatements*
69
+ * from re-entering memory. A negation/retraction ("user no longer lives in
70
+ * Berlin", "switched from vim to neovim") is deliberately NOT a duplicate —
71
+ * it is the update the confidence lifecycle exists to process, and it
72
+ * arrives sharing most of its tokens with the memory it retracts (a
73
+ * retraction necessarily names the same subject). Dropping it as a
74
+ * "near-duplicate" is how a retraction silently never reaches the
75
+ * confidence machine, leaving the old belief in place at full weight.
76
+ * This check reuses the SAME signal list as `classifyEvidence` so the gate
77
+ * and the state machine cannot drift apart.
78
+ */
79
+ export function carriesContradictionSignal(content) {
80
+ const lower = content.toLowerCase();
81
+ return CONTRADICTION_SIGNALS.some((w) => lower.includes(w));
82
+ }
83
+ /** Minimum alphanumeric characters for content to be storable at all. */
84
+ const MIN_SIGNAL_CHARS = 4;
85
+ /**
86
+ * Max token overlap of `content` against any entry of `existingContent`
87
+ * (0–1). Tokens are lowercase alphanumeric words longer than 2 chars.
88
+ */
89
+ export function maxTokenOverlap(content, existingContent) {
90
+ const tokens = new Set(content
91
+ .toLowerCase()
92
+ .split(/[^a-z0-9]+/i)
93
+ .filter((w) => w.length > 2));
94
+ if (tokens.size === 0)
95
+ return 0;
96
+ let maxOverlap = 0;
97
+ for (const existing of existingContent.slice(0, 20)) {
98
+ const exTokens = new Set(existing
99
+ .toLowerCase()
100
+ .split(/[^a-z0-9]+/i)
101
+ .filter((w) => w.length > 2));
102
+ let overlap = 0;
103
+ for (const t of tokens)
104
+ if (exTokens.has(t))
105
+ overlap++;
106
+ maxOverlap = Math.max(maxOverlap, overlap / tokens.size);
107
+ }
108
+ return maxOverlap;
109
+ }
110
+ /**
111
+ * Count distinct signal indicators in the content.
112
+ */
113
+ function countSignals(content) {
114
+ let count = 0;
115
+ for (const pattern of ENTITY_SIGNALS) {
116
+ const regex = new RegExp(pattern.source, pattern.flags);
117
+ const matches = content.match(regex);
118
+ if (matches)
119
+ count += new Set(matches).size;
120
+ }
121
+ return count;
122
+ }
123
+ /**
124
+ * Default local classifier: scores content on signal density (0-1).
125
+ *
126
+ * Components:
127
+ * - Length floor: tiny content scores ~0.
128
+ * - Signal density: entities / code refs / numbers per 100 chars.
129
+ * - Action / preference verbs: factual statements score higher.
130
+ * - Low-signal penalty: pure acknowledgements score ~0.
131
+ * - Novelty: down-weight content that duplicates existing memory.
132
+ *
133
+ * No LLM call, no I/O — runs in well under 1ms.
134
+ */
135
+ export function scoreRetain(input) {
136
+ const { content, existingContent = [] } = input;
137
+ if (!content || content.trim().length < MIN_LENGTH)
138
+ return 0;
139
+ // Hard penalty for pure acknowledgement turns.
140
+ if (LOW_SIGNAL_PATTERNS.test(content.trim()))
141
+ return 0.05;
142
+ let score = 0;
143
+ // Signal density.
144
+ const signalCount = countSignals(content);
145
+ const density = Math.min(1, signalCount / 3); // 3+ signals → max density
146
+ score += density * 0.45;
147
+ // Action / preference verbs (factual statements worth remembering).
148
+ const verbMatches = content.match(ACTION_VERBS) ?? [];
149
+ const verbDensity = Math.min(1, new Set(verbMatches.map((v) => v.toLowerCase())).size / 2);
150
+ score += verbDensity * 0.3;
151
+ // Length appropriateness.
152
+ const len = content.trim().length;
153
+ score += len >= 25 && len <= 500 ? 0.15 : 0.05;
154
+ // Novelty: down-weight near-duplicates of existing memory.
155
+ if (existingContent.length > 0) {
156
+ score += (1 - maxTokenOverlap(content, existingContent)) * 0.1;
157
+ }
158
+ else {
159
+ score += 0.1;
160
+ }
161
+ return Math.min(1, score);
162
+ }
163
+ /**
164
+ * Decide whether to retain (store) content. Default uses the local
165
+ * classifier; callers can inject a custom classifier via
166
+ * `setRetainClassifier()`.
167
+ *
168
+ * Conservative-first contract (the accuracy gate): a write is skipped
169
+ * ONLY on positive evidence of noise —
170
+ * 1. empty content,
171
+ * 2. a pure acknowledgement ("ok", "thanks", "ok ok ok", …),
172
+ * 3. a fragment with almost no alphanumeric content ("...", "k"),
173
+ * 4. a near-duplicate of an existing same-scope memory.
174
+ * Everything else is retained. When in doubt, keep the memory — a
175
+ * false skip silently loses user data, while a false keep only costs a
176
+ * little storage. `score` still reports the signal-density estimate
177
+ * from `scoreRetain` for debugging/telemetry.
178
+ */
179
+ export function shouldRetain(input) {
180
+ const score = scoreRetain(input);
181
+ const content = input.content ?? "";
182
+ const trimmed = content.trim();
183
+ if (trimmed.length === 0) {
184
+ return { retain: false, score, reason: "empty content" };
185
+ }
186
+ if (LOW_SIGNAL_PATTERNS.test(trimmed)) {
187
+ return { retain: false, score, reason: "low-signal acknowledgement" };
188
+ }
189
+ // Repeated acks the anchored phrase pattern misses ("ok ok ok").
190
+ const words = trimmed
191
+ .slice(0, stripTrailingPunctuation(trimmed).length)
192
+ .split(/\s+/)
193
+ .filter(Boolean);
194
+ if (words.length > 0 &&
195
+ words.every((w) => ACK_WORDS.test(stripTrailingPunctuation(w, true)))) {
196
+ return { retain: false, score, reason: "low-signal acknowledgement" };
197
+ }
198
+ const signalChars = trimmed.replace(/[^a-z0-9]/gi, "").length;
199
+ if (signalChars < MIN_SIGNAL_CHARS) {
200
+ return { retain: false, score, reason: "too short" };
201
+ }
202
+ const existing = input.existingContent ?? [];
203
+ if (existing.length > 0 &&
204
+ maxTokenOverlap(content, existing) >= DUPLICATE_OVERLAP &&
205
+ // A retraction necessarily overlaps the memory it retracts — it names
206
+ // the same subject. Never skip one of those as a "duplicate", or the
207
+ // contradiction never reaches the confidence machine.
208
+ !carriesContradictionSignal(trimmed)) {
209
+ return {
210
+ retain: false,
211
+ score,
212
+ reason: "near-duplicate of existing memory",
213
+ };
214
+ }
215
+ return { retain: true, score, reason: "no noise evidence — retained" };
216
+ }
217
+ /**
218
+ * Optional pluggable classifier. When set, `shouldRetain` delegates to it.
219
+ * Pass undefined to restore the default local classifier.
220
+ */
221
+ let customClassifier = null;
222
+ export function setRetainClassifier(classifier) {
223
+ customClassifier = classifier ?? null;
224
+ }
225
+ /** Decide whether to retain, using the custom classifier if installed. */
226
+ export function decideRetain(input) {
227
+ if (customClassifier)
228
+ return customClassifier(input);
229
+ return shouldRetain(input);
230
+ }
231
+ export { RETAIN_THRESHOLD };
232
+ //# sourceMappingURL=retain-filter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retain-filter.js","sourceRoot":"","sources":["../src/retain-filter.ts"],"names":[],"mappings":"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"}