@t0ken.ai/memoryx-openclaw-plugin 1.0.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,14 @@
1
+ /**
2
+ * MemoryX Real-time Plugin for OpenClaw
3
+ *
4
+ * Features:
5
+ * 1. Real-time message capture to MemoryX
6
+ * 2. Auto-recall memories before agent starts
7
+ * 3. Compatible with memoryx-realtime-plugin (avoids duplication)
8
+ */
9
+ export declare function onMessage(message: string, context: Record<string, any>): Promise<{
10
+ context: Record<string, any>;
11
+ }>;
12
+ export declare function onResponse(response: string, context: Record<string, any>): string;
13
+ export declare function register(api: any): void;
14
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AA6GH,wBAAsB,SAAS,CAC7B,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAC3B,OAAO,CAAC;IAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;CAAE,CAAC,CAmB3C;AAED,wBAAgB,UAAU,CACxB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAC3B,MAAM,CAER;AAGD,wBAAgB,QAAQ,CAAC,GAAG,EAAE,GAAG,QA0ChC"}
package/dist/index.js ADDED
@@ -0,0 +1,164 @@
1
+ /**
2
+ * MemoryX Real-time Plugin for OpenClaw
3
+ *
4
+ * Features:
5
+ * 1. Real-time message capture to MemoryX
6
+ * 2. Auto-recall memories before agent starts
7
+ * 3. Compatible with memoryx-realtime-plugin (avoids duplication)
8
+ */
9
+ // MemoryX API configuration
10
+ const MEMORYX_API_BASE = "http://t0ken.ai/api";
11
+ // Check if memoryx-realtime-plugin is installed
12
+ function isPluginInstalled() {
13
+ try {
14
+ const { execSync } = require("child_process");
15
+ const result = execSync("openclaw plugins list", {
16
+ encoding: "utf8",
17
+ timeout: 5000,
18
+ });
19
+ return (result.includes("memoryx-realtime") && result.includes("loaded"));
20
+ }
21
+ catch (e) {
22
+ return false;
23
+ }
24
+ }
25
+ // Store message to MemoryX
26
+ async function storeToMemoryX(content, category = "semantic", metadata = {}) {
27
+ try {
28
+ const response = await fetch(`${MEMORYX_API_BASE}/memories`, {
29
+ method: "POST",
30
+ headers: {
31
+ "Content-Type": "application/json",
32
+ },
33
+ body: JSON.stringify({
34
+ content,
35
+ category,
36
+ project_id: "default",
37
+ metadata: {
38
+ ...metadata,
39
+ source: "openclaw-realtime-plugin",
40
+ timestamp: new Date().toISOString(),
41
+ },
42
+ }),
43
+ });
44
+ return response.ok;
45
+ }
46
+ catch (error) {
47
+ return false;
48
+ }
49
+ }
50
+ // Search MemoryX
51
+ async function searchMemoryX(query, limit = 3) {
52
+ try {
53
+ const response = await fetch(`${MEMORYX_API_BASE}/memories/search`, {
54
+ method: "POST",
55
+ headers: {
56
+ "Content-Type": "application/json",
57
+ },
58
+ body: JSON.stringify({
59
+ query,
60
+ limit,
61
+ project_id: "default",
62
+ }),
63
+ });
64
+ if (!response.ok)
65
+ return [];
66
+ const data = (await response.json());
67
+ return data.data || [];
68
+ }
69
+ catch (error) {
70
+ return [];
71
+ }
72
+ }
73
+ // Check if content should be captured
74
+ function shouldCapture(text) {
75
+ if (!text || text.length < 5 || text.length > 500)
76
+ return false;
77
+ const skipPatterns = [
78
+ /^[好的ok谢谢嗯啊哈哈你好hihello拜拜再见]{1,3}$/i,
79
+ /^[??!!。,,\s]{1,5}$/,
80
+ ];
81
+ for (const pattern of skipPatterns) {
82
+ if (pattern.test(text.trim()))
83
+ return false;
84
+ }
85
+ const triggers = [
86
+ /记住|记一下|别忘了|save|remember/i,
87
+ /我喜欢|我讨厌|我习惯|我偏好|prefer|like|hate/i,
88
+ /我是|我在|我来自|i am|i work/i,
89
+ /纠正|更正|应该是|correct|actually/i,
90
+ /计划|打算|目标|plan|goal|will/i,
91
+ ];
92
+ return triggers.some((pattern) => pattern.test(text));
93
+ }
94
+ // Detect category
95
+ function detectCategory(text) {
96
+ const lower = text.toLowerCase();
97
+ if (/prefer|like|hate|习惯|偏好|喜欢|讨厌/.test(lower))
98
+ return "preference";
99
+ if (/correct|纠正|更正/.test(lower))
100
+ return "correction";
101
+ if (/plan|goal|计划|打算/.test(lower))
102
+ return "plan";
103
+ return "semantic";
104
+ }
105
+ // OpenClaw Hook handlers
106
+ export async function onMessage(message, context) {
107
+ // Skip if memoryx-realtime-plugin is installed (avoid duplication)
108
+ if (isPluginInstalled()) {
109
+ return { context };
110
+ }
111
+ if (!shouldCapture(message)) {
112
+ return { context };
113
+ }
114
+ const category = detectCategory(message);
115
+ // Async store (non-blocking)
116
+ storeToMemoryX(message, category, {
117
+ from: context?.from,
118
+ channel: context?.channelId,
119
+ }).catch(() => { });
120
+ return { context };
121
+ }
122
+ export function onResponse(response, context) {
123
+ return response;
124
+ }
125
+ // Lifecycle hooks for OpenClaw Extension
126
+ export function register(api) {
127
+ api.logger.info("[MemoryX Realtime] Plugin registering...");
128
+ // 1. Message capture
129
+ api.on("message_received", async (event, ctx) => {
130
+ if (isPluginInstalled())
131
+ return;
132
+ const { content, from, timestamp } = event;
133
+ if (!shouldCapture(content))
134
+ return;
135
+ const category = detectCategory(content);
136
+ await storeToMemoryX(content, category, {
137
+ from,
138
+ channel: ctx.channelId,
139
+ timestamp,
140
+ });
141
+ });
142
+ // 2. Auto-recall before agent starts
143
+ api.on("before_agent_start", async (event, ctx) => {
144
+ const { prompt } = event;
145
+ if (!prompt || prompt.length < 5)
146
+ return;
147
+ try {
148
+ const results = await searchMemoryX(prompt, 3);
149
+ if (results.length === 0)
150
+ return;
151
+ const memories = results
152
+ .map((r) => `- [${r.category}] ${r.content}`)
153
+ .join("\n");
154
+ api.logger.info(`[MemoryX] Recalled ${results.length} memories`);
155
+ return {
156
+ prependContext: `[相关记忆]\n${memories}\n[End of memories]`,
157
+ };
158
+ }
159
+ catch (error) {
160
+ api.logger.warn(`[MemoryX] Recall failed: ${error}`);
161
+ }
162
+ });
163
+ api.logger.info("[MemoryX Realtime] Plugin registered successfully");
164
+ }
@@ -0,0 +1,16 @@
1
+ {
2
+ "id": "memoryx-realtime-plugin",
3
+ "name": "MemoryX Real-time Plugin",
4
+ "version": "1.0.0",
5
+ "description": "Real-time memory capture and recall for OpenClaw",
6
+ "entry": "./dist/index.js",
7
+ "kind": "memory",
8
+ "configSchema": {
9
+ "type": "object",
10
+ "properties": {
11
+ "apiBaseUrl": {
12
+ "type": "string"
13
+ }
14
+ }
15
+ }
16
+ }
package/package.json ADDED
@@ -0,0 +1,27 @@
1
+ {
2
+ "name": "@t0ken.ai/memoryx-openclaw-plugin",
3
+ "version": "1.0.0",
4
+ "description": "MemoryX real-time memory capture and recall plugin for OpenClaw",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "scripts": {
9
+ "build": "tsc",
10
+ "prepare": "npm run build"
11
+ },
12
+ "keywords": ["openclaw", "memoryx", "memory", "plugin"],
13
+ "author": "MemoryX Team",
14
+ "license": "MIT",
15
+ "repository": {
16
+ "type": "git",
17
+ "url": "https://github.com/t0ken-ai/MemoryX.git",
18
+ "directory": "plugins/memoryx-realtime-plugin"
19
+ },
20
+ "openclaw": {
21
+ "extensions": ["./dist/index.js"]
22
+ },
23
+ "devDependencies": {
24
+ "typescript": "^5.0.0",
25
+ "@types/node": "^20.0.0"
26
+ }
27
+ }
package/src/index.ts ADDED
@@ -0,0 +1,191 @@
1
+ /**
2
+ * MemoryX Real-time Plugin for OpenClaw
3
+ *
4
+ * Features:
5
+ * 1. Real-time message capture to MemoryX
6
+ * 2. Auto-recall memories before agent starts
7
+ * 3. Compatible with memoryx-realtime-plugin (avoids duplication)
8
+ */
9
+
10
+ // MemoryX API configuration
11
+ const MEMORYX_API_BASE = "http://t0ken.ai/api";
12
+
13
+ // Check if memoryx-realtime-plugin is installed
14
+ function isPluginInstalled(): boolean {
15
+ try {
16
+ const { execSync } = require("child_process");
17
+ const result = execSync("openclaw plugins list", {
18
+ encoding: "utf8",
19
+ timeout: 5000,
20
+ });
21
+ return (
22
+ result.includes("memoryx-realtime") && result.includes("loaded")
23
+ );
24
+ } catch (e) {
25
+ return false;
26
+ }
27
+ }
28
+
29
+ // Store message to MemoryX
30
+ async function storeToMemoryX(
31
+ content: string,
32
+ category: string = "semantic",
33
+ metadata: Record<string, any> = {}
34
+ ): Promise<boolean> {
35
+ try {
36
+ const response = await fetch(`${MEMORYX_API_BASE}/memories`, {
37
+ method: "POST",
38
+ headers: {
39
+ "Content-Type": "application/json",
40
+ },
41
+ body: JSON.stringify({
42
+ content,
43
+ category,
44
+ project_id: "default",
45
+ metadata: {
46
+ ...metadata,
47
+ source: "openclaw-realtime-plugin",
48
+ timestamp: new Date().toISOString(),
49
+ },
50
+ }),
51
+ });
52
+ return response.ok;
53
+ } catch (error) {
54
+ return false;
55
+ }
56
+ }
57
+
58
+ // Search MemoryX
59
+ async function searchMemoryX(
60
+ query: string,
61
+ limit: number = 3
62
+ ): Promise<Array<{ id: string; content: string; category: string; similarity: number }>> {
63
+ try {
64
+ const response = await fetch(`${MEMORYX_API_BASE}/memories/search`, {
65
+ method: "POST",
66
+ headers: {
67
+ "Content-Type": "application/json",
68
+ },
69
+ body: JSON.stringify({
70
+ query,
71
+ limit,
72
+ project_id: "default",
73
+ }),
74
+ });
75
+ if (!response.ok) return [];
76
+ const data = (await response.json()) as { data?: any[] };
77
+ return data.data || [];
78
+ } catch (error) {
79
+ return [];
80
+ }
81
+ }
82
+
83
+ // Check if content should be captured
84
+ function shouldCapture(text: string): boolean {
85
+ if (!text || text.length < 5 || text.length > 500) return false;
86
+
87
+ const skipPatterns = [
88
+ /^[好的ok谢谢嗯啊哈哈你好hihello拜拜再见]{1,3}$/i,
89
+ /^[??!!。,,\s]{1,5}$/,
90
+ ];
91
+
92
+ for (const pattern of skipPatterns) {
93
+ if (pattern.test(text.trim())) return false;
94
+ }
95
+
96
+ const triggers = [
97
+ /记住|记一下|别忘了|save|remember/i,
98
+ /我喜欢|我讨厌|我习惯|我偏好|prefer|like|hate/i,
99
+ /我是|我在|我来自|i am|i work/i,
100
+ /纠正|更正|应该是|correct|actually/i,
101
+ /计划|打算|目标|plan|goal|will/i,
102
+ ];
103
+
104
+ return triggers.some((pattern) => pattern.test(text));
105
+ }
106
+
107
+ // Detect category
108
+ function detectCategory(text: string): string {
109
+ const lower = text.toLowerCase();
110
+ if (/prefer|like|hate|习惯|偏好|喜欢|讨厌/.test(lower)) return "preference";
111
+ if (/correct|纠正|更正/.test(lower)) return "correction";
112
+ if (/plan|goal|计划|打算/.test(lower)) return "plan";
113
+ return "semantic";
114
+ }
115
+
116
+ // OpenClaw Hook handlers
117
+ export async function onMessage(
118
+ message: string,
119
+ context: Record<string, any>
120
+ ): Promise<{ context: Record<string, any> }> {
121
+ // Skip if memoryx-realtime-plugin is installed (avoid duplication)
122
+ if (isPluginInstalled()) {
123
+ return { context };
124
+ }
125
+
126
+ if (!shouldCapture(message)) {
127
+ return { context };
128
+ }
129
+
130
+ const category = detectCategory(message);
131
+
132
+ // Async store (non-blocking)
133
+ storeToMemoryX(message, category, {
134
+ from: context?.from,
135
+ channel: context?.channelId,
136
+ }).catch(() => {});
137
+
138
+ return { context };
139
+ }
140
+
141
+ export function onResponse(
142
+ response: string,
143
+ context: Record<string, any>
144
+ ): string {
145
+ return response;
146
+ }
147
+
148
+ // Lifecycle hooks for OpenClaw Extension
149
+ export function register(api: any) {
150
+ api.logger.info("[MemoryX Realtime] Plugin registering...");
151
+
152
+ // 1. Message capture
153
+ api.on("message_received", async (event: any, ctx: any) => {
154
+ if (isPluginInstalled()) return;
155
+
156
+ const { content, from, timestamp } = event;
157
+ if (!shouldCapture(content)) return;
158
+
159
+ const category = detectCategory(content);
160
+ await storeToMemoryX(content, category, {
161
+ from,
162
+ channel: ctx.channelId,
163
+ timestamp,
164
+ });
165
+ });
166
+
167
+ // 2. Auto-recall before agent starts
168
+ api.on("before_agent_start", async (event: any, ctx: any) => {
169
+ const { prompt } = event;
170
+ if (!prompt || prompt.length < 5) return;
171
+
172
+ try {
173
+ const results = await searchMemoryX(prompt, 3);
174
+ if (results.length === 0) return;
175
+
176
+ const memories = results
177
+ .map((r) => `- [${r.category}] ${r.content}`)
178
+ .join("\n");
179
+
180
+ api.logger.info(`[MemoryX] Recalled ${results.length} memories`);
181
+
182
+ return {
183
+ prependContext: `[相关记忆]\n${memories}\n[End of memories]`,
184
+ };
185
+ } catch (error) {
186
+ api.logger.warn(`[MemoryX] Recall failed: ${error}`);
187
+ }
188
+ });
189
+
190
+ api.logger.info("[MemoryX Realtime] Plugin registered successfully");
191
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,17 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "NodeNext",
5
+ "moduleResolution": "NodeNext",
6
+ "lib": ["ES2022"],
7
+ "outDir": "./dist",
8
+ "rootDir": "./src",
9
+ "strict": true,
10
+ "esModuleInterop": true,
11
+ "skipLibCheck": true,
12
+ "forceConsistentCasingInFileNames": true,
13
+ "declaration": true,
14
+ "declarationMap": true
15
+ },
16
+ "include": ["src/**/*"]
17
+ }