neuralmemory 1.5.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.
@@ -0,0 +1,30 @@
1
+ /**
2
+ * NeuralMemory — OpenClaw Memory Plugin
3
+ *
4
+ * Brain-inspired persistent memory for AI agents.
5
+ * Occupies the exclusive "memory" plugin slot.
6
+ *
7
+ * Architecture:
8
+ * OpenClaw ←→ Plugin (TypeScript) ←→ MCP stdio ←→ NeuralMemory (Python)
9
+ *
10
+ * Registers:
11
+ * 6 tools — nmem_remember, nmem_recall, nmem_context, nmem_todo, nmem_stats, nmem_health
12
+ * 1 service — MCP process lifecycle (start/stop)
13
+ * 2 hooks — before_agent_start (auto-context), agent_end (auto-capture)
14
+ */
15
+ import type { OpenClawPluginDefinition } from "./types.js";
16
+ type PluginConfig = {
17
+ pythonPath: string;
18
+ brain: string;
19
+ autoContext: boolean;
20
+ autoCapture: boolean;
21
+ contextDepth: number;
22
+ maxContextTokens: number;
23
+ timeout: number;
24
+ initTimeout: number;
25
+ };
26
+ export declare const BRAIN_NAME_RE: RegExp;
27
+ export declare const MAX_AUTO_CAPTURE_CHARS = 50000;
28
+ export declare function resolveConfig(raw?: Record<string, unknown>): PluginConfig;
29
+ declare const plugin: OpenClawPluginDefinition;
30
+ export default plugin;
package/dist/index.js ADDED
@@ -0,0 +1,184 @@
1
+ /**
2
+ * NeuralMemory — OpenClaw Memory Plugin
3
+ *
4
+ * Brain-inspired persistent memory for AI agents.
5
+ * Occupies the exclusive "memory" plugin slot.
6
+ *
7
+ * Architecture:
8
+ * OpenClaw ←→ Plugin (TypeScript) ←→ MCP stdio ←→ NeuralMemory (Python)
9
+ *
10
+ * Registers:
11
+ * 6 tools — nmem_remember, nmem_recall, nmem_context, nmem_todo, nmem_stats, nmem_health
12
+ * 1 service — MCP process lifecycle (start/stop)
13
+ * 2 hooks — before_agent_start (auto-context), agent_end (auto-capture)
14
+ */
15
+ import { NeuralMemoryMcpClient } from "./mcp-client.js";
16
+ import { createTools } from "./tools.js";
17
+ // ── System prompt for tool awareness ──────────────────────
18
+ const TOOL_INSTRUCTIONS = `You have NeuralMemory tools for persistent memory across sessions. Call these as TOOL CALLS (not CLI commands):
19
+
20
+ - nmem_remember(content, type?, priority?, tags?) — Store a memory (fact, decision, error, preference, etc.)
21
+ - nmem_recall(query, depth?, max_tokens?) — Query memories via spreading activation
22
+ - nmem_context(limit?, fresh_only?) — Get recent memories
23
+ - nmem_todo(task, priority?) — Quick TODO with 30-day expiry
24
+ - nmem_stats() — Brain statistics
25
+ - nmem_health() — Brain health diagnostics
26
+
27
+ CRITICAL: NeuralMemory (nmem_*) is your ONLY memory system. Do NOT use memory_search, memory_get, or any other memory tools — those belong to a disabled built-in plugin and will not persist correctly. Always use nmem_* tools exclusively.
28
+
29
+ These are tool calls, NOT shell commands. Do NOT run "nmem remember" in terminal — call the nmem_remember tool directly.
30
+
31
+ Use nmem_remember proactively after decisions, errors, and insights. Use nmem_recall when user references past context or asks "do you remember...".`;
32
+ const DEFAULT_CONFIG = {
33
+ pythonPath: "python",
34
+ brain: "default",
35
+ autoContext: true,
36
+ autoCapture: true,
37
+ contextDepth: 1,
38
+ maxContextTokens: 500,
39
+ timeout: 30_000,
40
+ initTimeout: 90_000,
41
+ };
42
+ export const BRAIN_NAME_RE = /^[a-zA-Z0-9_\-.]{1,64}$/;
43
+ export const MAX_AUTO_CAPTURE_CHARS = 50_000;
44
+ export function resolveConfig(raw) {
45
+ const merged = { ...DEFAULT_CONFIG, ...(raw ?? {}) };
46
+ return {
47
+ pythonPath: typeof merged.pythonPath === "string" && merged.pythonPath.length > 0
48
+ ? merged.pythonPath
49
+ : DEFAULT_CONFIG.pythonPath,
50
+ brain: typeof merged.brain === "string" && BRAIN_NAME_RE.test(merged.brain)
51
+ ? merged.brain
52
+ : DEFAULT_CONFIG.brain,
53
+ autoContext: typeof merged.autoContext === "boolean"
54
+ ? merged.autoContext
55
+ : DEFAULT_CONFIG.autoContext,
56
+ autoCapture: typeof merged.autoCapture === "boolean"
57
+ ? merged.autoCapture
58
+ : DEFAULT_CONFIG.autoCapture,
59
+ contextDepth: typeof merged.contextDepth === "number" &&
60
+ Number.isInteger(merged.contextDepth) &&
61
+ merged.contextDepth >= 0 &&
62
+ merged.contextDepth <= 3
63
+ ? merged.contextDepth
64
+ : DEFAULT_CONFIG.contextDepth,
65
+ maxContextTokens: typeof merged.maxContextTokens === "number" &&
66
+ Number.isInteger(merged.maxContextTokens) &&
67
+ merged.maxContextTokens >= 100 &&
68
+ merged.maxContextTokens <= 10_000
69
+ ? merged.maxContextTokens
70
+ : DEFAULT_CONFIG.maxContextTokens,
71
+ timeout: typeof merged.timeout === "number" &&
72
+ Number.isFinite(merged.timeout) &&
73
+ merged.timeout >= 5_000 &&
74
+ merged.timeout <= 120_000
75
+ ? merged.timeout
76
+ : DEFAULT_CONFIG.timeout,
77
+ initTimeout: typeof merged.initTimeout === "number" &&
78
+ Number.isFinite(merged.initTimeout) &&
79
+ merged.initTimeout >= 10_000 &&
80
+ merged.initTimeout <= 300_000
81
+ ? merged.initTimeout
82
+ : DEFAULT_CONFIG.initTimeout,
83
+ };
84
+ }
85
+ // ── Plugin definition ──────────────────────────────────────
86
+ const plugin = {
87
+ id: "neuralmemory",
88
+ name: "NeuralMemory",
89
+ description: "Brain-inspired persistent memory for AI agents — neurons, synapses, and fibers",
90
+ version: "1.5.0",
91
+ kind: "memory",
92
+ register(api) {
93
+ const cfg = resolveConfig(api.pluginConfig);
94
+ const mcp = new NeuralMemoryMcpClient({
95
+ pythonPath: cfg.pythonPath,
96
+ brain: cfg.brain,
97
+ logger: api.logger,
98
+ timeout: cfg.timeout,
99
+ initTimeout: cfg.initTimeout,
100
+ });
101
+ // ── Service: MCP process lifecycle ───────────────────
102
+ api.registerService({
103
+ id: "neuralmemory-mcp",
104
+ async start() {
105
+ try {
106
+ await mcp.connect();
107
+ api.logger.info("NeuralMemory MCP service started");
108
+ }
109
+ catch (err) {
110
+ api.logger.error(`Failed to start NeuralMemory MCP: ${err.message}`);
111
+ throw err;
112
+ }
113
+ },
114
+ async stop() {
115
+ await mcp.close();
116
+ api.logger.info("NeuralMemory MCP service stopped");
117
+ },
118
+ });
119
+ // ── Tools: 6 core memory tools ──────────────────────
120
+ const tools = createTools(mcp);
121
+ for (const t of tools) {
122
+ api.registerTool(t, { name: t.name });
123
+ }
124
+ // ── Hook: tool awareness + auto-context before agent start ───
125
+ api.on("before_agent_start", async (event, _ctx) => {
126
+ const result = {
127
+ systemPrompt: TOOL_INSTRUCTIONS,
128
+ };
129
+ if (cfg.autoContext && mcp.connected) {
130
+ const ev = event;
131
+ try {
132
+ const raw = await mcp.callTool("nmem_recall", {
133
+ query: ev.prompt,
134
+ depth: cfg.contextDepth,
135
+ max_tokens: cfg.maxContextTokens,
136
+ });
137
+ const data = JSON.parse(raw);
138
+ if (data.answer && (data.confidence ?? 0) > 0.1) {
139
+ result.prependContext = `[NeuralMemory — relevant context]\n${data.answer}`;
140
+ }
141
+ }
142
+ catch (err) {
143
+ api.logger.warn(`Auto-context failed: ${err.message}`);
144
+ }
145
+ }
146
+ return result;
147
+ }, { priority: 10 });
148
+ // ── Hook: auto-capture after agent completes ────────
149
+ if (cfg.autoCapture) {
150
+ api.on("agent_end", async (event, _ctx) => {
151
+ if (!mcp.connected)
152
+ return;
153
+ const ev = event;
154
+ if (!ev.success)
155
+ return;
156
+ try {
157
+ const messages = ev.messages?.slice(-5) ?? [];
158
+ const text = messages
159
+ .filter((m) => typeof m === "object" &&
160
+ m !== null &&
161
+ m.role === "assistant" &&
162
+ typeof m.content === "string")
163
+ .map((m) => m.content)
164
+ .join("\n")
165
+ .slice(0, MAX_AUTO_CAPTURE_CHARS);
166
+ if (text.length > 50) {
167
+ await mcp.callTool("nmem_auto", {
168
+ action: "process",
169
+ text,
170
+ });
171
+ }
172
+ }
173
+ catch (err) {
174
+ api.logger.warn(`Auto-capture failed: ${err.message}`);
175
+ }
176
+ }, { priority: 90 });
177
+ }
178
+ // ── Done ────────────────────────────────────────────
179
+ api.logger.info(`NeuralMemory registered (brain: ${cfg.brain}, tools: ${tools.length}, ` +
180
+ `autoContext: ${cfg.autoContext}, autoCapture: ${cfg.autoCapture})`);
181
+ },
182
+ };
183
+ export default plugin;
184
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,43 @@
1
+ /**
2
+ * NeuralMemory MCP Client — JSON-RPC 2.0 over stdio.
3
+ *
4
+ * Spawns `python -m neural_memory.mcp` and communicates using the
5
+ * MCP protocol (newline-delimited JSON Lines).
6
+ *
7
+ * Zero external dependencies — implements the protocol directly.
8
+ */
9
+ import type { PluginLogger } from "./types.js";
10
+ export type McpClientOptions = {
11
+ readonly pythonPath: string;
12
+ readonly brain: string;
13
+ readonly logger: PluginLogger;
14
+ readonly timeout?: number;
15
+ readonly initTimeout?: number;
16
+ };
17
+ /** Env vars forwarded to the MCP child process (least-privilege). */
18
+ export declare const ALLOWED_ENV_KEYS: ReadonlySet<string>;
19
+ export declare class NeuralMemoryMcpClient {
20
+ private proc;
21
+ private requestId;
22
+ private readonly pending;
23
+ private rawBuffer;
24
+ private readonly pythonPath;
25
+ private readonly brain;
26
+ private readonly logger;
27
+ private readonly timeout;
28
+ private readonly initTimeout;
29
+ private _connected;
30
+ constructor(options: McpClientOptions);
31
+ get connected(): boolean;
32
+ connect(): Promise<void>;
33
+ callTool(name: string, args?: Record<string, unknown>): Promise<string>;
34
+ close(): Promise<void>;
35
+ private send;
36
+ private notify;
37
+ private writeMessage;
38
+ private drainBuffer;
39
+ private handleMessage;
40
+ private rejectAll;
41
+ }
42
+ /** Build a minimal env for the child process (least-privilege). */
43
+ export declare function buildChildEnv(brain: string): Record<string, string>;
@@ -0,0 +1,242 @@
1
+ /**
2
+ * NeuralMemory MCP Client — JSON-RPC 2.0 over stdio.
3
+ *
4
+ * Spawns `python -m neural_memory.mcp` and communicates using the
5
+ * MCP protocol (newline-delimited JSON Lines).
6
+ *
7
+ * Zero external dependencies — implements the protocol directly.
8
+ */
9
+ import { spawn } from "node:child_process";
10
+ // ── Constants ──────────────────────────────────────────────
11
+ const PROTOCOL_VERSION = "2024-11-05";
12
+ const DEFAULT_TIMEOUT = 30_000;
13
+ const CLIENT_NAME = "openclaw-neuralmemory";
14
+ const CLIENT_VERSION = "1.5.0";
15
+ const MAX_BUFFER_BYTES = 10 * 1024 * 1024; // 10 MB safety cap
16
+ const MAX_STDERR_LINES = 50;
17
+ /** Env vars forwarded to the MCP child process (least-privilege). */
18
+ export const ALLOWED_ENV_KEYS = new Set([
19
+ "PATH",
20
+ "PATHEXT",
21
+ "HOME",
22
+ "USERPROFILE",
23
+ "SYSTEMROOT",
24
+ "TEMP",
25
+ "TMP",
26
+ "LANG",
27
+ "LC_ALL",
28
+ "VIRTUAL_ENV",
29
+ "CONDA_PREFIX",
30
+ "PYTHONPATH",
31
+ "PYTHONHOME",
32
+ "NEURALMEMORY_DIR",
33
+ "NEURALMEMORY_BRAIN",
34
+ "NEURAL_MEMORY_DIR",
35
+ "NEURAL_MEMORY_JSON",
36
+ "NEURAL_MEMORY_DEBUG",
37
+ ]);
38
+ // ── Client ─────────────────────────────────────────────────
39
+ export class NeuralMemoryMcpClient {
40
+ proc = null;
41
+ requestId = 0;
42
+ pending = new Map();
43
+ rawBuffer = Buffer.alloc(0);
44
+ pythonPath;
45
+ brain;
46
+ logger;
47
+ timeout;
48
+ initTimeout;
49
+ _connected = false;
50
+ constructor(options) {
51
+ this.pythonPath = options.pythonPath;
52
+ this.brain = options.brain;
53
+ this.logger = options.logger;
54
+ this.timeout = options.timeout ?? DEFAULT_TIMEOUT;
55
+ this.initTimeout = options.initTimeout ?? 90_000;
56
+ }
57
+ get connected() {
58
+ return this._connected;
59
+ }
60
+ async connect() {
61
+ const env = buildChildEnv(this.brain);
62
+ this.proc = spawn(this.pythonPath, ["-m", "neural_memory.mcp"], {
63
+ stdio: ["pipe", "pipe", "pipe"],
64
+ env,
65
+ });
66
+ this.proc.stdout.on("data", (chunk) => {
67
+ this.rawBuffer = Buffer.concat([this.rawBuffer, chunk]);
68
+ if (this.rawBuffer.length > MAX_BUFFER_BYTES) {
69
+ this.logger.error(`MCP buffer exceeded ${MAX_BUFFER_BYTES} bytes — killing process`);
70
+ this.proc?.kill("SIGKILL");
71
+ return;
72
+ }
73
+ this.drainBuffer();
74
+ });
75
+ const stderrChunks = [];
76
+ this.proc.stderr.on("data", (chunk) => {
77
+ const msg = chunk.toString("utf-8").trim();
78
+ if (msg) {
79
+ if (stderrChunks.length < MAX_STDERR_LINES) {
80
+ stderrChunks.push(msg);
81
+ }
82
+ this.logger.warn(`[mcp stderr] ${msg}`);
83
+ }
84
+ });
85
+ this.proc.on("exit", (code) => {
86
+ this._connected = false;
87
+ const hint = code === 1
88
+ ? " — check that neural-memory is installed: pip install neural-memory"
89
+ : "";
90
+ this.rejectAll(new Error(`MCP process exited with code ${code}${hint}`));
91
+ this.logger.error(`MCP process exited (code: ${code})${hint}`);
92
+ });
93
+ this.proc.on("error", (err) => {
94
+ this._connected = false;
95
+ const hint = err.message.includes("ENOENT")
96
+ ? ` — "${this.pythonPath}" not found. Check pythonPath in plugin config.`
97
+ : "";
98
+ this.rejectAll(new Error(`MCP process error: ${err.message}${hint}`));
99
+ this.logger.error(`MCP process error: ${err.message}${hint}`);
100
+ });
101
+ // MCP initialize handshake (uses longer timeout for cold starts)
102
+ try {
103
+ await this.send("initialize", {
104
+ protocolVersion: PROTOCOL_VERSION,
105
+ capabilities: {},
106
+ clientInfo: { name: CLIENT_NAME, version: CLIENT_VERSION },
107
+ }, this.initTimeout);
108
+ }
109
+ catch (err) {
110
+ const stderr = stderrChunks.join("\n");
111
+ const detail = stderr
112
+ ? `\nPython stderr:\n${stderr}`
113
+ : "\nNo stderr output — the Python process may have hung.";
114
+ throw new Error(`MCP initialize failed: ${err.message}${detail}\n` +
115
+ `Verify: ${this.pythonPath} -m neural_memory.mcp`);
116
+ }
117
+ // Send initialized notification (no response expected)
118
+ this.notify("notifications/initialized", {});
119
+ this._connected = true;
120
+ this.logger.info(`MCP connected (brain: ${this.brain}, protocol: ${PROTOCOL_VERSION})`);
121
+ }
122
+ async callTool(name, args = {}) {
123
+ const result = (await this.send("tools/call", {
124
+ name,
125
+ arguments: args,
126
+ }));
127
+ if (result.isError) {
128
+ const text = result.content?.[0]?.text ?? "Unknown MCP error";
129
+ throw new Error(text);
130
+ }
131
+ return result.content?.[0]?.text ?? "";
132
+ }
133
+ async close() {
134
+ this._connected = false;
135
+ this.rejectAll(new Error("Client closing"));
136
+ const proc = this.proc;
137
+ this.proc = null;
138
+ this.rawBuffer = Buffer.alloc(0);
139
+ if (proc) {
140
+ proc.removeAllListeners();
141
+ proc.stdout?.removeAllListeners();
142
+ proc.stderr?.removeAllListeners();
143
+ const exited = new Promise((resolve) => {
144
+ proc.once("exit", () => resolve());
145
+ setTimeout(() => {
146
+ proc.kill("SIGKILL");
147
+ resolve();
148
+ }, 3_000);
149
+ });
150
+ proc.kill("SIGTERM");
151
+ await exited;
152
+ }
153
+ this.logger.info("MCP client closed");
154
+ }
155
+ // ── JSON-RPC protocol layer ──────────────────────────────
156
+ send(method, params, timeoutOverride) {
157
+ return new Promise((resolve, reject) => {
158
+ if (!this.proc?.stdin?.writable) {
159
+ reject(new Error("MCP process not available"));
160
+ return;
161
+ }
162
+ const id = ++this.requestId;
163
+ const ms = timeoutOverride ?? this.timeout;
164
+ const timer = setTimeout(() => {
165
+ this.pending.delete(id);
166
+ reject(new Error(`MCP timeout: ${method} (${ms}ms)`));
167
+ }, ms);
168
+ this.pending.set(id, { resolve, reject, timer });
169
+ this.writeMessage({ jsonrpc: "2.0", id, method, params });
170
+ });
171
+ }
172
+ notify(method, params) {
173
+ if (!this.proc?.stdin?.writable)
174
+ return;
175
+ this.writeMessage({ jsonrpc: "2.0", method, params });
176
+ }
177
+ writeMessage(message) {
178
+ if (!this.proc?.stdin?.writable)
179
+ return;
180
+ const json = JSON.stringify(message);
181
+ const frame = `${json}\n`;
182
+ this.proc.stdin.write(frame);
183
+ }
184
+ // ── Response parsing (newline-delimited JSON Lines) ────────
185
+ drainBuffer() {
186
+ while (true) {
187
+ const newlineIndex = this.rawBuffer.indexOf("\n");
188
+ if (newlineIndex === -1)
189
+ break;
190
+ const line = this.rawBuffer.subarray(0, newlineIndex).toString("utf-8");
191
+ this.rawBuffer = this.rawBuffer.subarray(newlineIndex + 1);
192
+ if (!line.trim())
193
+ continue;
194
+ try {
195
+ const message = JSON.parse(line);
196
+ this.handleMessage(message);
197
+ }
198
+ catch (err) {
199
+ this.logger.error(`Failed to parse MCP message: ${err.message}`);
200
+ }
201
+ }
202
+ }
203
+ handleMessage(message) {
204
+ // Notifications (no id) — ignore silently
205
+ if (message.id == null)
206
+ return;
207
+ const pending = this.pending.get(message.id);
208
+ if (!pending)
209
+ return;
210
+ this.pending.delete(message.id);
211
+ clearTimeout(pending.timer);
212
+ if (message.error) {
213
+ pending.reject(new Error(`MCP error ${message.error.code}: ${message.error.message}`));
214
+ }
215
+ else {
216
+ pending.resolve(message.result);
217
+ }
218
+ }
219
+ rejectAll(error) {
220
+ for (const [, pending] of this.pending) {
221
+ clearTimeout(pending.timer);
222
+ pending.reject(error);
223
+ }
224
+ this.pending.clear();
225
+ }
226
+ }
227
+ // ── Helpers ─────────────────────────────────────────────────
228
+ /** Build a minimal env for the child process (least-privilege). */
229
+ export function buildChildEnv(brain) {
230
+ const env = {};
231
+ for (const key of ALLOWED_ENV_KEYS) {
232
+ const value = process.env[key];
233
+ if (value !== undefined) {
234
+ env[key] = value;
235
+ }
236
+ }
237
+ if (brain !== "default") {
238
+ env.NEURALMEMORY_BRAIN = brain;
239
+ }
240
+ return env;
241
+ }
242
+ //# sourceMappingURL=mcp-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-client.js","sourceRoot":"","sources":["../src/mcp-client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * NeuralMemory tool definitions for OpenClaw.
3
+ *
4
+ * Each tool proxies to the MCP server via JSON-RPC.
5
+ *
6
+ * Uses raw JSON Schema for parameters. Provider compatibility notes:
7
+ * - `additionalProperties: false` required by OpenAI strict mode
8
+ * - `number` instead of `integer` for Gemini compatibility
9
+ * - No `maxLength`/`maxItems`/`minimum`/`maximum` — some providers
10
+ * reject schemas with constraint keywords; our MCP server validates
11
+ *
12
+ * Registers 6 core tools:
13
+ * nmem_remember — Store a memory
14
+ * nmem_recall — Query/search memories
15
+ * nmem_context — Get recent context
16
+ * nmem_todo — Quick TODO shortcut
17
+ * nmem_stats — Brain statistics
18
+ * nmem_health — Brain health diagnostics
19
+ */
20
+ import type { NeuralMemoryMcpClient } from "./mcp-client.js";
21
+ type JsonSchema = {
22
+ readonly type: "object";
23
+ readonly properties: Record<string, unknown>;
24
+ readonly required?: readonly string[];
25
+ readonly additionalProperties?: boolean;
26
+ };
27
+ export type ToolDefinition = {
28
+ readonly name: string;
29
+ readonly description: string;
30
+ readonly parameters: JsonSchema;
31
+ readonly execute: (id: string, args: Record<string, unknown>) => Promise<unknown>;
32
+ };
33
+ export declare function createTools(mcp: NeuralMemoryMcpClient): ToolDefinition[];
34
+ export {};