@psiclawops/hypermem 0.9.3 → 0.9.5
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/CHANGELOG.md +27 -2
- package/INSTALL.md +75 -68
- package/README.md +18 -36
- package/assets/default-config.json +41 -0
- package/bench/data-access-bench.mjs +1 -1
- package/bin/hypermem-doctor.mjs +76 -2
- package/bin/hypermem-status.mjs +255 -7
- package/dist/adaptive-lifecycle.d.ts +39 -0
- package/dist/adaptive-lifecycle.d.ts.map +1 -1
- package/dist/adaptive-lifecycle.js +87 -9
- package/dist/background-indexer.d.ts.map +1 -1
- package/dist/background-indexer.js +16 -14
- package/dist/compositor.d.ts.map +1 -1
- package/dist/compositor.js +239 -20
- package/dist/cross-agent.d.ts +1 -1
- package/dist/cross-agent.js +17 -17
- package/dist/hybrid-retrieval.d.ts +8 -0
- package/dist/hybrid-retrieval.d.ts.map +1 -1
- package/dist/hybrid-retrieval.js +112 -10
- package/dist/index.d.ts +16 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +19 -4
- package/dist/message-store.d.ts +62 -1
- package/dist/message-store.d.ts.map +1 -1
- package/dist/message-store.js +355 -2
- package/dist/open-domain.d.ts.map +1 -1
- package/dist/open-domain.js +3 -2
- package/dist/proactive-pass.d.ts +42 -2
- package/dist/proactive-pass.d.ts.map +1 -1
- package/dist/proactive-pass.js +294 -39
- package/dist/seed.d.ts +1 -1
- package/dist/seed.js +1 -1
- package/dist/session-flusher.d.ts +2 -2
- package/dist/session-flusher.js +2 -2
- package/dist/spawn-context.d.ts +1 -1
- package/dist/spawn-context.js +1 -1
- package/dist/topic-store.js +5 -5
- package/dist/topic-synthesizer.d.ts.map +1 -1
- package/dist/topic-synthesizer.js +10 -4
- package/dist/trigger-registry.d.ts +1 -1
- package/dist/trigger-registry.js +4 -4
- package/dist/types.d.ts +101 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/vector-store.d.ts +10 -1
- package/dist/vector-store.d.ts.map +1 -1
- package/dist/vector-store.js +45 -9
- package/docs/DIAGNOSTICS.md +88 -1
- package/docs/INTEGRATION_VALIDATION.md +40 -1
- package/docs/MIGRATION.md +1 -1
- package/docs/TUNING.md +47 -6
- package/install.sh +5 -60
- package/memory-plugin/dist/index.js +192 -0
- package/memory-plugin/openclaw.plugin.json +199 -2
- package/memory-plugin/package.json +2 -2
- package/package.json +29 -10
- package/plugin/dist/index.d.ts +2 -0
- package/plugin/dist/index.d.ts.map +1 -1
- package/plugin/dist/index.js +178 -11
- package/plugin/dist/index.js.map +1 -1
- package/plugin/openclaw.plugin.json +199 -2
- package/plugin/package.json +2 -2
- package/scripts/install-packed-runtime.mjs +99 -0
- package/scripts/install-runtime.mjs +164 -4
- package/ARCHITECTURE.md +0 -298
- package/docs/KNOWN_LIMITATIONS.md +0 -35
- package/docs/PHASE1-VALIDATION.md +0 -132
- package/docs/RELEASE_0.8.0_VALIDATION.md +0 -70
- package/docs/RELEASE_PROCESS.md +0 -10
- package/docs/ROADMAP.md +0 -266
|
@@ -3,11 +3,208 @@
|
|
|
3
3
|
"enabledByDefault": false,
|
|
4
4
|
"kind": "context-engine",
|
|
5
5
|
"activation": {
|
|
6
|
-
"onCapabilities": [
|
|
6
|
+
"onCapabilities": [
|
|
7
|
+
"context-engine"
|
|
8
|
+
]
|
|
7
9
|
},
|
|
8
10
|
"configSchema": {
|
|
9
11
|
"type": "object",
|
|
10
12
|
"additionalProperties": false,
|
|
11
|
-
"properties": {
|
|
13
|
+
"properties": {
|
|
14
|
+
"hyperMemPath": {
|
|
15
|
+
"type": "string"
|
|
16
|
+
},
|
|
17
|
+
"dataDir": {
|
|
18
|
+
"type": "string"
|
|
19
|
+
},
|
|
20
|
+
"contextWindowSize": {
|
|
21
|
+
"type": "integer",
|
|
22
|
+
"minimum": 1
|
|
23
|
+
},
|
|
24
|
+
"contextWindowReserve": {
|
|
25
|
+
"type": "number",
|
|
26
|
+
"minimum": 0,
|
|
27
|
+
"maximum": 0.5
|
|
28
|
+
},
|
|
29
|
+
"deferToolPruning": {
|
|
30
|
+
"type": "boolean"
|
|
31
|
+
},
|
|
32
|
+
"verboseLogging": {
|
|
33
|
+
"type": "boolean"
|
|
34
|
+
},
|
|
35
|
+
"warmCacheReplayThresholdMs": {
|
|
36
|
+
"type": "integer",
|
|
37
|
+
"minimum": 0
|
|
38
|
+
},
|
|
39
|
+
"subagentWarming": {
|
|
40
|
+
"type": "string",
|
|
41
|
+
"enum": [
|
|
42
|
+
"full",
|
|
43
|
+
"light",
|
|
44
|
+
"off"
|
|
45
|
+
]
|
|
46
|
+
},
|
|
47
|
+
"contextWindowOverrides": {
|
|
48
|
+
"type": "object",
|
|
49
|
+
"additionalProperties": {
|
|
50
|
+
"type": "object",
|
|
51
|
+
"additionalProperties": false,
|
|
52
|
+
"properties": {
|
|
53
|
+
"contextTokens": {
|
|
54
|
+
"type": "integer",
|
|
55
|
+
"minimum": 1
|
|
56
|
+
},
|
|
57
|
+
"contextWindow": {
|
|
58
|
+
"type": "integer",
|
|
59
|
+
"minimum": 1
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
"compositor": {
|
|
65
|
+
"type": "object",
|
|
66
|
+
"additionalProperties": true
|
|
67
|
+
},
|
|
68
|
+
"eviction": {
|
|
69
|
+
"type": "object",
|
|
70
|
+
"additionalProperties": false,
|
|
71
|
+
"properties": {
|
|
72
|
+
"enabled": {
|
|
73
|
+
"type": "boolean"
|
|
74
|
+
},
|
|
75
|
+
"imageAgeTurns": {
|
|
76
|
+
"type": "integer",
|
|
77
|
+
"minimum": 0
|
|
78
|
+
},
|
|
79
|
+
"toolResultAgeTurns": {
|
|
80
|
+
"type": "integer",
|
|
81
|
+
"minimum": 0
|
|
82
|
+
},
|
|
83
|
+
"minTokensToEvict": {
|
|
84
|
+
"type": "integer",
|
|
85
|
+
"minimum": 0
|
|
86
|
+
},
|
|
87
|
+
"keepPreviewChars": {
|
|
88
|
+
"type": "integer",
|
|
89
|
+
"minimum": 0
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
"embedding": {
|
|
94
|
+
"type": "object",
|
|
95
|
+
"additionalProperties": false,
|
|
96
|
+
"properties": {
|
|
97
|
+
"provider": {
|
|
98
|
+
"type": "string",
|
|
99
|
+
"enum": [
|
|
100
|
+
"none",
|
|
101
|
+
"ollama",
|
|
102
|
+
"openai",
|
|
103
|
+
"gemini"
|
|
104
|
+
]
|
|
105
|
+
},
|
|
106
|
+
"ollamaUrl": {
|
|
107
|
+
"type": "string"
|
|
108
|
+
},
|
|
109
|
+
"openaiApiKey": {
|
|
110
|
+
"type": "string"
|
|
111
|
+
},
|
|
112
|
+
"openaiBaseUrl": {
|
|
113
|
+
"type": "string"
|
|
114
|
+
},
|
|
115
|
+
"geminiApiKey": {
|
|
116
|
+
"type": "string"
|
|
117
|
+
},
|
|
118
|
+
"geminiBaseUrl": {
|
|
119
|
+
"type": "string"
|
|
120
|
+
},
|
|
121
|
+
"geminiIndexTaskType": {
|
|
122
|
+
"type": "string"
|
|
123
|
+
},
|
|
124
|
+
"geminiQueryTaskType": {
|
|
125
|
+
"type": "string"
|
|
126
|
+
},
|
|
127
|
+
"queryInputType": {
|
|
128
|
+
"type": "string"
|
|
129
|
+
},
|
|
130
|
+
"documentInputType": {
|
|
131
|
+
"type": "string"
|
|
132
|
+
},
|
|
133
|
+
"queryPrefix": {
|
|
134
|
+
"type": "string"
|
|
135
|
+
},
|
|
136
|
+
"documentPrefix": {
|
|
137
|
+
"type": "string"
|
|
138
|
+
},
|
|
139
|
+
"model": {
|
|
140
|
+
"type": "string"
|
|
141
|
+
},
|
|
142
|
+
"dimensions": {
|
|
143
|
+
"type": "integer",
|
|
144
|
+
"minimum": 1
|
|
145
|
+
},
|
|
146
|
+
"timeout": {
|
|
147
|
+
"type": "integer",
|
|
148
|
+
"minimum": 1
|
|
149
|
+
},
|
|
150
|
+
"batchSize": {
|
|
151
|
+
"type": "integer",
|
|
152
|
+
"minimum": 1
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
},
|
|
156
|
+
"reranker": {
|
|
157
|
+
"type": "object",
|
|
158
|
+
"additionalProperties": false,
|
|
159
|
+
"required": [
|
|
160
|
+
"provider"
|
|
161
|
+
],
|
|
162
|
+
"properties": {
|
|
163
|
+
"provider": {
|
|
164
|
+
"type": "string",
|
|
165
|
+
"enum": [
|
|
166
|
+
"zeroentropy",
|
|
167
|
+
"openrouter",
|
|
168
|
+
"local",
|
|
169
|
+
"none"
|
|
170
|
+
]
|
|
171
|
+
},
|
|
172
|
+
"minCandidates": {
|
|
173
|
+
"type": "integer",
|
|
174
|
+
"minimum": 0
|
|
175
|
+
},
|
|
176
|
+
"maxDocuments": {
|
|
177
|
+
"type": "integer",
|
|
178
|
+
"minimum": 1
|
|
179
|
+
},
|
|
180
|
+
"topK": {
|
|
181
|
+
"type": "integer",
|
|
182
|
+
"minimum": 1
|
|
183
|
+
},
|
|
184
|
+
"timeoutMs": {
|
|
185
|
+
"type": "integer",
|
|
186
|
+
"minimum": 1
|
|
187
|
+
},
|
|
188
|
+
"zeroEntropyApiKey": {
|
|
189
|
+
"type": "string"
|
|
190
|
+
},
|
|
191
|
+
"zeroEntropyModel": {
|
|
192
|
+
"type": "string"
|
|
193
|
+
},
|
|
194
|
+
"openrouterApiKey": {
|
|
195
|
+
"type": "string"
|
|
196
|
+
},
|
|
197
|
+
"openrouterModel": {
|
|
198
|
+
"type": "string"
|
|
199
|
+
},
|
|
200
|
+
"ollamaUrl": {
|
|
201
|
+
"type": "string"
|
|
202
|
+
},
|
|
203
|
+
"ollamaModel": {
|
|
204
|
+
"type": "string"
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
12
209
|
}
|
|
13
210
|
}
|
package/plugin/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@psiclawops/hypercompositor",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.5",
|
|
4
4
|
"description": "HyperCompositor \u2014 context engine plugin for OpenClaw",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
"typecheck": "tsc --noEmit"
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"@psiclawops/hypermem": "0.9.
|
|
43
|
+
"@psiclawops/hypermem": "0.9.5",
|
|
44
44
|
"zod": "^4.0.0"
|
|
45
45
|
},
|
|
46
46
|
"devDependencies": {
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { cpSync, existsSync, mkdtempSync, rmSync, statSync } from 'node:fs';
|
|
4
|
+
import os from 'node:os';
|
|
5
|
+
import path from 'node:path';
|
|
6
|
+
import { fileURLToPath } from 'node:url';
|
|
7
|
+
import { execFileSync } from 'node:child_process';
|
|
8
|
+
|
|
9
|
+
const __dirname = fileURLToPath(new URL('.', import.meta.url));
|
|
10
|
+
const repoRoot = path.resolve(__dirname, '..');
|
|
11
|
+
|
|
12
|
+
const argv = process.argv.slice(2);
|
|
13
|
+
let installRoot = path.join(os.homedir(), '.openclaw/plugins/hypermem');
|
|
14
|
+
let inputTarball = null;
|
|
15
|
+
|
|
16
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
17
|
+
const arg = argv[i];
|
|
18
|
+
if (arg === '--install-root' && argv[i + 1]) {
|
|
19
|
+
installRoot = path.resolve(argv[++i]);
|
|
20
|
+
} else if (arg === '--tarball' && argv[i + 1]) {
|
|
21
|
+
inputTarball = path.resolve(argv[++i]);
|
|
22
|
+
} else if (arg.endsWith('.tgz')) {
|
|
23
|
+
inputTarball = path.resolve(arg);
|
|
24
|
+
} else if (!arg.startsWith('--')) {
|
|
25
|
+
installRoot = path.resolve(arg);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function run(command, args, options = {}) {
|
|
30
|
+
return execFileSync(command, args, {
|
|
31
|
+
cwd: options.cwd ?? repoRoot,
|
|
32
|
+
stdio: options.stdio ?? 'pipe',
|
|
33
|
+
encoding: options.encoding ?? 'utf8',
|
|
34
|
+
env: process.env,
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function safeRemove(filePath) {
|
|
39
|
+
try {
|
|
40
|
+
if (existsSync(filePath) && statSync(filePath).isFile()) rmSync(filePath, { force: true });
|
|
41
|
+
} catch {
|
|
42
|
+
// Best-effort cleanup only. Never delete directories here.
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const stamp = new Date().toISOString().replace(/[-:]/g, '').replace(/\.\d{3}Z$/, 'Z');
|
|
47
|
+
const tempRoot = mkdtempSync(path.join(os.tmpdir(), 'hypermem-packed-runtime-'));
|
|
48
|
+
const tempApp = path.join(tempRoot, 'app');
|
|
49
|
+
let tarballPath = inputTarball;
|
|
50
|
+
let createdTarball = false;
|
|
51
|
+
|
|
52
|
+
try {
|
|
53
|
+
if (!tarballPath) {
|
|
54
|
+
console.log('Packing HyperMem via npm pack...');
|
|
55
|
+
const packOutput = run('npm', ['pack', '--silent']).trim();
|
|
56
|
+
const tarballName = packOutput.split('\n').filter(Boolean).pop();
|
|
57
|
+
if (!tarballName) throw new Error('npm pack did not return a tarball name');
|
|
58
|
+
tarballPath = path.join(repoRoot, tarballName);
|
|
59
|
+
createdTarball = true;
|
|
60
|
+
} else if (!existsSync(tarballPath) || !statSync(tarballPath).isFile()) {
|
|
61
|
+
throw new Error(`Tarball not found or not a file: ${tarballPath}`);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
console.log(`Installing packed artifact into temp app: ${tempApp}`);
|
|
65
|
+
run('npm', ['--prefix', tempApp, 'init', '-y'], { stdio: 'ignore' });
|
|
66
|
+
run('npm', ['--prefix', tempApp, 'install', '--no-audit', '--no-fund', tarballPath], {
|
|
67
|
+
stdio: 'inherit',
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
const backupPath = `${installRoot}.backup.${stamp}`;
|
|
71
|
+
if (existsSync(installRoot)) {
|
|
72
|
+
console.log(`Backing up current runtime: ${backupPath}`);
|
|
73
|
+
cpSync(installRoot, backupPath, { recursive: true, force: false, errorOnExist: true });
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const installer = path.join(
|
|
77
|
+
tempApp,
|
|
78
|
+
'node_modules',
|
|
79
|
+
'@psiclawops',
|
|
80
|
+
'hypermem',
|
|
81
|
+
'scripts',
|
|
82
|
+
'install-runtime.mjs',
|
|
83
|
+
);
|
|
84
|
+
console.log(`Installing packed runtime to: ${installRoot}`);
|
|
85
|
+
run(process.execPath, [installer, installRoot], { stdio: 'inherit' });
|
|
86
|
+
|
|
87
|
+
const pkg = JSON.parse(
|
|
88
|
+
run(process.execPath, [
|
|
89
|
+
'-e',
|
|
90
|
+
`console.log(require('fs').readFileSync(${JSON.stringify(path.join(installRoot, 'package.json'))}, 'utf8'))`,
|
|
91
|
+
]),
|
|
92
|
+
);
|
|
93
|
+
console.log(`Installed ${pkg.name}@${pkg.version} from packed artifact.`);
|
|
94
|
+
console.log(`Runtime path: ${installRoot}`);
|
|
95
|
+
console.log('Restart OpenClaw gateway before validating runtime behavior.');
|
|
96
|
+
} finally {
|
|
97
|
+
if (createdTarball && tarballPath) safeRemove(tarballPath);
|
|
98
|
+
rmSync(tempRoot, { recursive: true, force: true });
|
|
99
|
+
}
|
|
@@ -1,23 +1,99 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
import { cpSync, existsSync, mkdirSync, readdirSync, rmSync, symlinkSync } from 'node:fs';
|
|
3
|
+
import { cpSync, existsSync, mkdirSync, readdirSync, readFileSync, rmSync, symlinkSync, writeFileSync } from 'node:fs';
|
|
4
4
|
import os from 'node:os';
|
|
5
5
|
import path from 'node:path';
|
|
6
6
|
import { fileURLToPath } from 'node:url';
|
|
7
7
|
|
|
8
8
|
const __dirname = fileURLToPath(new URL('.', import.meta.url));
|
|
9
9
|
const REPO_ROOT = path.resolve(__dirname, '..');
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
|
|
11
|
+
function usage() {
|
|
12
|
+
console.log(`
|
|
13
|
+
hypermem-install — stage the HyperMem runtime for OpenClaw
|
|
14
|
+
|
|
15
|
+
Usage:
|
|
16
|
+
hypermem-install [install-root] [options]
|
|
17
|
+
hypermem-install --install-root <path> [options]
|
|
18
|
+
|
|
19
|
+
Options:
|
|
20
|
+
--install-root <path> Runtime install directory
|
|
21
|
+
default: ~/.openclaw/plugins/hypermem
|
|
22
|
+
--skip-embedding-check Do not require the configured embedding provider
|
|
23
|
+
to be reachable during install
|
|
24
|
+
--skip-openclaw-config Do not attempt OpenClaw config writes. Current
|
|
25
|
+
installer is read-only for OpenClaw config, so
|
|
26
|
+
this is accepted for CI/container scripts.
|
|
27
|
+
-h, --help Show this help
|
|
28
|
+
`);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function parseArgs(argv) {
|
|
32
|
+
const options = {
|
|
33
|
+
installRoot: null,
|
|
34
|
+
skipEmbeddingCheck: false,
|
|
35
|
+
skipOpenClawConfig: false,
|
|
36
|
+
help: false,
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
40
|
+
const arg = argv[i];
|
|
41
|
+
if (arg === '-h' || arg === '--help') {
|
|
42
|
+
options.help = true;
|
|
43
|
+
} else if (arg === '--install-root') {
|
|
44
|
+
const value = argv[i + 1];
|
|
45
|
+
if (!value || value.startsWith('--')) {
|
|
46
|
+
throw new Error('--install-root requires a path');
|
|
47
|
+
}
|
|
48
|
+
options.installRoot = value;
|
|
49
|
+
i += 1;
|
|
50
|
+
} else if (arg === '--skip-embedding-check') {
|
|
51
|
+
options.skipEmbeddingCheck = true;
|
|
52
|
+
} else if (arg === '--skip-openclaw-config') {
|
|
53
|
+
options.skipOpenClawConfig = true;
|
|
54
|
+
} else if (arg.startsWith('--')) {
|
|
55
|
+
throw new Error(`Unknown option: ${arg}`);
|
|
56
|
+
} else if (!options.installRoot) {
|
|
57
|
+
options.installRoot = arg;
|
|
58
|
+
} else {
|
|
59
|
+
throw new Error(`Unexpected positional argument: ${arg}`);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return options;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
let options;
|
|
67
|
+
try {
|
|
68
|
+
options = parseArgs(process.argv.slice(2));
|
|
69
|
+
} catch (err) {
|
|
70
|
+
console.error(`hypermem-install: ${err.message}`);
|
|
71
|
+
usage();
|
|
72
|
+
process.exit(2);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (options.help) {
|
|
76
|
+
usage();
|
|
77
|
+
process.exit(0);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const installRoot = options.installRoot
|
|
81
|
+
? path.resolve(options.installRoot)
|
|
12
82
|
: path.join(os.homedir(), '.openclaw/plugins/hypermem');
|
|
83
|
+
const hypermemConfigPath = path.join(os.homedir(), '.openclaw', 'hypermem', 'config.json');
|
|
84
|
+
const defaultConfigSource = path.join(REPO_ROOT, 'assets', 'default-config.json');
|
|
13
85
|
|
|
14
86
|
const requiredEntries = [
|
|
15
87
|
['dist', 'dist'],
|
|
16
88
|
['package.json', 'package.json'],
|
|
17
89
|
['README.md', 'README.md'],
|
|
18
90
|
['LICENSE', 'LICENSE'],
|
|
91
|
+
['assets/default-config.json', 'assets/default-config.json'],
|
|
19
92
|
['bin/hypermem-status.mjs', 'bin/hypermem-status.mjs'],
|
|
20
93
|
['bin/hypermem-model-audit.mjs', 'bin/hypermem-model-audit.mjs'],
|
|
94
|
+
['bin/hypermem-doctor.mjs', 'bin/hypermem-doctor.mjs'],
|
|
95
|
+
['bin/hypermem-bench.mjs', 'bin/hypermem-bench.mjs'],
|
|
96
|
+
['bench/data-access-bench.mjs', 'bench/data-access-bench.mjs'],
|
|
21
97
|
['plugin/dist', 'plugin/dist'],
|
|
22
98
|
['plugin/package.json', 'plugin/package.json'],
|
|
23
99
|
['plugin/openclaw.plugin.json', 'plugin/openclaw.plugin.json'],
|
|
@@ -57,6 +133,77 @@ const entries = [
|
|
|
57
133
|
...sqliteVecNativeEntries.filter(([srcRel]) => existsSync(path.join(REPO_ROOT, srcRel))),
|
|
58
134
|
];
|
|
59
135
|
|
|
136
|
+
|
|
137
|
+
function readJson(filePath) {
|
|
138
|
+
return JSON.parse(readFileSync(filePath, 'utf8'));
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function writeDefaultConfigIfMissing() {
|
|
142
|
+
if (!existsSync(defaultConfigSource)) {
|
|
143
|
+
console.error(`Missing default config artifact: ${defaultConfigSource}`);
|
|
144
|
+
process.exit(1);
|
|
145
|
+
}
|
|
146
|
+
if (existsSync(hypermemConfigPath)) {
|
|
147
|
+
return { path: hypermemConfigPath, created: false, config: readJson(hypermemConfigPath) };
|
|
148
|
+
}
|
|
149
|
+
mkdirSync(path.dirname(hypermemConfigPath), { recursive: true, mode: 0o700 });
|
|
150
|
+
const content = readFileSync(defaultConfigSource, 'utf8');
|
|
151
|
+
writeFileSync(hypermemConfigPath, content.endsWith('\n') ? content : `${content}\n`, { mode: 0o600 });
|
|
152
|
+
return { path: hypermemConfigPath, created: true, config: JSON.parse(content) };
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
async function probeEmbeddingProvider(config) {
|
|
156
|
+
const embedding = config?.embedding ?? {};
|
|
157
|
+
const provider = embedding.provider ?? 'ollama';
|
|
158
|
+
if (provider === 'none') return { ok: true, skipped: true, reason: 'embedding provider disabled' };
|
|
159
|
+
if (provider !== 'ollama') return { ok: true, skipped: true, reason: `embedding provider ${provider} is not probed by installer` };
|
|
160
|
+
|
|
161
|
+
const baseUrl = String(embedding.ollamaUrl ?? 'http://localhost:11434').replace(/\/$/, '');
|
|
162
|
+
const controller = new AbortController();
|
|
163
|
+
const timer = setTimeout(() => controller.abort(), 1500);
|
|
164
|
+
try {
|
|
165
|
+
const res = await fetch(`${baseUrl}/api/tags`, { signal: controller.signal });
|
|
166
|
+
if (!res.ok) return { ok: false, provider, baseUrl, reason: `HTTP ${res.status}` };
|
|
167
|
+
const body = await res.json().catch(() => ({}));
|
|
168
|
+
const model = embedding.model ?? 'nomic-embed-text';
|
|
169
|
+
const models = Array.isArray(body.models) ? body.models : [];
|
|
170
|
+
const hasModel = models.some((entry) => entry?.name === model || entry?.model === model || String(entry?.name ?? '').startsWith(`${model}:`));
|
|
171
|
+
if (!hasModel) {
|
|
172
|
+
return { ok: false, provider, baseUrl, reason: `model ${model} is not installed` };
|
|
173
|
+
}
|
|
174
|
+
return { ok: true, provider, baseUrl, model };
|
|
175
|
+
} catch (err) {
|
|
176
|
+
const detail = err.cause?.code ? `${err.message} (${err.cause.code})` : err.message;
|
|
177
|
+
return { ok: false, provider, baseUrl, reason: err.name === 'AbortError' ? 'probe timed out' : `cannot reach ${baseUrl}: ${detail}` };
|
|
178
|
+
} finally {
|
|
179
|
+
clearTimeout(timer);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
const configResult = writeDefaultConfigIfMissing();
|
|
184
|
+
|
|
185
|
+
if (!options.skipEmbeddingCheck) {
|
|
186
|
+
const probe = await probeEmbeddingProvider(configResult.config);
|
|
187
|
+
if (!probe.ok) {
|
|
188
|
+
console.error(`
|
|
189
|
+
Embedding provider check failed: ${probe.reason}
|
|
190
|
+
|
|
191
|
+
HyperMem default semantic recall uses Ollama with nomic-embed-text.
|
|
192
|
+
Remediation:
|
|
193
|
+
1. Install and start Ollama: https://ollama.com/download
|
|
194
|
+
2. Pull the embedding model: ollama pull nomic-embed-text
|
|
195
|
+
3. Re-run hypermem-install
|
|
196
|
+
|
|
197
|
+
Advanced/CI override:
|
|
198
|
+
hypermem-install --skip-embedding-check
|
|
199
|
+
|
|
200
|
+
Config checked:
|
|
201
|
+
${configResult.path}
|
|
202
|
+
`);
|
|
203
|
+
process.exit(3);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
60
207
|
rmSync(installRoot, { recursive: true, force: true });
|
|
61
208
|
mkdirSync(installRoot, { recursive: true });
|
|
62
209
|
|
|
@@ -75,7 +222,17 @@ symlinkSync(openclawInstallPath, path.join(installRoot, 'memory-plugin/node_modu
|
|
|
75
222
|
symlinkSync('../../..', path.join(installRoot, 'plugin/node_modules/@psiclawops/hypermem'));
|
|
76
223
|
symlinkSync('../../..', path.join(installRoot, 'memory-plugin/node_modules/@psiclawops/hypermem'));
|
|
77
224
|
|
|
78
|
-
console.log(
|
|
225
|
+
console.log(`
|
|
226
|
+
Runtime installed to:
|
|
227
|
+
${installRoot}
|
|
228
|
+
`);
|
|
229
|
+
console.log(` HyperMem config:
|
|
230
|
+
${configResult.path} ${configResult.created ? '(created)' : '(already existed, unchanged)'}
|
|
231
|
+
`);
|
|
232
|
+
if (options.skipEmbeddingCheck) {
|
|
233
|
+
console.log(` Embedding provider check skipped by --skip-embedding-check.
|
|
234
|
+
`);
|
|
235
|
+
}
|
|
79
236
|
console.log(` Next steps — wire the plugins into OpenClaw:\n`);
|
|
80
237
|
console.log(` openclaw config set plugins.load.paths '["${installRoot}/plugin","${installRoot}/memory-plugin"]' --strict-json`);
|
|
81
238
|
console.log(` openclaw config set plugins.slots.contextEngine hypercompositor`);
|
|
@@ -85,7 +242,10 @@ console.log(` openclaw config get plugins.allow`);
|
|
|
85
242
|
console.log(` # Example merge (if "my-plugin" was already allowed):`);
|
|
86
243
|
console.log(` # openclaw config set plugins.allow '["my-plugin","hypercompositor","hypermem"]' --strict-json`);
|
|
87
244
|
console.log(` # If plugins.allow is empty or unset, skip that step instead of creating a new allowlist.`);
|
|
245
|
+
console.log(` openclaw plugins registry --refresh`);
|
|
246
|
+
console.log(` openclaw doctor --fix --yes`);
|
|
88
247
|
console.log(` openclaw gateway restart\n`);
|
|
89
248
|
console.log(` Verify:\n`);
|
|
249
|
+
console.log(` openclaw plugins registry --refresh`);
|
|
90
250
|
console.log(` openclaw plugins list`);
|
|
91
251
|
console.log(` node bin/hypermem-status.mjs --health\n`);
|