@matrixorigin/thememoria 0.4.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,254 @@
1
+ {
2
+ "id": "memory-memoria",
3
+ "name": "Memory (Memoria)",
4
+ "description": "Memoria-backed long-term memory plugin for OpenClaw powered by the Rust memoria CLI and API.",
5
+ "version": "0.3.0",
6
+ "kind": "memory",
7
+ "uiHints": {
8
+ "backend": {
9
+ "label": "Backend Mode",
10
+ "help": "embedded runs the Rust memoria CLI locally against MatrixOne; http connects to an existing Memoria API.",
11
+ "placeholder": "embedded"
12
+ },
13
+ "dbUrl": {
14
+ "label": "MatrixOne Connection String",
15
+ "help": "Embedded mode only. Rust Memoria expects a MySQL DSN; old mysql+pymysql:// values are normalized automatically.",
16
+ "placeholder": "mysql://root:111@127.0.0.1:6001/memoria"
17
+ },
18
+ "apiUrl": {
19
+ "label": "Memoria API URL",
20
+ "help": "Only used when backend=http.",
21
+ "placeholder": "http://127.0.0.1:8100"
22
+ },
23
+ "apiKey": {
24
+ "label": "Memoria API Token",
25
+ "help": "Bearer token for backend=http.",
26
+ "sensitive": true,
27
+ "placeholder": "mem-..."
28
+ },
29
+ "memoriaExecutable": {
30
+ "label": "Memoria Executable",
31
+ "help": "Path or command name for the Rust memoria CLI.",
32
+ "advanced": true,
33
+ "placeholder": "memoria"
34
+ },
35
+ "defaultUserId": {
36
+ "label": "Default User ID",
37
+ "help": "Single-user quick-start identity used unless userIdStrategy derives one from the OpenClaw runtime context.",
38
+ "placeholder": "openclaw-user"
39
+ },
40
+ "userIdStrategy": {
41
+ "label": "User ID Strategy",
42
+ "help": "config keeps one shared Memoria user; agentId or sessionKey derive the identity from OpenClaw runtime context.",
43
+ "advanced": true,
44
+ "placeholder": "config"
45
+ },
46
+ "autoRecall": {
47
+ "label": "Auto-Recall",
48
+ "help": "Automatically inject relevant memories into the prompt before each run."
49
+ },
50
+ "autoObserve": {
51
+ "label": "Auto-Observe",
52
+ "help": "Automatically extract memories from recent conversation turns at agent_end."
53
+ },
54
+ "retrieveTopK": {
55
+ "label": "Recall Top K",
56
+ "help": "Maximum number of memories returned for memory_search and auto-recall.",
57
+ "placeholder": "5"
58
+ },
59
+ "recallMinPromptLength": {
60
+ "label": "Recall Min Length",
61
+ "help": "Prompts shorter than this are skipped for auto-recall.",
62
+ "advanced": true,
63
+ "placeholder": "8"
64
+ },
65
+ "includeCrossSession": {
66
+ "label": "Cross-Session Recall",
67
+ "help": "Compatibility flag retained from the Python plugin. Rust MCP currently uses the upstream default retrieval behavior.",
68
+ "advanced": true
69
+ },
70
+ "retrieveMemoryTypes": {
71
+ "label": "Memory Types",
72
+ "help": "Compatibility hint retained from the Python plugin. Rust MCP currently ignores this filter.",
73
+ "advanced": true
74
+ },
75
+ "observeTailMessages": {
76
+ "label": "Observe Tail Messages",
77
+ "help": "Number of recent user/assistant messages forwarded to memory_observe.",
78
+ "advanced": true,
79
+ "placeholder": "6"
80
+ },
81
+ "observeMaxChars": {
82
+ "label": "Observe Max Chars",
83
+ "help": "Maximum total characters forwarded to memory_observe.",
84
+ "advanced": true,
85
+ "placeholder": "6000"
86
+ },
87
+ "timeoutMs": {
88
+ "label": "Request Timeout",
89
+ "help": "Timeout for Rust Memoria CLI requests in milliseconds.",
90
+ "advanced": true,
91
+ "placeholder": "15000"
92
+ },
93
+ "maxListPages": {
94
+ "label": "List Scan Limit",
95
+ "help": "Used by OpenClaw-side fallback scans for memory_get and derived stats.",
96
+ "advanced": true,
97
+ "placeholder": "20"
98
+ },
99
+ "embeddingProvider": {
100
+ "label": "Embedding Provider",
101
+ "help": "Embedded mode only. Prebuilt Rust release binaries are typically used with openai-compatible embedding services.",
102
+ "placeholder": "openai"
103
+ },
104
+ "embeddingModel": {
105
+ "label": "Embedding Model",
106
+ "help": "Embedded mode only.",
107
+ "placeholder": "text-embedding-3-small"
108
+ },
109
+ "embeddingBaseUrl": {
110
+ "label": "Embedding Base URL",
111
+ "help": "Embedded mode only. Optional for official OpenAI; required for compatible gateways.",
112
+ "advanced": true,
113
+ "placeholder": "https://api.openai.com/v1"
114
+ },
115
+ "embeddingApiKey": {
116
+ "label": "Embedding API Key",
117
+ "help": "Embedded mode only. Required for OpenAI-compatible providers unless you built Memoria with local-embedding.",
118
+ "advanced": true,
119
+ "sensitive": true,
120
+ "placeholder": "sk-..."
121
+ },
122
+ "embeddingDim": {
123
+ "label": "Embedding Dimensions",
124
+ "help": "Embedded mode only. Set this before first startup so Memoria creates the right schema.",
125
+ "advanced": true,
126
+ "placeholder": "1536"
127
+ },
128
+ "llmApiKey": {
129
+ "label": "Observer LLM API Key",
130
+ "help": "Optional. Enables auto-observe extraction and internal LLM-backed Memoria tools.",
131
+ "advanced": true,
132
+ "sensitive": true,
133
+ "placeholder": "sk-..."
134
+ },
135
+ "llmBaseUrl": {
136
+ "label": "Observer LLM Base URL",
137
+ "help": "Optional OpenAI-compatible base URL for embedded auto-observe and reflection flows.",
138
+ "advanced": true,
139
+ "placeholder": "https://api.openai.com/v1"
140
+ },
141
+ "llmModel": {
142
+ "label": "Observer LLM Model",
143
+ "help": "Model used by embedded auto-observe and internal reflection/entity extraction.",
144
+ "advanced": true,
145
+ "placeholder": "gpt-4o-mini"
146
+ }
147
+ },
148
+ "configSchema": {
149
+ "type": "object",
150
+ "additionalProperties": false,
151
+ "properties": {
152
+ "backend": {
153
+ "type": "string",
154
+ "enum": ["embedded", "http"]
155
+ },
156
+ "dbUrl": {
157
+ "type": "string"
158
+ },
159
+ "apiUrl": {
160
+ "type": "string"
161
+ },
162
+ "apiKey": {
163
+ "type": "string"
164
+ },
165
+ "memoriaExecutable": {
166
+ "type": "string"
167
+ },
168
+ "pythonExecutable": {
169
+ "type": "string"
170
+ },
171
+ "memoriaRoot": {
172
+ "type": "string"
173
+ },
174
+ "defaultUserId": {
175
+ "type": "string"
176
+ },
177
+ "userIdStrategy": {
178
+ "type": "string",
179
+ "enum": ["config", "agentId", "sessionKey"]
180
+ },
181
+ "timeoutMs": {
182
+ "type": "integer",
183
+ "minimum": 1000,
184
+ "maximum": 120000
185
+ },
186
+ "maxListPages": {
187
+ "type": "integer",
188
+ "minimum": 1,
189
+ "maximum": 100
190
+ },
191
+ "autoRecall": {
192
+ "type": "boolean"
193
+ },
194
+ "autoObserve": {
195
+ "type": "boolean"
196
+ },
197
+ "retrieveTopK": {
198
+ "type": "integer",
199
+ "minimum": 1,
200
+ "maximum": 20
201
+ },
202
+ "recallMinPromptLength": {
203
+ "type": "integer",
204
+ "minimum": 1,
205
+ "maximum": 500
206
+ },
207
+ "includeCrossSession": {
208
+ "type": "boolean"
209
+ },
210
+ "retrieveMemoryTypes": {
211
+ "type": "array",
212
+ "items": {
213
+ "type": "string",
214
+ "enum": ["profile", "semantic", "procedural", "working", "tool_result"]
215
+ }
216
+ },
217
+ "observeTailMessages": {
218
+ "type": "integer",
219
+ "minimum": 2,
220
+ "maximum": 30
221
+ },
222
+ "observeMaxChars": {
223
+ "type": "integer",
224
+ "minimum": 256,
225
+ "maximum": 50000
226
+ },
227
+ "embeddingProvider": {
228
+ "type": "string"
229
+ },
230
+ "embeddingModel": {
231
+ "type": "string"
232
+ },
233
+ "embeddingBaseUrl": {
234
+ "type": "string"
235
+ },
236
+ "embeddingApiKey": {
237
+ "type": "string"
238
+ },
239
+ "embeddingDim": {
240
+ "type": "integer",
241
+ "minimum": 1
242
+ },
243
+ "llmApiKey": {
244
+ "type": "string"
245
+ },
246
+ "llmBaseUrl": {
247
+ "type": "string"
248
+ },
249
+ "llmModel": {
250
+ "type": "string"
251
+ }
252
+ }
253
+ }
254
+ }
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "@matrixorigin/thememoria",
3
+ "version": "0.4.0",
4
+ "description": "OpenClaw memory plugin that uses the Rust Memoria CLI/API for embedded and remote backends.",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "git+https://github.com/matrixorigin/Memoria.git"
8
+ },
9
+ "homepage": "https://github.com/matrixorigin/Memoria/tree/main/plugins/openclaw",
10
+ "bugs": {
11
+ "url": "https://github.com/matrixorigin/Memoria/issues"
12
+ },
13
+ "keywords": [
14
+ "openclaw",
15
+ "openclaw-plugin",
16
+ "memory",
17
+ "memoria",
18
+ "matrixone",
19
+ "local-first"
20
+ ],
21
+ "license": "Apache-2.0",
22
+ "type": "module",
23
+ "files": [
24
+ "README.md",
25
+ "scripts/",
26
+ "skills/",
27
+ "openclaw/",
28
+ "openclaw.plugin.json"
29
+ ],
30
+ "publishConfig": {
31
+ "access": "public"
32
+ },
33
+ "engines": {
34
+ "node": ">=22"
35
+ },
36
+ "peerDependencies": {
37
+ "openclaw": ">=2026.3.0"
38
+ },
39
+ "peerDependenciesMeta": {
40
+ "openclaw": {
41
+ "optional": true
42
+ }
43
+ },
44
+ "openclaw": {
45
+ "extensions": [
46
+ "./openclaw/index.ts"
47
+ ]
48
+ }
49
+ }
@@ -0,0 +1,172 @@
1
+ #!/usr/bin/env node
2
+ import fs from "node:fs";
3
+ import path from "node:path";
4
+
5
+ function fail(message) {
6
+ console.error(`[memory-memoria] ${message}`);
7
+ process.exit(1);
8
+ }
9
+
10
+ function readArg(name, fallback = "") {
11
+ const index = process.argv.indexOf(name);
12
+ if (index >= 0 && index + 1 < process.argv.length) {
13
+ return process.argv[index + 1];
14
+ }
15
+ return fallback;
16
+ }
17
+
18
+ function asObject(value) {
19
+ return value && typeof value === "object" && !Array.isArray(value) ? value : {};
20
+ }
21
+
22
+ function normalizeUrl(value) {
23
+ return value.trim().replace(/\/+$/, "");
24
+ }
25
+
26
+ const modeRaw = readArg("--mode", "cloud").trim().toLowerCase();
27
+ if (modeRaw !== "cloud" && modeRaw !== "local") {
28
+ fail("mode must be one of: cloud, local");
29
+ }
30
+ const mode = modeRaw;
31
+
32
+ const pluginId = readArg("--plugin-id", "memory-memoria").trim() || "memory-memoria";
33
+ const configFile = path.resolve(
34
+ readArg(
35
+ "--config-file",
36
+ path.join(process.env.HOME || "", ".openclaw", "openclaw.json"),
37
+ ),
38
+ );
39
+
40
+ const apiUrl = readArg("--api-url", "").trim();
41
+ const apiKey = readArg("--api-key", "").trim();
42
+ const dbUrl = readArg("--db-url", "").trim();
43
+ const memoriaExecutable = readArg("--memoria-executable", "").trim();
44
+ const defaultUserId = readArg("--default-user-id", "").trim();
45
+ const embeddingProviderArg = readArg("--embedding-provider", "").trim();
46
+ const embeddingModelArg = readArg("--embedding-model", "").trim();
47
+ const embeddingApiKeyArg = readArg("--embedding-api-key", "").trim();
48
+ const embeddingBaseUrlArg = readArg("--embedding-base-url", "").trim();
49
+ const embeddingDimArg = readArg("--embedding-dim", "").trim();
50
+
51
+ const embeddingDim =
52
+ embeddingDimArg.length > 0 ? Number.parseInt(embeddingDimArg, 10) : undefined;
53
+ if (embeddingDimArg.length > 0 && (!Number.isFinite(embeddingDim) || embeddingDim < 1)) {
54
+ fail("embedding-dim must be a positive integer");
55
+ }
56
+
57
+ let data = {};
58
+ if (fs.existsSync(configFile)) {
59
+ try {
60
+ data = JSON.parse(fs.readFileSync(configFile, "utf8"));
61
+ } catch (error) {
62
+ fail(`failed to parse config file ${configFile}: ${String(error)}`);
63
+ }
64
+ } else {
65
+ fs.mkdirSync(path.dirname(configFile), { recursive: true });
66
+ }
67
+
68
+ const root = asObject(data);
69
+ const plugins = asObject(root.plugins);
70
+ const entries = asObject(plugins.entries);
71
+ const slots = asObject(plugins.slots);
72
+ const allow = Array.isArray(plugins.allow)
73
+ ? plugins.allow.filter((entry) => typeof entry === "string" && entry.trim())
74
+ : [];
75
+ const pluginEntry = asObject(entries[pluginId]);
76
+ const pluginConfig = asObject(pluginEntry.config);
77
+
78
+ if (mode === "cloud") {
79
+ if (!apiUrl) {
80
+ fail("--api-url required when mode=cloud");
81
+ }
82
+ if (!apiKey) {
83
+ fail("--api-key required when mode=cloud");
84
+ }
85
+ pluginConfig.backend = "http";
86
+ pluginConfig.apiUrl = normalizeUrl(apiUrl);
87
+ pluginConfig.apiKey = apiKey;
88
+ delete pluginConfig.dbUrl;
89
+ delete pluginConfig.embeddingProvider;
90
+ delete pluginConfig.embeddingModel;
91
+ delete pluginConfig.embeddingApiKey;
92
+ delete pluginConfig.embeddingBaseUrl;
93
+ delete pluginConfig.embeddingDim;
94
+ } else {
95
+ if (!dbUrl) {
96
+ fail("--db-url required when mode=local");
97
+ }
98
+
99
+ const embeddingProvider = embeddingProviderArg || String(pluginConfig.embeddingProvider || "openai");
100
+ const embeddingModel =
101
+ embeddingModelArg || String(pluginConfig.embeddingModel || "text-embedding-3-small");
102
+ const embeddingApiKey =
103
+ embeddingApiKeyArg || (typeof pluginConfig.embeddingApiKey === "string" ? pluginConfig.embeddingApiKey.trim() : "");
104
+
105
+ if (embeddingProvider !== "local" && !embeddingApiKey) {
106
+ fail("--embedding-api-key required for mode=local when embedding-provider is not 'local'");
107
+ }
108
+
109
+ pluginConfig.backend = "embedded";
110
+ pluginConfig.dbUrl = dbUrl;
111
+ pluginConfig.embeddingProvider = embeddingProvider;
112
+ pluginConfig.embeddingModel = embeddingModel;
113
+ delete pluginConfig.apiUrl;
114
+ delete pluginConfig.apiKey;
115
+ if (embeddingApiKey) {
116
+ pluginConfig.embeddingApiKey = embeddingApiKey;
117
+ }
118
+ if (embeddingBaseUrlArg) {
119
+ pluginConfig.embeddingBaseUrl = normalizeUrl(embeddingBaseUrlArg);
120
+ }
121
+ if (typeof embeddingDim === "number" && Number.isFinite(embeddingDim)) {
122
+ pluginConfig.embeddingDim = embeddingDim;
123
+ }
124
+ }
125
+
126
+ if (memoriaExecutable) {
127
+ pluginConfig.memoriaExecutable = memoriaExecutable;
128
+ }
129
+ if (defaultUserId) {
130
+ pluginConfig.defaultUserId = defaultUserId;
131
+ }
132
+
133
+ pluginEntry.enabled = true;
134
+ pluginEntry.config = pluginConfig;
135
+ entries[pluginId] = pluginEntry;
136
+ slots.memory = pluginId;
137
+ if (!allow.includes(pluginId)) {
138
+ allow.push(pluginId);
139
+ }
140
+ plugins.allow = allow;
141
+ plugins.entries = entries;
142
+ plugins.slots = slots;
143
+ root.plugins = plugins;
144
+
145
+ fs.writeFileSync(configFile, `${JSON.stringify(root, null, 2)}\n`, "utf8");
146
+
147
+ console.log(
148
+ JSON.stringify(
149
+ {
150
+ ok: true,
151
+ mode,
152
+ configFile,
153
+ pluginId,
154
+ backend: pluginConfig.backend,
155
+ apiUrl:
156
+ pluginConfig.backend === "http" && typeof pluginConfig.apiUrl === "string"
157
+ ? pluginConfig.apiUrl
158
+ : undefined,
159
+ apiKeySet:
160
+ pluginConfig.backend === "http" &&
161
+ typeof pluginConfig.apiKey === "string" &&
162
+ pluginConfig.apiKey.length > 0,
163
+ dbUrl: typeof pluginConfig.dbUrl === "string" ? pluginConfig.dbUrl : undefined,
164
+ memoriaExecutable:
165
+ typeof pluginConfig.memoriaExecutable === "string"
166
+ ? pluginConfig.memoriaExecutable
167
+ : undefined,
168
+ },
169
+ null,
170
+ 2,
171
+ ),
172
+ );