@mnemoai/core 1.1.0 → 1.1.2
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 +136 -0
- package/dist/index.d.ts.map +1 -0
- package/{index.ts → dist/index.js} +537 -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
|
@@ -1,29 +1,11 @@
|
|
|
1
|
-
// SPDX-License-Identifier: LicenseRef-Mnemo-Pro
|
|
2
|
-
/**
|
|
3
|
-
* MCP Server for Mnemo
|
|
4
|
-
*
|
|
5
|
-
* Exposes memory tools (search, store, delete, update, list, stats) over
|
|
6
|
-
* stdio JSON-RPC so Claude Code can call them directly without going through
|
|
7
|
-
* the OpenClaw gateway.
|
|
8
|
-
*
|
|
9
|
-
* Usage:
|
|
10
|
-
* node --import jiti/register src/mcp-server.ts
|
|
11
|
-
*
|
|
12
|
-
* Register with Claude Code:
|
|
13
|
-
* claude mcp add memory -s user -- node --import jiti/register \
|
|
14
|
-
* /path/to/mnemo/src/mcp-server.ts
|
|
15
|
-
*/
|
|
16
|
-
|
|
17
|
-
// Redirect console.log to stderr — stdout is reserved for JSON-RPC
|
|
18
1
|
const _origLog = console.log;
|
|
19
|
-
console.log = (...args
|
|
20
|
-
|
|
2
|
+
console.log = (...args) => console.error(...args);
|
|
21
3
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
22
4
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
23
5
|
import { z } from "zod";
|
|
24
6
|
import { join } from "node:path";
|
|
25
7
|
import { mkdir, appendFile } from "node:fs/promises";
|
|
26
|
-
|
|
8
|
+
import { log } from "./logger.js";
|
|
27
9
|
import { loadConfigFromOpenClaw, getDefaultDbPath } from "./config.js";
|
|
28
10
|
import { MemoryStore, validateStoragePath } from "./store.js";
|
|
29
11
|
import { createEmbedder, getVectorDimensions } from "./embedder.js";
|
|
@@ -32,25 +14,17 @@ import { createScopeManager } from "./scopes.js";
|
|
|
32
14
|
import { isNoise } from "./noise-filter.js";
|
|
33
15
|
import { SemanticGate } from "./semantic-gate.js";
|
|
34
16
|
import { recoverPendingWrites } from "./wal-recovery.js";
|
|
35
|
-
|
|
36
|
-
// ============================================================================
|
|
37
|
-
// Initialization
|
|
38
|
-
// ============================================================================
|
|
39
|
-
|
|
40
17
|
const config = loadConfigFromOpenClaw();
|
|
41
|
-
|
|
42
18
|
const dbPath = config.dbPath || getDefaultDbPath();
|
|
43
19
|
try {
|
|
44
20
|
validateStoragePath(dbPath);
|
|
45
21
|
} catch (err) {
|
|
46
|
-
|
|
22
|
+
log.error(`mnemo mcp: storage path issue \u2014 ${String(err)}`);
|
|
47
23
|
}
|
|
48
|
-
|
|
49
24
|
const vectorDim = getVectorDimensions(
|
|
50
25
|
config.embedding.model || "text-embedding-3-small",
|
|
51
|
-
config.embedding.dimensions
|
|
26
|
+
config.embedding.dimensions
|
|
52
27
|
);
|
|
53
|
-
|
|
54
28
|
const store = new MemoryStore({ dbPath, vectorDim });
|
|
55
29
|
const embedder = createEmbedder({
|
|
56
30
|
provider: "openai-compatible",
|
|
@@ -60,77 +34,47 @@ const embedder = createEmbedder({
|
|
|
60
34
|
dimensions: config.embedding.dimensions,
|
|
61
35
|
taskQuery: config.embedding.taskQuery,
|
|
62
36
|
taskPassage: config.embedding.taskPassage,
|
|
63
|
-
normalized: config.embedding.normalized
|
|
37
|
+
normalized: config.embedding.normalized
|
|
64
38
|
});
|
|
65
|
-
|
|
66
|
-
|
|
39
|
+
log.warn(`[config-debug] config.retrieval keys: ${JSON.stringify(Object.keys(config.retrieval || {}))}`);
|
|
40
|
+
log.warn(`[config-debug] config.retrieval.rerankApiKey: ${config.retrieval?.rerankApiKey ? "SET(" + String(config.retrieval.rerankApiKey).substring(0, 8) + ")" : "EMPTY"}`);
|
|
67
41
|
const retriever = createRetriever(store, embedder, {
|
|
68
42
|
...DEFAULT_RETRIEVAL_CONFIG,
|
|
69
|
-
...config.retrieval
|
|
43
|
+
...config.retrieval
|
|
70
44
|
});
|
|
71
45
|
const scopeManager = createScopeManager(config.scopes);
|
|
72
|
-
|
|
73
|
-
// Inject semantic gate into store
|
|
74
46
|
const semanticGate = new SemanticGate(embedder);
|
|
75
47
|
store.setSemanticGate(semanticGate);
|
|
76
|
-
|
|
77
|
-
// WAL recovery: fire-and-forget on startup
|
|
78
48
|
recoverPendingWrites().catch((err) => {
|
|
79
|
-
|
|
49
|
+
log.error(`mnemo mcp: WAL recovery failed \u2014 ${String(err)}`);
|
|
80
50
|
});
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
// Markdown Mirror (simplified — no OpenClaw API dependency)
|
|
84
|
-
// ============================================================================
|
|
85
|
-
|
|
86
|
-
const mirrorDir = config.mdMirror?.enabled
|
|
87
|
-
? (config.mdMirror.dir || join(getDefaultDbPath(), "..", "lancedb-pro-mirror"))
|
|
88
|
-
: null;
|
|
89
|
-
|
|
90
|
-
async function mirrorWrite(
|
|
91
|
-
text: string,
|
|
92
|
-
category: string,
|
|
93
|
-
scope: string,
|
|
94
|
-
timestamp?: number,
|
|
95
|
-
): Promise<void> {
|
|
51
|
+
const mirrorDir = config.mdMirror?.enabled ? config.mdMirror.dir || join(getDefaultDbPath(), "..", "lancedb-pro-mirror") : null;
|
|
52
|
+
async function mirrorWrite(text, category, scope, timestamp) {
|
|
96
53
|
if (!mirrorDir) return;
|
|
97
54
|
try {
|
|
98
55
|
const ts = new Date(timestamp || Date.now());
|
|
99
56
|
const dateStr = ts.toISOString().split("T")[0];
|
|
100
57
|
const filePath = join(mirrorDir, `${dateStr}.md`);
|
|
101
58
|
const safeText = text.replace(/\n/g, " ").slice(0, 500);
|
|
102
|
-
const line = `- ${ts.toISOString()} [${category}:${scope}] source=mcp ${safeText}
|
|
59
|
+
const line = `- ${ts.toISOString()} [${category}:${scope}] source=mcp ${safeText}
|
|
60
|
+
`;
|
|
103
61
|
await mkdir(mirrorDir, { recursive: true });
|
|
104
62
|
await appendFile(filePath, line, "utf8");
|
|
105
63
|
} catch {
|
|
106
|
-
// Fail-open: mirror errors never block tool responses
|
|
107
64
|
}
|
|
108
65
|
}
|
|
109
|
-
|
|
110
|
-
// ============================================================================
|
|
111
|
-
// Helpers
|
|
112
|
-
// ============================================================================
|
|
113
|
-
|
|
114
|
-
function clampInt(value: number, min: number, max: number): number {
|
|
66
|
+
function clampInt(value, min, max) {
|
|
115
67
|
if (!Number.isFinite(value)) return min;
|
|
116
68
|
return Math.min(max, Math.max(min, Math.floor(value)));
|
|
117
69
|
}
|
|
118
|
-
|
|
119
|
-
function clamp01(value: number, fallback = 0.7): number {
|
|
70
|
+
function clamp01(value, fallback = 0.7) {
|
|
120
71
|
if (!Number.isFinite(value)) return fallback;
|
|
121
72
|
return Math.min(1, Math.max(0, value));
|
|
122
73
|
}
|
|
123
|
-
|
|
124
|
-
// ============================================================================
|
|
125
|
-
// MCP Server
|
|
126
|
-
// ============================================================================
|
|
127
|
-
|
|
128
74
|
const server = new McpServer({
|
|
129
75
|
name: "mnemo",
|
|
130
|
-
version: "1.0.0"
|
|
76
|
+
version: "1.0.0"
|
|
131
77
|
});
|
|
132
|
-
|
|
133
|
-
// --- memory_search ---
|
|
134
78
|
server.tool(
|
|
135
79
|
"memory_search",
|
|
136
80
|
"Search through long-term memories using hybrid retrieval (vector + keyword search). Use when you need context about user preferences, past decisions, or previously discussed topics.",
|
|
@@ -138,51 +82,44 @@ server.tool(
|
|
|
138
82
|
query: z.string().describe("Search query for finding relevant memories"),
|
|
139
83
|
limit: z.number().optional().describe("Max results to return (default: 5, max: 20)"),
|
|
140
84
|
scope: z.string().optional().describe("Specific memory scope to search in"),
|
|
141
|
-
category: z.enum(["preference", "fact", "decision", "entity", "other"]).optional()
|
|
85
|
+
category: z.enum(["preference", "fact", "decision", "entity", "other"]).optional()
|
|
142
86
|
},
|
|
143
87
|
async ({ query, limit = 5, scope, category }) => {
|
|
144
88
|
try {
|
|
145
89
|
const safeLimit = clampInt(limit, 1, 20);
|
|
146
|
-
|
|
147
90
|
let scopeFilter = scopeManager.getAccessibleScopes();
|
|
148
91
|
if (scope) {
|
|
149
92
|
if (scopeManager.isAccessible(scope)) {
|
|
150
93
|
scopeFilter = [scope];
|
|
151
94
|
} else {
|
|
152
|
-
return { content: [{ type: "text"
|
|
95
|
+
return { content: [{ type: "text", text: `Access denied to scope: ${scope}` }] };
|
|
153
96
|
}
|
|
154
97
|
}
|
|
155
|
-
|
|
156
98
|
const results = await retriever.retrieve({
|
|
157
99
|
query,
|
|
158
100
|
limit: safeLimit,
|
|
159
101
|
scopeFilter,
|
|
160
102
|
category,
|
|
161
|
-
source: "manual"
|
|
103
|
+
source: "manual"
|
|
162
104
|
});
|
|
163
|
-
|
|
164
105
|
if (results.length === 0) {
|
|
165
|
-
return { content: [{ type: "text"
|
|
106
|
+
return { content: [{ type: "text", text: "No relevant memories found." }] };
|
|
166
107
|
}
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
return { content: [{ type: "text" as const, text: `Found ${results.length} memories:\n\n${text}` }] };
|
|
108
|
+
const text = results.map((r, i) => {
|
|
109
|
+
const sources = [];
|
|
110
|
+
if (r.sources.vector) sources.push("vector");
|
|
111
|
+
if (r.sources.bm25) sources.push("BM25");
|
|
112
|
+
if (r.sources.reranked) sources.push("reranked");
|
|
113
|
+
return `${i + 1}. [${r.entry.id}] [${r.entry.category}:${r.entry.scope}] ${r.entry.text} (${(r.score * 100).toFixed(0)}%${sources.length > 0 ? `, ${sources.join("+")}` : ""})`;
|
|
114
|
+
}).join("\n");
|
|
115
|
+
return { content: [{ type: "text", text: `Found ${results.length} memories:
|
|
116
|
+
|
|
117
|
+
${text}` }] };
|
|
179
118
|
} catch (error) {
|
|
180
|
-
return { content: [{ type: "text"
|
|
119
|
+
return { content: [{ type: "text", text: `Memory search failed: ${error instanceof Error ? error.message : String(error)}` }] };
|
|
181
120
|
}
|
|
182
|
-
}
|
|
121
|
+
}
|
|
183
122
|
);
|
|
184
|
-
|
|
185
|
-
// --- memory_store ---
|
|
186
123
|
server.tool(
|
|
187
124
|
"memory_store",
|
|
188
125
|
"Save important information in long-term memory. Use for preferences, facts, decisions, and other notable information.",
|
|
@@ -190,78 +127,64 @@ server.tool(
|
|
|
190
127
|
text: z.string().describe("Information to remember"),
|
|
191
128
|
importance: z.number().optional().describe("Importance score 0-1 (default: 0.7)"),
|
|
192
129
|
category: z.enum(["preference", "fact", "decision", "entity", "other"]).optional(),
|
|
193
|
-
scope: z.string().optional().describe("Memory scope (optional, defaults to global)")
|
|
130
|
+
scope: z.string().optional().describe("Memory scope (optional, defaults to global)")
|
|
194
131
|
},
|
|
195
132
|
async ({ text, importance = 0.7, category = "other", scope }) => {
|
|
196
133
|
try {
|
|
197
134
|
let targetScope = scope || scopeManager.getDefaultScope();
|
|
198
|
-
|
|
199
135
|
if (!scopeManager.isAccessible(targetScope)) {
|
|
200
|
-
return { content: [{ type: "text"
|
|
136
|
+
return { content: [{ type: "text", text: `Access denied to scope: ${targetScope}` }] };
|
|
201
137
|
}
|
|
202
|
-
|
|
203
138
|
if (isNoise(text)) {
|
|
204
|
-
return { content: [{ type: "text"
|
|
139
|
+
return { content: [{ type: "text", text: "Skipped: text detected as noise (greeting, boilerplate, or meta-question)" }] };
|
|
205
140
|
}
|
|
206
|
-
|
|
207
141
|
const safeImportance = clamp01(importance, 0.7);
|
|
208
142
|
const vector = await embedder.embedPassage(text);
|
|
209
|
-
|
|
210
|
-
// Dedup check (fail-open)
|
|
211
|
-
let existing: Awaited<ReturnType<typeof store.vectorSearch>> = [];
|
|
143
|
+
let existing = [];
|
|
212
144
|
try {
|
|
213
145
|
existing = await store.vectorSearch(vector, 1, 0.1, [targetScope]);
|
|
214
146
|
} catch {
|
|
215
|
-
// Dedup check failed — continue store
|
|
216
147
|
}
|
|
217
|
-
|
|
218
148
|
if (existing.length > 0 && existing[0].score > 0.98) {
|
|
219
149
|
return {
|
|
220
|
-
content: [{ type: "text"
|
|
150
|
+
content: [{ type: "text", text: `Similar memory already exists: "${existing[0].entry.text}"` }]
|
|
221
151
|
};
|
|
222
152
|
}
|
|
223
|
-
|
|
224
153
|
const entry = await store.store({
|
|
225
154
|
text,
|
|
226
155
|
vector,
|
|
227
156
|
importance: safeImportance,
|
|
228
|
-
category
|
|
229
|
-
scope: targetScope
|
|
157
|
+
category,
|
|
158
|
+
scope: targetScope
|
|
230
159
|
});
|
|
231
|
-
|
|
232
160
|
await mirrorWrite(text, category, targetScope, entry.timestamp);
|
|
233
|
-
|
|
234
161
|
return {
|
|
235
|
-
content: [{ type: "text"
|
|
162
|
+
content: [{ type: "text", text: `Stored: "${text.slice(0, 100)}${text.length > 100 ? "..." : ""}" [id=${entry.id}] in scope '${targetScope}'` }]
|
|
236
163
|
};
|
|
237
164
|
} catch (error) {
|
|
238
|
-
return { content: [{ type: "text"
|
|
165
|
+
return { content: [{ type: "text", text: `Memory storage failed: ${error instanceof Error ? error.message : String(error)}` }] };
|
|
239
166
|
}
|
|
240
|
-
}
|
|
167
|
+
}
|
|
241
168
|
);
|
|
242
|
-
|
|
243
|
-
// --- memory_delete ---
|
|
244
169
|
server.tool(
|
|
245
170
|
"memory_delete",
|
|
246
171
|
"Delete a specific memory by ID.",
|
|
247
172
|
{
|
|
248
|
-
memoryId: z.string().describe("Memory ID to delete (full UUID or 8+ char prefix)")
|
|
173
|
+
memoryId: z.string().describe("Memory ID to delete (full UUID or 8+ char prefix)")
|
|
249
174
|
},
|
|
250
175
|
async ({ memoryId }) => {
|
|
251
176
|
try {
|
|
252
177
|
const scopeFilter = scopeManager.getAccessibleScopes();
|
|
253
178
|
const deleted = await store.delete(memoryId, scopeFilter);
|
|
254
179
|
if (deleted) {
|
|
255
|
-
return { content: [{ type: "text"
|
|
180
|
+
return { content: [{ type: "text", text: `Memory ${memoryId} deleted.` }] };
|
|
256
181
|
}
|
|
257
|
-
return { content: [{ type: "text"
|
|
182
|
+
return { content: [{ type: "text", text: `Memory ${memoryId} not found or access denied.` }] };
|
|
258
183
|
} catch (error) {
|
|
259
|
-
return { content: [{ type: "text"
|
|
184
|
+
return { content: [{ type: "text", text: `Memory deletion failed: ${error instanceof Error ? error.message : String(error)}` }] };
|
|
260
185
|
}
|
|
261
|
-
}
|
|
186
|
+
}
|
|
262
187
|
);
|
|
263
|
-
|
|
264
|
-
// --- memory_update ---
|
|
265
188
|
server.tool(
|
|
266
189
|
"memory_update",
|
|
267
190
|
"Update an existing memory in-place. Preserves original timestamp.",
|
|
@@ -269,46 +192,38 @@ server.tool(
|
|
|
269
192
|
memoryId: z.string().describe("ID of the memory to update (full UUID or 8+ char prefix)"),
|
|
270
193
|
text: z.string().optional().describe("New text content (triggers re-embedding)"),
|
|
271
194
|
importance: z.number().optional().describe("New importance score 0-1"),
|
|
272
|
-
category: z.enum(["preference", "fact", "decision", "entity", "other"]).optional()
|
|
195
|
+
category: z.enum(["preference", "fact", "decision", "entity", "other"]).optional()
|
|
273
196
|
},
|
|
274
197
|
async ({ memoryId, text, importance, category }) => {
|
|
275
198
|
try {
|
|
276
|
-
if (!text && importance ===
|
|
277
|
-
return { content: [{ type: "text"
|
|
199
|
+
if (!text && importance === void 0 && !category) {
|
|
200
|
+
return { content: [{ type: "text", text: "Nothing to update. Provide at least one of: text, importance, category." }] };
|
|
278
201
|
}
|
|
279
|
-
|
|
280
202
|
const scopeFilter = scopeManager.getAccessibleScopes();
|
|
281
|
-
|
|
282
|
-
let newVector: number[] | undefined;
|
|
203
|
+
let newVector;
|
|
283
204
|
if (text) {
|
|
284
205
|
if (isNoise(text)) {
|
|
285
|
-
return { content: [{ type: "text"
|
|
206
|
+
return { content: [{ type: "text", text: "Skipped: updated text detected as noise" }] };
|
|
286
207
|
}
|
|
287
208
|
newVector = await embedder.embedPassage(text);
|
|
288
209
|
}
|
|
289
|
-
|
|
290
|
-
const updates: Record<string, any> = {};
|
|
210
|
+
const updates = {};
|
|
291
211
|
if (text) updates.text = text;
|
|
292
212
|
if (newVector) updates.vector = newVector;
|
|
293
|
-
if (importance !==
|
|
213
|
+
if (importance !== void 0) updates.importance = clamp01(importance, 0.7);
|
|
294
214
|
if (category) updates.category = category;
|
|
295
|
-
|
|
296
215
|
const updated = await store.update(memoryId, updates, scopeFilter);
|
|
297
|
-
|
|
298
216
|
if (!updated) {
|
|
299
|
-
return { content: [{ type: "text"
|
|
217
|
+
return { content: [{ type: "text", text: `Memory ${memoryId} not found or access denied.` }] };
|
|
300
218
|
}
|
|
301
|
-
|
|
302
219
|
return {
|
|
303
|
-
content: [{ type: "text"
|
|
220
|
+
content: [{ type: "text", text: `Updated memory ${updated.id.slice(0, 8)}...: "${updated.text.slice(0, 80)}${updated.text.length > 80 ? "..." : ""}"` }]
|
|
304
221
|
};
|
|
305
222
|
} catch (error) {
|
|
306
|
-
return { content: [{ type: "text"
|
|
223
|
+
return { content: [{ type: "text", text: `Memory update failed: ${error instanceof Error ? error.message : String(error)}` }] };
|
|
307
224
|
}
|
|
308
|
-
}
|
|
225
|
+
}
|
|
309
226
|
);
|
|
310
|
-
|
|
311
|
-
// --- memory_list ---
|
|
312
227
|
server.tool(
|
|
313
228
|
"memory_list",
|
|
314
229
|
"List recent memories with optional filtering by scope and category.",
|
|
@@ -316,48 +231,41 @@ server.tool(
|
|
|
316
231
|
limit: z.number().optional().describe("Max memories to list (default: 10, max: 50)"),
|
|
317
232
|
offset: z.number().optional().describe("Number of memories to skip (default: 0)"),
|
|
318
233
|
scope: z.string().optional().describe("Filter by specific scope"),
|
|
319
|
-
category: z.enum(["preference", "fact", "decision", "entity", "other"]).optional()
|
|
234
|
+
category: z.enum(["preference", "fact", "decision", "entity", "other"]).optional()
|
|
320
235
|
},
|
|
321
236
|
async ({ limit = 10, offset = 0, scope, category }) => {
|
|
322
237
|
try {
|
|
323
238
|
const safeLimit = clampInt(limit, 1, 50);
|
|
324
|
-
const safeOffset = clampInt(offset, 0,
|
|
325
|
-
|
|
239
|
+
const safeOffset = clampInt(offset, 0, 1e3);
|
|
326
240
|
let scopeFilter = scopeManager.getAccessibleScopes();
|
|
327
241
|
if (scope) {
|
|
328
242
|
if (scopeManager.isAccessible(scope)) {
|
|
329
243
|
scopeFilter = [scope];
|
|
330
244
|
} else {
|
|
331
|
-
return { content: [{ type: "text"
|
|
245
|
+
return { content: [{ type: "text", text: `Access denied to scope: ${scope}` }] };
|
|
332
246
|
}
|
|
333
247
|
}
|
|
334
|
-
|
|
335
248
|
const entries = await store.list(scopeFilter, category, safeLimit, safeOffset);
|
|
336
|
-
|
|
337
249
|
if (entries.length === 0) {
|
|
338
|
-
return { content: [{ type: "text"
|
|
250
|
+
return { content: [{ type: "text", text: "No memories found." }] };
|
|
339
251
|
}
|
|
252
|
+
const text = entries.map((entry, i) => {
|
|
253
|
+
const date = new Date(entry.timestamp).toISOString().split("T")[0];
|
|
254
|
+
return `${safeOffset + i + 1}. [${entry.id}] [${entry.category}:${entry.scope}] ${entry.text.slice(0, 100)}${entry.text.length > 100 ? "..." : ""} (${date})`;
|
|
255
|
+
}).join("\n");
|
|
256
|
+
return { content: [{ type: "text", text: `Recent memories (showing ${entries.length}):
|
|
340
257
|
|
|
341
|
-
|
|
342
|
-
.map((entry, i) => {
|
|
343
|
-
const date = new Date(entry.timestamp).toISOString().split("T")[0];
|
|
344
|
-
return `${safeOffset + i + 1}. [${entry.id}] [${entry.category}:${entry.scope}] ${entry.text.slice(0, 100)}${entry.text.length > 100 ? "..." : ""} (${date})`;
|
|
345
|
-
})
|
|
346
|
-
.join("\n");
|
|
347
|
-
|
|
348
|
-
return { content: [{ type: "text" as const, text: `Recent memories (showing ${entries.length}):\n\n${text}` }] };
|
|
258
|
+
${text}` }] };
|
|
349
259
|
} catch (error) {
|
|
350
|
-
return { content: [{ type: "text"
|
|
260
|
+
return { content: [{ type: "text", text: `Failed to list memories: ${error instanceof Error ? error.message : String(error)}` }] };
|
|
351
261
|
}
|
|
352
|
-
}
|
|
262
|
+
}
|
|
353
263
|
);
|
|
354
|
-
|
|
355
|
-
// --- memory_stats ---
|
|
356
264
|
server.tool(
|
|
357
265
|
"memory_stats",
|
|
358
266
|
"Get statistics about memory usage, scopes, and categories.",
|
|
359
267
|
{
|
|
360
|
-
scope: z.string().optional().describe("Specific scope to get stats for")
|
|
268
|
+
scope: z.string().optional().describe("Specific scope to get stats for")
|
|
361
269
|
},
|
|
362
270
|
async ({ scope }) => {
|
|
363
271
|
try {
|
|
@@ -366,14 +274,12 @@ server.tool(
|
|
|
366
274
|
if (scopeManager.isAccessible(scope)) {
|
|
367
275
|
scopeFilter = [scope];
|
|
368
276
|
} else {
|
|
369
|
-
return { content: [{ type: "text"
|
|
277
|
+
return { content: [{ type: "text", text: `Access denied to scope: ${scope}` }] };
|
|
370
278
|
}
|
|
371
279
|
}
|
|
372
|
-
|
|
373
280
|
const stats = await store.stats(scopeFilter);
|
|
374
281
|
const scopeManagerStats = scopeManager.getStats();
|
|
375
282
|
const retrievalConfig = retriever.getConfig();
|
|
376
|
-
|
|
377
283
|
const text = [
|
|
378
284
|
`Memory Statistics:`,
|
|
379
285
|
` Total memories: ${stats.totalCount}`,
|
|
@@ -383,33 +289,27 @@ server.tool(
|
|
|
383
289
|
``,
|
|
384
290
|
`Memories by scope:`,
|
|
385
291
|
...Object.entries(stats.scopeCounts).map(
|
|
386
|
-
([s, count]) => ` ${s}: ${count}
|
|
292
|
+
([s, count]) => ` ${s}: ${count}`
|
|
387
293
|
),
|
|
388
294
|
``,
|
|
389
295
|
`Memories by category:`,
|
|
390
296
|
...Object.entries(stats.categoryCounts).map(
|
|
391
|
-
([c, count]) => ` ${c}: ${count}
|
|
392
|
-
)
|
|
297
|
+
([c, count]) => ` ${c}: ${count}`
|
|
298
|
+
)
|
|
393
299
|
].join("\n");
|
|
394
|
-
|
|
395
|
-
return { content: [{ type: "text" as const, text }] };
|
|
300
|
+
return { content: [{ type: "text", text }] };
|
|
396
301
|
} catch (error) {
|
|
397
|
-
return { content: [{ type: "text"
|
|
302
|
+
return { content: [{ type: "text", text: `Failed to get memory stats: ${error instanceof Error ? error.message : String(error)}` }] };
|
|
398
303
|
}
|
|
399
|
-
}
|
|
304
|
+
}
|
|
400
305
|
);
|
|
401
|
-
|
|
402
|
-
// ============================================================================
|
|
403
|
-
// Start
|
|
404
|
-
// ============================================================================
|
|
405
|
-
|
|
406
306
|
async function main() {
|
|
407
307
|
const transport = new StdioServerTransport();
|
|
408
308
|
await server.connect(transport);
|
|
409
|
-
|
|
309
|
+
log.error("mnemo MCP server started (stdio)");
|
|
410
310
|
}
|
|
411
|
-
|
|
412
311
|
main().catch((err) => {
|
|
413
|
-
|
|
312
|
+
log.error("Fatal:", err);
|
|
414
313
|
process.exit(1);
|
|
415
314
|
});
|
|
315
|
+
//# sourceMappingURL=mcp-server.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/mcp-server.ts"],
|
|
4
|
+
"sourcesContent": ["// SPDX-License-Identifier: LicenseRef-Mnemo-Pro\n/**\n * MCP Server for Mnemo\n *\n * Exposes memory tools (search, store, delete, update, list, stats) over\n * stdio JSON-RPC so Claude Code can call them directly without going through\n * the OpenClaw gateway.\n *\n * Usage:\n * node --import jiti/register src/mcp-server.ts\n *\n * Register with Claude Code:\n * claude mcp add memory -s user -- node --import jiti/register \\\n * /path/to/mnemo/src/mcp-server.ts\n */\n\n// Redirect console.log to stderr \u2014 stdout is reserved for JSON-RPC\nconst _origLog = console.log;\nconsole.log = (...args: any[]) => console.error(...args);\n\nimport { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { z } from \"zod\";\nimport { join } from \"node:path\";\nimport { mkdir, appendFile } from \"node:fs/promises\";\n\nimport { log } from \"./logger.js\";\nimport { loadConfigFromOpenClaw, getDefaultDbPath } from \"./config.js\";\nimport { MemoryStore, validateStoragePath } from \"./store.js\";\nimport { createEmbedder, getVectorDimensions } from \"./embedder.js\";\nimport { createRetriever, DEFAULT_RETRIEVAL_CONFIG } from \"./retriever.js\";\nimport { createScopeManager } from \"./scopes.js\";\nimport { isNoise } from \"./noise-filter.js\";\nimport { SemanticGate } from \"./semantic-gate.js\";\nimport { recoverPendingWrites } from \"./wal-recovery.js\";\n\n// ============================================================================\n// Initialization\n// ============================================================================\n\nconst config = loadConfigFromOpenClaw();\n\nconst dbPath = config.dbPath || getDefaultDbPath();\ntry {\n validateStoragePath(dbPath);\n} catch (err) {\n log.error(`mnemo mcp: storage path issue \u2014 ${String(err)}`);\n}\n\nconst vectorDim = getVectorDimensions(\n config.embedding.model || \"text-embedding-3-small\",\n config.embedding.dimensions,\n);\n\nconst store = new MemoryStore({ dbPath, vectorDim });\nconst embedder = createEmbedder({\n provider: \"openai-compatible\",\n apiKey: config.embedding.apiKey,\n model: config.embedding.model || \"text-embedding-3-small\",\n baseURL: config.embedding.baseURL,\n dimensions: config.embedding.dimensions,\n taskQuery: config.embedding.taskQuery,\n taskPassage: config.embedding.taskPassage,\n normalized: config.embedding.normalized,\n});\nlog.warn(`[config-debug] config.retrieval keys: ${JSON.stringify(Object.keys(config.retrieval || {}))}`);\nlog.warn(`[config-debug] config.retrieval.rerankApiKey: ${config.retrieval?.rerankApiKey ? 'SET(' + String(config.retrieval.rerankApiKey).substring(0, 8) + ')' : 'EMPTY'}`);\nconst retriever = createRetriever(store, embedder, {\n ...DEFAULT_RETRIEVAL_CONFIG,\n ...config.retrieval,\n});\nconst scopeManager = createScopeManager(config.scopes);\n\n// Inject semantic gate into store\nconst semanticGate = new SemanticGate(embedder);\nstore.setSemanticGate(semanticGate);\n\n// WAL recovery: fire-and-forget on startup\nrecoverPendingWrites().catch((err) => {\n log.error(`mnemo mcp: WAL recovery failed \u2014 ${String(err)}`);\n});\n\n// ============================================================================\n// Markdown Mirror (simplified \u2014 no OpenClaw API dependency)\n// ============================================================================\n\nconst mirrorDir = config.mdMirror?.enabled\n ? (config.mdMirror.dir || join(getDefaultDbPath(), \"..\", \"lancedb-pro-mirror\"))\n : null;\n\nasync function mirrorWrite(\n text: string,\n category: string,\n scope: string,\n timestamp?: number,\n): Promise<void> {\n if (!mirrorDir) return;\n try {\n const ts = new Date(timestamp || Date.now());\n const dateStr = ts.toISOString().split(\"T\")[0];\n const filePath = join(mirrorDir, `${dateStr}.md`);\n const safeText = text.replace(/\\n/g, \" \").slice(0, 500);\n const line = `- ${ts.toISOString()} [${category}:${scope}] source=mcp ${safeText}\\n`;\n await mkdir(mirrorDir, { recursive: true });\n await appendFile(filePath, line, \"utf8\");\n } catch {\n // Fail-open: mirror errors never block tool responses\n }\n}\n\n// ============================================================================\n// Helpers\n// ============================================================================\n\nfunction clampInt(value: number, min: number, max: number): number {\n if (!Number.isFinite(value)) return min;\n return Math.min(max, Math.max(min, Math.floor(value)));\n}\n\nfunction clamp01(value: number, fallback = 0.7): number {\n if (!Number.isFinite(value)) return fallback;\n return Math.min(1, Math.max(0, value));\n}\n\n// ============================================================================\n// MCP Server\n// ============================================================================\n\nconst server = new McpServer({\n name: \"mnemo\",\n version: \"1.0.0\",\n});\n\n// --- memory_search ---\nserver.tool(\n \"memory_search\",\n \"Search through long-term memories using hybrid retrieval (vector + keyword search). Use when you need context about user preferences, past decisions, or previously discussed topics.\",\n {\n query: z.string().describe(\"Search query for finding relevant memories\"),\n limit: z.number().optional().describe(\"Max results to return (default: 5, max: 20)\"),\n scope: z.string().optional().describe(\"Specific memory scope to search in\"),\n category: z.enum([\"preference\", \"fact\", \"decision\", \"entity\", \"other\"]).optional(),\n },\n async ({ query, limit = 5, scope, category }) => {\n try {\n const safeLimit = clampInt(limit, 1, 20);\n\n let scopeFilter = scopeManager.getAccessibleScopes();\n if (scope) {\n if (scopeManager.isAccessible(scope)) {\n scopeFilter = [scope];\n } else {\n return { content: [{ type: \"text\" as const, text: `Access denied to scope: ${scope}` }] };\n }\n }\n\n const results = await retriever.retrieve({\n query,\n limit: safeLimit,\n scopeFilter,\n category,\n source: \"manual\",\n });\n\n if (results.length === 0) {\n return { content: [{ type: \"text\" as const, text: \"No relevant memories found.\" }] };\n }\n\n const text = results\n .map((r, i) => {\n const sources: string[] = [];\n if (r.sources.vector) sources.push(\"vector\");\n if (r.sources.bm25) sources.push(\"BM25\");\n if (r.sources.reranked) sources.push(\"reranked\");\n return `${i + 1}. [${r.entry.id}] [${r.entry.category}:${r.entry.scope}] ${r.entry.text} (${(r.score * 100).toFixed(0)}%${sources.length > 0 ? `, ${sources.join(\"+\")}` : \"\"})`;\n })\n .join(\"\\n\");\n\n return { content: [{ type: \"text\" as const, text: `Found ${results.length} memories:\\n\\n${text}` }] };\n } catch (error) {\n return { content: [{ type: \"text\" as const, text: `Memory search failed: ${error instanceof Error ? error.message : String(error)}` }] };\n }\n },\n);\n\n// --- memory_store ---\nserver.tool(\n \"memory_store\",\n \"Save important information in long-term memory. Use for preferences, facts, decisions, and other notable information.\",\n {\n text: z.string().describe(\"Information to remember\"),\n importance: z.number().optional().describe(\"Importance score 0-1 (default: 0.7)\"),\n category: z.enum([\"preference\", \"fact\", \"decision\", \"entity\", \"other\"]).optional(),\n scope: z.string().optional().describe(\"Memory scope (optional, defaults to global)\"),\n },\n async ({ text, importance = 0.7, category = \"other\", scope }) => {\n try {\n let targetScope = scope || scopeManager.getDefaultScope();\n\n if (!scopeManager.isAccessible(targetScope)) {\n return { content: [{ type: \"text\" as const, text: `Access denied to scope: ${targetScope}` }] };\n }\n\n if (isNoise(text)) {\n return { content: [{ type: \"text\" as const, text: \"Skipped: text detected as noise (greeting, boilerplate, or meta-question)\" }] };\n }\n\n const safeImportance = clamp01(importance, 0.7);\n const vector = await embedder.embedPassage(text);\n\n // Dedup check (fail-open)\n let existing: Awaited<ReturnType<typeof store.vectorSearch>> = [];\n try {\n existing = await store.vectorSearch(vector, 1, 0.1, [targetScope]);\n } catch {\n // Dedup check failed \u2014 continue store\n }\n\n if (existing.length > 0 && existing[0].score > 0.98) {\n return {\n content: [{ type: \"text\" as const, text: `Similar memory already exists: \"${existing[0].entry.text}\"` }],\n };\n }\n\n const entry = await store.store({\n text,\n vector,\n importance: safeImportance,\n category: category as any,\n scope: targetScope,\n });\n\n await mirrorWrite(text, category, targetScope, entry.timestamp);\n\n return {\n content: [{ type: \"text\" as const, text: `Stored: \"${text.slice(0, 100)}${text.length > 100 ? \"...\" : \"\"}\" [id=${entry.id}] in scope '${targetScope}'` }],\n };\n } catch (error) {\n return { content: [{ type: \"text\" as const, text: `Memory storage failed: ${error instanceof Error ? error.message : String(error)}` }] };\n }\n },\n);\n\n// --- memory_delete ---\nserver.tool(\n \"memory_delete\",\n \"Delete a specific memory by ID.\",\n {\n memoryId: z.string().describe(\"Memory ID to delete (full UUID or 8+ char prefix)\"),\n },\n async ({ memoryId }) => {\n try {\n const scopeFilter = scopeManager.getAccessibleScopes();\n const deleted = await store.delete(memoryId, scopeFilter);\n if (deleted) {\n return { content: [{ type: \"text\" as const, text: `Memory ${memoryId} deleted.` }] };\n }\n return { content: [{ type: \"text\" as const, text: `Memory ${memoryId} not found or access denied.` }] };\n } catch (error) {\n return { content: [{ type: \"text\" as const, text: `Memory deletion failed: ${error instanceof Error ? error.message : String(error)}` }] };\n }\n },\n);\n\n// --- memory_update ---\nserver.tool(\n \"memory_update\",\n \"Update an existing memory in-place. Preserves original timestamp.\",\n {\n memoryId: z.string().describe(\"ID of the memory to update (full UUID or 8+ char prefix)\"),\n text: z.string().optional().describe(\"New text content (triggers re-embedding)\"),\n importance: z.number().optional().describe(\"New importance score 0-1\"),\n category: z.enum([\"preference\", \"fact\", \"decision\", \"entity\", \"other\"]).optional(),\n },\n async ({ memoryId, text, importance, category }) => {\n try {\n if (!text && importance === undefined && !category) {\n return { content: [{ type: \"text\" as const, text: \"Nothing to update. Provide at least one of: text, importance, category.\" }] };\n }\n\n const scopeFilter = scopeManager.getAccessibleScopes();\n\n let newVector: number[] | undefined;\n if (text) {\n if (isNoise(text)) {\n return { content: [{ type: \"text\" as const, text: \"Skipped: updated text detected as noise\" }] };\n }\n newVector = await embedder.embedPassage(text);\n }\n\n const updates: Record<string, any> = {};\n if (text) updates.text = text;\n if (newVector) updates.vector = newVector;\n if (importance !== undefined) updates.importance = clamp01(importance, 0.7);\n if (category) updates.category = category;\n\n const updated = await store.update(memoryId, updates, scopeFilter);\n\n if (!updated) {\n return { content: [{ type: \"text\" as const, text: `Memory ${memoryId} not found or access denied.` }] };\n }\n\n return {\n content: [{ type: \"text\" as const, text: `Updated memory ${updated.id.slice(0, 8)}...: \"${updated.text.slice(0, 80)}${updated.text.length > 80 ? \"...\" : \"\"}\"` }],\n };\n } catch (error) {\n return { content: [{ type: \"text\" as const, text: `Memory update failed: ${error instanceof Error ? error.message : String(error)}` }] };\n }\n },\n);\n\n// --- memory_list ---\nserver.tool(\n \"memory_list\",\n \"List recent memories with optional filtering by scope and category.\",\n {\n limit: z.number().optional().describe(\"Max memories to list (default: 10, max: 50)\"),\n offset: z.number().optional().describe(\"Number of memories to skip (default: 0)\"),\n scope: z.string().optional().describe(\"Filter by specific scope\"),\n category: z.enum([\"preference\", \"fact\", \"decision\", \"entity\", \"other\"]).optional(),\n },\n async ({ limit = 10, offset = 0, scope, category }) => {\n try {\n const safeLimit = clampInt(limit, 1, 50);\n const safeOffset = clampInt(offset, 0, 1000);\n\n let scopeFilter = scopeManager.getAccessibleScopes();\n if (scope) {\n if (scopeManager.isAccessible(scope)) {\n scopeFilter = [scope];\n } else {\n return { content: [{ type: \"text\" as const, text: `Access denied to scope: ${scope}` }] };\n }\n }\n\n const entries = await store.list(scopeFilter, category, safeLimit, safeOffset);\n\n if (entries.length === 0) {\n return { content: [{ type: \"text\" as const, text: \"No memories found.\" }] };\n }\n\n const text = entries\n .map((entry, i) => {\n const date = new Date(entry.timestamp).toISOString().split(\"T\")[0];\n return `${safeOffset + i + 1}. [${entry.id}] [${entry.category}:${entry.scope}] ${entry.text.slice(0, 100)}${entry.text.length > 100 ? \"...\" : \"\"} (${date})`;\n })\n .join(\"\\n\");\n\n return { content: [{ type: \"text\" as const, text: `Recent memories (showing ${entries.length}):\\n\\n${text}` }] };\n } catch (error) {\n return { content: [{ type: \"text\" as const, text: `Failed to list memories: ${error instanceof Error ? error.message : String(error)}` }] };\n }\n },\n);\n\n// --- memory_stats ---\nserver.tool(\n \"memory_stats\",\n \"Get statistics about memory usage, scopes, and categories.\",\n {\n scope: z.string().optional().describe(\"Specific scope to get stats for\"),\n },\n async ({ scope }) => {\n try {\n let scopeFilter = scopeManager.getAccessibleScopes();\n if (scope) {\n if (scopeManager.isAccessible(scope)) {\n scopeFilter = [scope];\n } else {\n return { content: [{ type: \"text\" as const, text: `Access denied to scope: ${scope}` }] };\n }\n }\n\n const stats = await store.stats(scopeFilter);\n const scopeManagerStats = scopeManager.getStats();\n const retrievalConfig = retriever.getConfig();\n\n const text = [\n `Memory Statistics:`,\n ` Total memories: ${stats.totalCount}`,\n ` Available scopes: ${scopeManagerStats.totalScopes}`,\n ` Retrieval mode: ${retrievalConfig.mode}`,\n ` FTS support: ${store.hasFtsSupport ? \"Yes\" : \"No\"}`,\n ``,\n `Memories by scope:`,\n ...Object.entries(stats.scopeCounts).map(\n ([s, count]) => ` ${s}: ${count}`,\n ),\n ``,\n `Memories by category:`,\n ...Object.entries(stats.categoryCounts).map(\n ([c, count]) => ` ${c}: ${count}`,\n ),\n ].join(\"\\n\");\n\n return { content: [{ type: \"text\" as const, text }] };\n } catch (error) {\n return { content: [{ type: \"text\" as const, text: `Failed to get memory stats: ${error instanceof Error ? error.message : String(error)}` }] };\n }\n },\n);\n\n// ============================================================================\n// Start\n// ============================================================================\n\nasync function main() {\n const transport = new StdioServerTransport();\n await server.connect(transport);\n log.error(\"mnemo MCP server started (stdio)\");\n}\n\nmain().catch((err) => {\n log.error(\"Fatal:\", err);\n process.exit(1);\n});\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Memory Categories — 6-category classification system
|
|
3
|
+
*
|
|
4
|
+
* UserMemory: profile, preferences, entities, events
|
|
5
|
+
* AgentMemory: cases, patterns
|
|
6
|
+
*/
|
|
7
|
+
export declare const MEMORY_CATEGORIES: readonly ["profile", "preferences", "entities", "events", "cases", "patterns"];
|
|
8
|
+
export type MemoryCategory = (typeof MEMORY_CATEGORIES)[number];
|
|
9
|
+
/** Categories that always merge (skip dedup entirely). */
|
|
10
|
+
export declare const ALWAYS_MERGE_CATEGORIES: Set<"profile" | "preferences" | "entities" | "events" | "cases" | "patterns">;
|
|
11
|
+
/** Categories that support MERGE decision from LLM dedup. */
|
|
12
|
+
export declare const MERGE_SUPPORTED_CATEGORIES: Set<"profile" | "preferences" | "entities" | "events" | "cases" | "patterns">;
|
|
13
|
+
/** Categories that are append-only (CREATE or SKIP only, no MERGE). */
|
|
14
|
+
export declare const APPEND_ONLY_CATEGORIES: Set<"profile" | "preferences" | "entities" | "events" | "cases" | "patterns">;
|
|
15
|
+
/** Memory tier levels for lifecycle management. */
|
|
16
|
+
export type MemoryTier = "core" | "working" | "peripheral";
|
|
17
|
+
/** A candidate memory extracted from conversation by LLM. */
|
|
18
|
+
export type CandidateMemory = {
|
|
19
|
+
category: MemoryCategory;
|
|
20
|
+
abstract: string;
|
|
21
|
+
overview: string;
|
|
22
|
+
content: string;
|
|
23
|
+
};
|
|
24
|
+
/** Dedup decision from LLM. */
|
|
25
|
+
export type DedupDecision = "create" | "merge" | "skip" | "support" | "contextualize" | "contradict";
|
|
26
|
+
export type DedupResult = {
|
|
27
|
+
decision: DedupDecision;
|
|
28
|
+
reason: string;
|
|
29
|
+
matchId?: string;
|
|
30
|
+
contextLabel?: string;
|
|
31
|
+
};
|
|
32
|
+
export type ExtractionStats = {
|
|
33
|
+
created: number;
|
|
34
|
+
merged: number;
|
|
35
|
+
skipped: number;
|
|
36
|
+
supported?: number;
|
|
37
|
+
};
|
|
38
|
+
/** Validate and normalize a category string. */
|
|
39
|
+
export declare function normalizeCategory(raw: string): MemoryCategory | null;
|
|
40
|
+
//# sourceMappingURL=memory-categories.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory-categories.d.ts","sourceRoot":"","sources":["../../src/memory-categories.ts"],"names":[],"mappings":"AACA;;;;;GAKG;AAEH,eAAO,MAAM,iBAAiB,gFAOpB,CAAC;AAEX,MAAM,MAAM,cAAc,GAAG,CAAC,OAAO,iBAAiB,CAAC,CAAC,MAAM,CAAC,CAAC;AAEhE,0DAA0D;AAC1D,eAAO,MAAM,uBAAuB,+EAAuC,CAAC;AAE5E,6DAA6D;AAC7D,eAAO,MAAM,0BAA0B,+EAIrC,CAAC;AAEH,uEAAuE;AACvE,eAAO,MAAM,sBAAsB,+EAGjC,CAAC;AAEH,mDAAmD;AACnD,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,SAAS,GAAG,YAAY,CAAC;AAE3D,6DAA6D;AAC7D,MAAM,MAAM,eAAe,GAAG;IAC5B,QAAQ,EAAE,cAAc,CAAC;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,+BAA+B;AAC/B,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,SAAS,GAAG,eAAe,GAAG,YAAY,CAAC;AAErG,MAAM,MAAM,WAAW,GAAG;IACxB,QAAQ,EAAE,aAAa,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,gDAAgD;AAChD,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,cAAc,GAAG,IAAI,CAMpE"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
const MEMORY_CATEGORIES = [
|
|
2
|
+
"profile",
|
|
3
|
+
"preferences",
|
|
4
|
+
"entities",
|
|
5
|
+
"events",
|
|
6
|
+
"cases",
|
|
7
|
+
"patterns"
|
|
8
|
+
];
|
|
9
|
+
const ALWAYS_MERGE_CATEGORIES = /* @__PURE__ */ new Set(["profile"]);
|
|
10
|
+
const MERGE_SUPPORTED_CATEGORIES = /* @__PURE__ */ new Set([
|
|
11
|
+
"preferences",
|
|
12
|
+
"entities",
|
|
13
|
+
"patterns"
|
|
14
|
+
]);
|
|
15
|
+
const APPEND_ONLY_CATEGORIES = /* @__PURE__ */ new Set([
|
|
16
|
+
"events",
|
|
17
|
+
"cases"
|
|
18
|
+
]);
|
|
19
|
+
function normalizeCategory(raw) {
|
|
20
|
+
const lower = raw.toLowerCase().trim();
|
|
21
|
+
if (MEMORY_CATEGORIES.includes(lower)) {
|
|
22
|
+
return lower;
|
|
23
|
+
}
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
export {
|
|
27
|
+
ALWAYS_MERGE_CATEGORIES,
|
|
28
|
+
APPEND_ONLY_CATEGORIES,
|
|
29
|
+
MEMORY_CATEGORIES,
|
|
30
|
+
MERGE_SUPPORTED_CATEGORIES,
|
|
31
|
+
normalizeCategory
|
|
32
|
+
};
|
|
33
|
+
//# sourceMappingURL=memory-categories.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/memory-categories.ts"],
|
|
4
|
+
"sourcesContent": ["// SPDX-License-Identifier: MIT\n/**\n * Memory Categories \u2014 6-category classification system\n *\n * UserMemory: profile, preferences, entities, events\n * AgentMemory: cases, patterns\n */\n\nexport const MEMORY_CATEGORIES = [\n \"profile\",\n \"preferences\",\n \"entities\",\n \"events\",\n \"cases\",\n \"patterns\",\n] as const;\n\nexport type MemoryCategory = (typeof MEMORY_CATEGORIES)[number];\n\n/** Categories that always merge (skip dedup entirely). */\nexport const ALWAYS_MERGE_CATEGORIES = new Set<MemoryCategory>([\"profile\"]);\n\n/** Categories that support MERGE decision from LLM dedup. */\nexport const MERGE_SUPPORTED_CATEGORIES = new Set<MemoryCategory>([\n \"preferences\",\n \"entities\",\n \"patterns\",\n]);\n\n/** Categories that are append-only (CREATE or SKIP only, no MERGE). */\nexport const APPEND_ONLY_CATEGORIES = new Set<MemoryCategory>([\n \"events\",\n \"cases\",\n]);\n\n/** Memory tier levels for lifecycle management. */\nexport type MemoryTier = \"core\" | \"working\" | \"peripheral\";\n\n/** A candidate memory extracted from conversation by LLM. */\nexport type CandidateMemory = {\n category: MemoryCategory;\n abstract: string; // L0: one-sentence index\n overview: string; // L1: structured markdown summary\n content: string; // L2: full narrative\n};\n\n/** Dedup decision from LLM. */\nexport type DedupDecision = \"create\" | \"merge\" | \"skip\" | \"support\" | \"contextualize\" | \"contradict\";\n\nexport type DedupResult = {\n decision: DedupDecision;\n reason: string;\n matchId?: string; // ID of existing memory to merge with\n contextLabel?: string; // Optional context label for support/contextualize/contradict\n};\n\nexport type ExtractionStats = {\n created: number;\n merged: number;\n skipped: number;\n supported?: number; // context-aware support count\n};\n\n/** Validate and normalize a category string. */\nexport function normalizeCategory(raw: string): MemoryCategory | null {\n const lower = raw.toLowerCase().trim();\n if ((MEMORY_CATEGORIES as readonly string[]).includes(lower)) {\n return lower as MemoryCategory;\n }\n return null;\n}\n"],
|
|
5
|
+
"mappings": "AAQO,MAAM,oBAAoB;AAAA,EAC/B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAKO,MAAM,0BAA0B,oBAAI,IAAoB,CAAC,SAAS,CAAC;AAGnE,MAAM,6BAA6B,oBAAI,IAAoB;AAAA,EAChE;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAGM,MAAM,yBAAyB,oBAAI,IAAoB;AAAA,EAC5D;AAAA,EACA;AACF,CAAC;AA+BM,SAAS,kBAAkB,KAAoC;AACpE,QAAM,QAAQ,IAAI,YAAY,EAAE,KAAK;AACrC,MAAK,kBAAwC,SAAS,KAAK,GAAG;AAC5D,WAAO;AAAA,EACT;AACA,SAAO;AACT;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|