@mnemoai/core 1.1.0 → 1.1.1
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/cli.d.ts +2 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +7 -0
- package/dist/cli.js.map +7 -0
- package/dist/index.d.ts +128 -0
- package/dist/index.d.ts.map +1 -0
- package/{index.ts → dist/index.js} +526 -1333
- package/dist/index.js.map +7 -0
- package/dist/src/access-tracker.d.ts +97 -0
- package/dist/src/access-tracker.d.ts.map +1 -0
- package/dist/src/access-tracker.js +184 -0
- package/dist/src/access-tracker.js.map +7 -0
- package/dist/src/adapters/chroma.d.ts +31 -0
- package/dist/src/adapters/chroma.d.ts.map +1 -0
- package/{src/adapters/chroma.ts → dist/src/adapters/chroma.js} +45 -107
- package/dist/src/adapters/chroma.js.map +7 -0
- package/dist/src/adapters/lancedb.d.ts +29 -0
- package/dist/src/adapters/lancedb.d.ts.map +1 -0
- package/{src/adapters/lancedb.ts → dist/src/adapters/lancedb.js} +41 -109
- package/dist/src/adapters/lancedb.js.map +7 -0
- package/dist/src/adapters/pgvector.d.ts +33 -0
- package/dist/src/adapters/pgvector.d.ts.map +1 -0
- package/{src/adapters/pgvector.ts → dist/src/adapters/pgvector.js} +42 -104
- package/dist/src/adapters/pgvector.js.map +7 -0
- package/dist/src/adapters/qdrant.d.ts +34 -0
- package/dist/src/adapters/qdrant.d.ts.map +1 -0
- package/dist/src/adapters/qdrant.js +132 -0
- package/dist/src/adapters/qdrant.js.map +7 -0
- package/dist/src/adaptive-retrieval.d.ts +14 -0
- package/dist/src/adaptive-retrieval.d.ts.map +1 -0
- package/dist/src/adaptive-retrieval.js +52 -0
- package/dist/src/adaptive-retrieval.js.map +7 -0
- package/dist/src/audit-log.d.ts +56 -0
- package/dist/src/audit-log.d.ts.map +1 -0
- package/dist/src/audit-log.js +139 -0
- package/dist/src/audit-log.js.map +7 -0
- package/dist/src/chunker.d.ts +45 -0
- package/dist/src/chunker.d.ts.map +1 -0
- package/dist/src/chunker.js +157 -0
- package/dist/src/chunker.js.map +7 -0
- package/dist/src/config.d.ts +70 -0
- package/dist/src/config.d.ts.map +1 -0
- package/dist/src/config.js +142 -0
- package/dist/src/config.js.map +7 -0
- package/dist/src/decay-engine.d.ts +73 -0
- package/dist/src/decay-engine.d.ts.map +1 -0
- package/dist/src/decay-engine.js +119 -0
- package/dist/src/decay-engine.js.map +7 -0
- package/dist/src/embedder.d.ts +94 -0
- package/dist/src/embedder.d.ts.map +1 -0
- package/{src/embedder.ts → dist/src/embedder.js} +119 -317
- package/dist/src/embedder.js.map +7 -0
- package/dist/src/extraction-prompts.d.ts +12 -0
- package/dist/src/extraction-prompts.d.ts.map +1 -0
- package/dist/src/extraction-prompts.js +311 -0
- package/dist/src/extraction-prompts.js.map +7 -0
- package/dist/src/license.d.ts +29 -0
- package/dist/src/license.d.ts.map +1 -0
- package/{src/license.ts → dist/src/license.js} +42 -113
- package/dist/src/license.js.map +7 -0
- package/dist/src/llm-client.d.ts +23 -0
- package/dist/src/llm-client.d.ts.map +1 -0
- package/{src/llm-client.ts → dist/src/llm-client.js} +22 -55
- package/dist/src/llm-client.js.map +7 -0
- package/dist/src/logger.d.ts +33 -0
- package/dist/src/logger.d.ts.map +1 -0
- package/dist/src/logger.js +35 -0
- package/dist/src/logger.js.map +7 -0
- package/dist/src/mcp-server.d.ts +16 -0
- package/dist/src/mcp-server.d.ts.map +1 -0
- package/{src/mcp-server.ts → dist/src/mcp-server.js} +81 -181
- package/dist/src/mcp-server.js.map +7 -0
- package/dist/src/memory-categories.d.ts +40 -0
- package/dist/src/memory-categories.d.ts.map +1 -0
- package/dist/src/memory-categories.js +33 -0
- package/dist/src/memory-categories.js.map +7 -0
- package/dist/src/memory-upgrader.d.ts +71 -0
- package/dist/src/memory-upgrader.d.ts.map +1 -0
- package/dist/src/memory-upgrader.js +238 -0
- package/dist/src/memory-upgrader.js.map +7 -0
- package/dist/src/migrate.d.ts +47 -0
- package/dist/src/migrate.d.ts.map +1 -0
- package/{src/migrate.ts → dist/src/migrate.js} +57 -165
- package/dist/src/migrate.js.map +7 -0
- package/dist/src/mnemo.d.ts +67 -0
- package/dist/src/mnemo.d.ts.map +1 -0
- package/dist/src/mnemo.js +66 -0
- package/dist/src/mnemo.js.map +7 -0
- package/dist/src/noise-filter.d.ts +23 -0
- package/dist/src/noise-filter.d.ts.map +1 -0
- package/dist/src/noise-filter.js +62 -0
- package/dist/src/noise-filter.js.map +7 -0
- package/dist/src/noise-prototypes.d.ts +40 -0
- package/dist/src/noise-prototypes.d.ts.map +1 -0
- package/dist/src/noise-prototypes.js +116 -0
- package/dist/src/noise-prototypes.js.map +7 -0
- package/dist/src/observability.d.ts +16 -0
- package/dist/src/observability.d.ts.map +1 -0
- package/dist/src/observability.js +53 -0
- package/dist/src/observability.js.map +7 -0
- package/dist/src/query-tracker.d.ts +27 -0
- package/dist/src/query-tracker.d.ts.map +1 -0
- package/dist/src/query-tracker.js +32 -0
- package/dist/src/query-tracker.js.map +7 -0
- package/dist/src/reflection-event-store.d.ts +44 -0
- package/dist/src/reflection-event-store.d.ts.map +1 -0
- package/dist/src/reflection-event-store.js +50 -0
- package/dist/src/reflection-event-store.js.map +7 -0
- package/dist/src/reflection-item-store.d.ts +58 -0
- package/dist/src/reflection-item-store.d.ts.map +1 -0
- package/dist/src/reflection-item-store.js +69 -0
- package/dist/src/reflection-item-store.js.map +7 -0
- package/dist/src/reflection-mapped-metadata.d.ts +47 -0
- package/dist/src/reflection-mapped-metadata.d.ts.map +1 -0
- package/dist/src/reflection-mapped-metadata.js +40 -0
- package/dist/src/reflection-mapped-metadata.js.map +7 -0
- package/dist/src/reflection-metadata.d.ts +11 -0
- package/dist/src/reflection-metadata.d.ts.map +1 -0
- package/dist/src/reflection-metadata.js +24 -0
- package/dist/src/reflection-metadata.js.map +7 -0
- package/dist/src/reflection-ranking.d.ts +13 -0
- package/dist/src/reflection-ranking.d.ts.map +1 -0
- package/{src/reflection-ranking.ts → dist/src/reflection-ranking.js} +12 -21
- package/dist/src/reflection-ranking.js.map +7 -0
- package/dist/src/reflection-retry.d.ts +30 -0
- package/dist/src/reflection-retry.d.ts.map +1 -0
- package/{src/reflection-retry.ts → dist/src/reflection-retry.js} +24 -64
- package/dist/src/reflection-retry.js.map +7 -0
- package/dist/src/reflection-slices.d.ts +42 -0
- package/dist/src/reflection-slices.d.ts.map +1 -0
- package/{src/reflection-slices.ts → dist/src/reflection-slices.js} +60 -136
- package/dist/src/reflection-slices.js.map +7 -0
- package/dist/src/reflection-store.d.ts +85 -0
- package/dist/src/reflection-store.d.ts.map +1 -0
- package/dist/src/reflection-store.js +407 -0
- package/dist/src/reflection-store.js.map +7 -0
- package/dist/src/resonance-state.d.ts +19 -0
- package/dist/src/resonance-state.d.ts.map +1 -0
- package/{src/resonance-state.ts → dist/src/resonance-state.js} +13 -42
- package/dist/src/resonance-state.js.map +7 -0
- package/dist/src/retriever.d.ts +228 -0
- package/dist/src/retriever.d.ts.map +1 -0
- package/dist/src/retriever.js +1006 -0
- package/dist/src/retriever.js.map +7 -0
- package/dist/src/scopes.d.ts +58 -0
- package/dist/src/scopes.d.ts.map +1 -0
- package/dist/src/scopes.js +252 -0
- package/dist/src/scopes.js.map +7 -0
- package/dist/src/self-improvement-files.d.ts +20 -0
- package/dist/src/self-improvement-files.d.ts.map +1 -0
- package/{src/self-improvement-files.ts → dist/src/self-improvement-files.js} +24 -49
- package/dist/src/self-improvement-files.js.map +7 -0
- package/dist/src/semantic-gate.d.ts +24 -0
- package/dist/src/semantic-gate.d.ts.map +1 -0
- package/dist/src/semantic-gate.js +86 -0
- package/dist/src/semantic-gate.js.map +7 -0
- package/dist/src/session-recovery.d.ts +9 -0
- package/dist/src/session-recovery.d.ts.map +1 -0
- package/{src/session-recovery.ts → dist/src/session-recovery.js} +40 -57
- package/dist/src/session-recovery.js.map +7 -0
- package/dist/src/smart-extractor.d.ts +107 -0
- package/dist/src/smart-extractor.d.ts.map +1 -0
- package/{src/smart-extractor.ts → dist/src/smart-extractor.js} +130 -383
- package/dist/src/smart-extractor.js.map +7 -0
- package/dist/src/smart-metadata.d.ts +103 -0
- package/dist/src/smart-metadata.d.ts.map +1 -0
- package/dist/src/smart-metadata.js +361 -0
- package/dist/src/smart-metadata.js.map +7 -0
- package/dist/src/storage-adapter.d.ts +102 -0
- package/dist/src/storage-adapter.d.ts.map +1 -0
- package/dist/src/storage-adapter.js +22 -0
- package/dist/src/storage-adapter.js.map +7 -0
- package/dist/src/store.d.ts +108 -0
- package/dist/src/store.d.ts.map +1 -0
- package/dist/src/store.js +939 -0
- package/dist/src/store.js.map +7 -0
- package/dist/src/tier-manager.d.ts +57 -0
- package/dist/src/tier-manager.d.ts.map +1 -0
- package/dist/src/tier-manager.js +80 -0
- package/dist/src/tier-manager.js.map +7 -0
- package/dist/src/tools.d.ts +43 -0
- package/dist/src/tools.d.ts.map +1 -0
- package/dist/src/tools.js +1075 -0
- package/dist/src/tools.js.map +7 -0
- package/dist/src/wal-recovery.d.ts +30 -0
- package/dist/src/wal-recovery.d.ts.map +1 -0
- package/{src/wal-recovery.ts → dist/src/wal-recovery.js} +26 -79
- package/dist/src/wal-recovery.js.map +7 -0
- package/package.json +21 -2
- package/openclaw.plugin.json +0 -815
- package/src/access-tracker.ts +0 -341
- package/src/adapters/README.md +0 -78
- package/src/adapters/qdrant.ts +0 -191
- package/src/adaptive-retrieval.ts +0 -90
- package/src/audit-log.ts +0 -238
- package/src/chunker.ts +0 -254
- package/src/config.ts +0 -271
- package/src/decay-engine.ts +0 -238
- package/src/extraction-prompts.ts +0 -339
- package/src/memory-categories.ts +0 -71
- package/src/memory-upgrader.ts +0 -388
- package/src/mnemo.ts +0 -142
- package/src/noise-filter.ts +0 -97
- package/src/noise-prototypes.ts +0 -164
- package/src/observability.ts +0 -81
- package/src/query-tracker.ts +0 -57
- package/src/reflection-event-store.ts +0 -98
- package/src/reflection-item-store.ts +0 -112
- package/src/reflection-mapped-metadata.ts +0 -84
- package/src/reflection-metadata.ts +0 -23
- package/src/reflection-store.ts +0 -602
- package/src/retriever.ts +0 -1510
- package/src/scopes.ts +0 -375
- package/src/semantic-gate.ts +0 -121
- package/src/smart-metadata.ts +0 -561
- package/src/storage-adapter.ts +0 -153
- package/src/store.ts +0 -1330
- package/src/tier-manager.ts +0 -189
- package/src/tools.ts +0 -1292
- package/test/core.test.mjs +0 -301
package/src/memory-upgrader.ts
DELETED
|
@@ -1,388 +0,0 @@
|
|
|
1
|
-
// SPDX-License-Identifier: LicenseRef-Mnemo-Pro
|
|
2
|
-
/**
|
|
3
|
-
* Memory Upgrader — Convert legacy memories to new smart memory format
|
|
4
|
-
*
|
|
5
|
-
* Legacy memories lack L0/L1/L2 metadata, memory_category (6-category),
|
|
6
|
-
* tier, access_count, and confidence fields. This module enriches them
|
|
7
|
-
* to enable unified memory lifecycle management (decay, tier promotion,
|
|
8
|
-
* smart dedup).
|
|
9
|
-
*
|
|
10
|
-
* Pipeline per memory:
|
|
11
|
-
* 1. Detect legacy format (missing `memory_category` in metadata)
|
|
12
|
-
* 2. Reverse-map 5-category → 6-category
|
|
13
|
-
* 3. Generate L0/L1/L2 via LLM (or fallback to simple rules)
|
|
14
|
-
* 4. Write enriched metadata back via store.update()
|
|
15
|
-
*/
|
|
16
|
-
|
|
17
|
-
import type { MemoryStore, MemoryEntry } from "./store.js";
|
|
18
|
-
import type { LlmClient } from "./llm-client.js";
|
|
19
|
-
import type { MemoryCategory } from "./memory-categories.js";
|
|
20
|
-
import type { MemoryTier } from "./memory-categories.js";
|
|
21
|
-
import { buildSmartMetadata, stringifySmartMetadata } from "./smart-metadata.js";
|
|
22
|
-
|
|
23
|
-
// ============================================================================
|
|
24
|
-
// Types
|
|
25
|
-
// ============================================================================
|
|
26
|
-
|
|
27
|
-
export interface UpgradeOptions {
|
|
28
|
-
/** Only report counts without modifying data (default: false) */
|
|
29
|
-
dryRun?: boolean;
|
|
30
|
-
/** Number of memories to process per batch (default: 10) */
|
|
31
|
-
batchSize?: number;
|
|
32
|
-
/** Skip LLM calls; use simple text truncation for L0/L1 (default: false) */
|
|
33
|
-
noLlm?: boolean;
|
|
34
|
-
/** Maximum number of memories to upgrade (default: unlimited) */
|
|
35
|
-
limit?: number;
|
|
36
|
-
/** Scope filter — only upgrade memories in these scopes */
|
|
37
|
-
scopeFilter?: string[];
|
|
38
|
-
/** Logger function */
|
|
39
|
-
log?: (msg: string) => void;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export interface UpgradeResult {
|
|
43
|
-
/** Total legacy memories found */
|
|
44
|
-
totalLegacy: number;
|
|
45
|
-
/** Successfully upgraded count */
|
|
46
|
-
upgraded: number;
|
|
47
|
-
/** Skipped (already new format) */
|
|
48
|
-
skipped: number;
|
|
49
|
-
/** Errors encountered */
|
|
50
|
-
errors: string[];
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
interface EnrichedMetadata {
|
|
54
|
-
l0_abstract: string;
|
|
55
|
-
l1_overview: string;
|
|
56
|
-
l2_content: string;
|
|
57
|
-
memory_category: MemoryCategory;
|
|
58
|
-
tier: MemoryTier;
|
|
59
|
-
access_count: number;
|
|
60
|
-
confidence: number;
|
|
61
|
-
last_accessed_at: number;
|
|
62
|
-
upgraded_from: string; // original 5-category
|
|
63
|
-
upgraded_at: number; // timestamp of upgrade
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
// ============================================================================
|
|
67
|
-
// Reverse Category Mapping
|
|
68
|
-
// ============================================================================
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* Reverse-map old 5-category → new 6-category.
|
|
72
|
-
*
|
|
73
|
-
* Ambiguous case: `fact` maps to both `profile` and `cases`.
|
|
74
|
-
* Without LLM, defaults to `cases` (conservative).
|
|
75
|
-
* With LLM, the enrichment prompt will determine the correct category.
|
|
76
|
-
*/
|
|
77
|
-
function reverseMapCategory(
|
|
78
|
-
oldCategory: MemoryEntry["category"],
|
|
79
|
-
text: string,
|
|
80
|
-
): MemoryCategory {
|
|
81
|
-
switch (oldCategory) {
|
|
82
|
-
case "preference":
|
|
83
|
-
return "preferences";
|
|
84
|
-
case "entity":
|
|
85
|
-
return "entities";
|
|
86
|
-
case "decision":
|
|
87
|
-
return "events";
|
|
88
|
-
case "other":
|
|
89
|
-
return "patterns";
|
|
90
|
-
case "fact":
|
|
91
|
-
// Heuristic: if text looks like personal identity info, map to profile
|
|
92
|
-
if (
|
|
93
|
-
/\b(my |i am |i'm |name is |叫我|我的|我是)\b/i.test(text) &&
|
|
94
|
-
text.length < 200
|
|
95
|
-
) {
|
|
96
|
-
return "profile";
|
|
97
|
-
}
|
|
98
|
-
return "cases";
|
|
99
|
-
default:
|
|
100
|
-
return "patterns";
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
// ============================================================================
|
|
105
|
-
// LLM Upgrade Prompt
|
|
106
|
-
// ============================================================================
|
|
107
|
-
|
|
108
|
-
function buildUpgradePrompt(text: string, category: MemoryCategory): string {
|
|
109
|
-
return `You are a memory librarian. Given a raw memory text and its category, produce a structured 3-layer summary.
|
|
110
|
-
|
|
111
|
-
**Category**: ${category}
|
|
112
|
-
|
|
113
|
-
**Raw memory text**:
|
|
114
|
-
"""
|
|
115
|
-
${text.slice(0, 2000)}
|
|
116
|
-
"""
|
|
117
|
-
|
|
118
|
-
Return ONLY valid JSON (no markdown fences):
|
|
119
|
-
{
|
|
120
|
-
"l0_abstract": "One sentence (≤30 words) summarizing the core fact/preference/event",
|
|
121
|
-
"l1_overview": "A structured markdown summary (2-5 bullet points)",
|
|
122
|
-
"l2_content": "The full original text, cleaned up if needed",
|
|
123
|
-
"resolved_category": "${category}"
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
Rules:
|
|
127
|
-
- l0_abstract must be a single concise sentence, suitable as a search index key
|
|
128
|
-
- l1_overview should use markdown bullet points to structure the information
|
|
129
|
-
- l2_content should preserve the original meaning; may clean up formatting
|
|
130
|
-
- resolved_category: if the text is clearly about personal identity/profile info (name, age, role, etc.), set to "profile"; if it's a reusable problem-solution pair, set to "cases"; otherwise keep "${category}"
|
|
131
|
-
- Respond in the SAME language as the raw memory text`;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
// ============================================================================
|
|
135
|
-
// Simple (No-LLM) Enrichment
|
|
136
|
-
// ============================================================================
|
|
137
|
-
|
|
138
|
-
function simpleEnrich(
|
|
139
|
-
text: string,
|
|
140
|
-
category: MemoryCategory,
|
|
141
|
-
): Pick<EnrichedMetadata, "l0_abstract" | "l1_overview" | "l2_content"> {
|
|
142
|
-
// L0: first sentence or first 80 chars
|
|
143
|
-
const firstSentence = text.match(/^[^.!?。!?\n]+[.!?。!?]?/)?.[0] || text;
|
|
144
|
-
const l0 = firstSentence.slice(0, 100).trim();
|
|
145
|
-
|
|
146
|
-
// L1: structured as a single bullet
|
|
147
|
-
const l1 = `- ${l0}`;
|
|
148
|
-
|
|
149
|
-
// L2: full text
|
|
150
|
-
return {
|
|
151
|
-
l0_abstract: l0,
|
|
152
|
-
l1_overview: l1,
|
|
153
|
-
l2_content: text,
|
|
154
|
-
};
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
// ============================================================================
|
|
158
|
-
// Memory Upgrader
|
|
159
|
-
// ============================================================================
|
|
160
|
-
|
|
161
|
-
export class MemoryUpgrader {
|
|
162
|
-
private log: (msg: string) => void;
|
|
163
|
-
|
|
164
|
-
constructor(
|
|
165
|
-
private store: MemoryStore,
|
|
166
|
-
private llm: LlmClient | null,
|
|
167
|
-
private options: UpgradeOptions = {},
|
|
168
|
-
) {
|
|
169
|
-
this.log = options.log ?? console.log;
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
/**
|
|
173
|
-
* Check if a memory entry is in legacy format (needs upgrade).
|
|
174
|
-
* Legacy = no metadata, or metadata lacks `memory_category`.
|
|
175
|
-
*/
|
|
176
|
-
isLegacyMemory(entry: MemoryEntry): boolean {
|
|
177
|
-
if (!entry.metadata) return true;
|
|
178
|
-
try {
|
|
179
|
-
const meta = JSON.parse(entry.metadata);
|
|
180
|
-
// If it has memory_category, it was created by SmartExtractor → new format
|
|
181
|
-
return !meta.memory_category;
|
|
182
|
-
} catch {
|
|
183
|
-
return true;
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
/**
|
|
188
|
-
* Scan and count legacy memories without modifying them.
|
|
189
|
-
*/
|
|
190
|
-
async countLegacy(scopeFilter?: string[]): Promise<{
|
|
191
|
-
total: number;
|
|
192
|
-
legacy: number;
|
|
193
|
-
byCategory: Record<string, number>;
|
|
194
|
-
}> {
|
|
195
|
-
const allMemories = await this.store.list(scopeFilter, undefined, 10000, 0);
|
|
196
|
-
let legacy = 0;
|
|
197
|
-
const byCategory: Record<string, number> = {};
|
|
198
|
-
|
|
199
|
-
for (const entry of allMemories) {
|
|
200
|
-
if (this.isLegacyMemory(entry)) {
|
|
201
|
-
legacy++;
|
|
202
|
-
byCategory[entry.category] = (byCategory[entry.category] || 0) + 1;
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
return { total: allMemories.length, legacy, byCategory };
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
/**
|
|
210
|
-
* Main upgrade entry point.
|
|
211
|
-
* Scans all memories, filters legacy ones, and enriches them.
|
|
212
|
-
*/
|
|
213
|
-
async upgrade(options: UpgradeOptions = {}): Promise<UpgradeResult> {
|
|
214
|
-
const batchSize = options.batchSize ?? this.options.batchSize ?? 10;
|
|
215
|
-
const noLlm = options.noLlm ?? this.options.noLlm ?? false;
|
|
216
|
-
const dryRun = options.dryRun ?? this.options.dryRun ?? false;
|
|
217
|
-
const limit = options.limit ?? this.options.limit;
|
|
218
|
-
|
|
219
|
-
const result: UpgradeResult = {
|
|
220
|
-
totalLegacy: 0,
|
|
221
|
-
upgraded: 0,
|
|
222
|
-
skipped: 0,
|
|
223
|
-
errors: [],
|
|
224
|
-
};
|
|
225
|
-
|
|
226
|
-
// Load all memories
|
|
227
|
-
this.log("memory-upgrader: scanning memories...");
|
|
228
|
-
const allMemories = await this.store.list(
|
|
229
|
-
options.scopeFilter ?? this.options.scopeFilter,
|
|
230
|
-
undefined,
|
|
231
|
-
10000,
|
|
232
|
-
0,
|
|
233
|
-
);
|
|
234
|
-
|
|
235
|
-
// Filter legacy memories
|
|
236
|
-
const legacyMemories = allMemories.filter((m) => this.isLegacyMemory(m));
|
|
237
|
-
result.totalLegacy = legacyMemories.length;
|
|
238
|
-
result.skipped = allMemories.length - legacyMemories.length;
|
|
239
|
-
|
|
240
|
-
if (legacyMemories.length === 0) {
|
|
241
|
-
this.log("memory-upgrader: no legacy memories found — all memories are already in new format");
|
|
242
|
-
return result;
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
this.log(
|
|
246
|
-
`memory-upgrader: found ${legacyMemories.length} legacy memories out of ${allMemories.length} total`,
|
|
247
|
-
);
|
|
248
|
-
|
|
249
|
-
if (dryRun) {
|
|
250
|
-
const byCategory: Record<string, number> = {};
|
|
251
|
-
for (const m of legacyMemories) {
|
|
252
|
-
byCategory[m.category] = (byCategory[m.category] || 0) + 1;
|
|
253
|
-
}
|
|
254
|
-
this.log(
|
|
255
|
-
`memory-upgrader: [DRY-RUN] would upgrade ${legacyMemories.length} memories`,
|
|
256
|
-
);
|
|
257
|
-
this.log(`memory-upgrader: [DRY-RUN] breakdown: ${JSON.stringify(byCategory)}`);
|
|
258
|
-
return result;
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
// Process in batches
|
|
262
|
-
const toProcess = limit
|
|
263
|
-
? legacyMemories.slice(0, limit)
|
|
264
|
-
: legacyMemories;
|
|
265
|
-
|
|
266
|
-
for (let i = 0; i < toProcess.length; i += batchSize) {
|
|
267
|
-
const batch = toProcess.slice(i, i + batchSize);
|
|
268
|
-
this.log(
|
|
269
|
-
`memory-upgrader: processing batch ${Math.floor(i / batchSize) + 1}/${Math.ceil(toProcess.length / batchSize)} (${batch.length} memories)`,
|
|
270
|
-
);
|
|
271
|
-
|
|
272
|
-
for (const entry of batch) {
|
|
273
|
-
try {
|
|
274
|
-
await this.upgradeEntry(entry, noLlm);
|
|
275
|
-
result.upgraded++;
|
|
276
|
-
} catch (err) {
|
|
277
|
-
const errMsg = `Failed to upgrade ${entry.id}: ${String(err)}`;
|
|
278
|
-
result.errors.push(errMsg);
|
|
279
|
-
this.log(`memory-upgrader: ERROR — ${errMsg}`);
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
// Progress report
|
|
284
|
-
this.log(
|
|
285
|
-
`memory-upgrader: progress — ${result.upgraded} upgraded, ${result.errors.length} errors`,
|
|
286
|
-
);
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
this.log(
|
|
290
|
-
`memory-upgrader: upgrade complete — ${result.upgraded} upgraded, ${result.skipped} already new, ${result.errors.length} errors`,
|
|
291
|
-
);
|
|
292
|
-
return result;
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
/**
|
|
296
|
-
* Upgrade a single legacy memory entry.
|
|
297
|
-
*/
|
|
298
|
-
private async upgradeEntry(
|
|
299
|
-
entry: MemoryEntry,
|
|
300
|
-
noLlm: boolean,
|
|
301
|
-
): Promise<void> {
|
|
302
|
-
// Step 1: Reverse-map category
|
|
303
|
-
let newCategory = reverseMapCategory(entry.category, entry.text);
|
|
304
|
-
|
|
305
|
-
// Step 2: Generate L0/L1/L2
|
|
306
|
-
let enriched: Pick<EnrichedMetadata, "l0_abstract" | "l1_overview" | "l2_content">;
|
|
307
|
-
|
|
308
|
-
if (!noLlm && this.llm) {
|
|
309
|
-
try {
|
|
310
|
-
const prompt = buildUpgradePrompt(entry.text, newCategory);
|
|
311
|
-
const llmResult = await this.llm.completeJson<{
|
|
312
|
-
l0_abstract: string;
|
|
313
|
-
l1_overview: string;
|
|
314
|
-
l2_content: string;
|
|
315
|
-
resolved_category?: string;
|
|
316
|
-
}>(prompt);
|
|
317
|
-
|
|
318
|
-
if (!llmResult) {
|
|
319
|
-
throw new Error("LLM returned null");
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
enriched = {
|
|
323
|
-
l0_abstract: llmResult.l0_abstract || simpleEnrich(entry.text, newCategory).l0_abstract,
|
|
324
|
-
l1_overview: llmResult.l1_overview || simpleEnrich(entry.text, newCategory).l1_overview,
|
|
325
|
-
l2_content: llmResult.l2_content || entry.text,
|
|
326
|
-
};
|
|
327
|
-
|
|
328
|
-
// LLM may have resolved the ambiguous fact→profile/cases
|
|
329
|
-
if (llmResult.resolved_category) {
|
|
330
|
-
const validCategories = new Set([
|
|
331
|
-
"profile", "preferences", "entities", "events", "cases", "patterns",
|
|
332
|
-
]);
|
|
333
|
-
if (validCategories.has(llmResult.resolved_category)) {
|
|
334
|
-
newCategory = llmResult.resolved_category as MemoryCategory;
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
} catch (err) {
|
|
338
|
-
this.log(
|
|
339
|
-
`memory-upgrader: LLM enrichment failed for ${entry.id}, falling back to simple — ${String(err)}`,
|
|
340
|
-
);
|
|
341
|
-
enriched = simpleEnrich(entry.text, newCategory);
|
|
342
|
-
}
|
|
343
|
-
} else {
|
|
344
|
-
enriched = simpleEnrich(entry.text, newCategory);
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
// Step 3: Build enriched metadata
|
|
348
|
-
const existingMeta = entry.metadata ? (() => {
|
|
349
|
-
try { return JSON.parse(entry.metadata!); } catch { return {}; }
|
|
350
|
-
})() : {};
|
|
351
|
-
|
|
352
|
-
const newMetadata: EnrichedMetadata = {
|
|
353
|
-
...buildSmartMetadata(
|
|
354
|
-
{ ...entry, metadata: JSON.stringify(existingMeta) },
|
|
355
|
-
{
|
|
356
|
-
l0_abstract: enriched.l0_abstract,
|
|
357
|
-
l1_overview: enriched.l1_overview,
|
|
358
|
-
l2_content: enriched.l2_content,
|
|
359
|
-
memory_category: newCategory,
|
|
360
|
-
tier: "working" as MemoryTier,
|
|
361
|
-
access_count: 0,
|
|
362
|
-
confidence: 0.7,
|
|
363
|
-
},
|
|
364
|
-
),
|
|
365
|
-
upgraded_from: entry.category,
|
|
366
|
-
upgraded_at: Date.now(),
|
|
367
|
-
};
|
|
368
|
-
|
|
369
|
-
// Step 4: Update the memory entry
|
|
370
|
-
await this.store.update(entry.id, {
|
|
371
|
-
// Update text to L0 abstract for better search indexing
|
|
372
|
-
text: enriched.l0_abstract,
|
|
373
|
-
metadata: stringifySmartMetadata(newMetadata),
|
|
374
|
-
});
|
|
375
|
-
}
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
// ============================================================================
|
|
379
|
-
// Factory
|
|
380
|
-
// ============================================================================
|
|
381
|
-
|
|
382
|
-
export function createMemoryUpgrader(
|
|
383
|
-
store: MemoryStore,
|
|
384
|
-
llm: LlmClient | null,
|
|
385
|
-
options: UpgradeOptions = {},
|
|
386
|
-
): MemoryUpgrader {
|
|
387
|
-
return new MemoryUpgrader(store, llm, options);
|
|
388
|
-
}
|
package/src/mnemo.ts
DELETED
|
@@ -1,142 +0,0 @@
|
|
|
1
|
-
// SPDX-License-Identifier: MIT
|
|
2
|
-
/**
|
|
3
|
-
* Mnemo Core — simplified entry point
|
|
4
|
-
* Usage: const mnemo = await createMnemo(config)
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { MemoryStore } from "./store.js";
|
|
8
|
-
import { createRetriever, DEFAULT_RETRIEVAL_CONFIG } from "./retriever.js";
|
|
9
|
-
import { Embedder } from "./embedder.js";
|
|
10
|
-
import { createDecayEngine, DEFAULT_DECAY_CONFIG } from "./decay-engine.js";
|
|
11
|
-
import { SmartExtractor } from "./smart-extractor.js";
|
|
12
|
-
import { createLlmClient } from "./llm-client.js";
|
|
13
|
-
|
|
14
|
-
export interface MnemoConfig {
|
|
15
|
-
embedding: {
|
|
16
|
-
provider: "openai-compatible";
|
|
17
|
-
apiKey: string;
|
|
18
|
-
baseURL?: string;
|
|
19
|
-
model?: string;
|
|
20
|
-
dimensions?: number;
|
|
21
|
-
taskQuery?: string;
|
|
22
|
-
taskPassage?: string;
|
|
23
|
-
};
|
|
24
|
-
dbPath: string;
|
|
25
|
-
decay?: {
|
|
26
|
-
recencyHalfLifeDays?: number;
|
|
27
|
-
recencyWeight?: number;
|
|
28
|
-
frequencyWeight?: number;
|
|
29
|
-
intrinsicWeight?: number;
|
|
30
|
-
};
|
|
31
|
-
tier?: {
|
|
32
|
-
coreAccessThreshold?: number;
|
|
33
|
-
coreImportanceThreshold?: number;
|
|
34
|
-
peripheralAgeDays?: number;
|
|
35
|
-
};
|
|
36
|
-
llm?: {
|
|
37
|
-
model?: string;
|
|
38
|
-
baseURL?: string;
|
|
39
|
-
apiKey?: string;
|
|
40
|
-
};
|
|
41
|
-
retrieval?: {
|
|
42
|
-
candidatePoolSize?: number;
|
|
43
|
-
rerank?: "cross-encoder" | "lightweight" | "none";
|
|
44
|
-
rerankApiKey?: string;
|
|
45
|
-
rerankModel?: string;
|
|
46
|
-
rerankEndpoint?: string;
|
|
47
|
-
rerankProvider?: string;
|
|
48
|
-
};
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
export interface MnemoInstance {
|
|
52
|
-
store(entry: {
|
|
53
|
-
text: string;
|
|
54
|
-
category?: string;
|
|
55
|
-
importance?: number;
|
|
56
|
-
scope?: string;
|
|
57
|
-
}): Promise<{ id: string }>;
|
|
58
|
-
|
|
59
|
-
recall(query: string, options?: {
|
|
60
|
-
limit?: number;
|
|
61
|
-
scopeFilter?: string[];
|
|
62
|
-
category?: string;
|
|
63
|
-
}): Promise<Array<{
|
|
64
|
-
text: string;
|
|
65
|
-
score: number;
|
|
66
|
-
category: string;
|
|
67
|
-
importance: number;
|
|
68
|
-
timestamp: number;
|
|
69
|
-
}>>;
|
|
70
|
-
|
|
71
|
-
stats(): Promise<{ totalEntries: number }>;
|
|
72
|
-
|
|
73
|
-
close(): Promise<void>;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
export async function createMnemo(config: MnemoConfig): Promise<MnemoInstance> {
|
|
77
|
-
const embedder = new Embedder({
|
|
78
|
-
apiKey: config.embedding.apiKey,
|
|
79
|
-
baseURL: config.embedding.baseURL,
|
|
80
|
-
model: config.embedding.model || "voyage-3-large",
|
|
81
|
-
dimensions: config.embedding.dimensions || 1024,
|
|
82
|
-
taskQuery: config.embedding.taskQuery,
|
|
83
|
-
taskPassage: config.embedding.taskPassage,
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
const store = new MemoryStore({
|
|
87
|
-
dbPath: config.dbPath,
|
|
88
|
-
embedder,
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
await store.initialize();
|
|
92
|
-
|
|
93
|
-
const decayEngine = createDecayEngine({
|
|
94
|
-
...DEFAULT_DECAY_CONFIG,
|
|
95
|
-
...(config.decay || {}),
|
|
96
|
-
});
|
|
97
|
-
|
|
98
|
-
const retriever = createRetriever(store, embedder, {
|
|
99
|
-
...DEFAULT_RETRIEVAL_CONFIG,
|
|
100
|
-
...(config.retrieval || {}),
|
|
101
|
-
}, { decayEngine });
|
|
102
|
-
|
|
103
|
-
return {
|
|
104
|
-
async store(entry) {
|
|
105
|
-
const vector = await embedder.embed(entry.text);
|
|
106
|
-
const result = await store.store({
|
|
107
|
-
text: entry.text,
|
|
108
|
-
vector,
|
|
109
|
-
category: entry.category || "fact",
|
|
110
|
-
importance: entry.importance ?? 0.7,
|
|
111
|
-
scope: entry.scope || "global",
|
|
112
|
-
});
|
|
113
|
-
return { id: result.id };
|
|
114
|
-
},
|
|
115
|
-
|
|
116
|
-
async recall(query, options = {}) {
|
|
117
|
-
const results = await retriever.retrieve({
|
|
118
|
-
query,
|
|
119
|
-
limit: options.limit ?? 5,
|
|
120
|
-
scopeFilter: options.scopeFilter,
|
|
121
|
-
category: options.category,
|
|
122
|
-
source: "manual",
|
|
123
|
-
});
|
|
124
|
-
return results.map(r => ({
|
|
125
|
-
text: r.entry.text,
|
|
126
|
-
score: r.score,
|
|
127
|
-
category: r.entry.category || "fact",
|
|
128
|
-
importance: r.entry.importance ?? 0.7,
|
|
129
|
-
timestamp: r.entry.timestamp ?? Date.now(),
|
|
130
|
-
}));
|
|
131
|
-
},
|
|
132
|
-
|
|
133
|
-
async stats() {
|
|
134
|
-
const count = await store.count();
|
|
135
|
-
return { totalEntries: count };
|
|
136
|
-
},
|
|
137
|
-
|
|
138
|
-
async close() {
|
|
139
|
-
// LanceDB handles cleanup automatically
|
|
140
|
-
},
|
|
141
|
-
};
|
|
142
|
-
}
|
package/src/noise-filter.ts
DELETED
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
// SPDX-License-Identifier: MIT
|
|
2
|
-
/**
|
|
3
|
-
* Noise Filter
|
|
4
|
-
* Filters out low-quality memories (meta-questions, agent denials, session boilerplate)
|
|
5
|
-
* Inspired by openclaw-plugin-continuity's noise filtering approach.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
// Agent-side denial patterns
|
|
9
|
-
const DENIAL_PATTERNS = [
|
|
10
|
-
/i don'?t have (any )?(information|data|memory|record)/i,
|
|
11
|
-
/i'?m not sure about/i,
|
|
12
|
-
/i don'?t recall/i,
|
|
13
|
-
/i don'?t remember/i,
|
|
14
|
-
/it looks like i don'?t/i,
|
|
15
|
-
/i wasn'?t able to find/i,
|
|
16
|
-
/no (relevant )?memories found/i,
|
|
17
|
-
/i don'?t have access to/i,
|
|
18
|
-
];
|
|
19
|
-
|
|
20
|
-
// User-side meta-question patterns (about memory itself, not content)
|
|
21
|
-
const META_QUESTION_PATTERNS = [
|
|
22
|
-
/\bdo you (remember|recall|know about)\b/i,
|
|
23
|
-
/\bcan you (remember|recall)\b/i,
|
|
24
|
-
/\bdid i (tell|mention|say|share)\b/i,
|
|
25
|
-
/\bhave i (told|mentioned|said)\b/i,
|
|
26
|
-
/\bwhat did i (tell|say|mention)\b/i,
|
|
27
|
-
/如果你知道.+只回复/i,
|
|
28
|
-
/如果不知道.+只回复\s*none/i,
|
|
29
|
-
/只回复精确代号/i,
|
|
30
|
-
/只回复\s*none/i,
|
|
31
|
-
// Chinese recall / meta-question patterns
|
|
32
|
-
/你还?记得/,
|
|
33
|
-
/记不记得/,
|
|
34
|
-
/还记得.*吗/,
|
|
35
|
-
/你[知晓]道.+吗/,
|
|
36
|
-
/我(?:之前|上次|以前)(?:说|提|讲).*(?:吗|呢|?|\?)/,
|
|
37
|
-
];
|
|
38
|
-
|
|
39
|
-
// Session boilerplate
|
|
40
|
-
const BOILERPLATE_PATTERNS = [
|
|
41
|
-
/^(hi|hello|hey|good morning|good evening|greetings)/i,
|
|
42
|
-
/^fresh session/i,
|
|
43
|
-
/^new session/i,
|
|
44
|
-
/^HEARTBEAT/i,
|
|
45
|
-
];
|
|
46
|
-
|
|
47
|
-
// Extractor artifacts from validation prompts / synthetic summaries
|
|
48
|
-
const DIAGNOSTIC_ARTIFACT_PATTERNS = [
|
|
49
|
-
/\bquery\s*->\s*(none|no explicit solution|unknown|not found)\b/i,
|
|
50
|
-
/\buser asked for\b.*\b(none|no explicit solution|unknown|not found)\b/i,
|
|
51
|
-
/\bno explicit solution\b/i,
|
|
52
|
-
];
|
|
53
|
-
|
|
54
|
-
export interface NoiseFilterOptions {
|
|
55
|
-
/** Filter agent denial responses (default: true) */
|
|
56
|
-
filterDenials?: boolean;
|
|
57
|
-
/** Filter meta-questions about memory (default: true) */
|
|
58
|
-
filterMetaQuestions?: boolean;
|
|
59
|
-
/** Filter session boilerplate (default: true) */
|
|
60
|
-
filterBoilerplate?: boolean;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
const DEFAULT_OPTIONS: Required<NoiseFilterOptions> = {
|
|
64
|
-
filterDenials: true,
|
|
65
|
-
filterMetaQuestions: true,
|
|
66
|
-
filterBoilerplate: true,
|
|
67
|
-
};
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* Check if a memory text is noise that should be filtered out.
|
|
71
|
-
* Returns true if the text is noise.
|
|
72
|
-
*/
|
|
73
|
-
export function isNoise(text: string, options: NoiseFilterOptions = {}): boolean {
|
|
74
|
-
const opts = { ...DEFAULT_OPTIONS, ...options };
|
|
75
|
-
const trimmed = text.trim();
|
|
76
|
-
|
|
77
|
-
if (trimmed.length < 5) return true;
|
|
78
|
-
|
|
79
|
-
if (opts.filterDenials && DENIAL_PATTERNS.some(p => p.test(trimmed))) return true;
|
|
80
|
-
if (opts.filterMetaQuestions && META_QUESTION_PATTERNS.some(p => p.test(trimmed))) return true;
|
|
81
|
-
if (opts.filterBoilerplate && BOILERPLATE_PATTERNS.some(p => p.test(trimmed))) return true;
|
|
82
|
-
if (DIAGNOSTIC_ARTIFACT_PATTERNS.some(p => p.test(trimmed))) return true;
|
|
83
|
-
|
|
84
|
-
return false;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
/**
|
|
88
|
-
* Filter an array of items, removing noise entries.
|
|
89
|
-
*/
|
|
90
|
-
export function filterNoise<T>(
|
|
91
|
-
items: T[],
|
|
92
|
-
getText: (item: T) => string,
|
|
93
|
-
options?: NoiseFilterOptions
|
|
94
|
-
): T[] {
|
|
95
|
-
const opts = { ...DEFAULT_OPTIONS, ...options };
|
|
96
|
-
return items.filter(item => !isNoise(getText(item), opts));
|
|
97
|
-
}
|