anno-extension 0.1.0

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 (199) hide show
  1. package/LICENSE +7 -0
  2. package/README.md +30 -0
  3. package/THIRD_PARTY_NOTICES.md +8 -0
  4. package/dist/browser-fs.d.ts +14 -0
  5. package/dist/browser-fs.d.ts.map +1 -0
  6. package/dist/browser-fs.js +69 -0
  7. package/dist/browser-fs.js.map +1 -0
  8. package/dist/config.d.ts +81 -0
  9. package/dist/config.d.ts.map +1 -0
  10. package/dist/config.js +82 -0
  11. package/dist/config.js.map +1 -0
  12. package/dist/consolidate-v2.d.ts +15 -0
  13. package/dist/consolidate-v2.d.ts.map +1 -0
  14. package/dist/consolidate-v2.js +125 -0
  15. package/dist/consolidate-v2.js.map +1 -0
  16. package/dist/consolidation.d.ts +12 -0
  17. package/dist/consolidation.d.ts.map +1 -0
  18. package/dist/consolidation.js +199 -0
  19. package/dist/consolidation.js.map +1 -0
  20. package/dist/dedup.d.ts +18 -0
  21. package/dist/dedup.d.ts.map +1 -0
  22. package/dist/dedup.js +85 -0
  23. package/dist/dedup.js.map +1 -0
  24. package/dist/diagnostics.d.ts +24 -0
  25. package/dist/diagnostics.d.ts.map +1 -0
  26. package/dist/diagnostics.js +53 -0
  27. package/dist/diagnostics.js.map +1 -0
  28. package/dist/embedding-index.d.ts +27 -0
  29. package/dist/embedding-index.d.ts.map +1 -0
  30. package/dist/embedding-index.js +111 -0
  31. package/dist/embedding-index.js.map +1 -0
  32. package/dist/engine-archive.d.ts +37 -0
  33. package/dist/engine-archive.d.ts.map +1 -0
  34. package/dist/engine-archive.js +155 -0
  35. package/dist/engine-archive.js.map +1 -0
  36. package/dist/engine-episode-sync.d.ts +19 -0
  37. package/dist/engine-episode-sync.d.ts.map +1 -0
  38. package/dist/engine-episode-sync.js +186 -0
  39. package/dist/engine-episode-sync.js.map +1 -0
  40. package/dist/engine-injection-text.d.ts +46 -0
  41. package/dist/engine-injection-text.d.ts.map +1 -0
  42. package/dist/engine-injection-text.js +271 -0
  43. package/dist/engine-injection-text.js.map +1 -0
  44. package/dist/engine-insights.d.ts +22 -0
  45. package/dist/engine-insights.d.ts.map +1 -0
  46. package/dist/engine-insights.js +127 -0
  47. package/dist/engine-insights.js.map +1 -0
  48. package/dist/engine-links.d.ts +43 -0
  49. package/dist/engine-links.d.ts.map +1 -0
  50. package/dist/engine-links.js +223 -0
  51. package/dist/engine-links.js.map +1 -0
  52. package/dist/engine-recall-select.d.ts +84 -0
  53. package/dist/engine-recall-select.d.ts.map +1 -0
  54. package/dist/engine-recall-select.js +127 -0
  55. package/dist/engine-recall-select.js.map +1 -0
  56. package/dist/engine-reinforce.d.ts +18 -0
  57. package/dist/engine-reinforce.d.ts.map +1 -0
  58. package/dist/engine-reinforce.js +116 -0
  59. package/dist/engine-reinforce.js.map +1 -0
  60. package/dist/engine-scoring-v2.d.ts +35 -0
  61. package/dist/engine-scoring-v2.d.ts.map +1 -0
  62. package/dist/engine-scoring-v2.js +178 -0
  63. package/dist/engine-scoring-v2.js.map +1 -0
  64. package/dist/engine-v2-mapping.d.ts +17 -0
  65. package/dist/engine-v2-mapping.d.ts.map +1 -0
  66. package/dist/engine-v2-mapping.js +190 -0
  67. package/dist/engine-v2-mapping.js.map +1 -0
  68. package/dist/engine.d.ts +339 -0
  69. package/dist/engine.d.ts.map +1 -0
  70. package/dist/engine.js +1964 -0
  71. package/dist/engine.js.map +1 -0
  72. package/dist/eviction.d.ts +14 -0
  73. package/dist/eviction.d.ts.map +1 -0
  74. package/dist/eviction.js +26 -0
  75. package/dist/eviction.js.map +1 -0
  76. package/dist/extraction.d.ts +11 -0
  77. package/dist/extraction.d.ts.map +1 -0
  78. package/dist/extraction.js +261 -0
  79. package/dist/extraction.js.map +1 -0
  80. package/dist/full-insights-html.d.ts +9 -0
  81. package/dist/full-insights-html.d.ts.map +1 -0
  82. package/dist/full-insights-html.js +422 -0
  83. package/dist/full-insights-html.js.map +1 -0
  84. package/dist/full-insights-sections.d.ts +48 -0
  85. package/dist/full-insights-sections.d.ts.map +1 -0
  86. package/dist/full-insights-sections.js +231 -0
  87. package/dist/full-insights-sections.js.map +1 -0
  88. package/dist/full-insights.d.ts +22 -0
  89. package/dist/full-insights.d.ts.map +1 -0
  90. package/dist/full-insights.js +370 -0
  91. package/dist/full-insights.js.map +1 -0
  92. package/dist/hash-embedding.d.ts +9 -0
  93. package/dist/hash-embedding.d.ts.map +1 -0
  94. package/dist/hash-embedding.js +44 -0
  95. package/dist/hash-embedding.js.map +1 -0
  96. package/dist/human-insights.d.ts +28 -0
  97. package/dist/human-insights.d.ts.map +1 -0
  98. package/dist/human-insights.js +260 -0
  99. package/dist/human-insights.js.map +1 -0
  100. package/dist/i18n.d.ts +64 -0
  101. package/dist/i18n.d.ts.map +1 -0
  102. package/dist/i18n.js +367 -0
  103. package/dist/i18n.js.map +1 -0
  104. package/dist/index.d.ts +27 -0
  105. package/dist/index.d.ts.map +1 -0
  106. package/dist/index.js +21 -0
  107. package/dist/index.js.map +1 -0
  108. package/dist/insights-html.d.ts +9 -0
  109. package/dist/insights-html.d.ts.map +1 -0
  110. package/dist/insights-html.js +432 -0
  111. package/dist/insights-html.js.map +1 -0
  112. package/dist/linking.d.ts +22 -0
  113. package/dist/linking.d.ts.map +1 -0
  114. package/dist/linking.js +192 -0
  115. package/dist/linking.js.map +1 -0
  116. package/dist/llm-json.d.ts +10 -0
  117. package/dist/llm-json.d.ts.map +1 -0
  118. package/dist/llm-json.js +193 -0
  119. package/dist/llm-json.js.map +1 -0
  120. package/dist/privacy.d.ts +17 -0
  121. package/dist/privacy.d.ts.map +1 -0
  122. package/dist/privacy.js +53 -0
  123. package/dist/privacy.js.map +1 -0
  124. package/dist/procedural-v2.d.ts +9 -0
  125. package/dist/procedural-v2.d.ts.map +1 -0
  126. package/dist/procedural-v2.js +123 -0
  127. package/dist/procedural-v2.js.map +1 -0
  128. package/dist/reconsolidate-v2.d.ts +19 -0
  129. package/dist/reconsolidate-v2.d.ts.map +1 -0
  130. package/dist/reconsolidate-v2.js +115 -0
  131. package/dist/reconsolidate-v2.js.map +1 -0
  132. package/dist/scoring.d.ts +32 -0
  133. package/dist/scoring.d.ts.map +1 -0
  134. package/dist/scoring.js +108 -0
  135. package/dist/scoring.js.map +1 -0
  136. package/dist/store-v2.d.ts +35 -0
  137. package/dist/store-v2.d.ts.map +1 -0
  138. package/dist/store-v2.js +98 -0
  139. package/dist/store-v2.js.map +1 -0
  140. package/dist/store.d.ts +22 -0
  141. package/dist/store.d.ts.map +1 -0
  142. package/dist/store.js +116 -0
  143. package/dist/store.js.map +1 -0
  144. package/dist/turn-context.d.ts +37 -0
  145. package/dist/turn-context.d.ts.map +1 -0
  146. package/dist/turn-context.js +31 -0
  147. package/dist/turn-context.js.map +1 -0
  148. package/dist/types-v2.d.ts +190 -0
  149. package/dist/types-v2.d.ts.map +1 -0
  150. package/dist/types-v2.js +8 -0
  151. package/dist/types-v2.js.map +1 -0
  152. package/dist/types.d.ts +330 -0
  153. package/dist/types.d.ts.map +1 -0
  154. package/dist/types.js +8 -0
  155. package/dist/types.js.map +1 -0
  156. package/dist/update.d.ts +31 -0
  157. package/dist/update.d.ts.map +1 -0
  158. package/dist/update.js +250 -0
  159. package/dist/update.js.map +1 -0
  160. package/package.json +34 -0
  161. package/src/browser-fs.ts +67 -0
  162. package/src/config.ts +138 -0
  163. package/src/consolidate-v2.ts +158 -0
  164. package/src/consolidation.ts +229 -0
  165. package/src/dedup.ts +91 -0
  166. package/src/diagnostics.ts +81 -0
  167. package/src/embedding-index.ts +138 -0
  168. package/src/engine-archive.ts +167 -0
  169. package/src/engine-episode-sync.ts +237 -0
  170. package/src/engine-injection-text.ts +334 -0
  171. package/src/engine-insights.ts +182 -0
  172. package/src/engine-links.ts +311 -0
  173. package/src/engine-recall-select.ts +298 -0
  174. package/src/engine-reinforce.ts +154 -0
  175. package/src/engine-scoring-v2.ts +188 -0
  176. package/src/engine-v2-mapping.ts +204 -0
  177. package/src/engine.ts +2499 -0
  178. package/src/eviction.ts +38 -0
  179. package/src/extraction.ts +300 -0
  180. package/src/full-insights-html.ts +474 -0
  181. package/src/full-insights-sections.ts +305 -0
  182. package/src/full-insights.ts +423 -0
  183. package/src/hash-embedding.ts +48 -0
  184. package/src/human-insights.ts +345 -0
  185. package/src/i18n.ts +455 -0
  186. package/src/index.ts +117 -0
  187. package/src/insights-html.ts +478 -0
  188. package/src/linking.ts +228 -0
  189. package/src/llm-json.ts +194 -0
  190. package/src/privacy.ts +54 -0
  191. package/src/procedural-v2.ts +142 -0
  192. package/src/reconsolidate-v2.ts +145 -0
  193. package/src/scoring.ts +156 -0
  194. package/src/store-v2.ts +138 -0
  195. package/src/store.ts +137 -0
  196. package/src/turn-context.ts +56 -0
  197. package/src/types-v2.ts +244 -0
  198. package/src/types.ts +372 -0
  199. package/src/update.ts +271 -0
package/src/update.ts ADDED
@@ -0,0 +1,271 @@
1
+ /**
2
+ * [WHO]: contentSimilarity, applyExtraction, checkConsolidationEntry, checkWorkDuplicate, applyWorkExtraction
3
+ * [FROM]: Depends on ./config.js, ./linking.js, ./privacy.js, ./scoring.js, ./store.js, ./types.js
4
+ * [TO]: Consumed by packages/mem-core/src/index.ts
5
+ * [HERE]: packages/mem-core/src/update.ts - Mem0 four-operation pipeline (ADD/UPDATE/DELETE/NOOP)
6
+ */
7
+
8
+
9
+ import type { NanomemConfig } from "./config.js";
10
+ import { linkNewEntry } from "./linking.js";
11
+ import { filterPII } from "./privacy.js";
12
+ import { extractTags, tagOverlap } from "./scoring.js";
13
+ import { deriveNameFromContent, deriveSummaryFromContent } from "./store.js";
14
+ import type { ExtractedItem, MemoryEntry, MemoryRetention, MemoryStability, WorkEntry } from "./types.js";
15
+
16
+ const UPDATE_OVERLAP_THRESHOLD = 0.7;
17
+ const NOOP_SIMILARITY_THRESHOLD = 0.8;
18
+ const CONTENT_SIMILARITY_THRESHOLD = 0.85;
19
+
20
+ function makeId(): string {
21
+ return `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
22
+ }
23
+
24
+ /** Simple content similarity check using character overlap — exported for dedup/consolidation */
25
+ export function contentSimilarity(a: string, b: string): number {
26
+ const aLower = a.toLowerCase().trim();
27
+ const bLower = b.toLowerCase().trim();
28
+ if (aLower === bLower) return 1;
29
+ const shorter = aLower.length < bLower.length ? aLower : bLower;
30
+ const longer = aLower.length >= bLower.length ? aLower : bLower;
31
+ if (longer.includes(shorter)) return shorter.length / longer.length;
32
+ // Simple word overlap
33
+ const aWords = new Set(aLower.split(/\s+/).filter((w) => w.length > 2));
34
+ const bWords = new Set(bLower.split(/\s+/).filter((w) => w.length > 2));
35
+ if (aWords.size === 0 || bWords.size === 0) return 0;
36
+ let overlap = 0;
37
+ for (const w of aWords) if (bWords.has(w)) overlap++;
38
+ return (2 * overlap) / (aWords.size + bWords.size);
39
+ }
40
+
41
+ /** Check if new content is too similar to an existing entry of same type */
42
+ function isDuplicate(entries: MemoryEntry[], type: string, tags: string[], nameSummary: string): boolean {
43
+ return entries.some((e) => {
44
+ if (e.type !== type) return false;
45
+ const existingNameSummary = `${e.name || ""} ${e.summary || e.content || ""}`.trim();
46
+ // Check both tag overlap and content similarity
47
+ const tagMatch = tagOverlap(e.tags, tags) >= NOOP_SIMILARITY_THRESHOLD;
48
+ const contentMatch = contentSimilarity(existingNameSummary, nameSummary) >= CONTENT_SIMILARITY_THRESHOLD;
49
+ return tagMatch || contentMatch;
50
+ });
51
+ }
52
+
53
+ /** Find existing entry with high tag overlap for UPDATE */
54
+ function findUpdateCandidate(entries: MemoryEntry[], type: string, tags: string[]): number {
55
+ return entries.findIndex((e) => e.type === type && tagOverlap(e.tags, tags) >= UPDATE_OVERLAP_THRESHOLD);
56
+ }
57
+
58
+ function inferRetention(item: ExtractedItem): MemoryRetention {
59
+ if (item.retention) return item.retention;
60
+ if (item.stability === "situational" || item.stateData) return "ambient";
61
+ switch (item.type) {
62
+ case "preference":
63
+ case "pattern":
64
+ return "core";
65
+ case "lesson":
66
+ case "struggle":
67
+ case "decision":
68
+ case "event":
69
+ return "key-event";
70
+ default:
71
+ return "ambient";
72
+ }
73
+ }
74
+
75
+ function inferStability(item: ExtractedItem): MemoryStability {
76
+ if (item.stability) return item.stability;
77
+ if (item.stateData) return "situational";
78
+ switch (item.type) {
79
+ case "preference":
80
+ case "pattern":
81
+ return "stable";
82
+ case "event":
83
+ return item.eventData?.kind === "milestone" ? "stable" : "situational";
84
+ default:
85
+ return "stable";
86
+ }
87
+ }
88
+
89
+ function inferSalience(item: ExtractedItem): number {
90
+ if (typeof item.salience === "number") {
91
+ return Math.max(1, Math.min(10, item.salience));
92
+ }
93
+ switch (item.type) {
94
+ case "event":
95
+ case "struggle":
96
+ return 9;
97
+ case "lesson":
98
+ case "decision":
99
+ return 8;
100
+ case "pattern":
101
+ return 7;
102
+ case "preference":
103
+ return 6;
104
+ default:
105
+ return 4;
106
+ }
107
+ }
108
+
109
+ function inferTtl(item: ExtractedItem, cfg: NanomemConfig, retention: MemoryRetention, salience: number): number | undefined {
110
+ if (item.stability === "situational" || item.stateData) return Math.min(14, cfg.forgetting.ambientTtlDays);
111
+ if (retention !== "ambient") return undefined;
112
+ if (item.type === "fact" && salience <= 5) return cfg.forgetting.ambientTtlDays;
113
+ return undefined;
114
+ }
115
+
116
+ /** Process a single extracted item through the Mem0 pipeline */
117
+ export function applyExtraction(
118
+ entries: MemoryEntry[],
119
+ item: ExtractedItem,
120
+ project: string,
121
+ cfg: NanomemConfig,
122
+ ): void {
123
+ if (item.type === "retract") {
124
+ applyDelete(entries, item.detail || item.content || item.summary || "");
125
+ return;
126
+ }
127
+
128
+ const memType = mapType(item.type);
129
+ const rawDetail = item.detail || item.content || "";
130
+ const detail = filterPII(rawDetail);
131
+ const name = item.name || deriveNameFromContent(detail);
132
+ const summary = item.summary || deriveSummaryFromContent(detail);
133
+ const tags = extractTags(`${name} ${summary} ${detail}`);
134
+ const nameSummary = `${name} ${summary}`;
135
+ const retention = inferRetention(item);
136
+ const salience = inferSalience(item);
137
+ const stability = inferStability(item);
138
+
139
+ if (isDuplicate(entries, memType, tags, nameSummary)) return;
140
+
141
+ const updateIdx = findUpdateCandidate(entries, memType, tags);
142
+ if (updateIdx >= 0) {
143
+ const existing = entries[updateIdx]!;
144
+ entries[updateIdx] = {
145
+ ...existing,
146
+ name,
147
+ summary,
148
+ detail,
149
+ content: detail,
150
+ tags,
151
+ lastAccessed: new Date().toISOString(),
152
+ retention:
153
+ existing.retention === "core" || retention === "core"
154
+ ? "core"
155
+ : existing.retention === "key-event" || retention === "key-event"
156
+ ? "key-event"
157
+ : "ambient",
158
+ salience: Math.max(existing.salience ?? existing.importance, salience),
159
+ eventData: item.eventData ?? existing.eventData,
160
+ stateData: item.stateData ?? existing.stateData,
161
+ stability: existing.stability === "stable" || stability === "stable" ? "stable" : "situational",
162
+ ttl: inferTtl(item, cfg, retention, salience) ?? existing.ttl,
163
+ };
164
+ return;
165
+ }
166
+
167
+ const now = new Date().toISOString();
168
+ const newEntry: MemoryEntry = {
169
+ id: makeId(),
170
+ type: memType,
171
+ name,
172
+ summary,
173
+ detail,
174
+ content: detail,
175
+ tags,
176
+ project,
177
+ importance:
178
+ item.type === "struggle"
179
+ ? 9
180
+ : item.type === "lesson"
181
+ ? 8
182
+ : item.type === "pattern"
183
+ ? 7
184
+ : item.type === "preference"
185
+ ? 6
186
+ : 5,
187
+ strength: cfg.halfLife[memType] ?? 30,
188
+ created: now,
189
+ eventTime: now,
190
+ accessCount: 0,
191
+ relatedIds: [],
192
+ scope: cfg.defaultScope,
193
+ facetData: item.facetData,
194
+ eventData: item.eventData,
195
+ retention,
196
+ salience,
197
+ stability,
198
+ stateData: item.stateData,
199
+ ttl: inferTtl(item, cfg, retention, salience),
200
+ };
201
+
202
+ linkNewEntry(newEntry, entries);
203
+ entries.push(newEntry);
204
+ }
205
+
206
+ function applyDelete(entries: MemoryEntry[], text: string): void {
207
+ const tags = extractTags(text);
208
+ const idx = entries.findIndex(
209
+ (e) => (e.type === "fact" || e.type === "preference") && tagOverlap(e.tags, tags) >= UPDATE_OVERLAP_THRESHOLD,
210
+ );
211
+ if (idx >= 0) entries.splice(idx, 1);
212
+ }
213
+
214
+ function mapType(t: ExtractedItem["type"]): MemoryEntry["type"] {
215
+ switch (t) {
216
+ case "preference":
217
+ return "preference";
218
+ case "lesson":
219
+ return "lesson";
220
+ case "decision":
221
+ return "decision";
222
+ case "pattern":
223
+ return "pattern";
224
+ case "struggle":
225
+ return "struggle";
226
+ case "event":
227
+ return "event";
228
+ default:
229
+ return "fact";
230
+ }
231
+ }
232
+
233
+ // ─── Dedup helpers for consolidation & work ────────────────────────────────
234
+
235
+ const WORK_DEDUP_TAG_THRESHOLD = 0.75;
236
+ const WORK_DEDUP_CONTENT_THRESHOLD = 0.8;
237
+ const WORK_UPDATE_TAG_THRESHOLD = 0.65;
238
+
239
+ /** Check if consolidation candidate is duplicate or update of existing. Used before pushing to knowledge/lessons. */
240
+ export function checkConsolidationEntry(
241
+ target: MemoryEntry[],
242
+ candidate: MemoryEntry,
243
+ allExisting: MemoryEntry[],
244
+ ): { action: "skip" } | { action: "update"; index: number } | { action: "add" } {
245
+ const nameSummary = `${candidate.name || ""} ${candidate.summary || ""}`.trim();
246
+ const sameTypeExisting = allExisting.filter((e) => e.type === candidate.type);
247
+ if (isDuplicate(sameTypeExisting, candidate.type, candidate.tags, nameSummary)) return { action: "skip" };
248
+ const updateIdx = findUpdateCandidate(target, candidate.type, candidate.tags);
249
+ if (updateIdx >= 0) return { action: "update", index: updateIdx };
250
+ return { action: "add" };
251
+ }
252
+
253
+ /** Check if work candidate is duplicate or update of existing work entries. */
254
+ export function checkWorkDuplicate(
255
+ entries: WorkEntry[],
256
+ candidate: WorkEntry,
257
+ ): { action: "skip" } | { action: "update"; index: number } | { action: "add" } {
258
+ const candidateText = `${candidate.goal} ${candidate.summary}`.trim();
259
+ for (let i = 0; i < entries.length; i++) {
260
+ const e = entries[i]!;
261
+ const existingText = `${e.goal} ${e.summary}`.trim();
262
+ const tagMatch = tagOverlap(e.tags, candidate.tags) >= WORK_DEDUP_TAG_THRESHOLD;
263
+ const contentMatch = contentSimilarity(existingText, candidateText) >= WORK_DEDUP_CONTENT_THRESHOLD;
264
+ if (tagMatch || contentMatch) return { action: "skip" };
265
+ }
266
+ for (let i = 0; i < entries.length; i++) {
267
+ const e = entries[i]!;
268
+ if (tagOverlap(e.tags, candidate.tags) >= WORK_UPDATE_TAG_THRESHOLD) return { action: "update", index: i };
269
+ }
270
+ return { action: "add" };
271
+ }