@memtensor/memos-local-openclaw-plugin 1.0.4-beta.4 → 1.0.4-beta.6
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/README.md +22 -39
- package/dist/capture/index.d.ts.map +1 -1
- package/dist/capture/index.js +6 -0
- package/dist/capture/index.js.map +1 -1
- package/dist/config.d.ts +1 -2
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +3 -72
- package/dist/config.js.map +1 -1
- package/dist/embedding/index.d.ts +2 -4
- package/dist/embedding/index.d.ts.map +1 -1
- package/dist/embedding/index.js +1 -17
- package/dist/embedding/index.js.map +1 -1
- package/dist/index.d.ts +0 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -4
- package/dist/index.js.map +1 -1
- package/dist/ingest/providers/index.d.ts +2 -10
- package/dist/ingest/providers/index.d.ts.map +1 -1
- package/dist/ingest/providers/index.js +43 -209
- package/dist/ingest/providers/index.js.map +1 -1
- package/dist/ingest/providers/openai.d.ts +0 -1
- package/dist/ingest/providers/openai.d.ts.map +1 -1
- package/dist/ingest/providers/openai.js +0 -1
- package/dist/ingest/providers/openai.js.map +1 -1
- package/dist/ingest/task-processor.js +1 -1
- package/dist/ingest/task-processor.js.map +1 -1
- package/dist/recall/engine.js +1 -1
- package/dist/recall/engine.js.map +1 -1
- package/dist/shared/llm-call.d.ts +2 -4
- package/dist/shared/llm-call.d.ts.map +1 -1
- package/dist/shared/llm-call.js +81 -20
- package/dist/shared/llm-call.js.map +1 -1
- package/dist/skill/evaluator.d.ts.map +1 -1
- package/dist/skill/evaluator.js +2 -2
- package/dist/skill/evaluator.js.map +1 -1
- package/dist/skill/evolver.d.ts +2 -0
- package/dist/skill/evolver.d.ts.map +1 -1
- package/dist/skill/evolver.js +3 -0
- package/dist/skill/evolver.js.map +1 -1
- package/dist/skill/generator.d.ts.map +1 -1
- package/dist/skill/generator.js +4 -4
- package/dist/skill/generator.js.map +1 -1
- package/dist/skill/upgrader.js +1 -1
- package/dist/skill/upgrader.js.map +1 -1
- package/dist/skill/validator.js +1 -1
- package/dist/skill/validator.js.map +1 -1
- package/dist/storage/ensure-binding.d.ts.map +1 -1
- package/dist/storage/ensure-binding.js +1 -3
- package/dist/storage/ensure-binding.js.map +1 -1
- package/dist/storage/sqlite.d.ts +0 -294
- package/dist/storage/sqlite.d.ts.map +1 -1
- package/dist/storage/sqlite.js +0 -821
- package/dist/storage/sqlite.js.map +1 -1
- package/dist/telemetry.d.ts +12 -5
- package/dist/telemetry.d.ts.map +1 -1
- package/dist/telemetry.js +135 -38
- package/dist/telemetry.js.map +1 -1
- package/dist/tools/index.d.ts +0 -1
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +1 -3
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/memory-search.d.ts +2 -3
- package/dist/tools/memory-search.d.ts.map +1 -1
- package/dist/tools/memory-search.js +7 -48
- package/dist/tools/memory-search.js.map +1 -1
- package/dist/types.d.ts +2 -49
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/viewer/html.d.ts.map +1 -1
- package/dist/viewer/html.js +471 -2974
- package/dist/viewer/html.js.map +1 -1
- package/dist/viewer/server.d.ts +0 -45
- package/dist/viewer/server.d.ts.map +1 -1
- package/dist/viewer/server.js +18 -1155
- package/dist/viewer/server.js.map +1 -1
- package/index.ts +42 -430
- package/openclaw.plugin.json +1 -2
- package/package.json +3 -4
- package/scripts/postinstall.cjs +46 -283
- package/skill/memos-memory-guide/SKILL.md +2 -26
- package/src/capture/index.ts +8 -0
- package/src/config.ts +3 -94
- package/src/embedding/index.ts +1 -21
- package/src/index.ts +4 -7
- package/src/ingest/providers/index.ts +46 -246
- package/src/ingest/providers/openai.ts +1 -1
- package/src/ingest/task-processor.ts +1 -1
- package/src/recall/engine.ts +1 -1
- package/src/shared/llm-call.ts +95 -23
- package/src/skill/evaluator.ts +2 -3
- package/src/skill/evolver.ts +5 -0
- package/src/skill/generator.ts +4 -6
- package/src/skill/upgrader.ts +1 -1
- package/src/skill/validator.ts +1 -1
- package/src/storage/ensure-binding.ts +1 -3
- package/src/storage/sqlite.ts +0 -1085
- package/src/telemetry.ts +152 -39
- package/src/tools/index.ts +0 -1
- package/src/tools/memory-search.ts +8 -57
- package/src/types.ts +2 -44
- package/src/viewer/html.ts +471 -2974
- package/src/viewer/server.ts +21 -1070
- package/dist/client/connector.d.ts +0 -30
- package/dist/client/connector.d.ts.map +0 -1
- package/dist/client/connector.js +0 -219
- package/dist/client/connector.js.map +0 -1
- package/dist/client/hub.d.ts +0 -61
- package/dist/client/hub.d.ts.map +0 -1
- package/dist/client/hub.js +0 -148
- package/dist/client/hub.js.map +0 -1
- package/dist/client/skill-sync.d.ts +0 -29
- package/dist/client/skill-sync.d.ts.map +0 -1
- package/dist/client/skill-sync.js +0 -216
- package/dist/client/skill-sync.js.map +0 -1
- package/dist/hub/auth.d.ts +0 -19
- package/dist/hub/auth.d.ts.map +0 -1
- package/dist/hub/auth.js +0 -70
- package/dist/hub/auth.js.map +0 -1
- package/dist/hub/server.d.ts +0 -41
- package/dist/hub/server.d.ts.map +0 -1
- package/dist/hub/server.js +0 -747
- package/dist/hub/server.js.map +0 -1
- package/dist/hub/user-manager.d.ts +0 -29
- package/dist/hub/user-manager.d.ts.map +0 -1
- package/dist/hub/user-manager.js +0 -125
- package/dist/hub/user-manager.js.map +0 -1
- package/dist/openclaw-api.d.ts +0 -53
- package/dist/openclaw-api.d.ts.map +0 -1
- package/dist/openclaw-api.js +0 -189
- package/dist/openclaw-api.js.map +0 -1
- package/dist/sharing/types.contract.d.ts +0 -2
- package/dist/sharing/types.contract.d.ts.map +0 -1
- package/dist/sharing/types.contract.js +0 -3
- package/dist/sharing/types.contract.js.map +0 -1
- package/dist/sharing/types.d.ts +0 -80
- package/dist/sharing/types.d.ts.map +0 -1
- package/dist/sharing/types.js +0 -3
- package/dist/sharing/types.js.map +0 -1
- package/dist/tools/network-memory-detail.d.ts +0 -4
- package/dist/tools/network-memory-detail.d.ts.map +0 -1
- package/dist/tools/network-memory-detail.js +0 -34
- package/dist/tools/network-memory-detail.js.map +0 -1
- package/src/client/connector.ts +0 -218
- package/src/client/hub.ts +0 -189
- package/src/client/skill-sync.ts +0 -202
- package/src/hub/auth.ts +0 -78
- package/src/hub/server.ts +0 -740
- package/src/hub/user-manager.ts +0 -139
- package/src/openclaw-api.ts +0 -287
- package/src/sharing/types.contract.ts +0 -40
- package/src/sharing/types.ts +0 -102
- package/src/tools/network-memory-detail.ts +0 -34
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@memtensor/memos-local-openclaw-plugin",
|
|
3
|
-
"version": "1.0.4-beta.
|
|
4
|
-
"description": "MemOS Local memory plugin for OpenClaw
|
|
3
|
+
"version": "1.0.4-beta.6",
|
|
4
|
+
"description": "MemOS Local memory plugin for OpenClaw \u2014 full-write, hybrid-recall, progressive retrieval",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.ts",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
@@ -51,7 +51,6 @@
|
|
|
51
51
|
"@huggingface/transformers": "^3.8.0",
|
|
52
52
|
"@sinclair/typebox": "^0.34.48",
|
|
53
53
|
"better-sqlite3": "^12.6.2",
|
|
54
|
-
"posthog-node": "^5.28.0",
|
|
55
54
|
"puppeteer": "^24.38.0",
|
|
56
55
|
"semver": "^7.7.4",
|
|
57
56
|
"uuid": "^10.0.0"
|
|
@@ -65,4 +64,4 @@
|
|
|
65
64
|
"typescript": "^5.7.0",
|
|
66
65
|
"vitest": "^2.1.0"
|
|
67
66
|
}
|
|
68
|
-
}
|
|
67
|
+
}
|
package/scripts/postinstall.cjs
CHANGED
|
@@ -112,7 +112,7 @@ try {
|
|
|
112
112
|
function ensureDependencies() {
|
|
113
113
|
phase(0, "检测核心依赖 / Check core dependencies");
|
|
114
114
|
|
|
115
|
-
const coreDeps = ["@sinclair/typebox", "uuid", "
|
|
115
|
+
const coreDeps = ["@sinclair/typebox", "uuid", "@huggingface/transformers"];
|
|
116
116
|
const missing = [];
|
|
117
117
|
for (const dep of coreDeps) {
|
|
118
118
|
try {
|
|
@@ -380,30 +380,58 @@ function sqliteBindingsExist() {
|
|
|
380
380
|
|
|
381
381
|
if (sqliteBindingsExist()) {
|
|
382
382
|
ok("better-sqlite3 is ready.");
|
|
383
|
+
console.log(`
|
|
384
|
+
${GREEN}${BOLD} ┌──────────────────────────────────────────────────┐
|
|
385
|
+
│ ✔ Setup complete! │
|
|
386
|
+
│ │
|
|
387
|
+
│ Restart gateway: │
|
|
388
|
+
│ ${CYAN}openclaw gateway stop && openclaw gateway start${GREEN} │
|
|
389
|
+
└──────────────────────────────────────────────────┘${RESET}
|
|
390
|
+
`);
|
|
391
|
+
process.exit(0);
|
|
383
392
|
} else {
|
|
384
393
|
warn("better-sqlite3 native bindings not found in plugin dir.");
|
|
385
394
|
log(`Searched in: ${DIM}${sqliteModulePath}/build/${RESET}`);
|
|
386
395
|
log("Running: npm rebuild better-sqlite3 (may take 30-60s)...");
|
|
396
|
+
}
|
|
387
397
|
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
398
|
+
const startMs = Date.now();
|
|
399
|
+
|
|
400
|
+
const result = spawnSync("npm", ["rebuild", "better-sqlite3"], {
|
|
401
|
+
cwd: pluginDir,
|
|
402
|
+
stdio: "pipe",
|
|
403
|
+
shell: true,
|
|
404
|
+
timeout: 180_000,
|
|
405
|
+
});
|
|
406
|
+
|
|
407
|
+
const elapsed = ((Date.now() - startMs) / 1000).toFixed(1);
|
|
408
|
+
const stdout = (result.stdout || "").toString().trim();
|
|
409
|
+
const stderr = (result.stderr || "").toString().trim();
|
|
410
|
+
|
|
411
|
+
if (stdout) log(`rebuild output: ${DIM}${stdout.slice(0, 500)}${RESET}`);
|
|
412
|
+
if (stderr) warn(`rebuild stderr: ${DIM}${stderr.slice(0, 500)}${RESET}`);
|
|
400
413
|
|
|
401
|
-
|
|
414
|
+
if (result.status === 0) {
|
|
415
|
+
if (sqliteBindingsExist()) {
|
|
402
416
|
ok(`better-sqlite3 rebuilt successfully (${elapsed}s).`);
|
|
403
|
-
} else {
|
|
404
|
-
if (result.status !== 0) fail(`Rebuild failed with exit code ${result.status} (${elapsed}s).`);
|
|
405
|
-
else { fail(`Rebuild completed but bindings still missing (${elapsed}s).`); fail(`Looked in: ${sqliteModulePath}/build/`); }
|
|
406
417
|
console.log(`
|
|
418
|
+
${GREEN}${BOLD} ┌──────────────────────────────────────────────────┐
|
|
419
|
+
│ ✔ Setup complete! │
|
|
420
|
+
│ │
|
|
421
|
+
│ Restart gateway: │
|
|
422
|
+
│ ${CYAN}openclaw gateway stop && openclaw gateway start${GREEN} │
|
|
423
|
+
└──────────────────────────────────────────────────┘${RESET}
|
|
424
|
+
`);
|
|
425
|
+
process.exit(0);
|
|
426
|
+
} else {
|
|
427
|
+
fail(`Rebuild completed but bindings still missing (${elapsed}s).`);
|
|
428
|
+
fail(`Looked in: ${sqliteModulePath}/build/`);
|
|
429
|
+
}
|
|
430
|
+
} else {
|
|
431
|
+
fail(`Rebuild failed with exit code ${result.status} (${elapsed}s).`);
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
console.log(`
|
|
407
435
|
${YELLOW}${BOLD} ╔══════════════════════════════════════════════════════════════╗
|
|
408
436
|
║ ✖ better-sqlite3 native module build failed ║
|
|
409
437
|
╠══════════════════════════════════════════════════════════════╣${RESET}
|
|
@@ -424,270 +452,5 @@ ${YELLOW} ║${RESET} ${GREEN}openclaw gateway stop && openclaw gateway start$
|
|
|
424
452
|
${YELLOW} ║${RESET} ${YELLOW}║${RESET}
|
|
425
453
|
${YELLOW}${BOLD} ╚══════════════════════════════════════════════════════════════╝${RESET}
|
|
426
454
|
`);
|
|
427
|
-
}
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
/* ═══════════════════════════════════════════════════════════
|
|
431
|
-
* Phase 3: Interactive LAN Sharing Setup
|
|
432
|
-
* ═══════════════════════════════════════════════════════════ */
|
|
433
|
-
|
|
434
|
-
const rlMod = require("readline");
|
|
435
|
-
const os = require("os");
|
|
436
|
-
const crypto = require("crypto");
|
|
437
|
-
|
|
438
|
-
function getLocalIPs() {
|
|
439
|
-
const nets = os.networkInterfaces();
|
|
440
|
-
const results = [];
|
|
441
|
-
for (const name of Object.keys(nets)) {
|
|
442
|
-
for (const net of nets[name]) {
|
|
443
|
-
if (net.family === "IPv4" && !net.internal) {
|
|
444
|
-
results.push({ name, address: net.address });
|
|
445
|
-
}
|
|
446
|
-
}
|
|
447
|
-
}
|
|
448
|
-
return results;
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
function generateTeamToken() {
|
|
452
|
-
return crypto.randomBytes(18).toString("base64url");
|
|
453
|
-
}
|
|
454
|
-
|
|
455
|
-
function createPrompt() {
|
|
456
|
-
const rl = rlMod.createInterface({ input: process.stdin, output: process.stdout });
|
|
457
|
-
return {
|
|
458
|
-
ask(q) { return new Promise((resolve) => rl.question(q, (a) => resolve(a.trim()))); },
|
|
459
|
-
close() { rl.close(); },
|
|
460
|
-
};
|
|
461
|
-
}
|
|
462
|
-
|
|
463
|
-
async function setupSharingWizard() {
|
|
464
|
-
if (!process.stdin.isTTY) {
|
|
465
|
-
log("Non-interactive environment, skipping sharing setup wizard.");
|
|
466
|
-
return;
|
|
467
|
-
}
|
|
468
|
-
if (process.env.MEMOS_SKIP_SETUP === "1") {
|
|
469
|
-
log("MEMOS_SKIP_SETUP=1, skipping sharing setup.");
|
|
470
|
-
return;
|
|
471
|
-
}
|
|
472
|
-
|
|
473
|
-
const home = process.env.HOME || process.env.USERPROFILE || "";
|
|
474
|
-
const cfgPath = path.join(home, ".openclaw", "openclaw.json");
|
|
475
|
-
if (!fs.existsSync(cfgPath)) {
|
|
476
|
-
log("~/.openclaw/openclaw.json not found, skipping sharing setup.");
|
|
477
|
-
return;
|
|
478
|
-
}
|
|
479
|
-
|
|
480
|
-
let cfg;
|
|
481
|
-
try {
|
|
482
|
-
cfg = JSON.parse(fs.readFileSync(cfgPath, "utf-8"));
|
|
483
|
-
} catch (e) {
|
|
484
|
-
warn(`Cannot parse openclaw.json: ${e.message}`);
|
|
485
|
-
return;
|
|
486
|
-
}
|
|
487
|
-
|
|
488
|
-
const pluginEntry = cfg?.plugins?.entries?.["memos-local-openclaw-plugin"];
|
|
489
|
-
const existingSharing = pluginEntry?.config?.sharing;
|
|
490
|
-
|
|
491
|
-
if (existingSharing?.enabled) {
|
|
492
|
-
const roleLabel = existingSharing.role === "hub" ? "Hub (团队中心)" : "Client (团队成员)";
|
|
493
|
-
log(`已检测到共享配置: 角色 = ${BOLD}${roleLabel}${RESET}`);
|
|
494
|
-
const prompt = createPrompt();
|
|
495
|
-
const ans = await prompt.ask(` 是否重新配置?/ Reconfigure? (y/N) > `);
|
|
496
|
-
prompt.close();
|
|
497
|
-
if (ans.toLowerCase() !== "y") {
|
|
498
|
-
ok("保留现有共享配置。");
|
|
499
|
-
return;
|
|
500
|
-
}
|
|
501
|
-
}
|
|
502
|
-
|
|
503
|
-
phase(3, "局域网共享设置 / LAN Sharing Setup");
|
|
504
|
-
|
|
505
|
-
const prompt = createPrompt();
|
|
506
|
-
|
|
507
|
-
const enableAns = await prompt.ask(` 是否启用局域网记忆共享?/ Enable LAN sharing? (y/N) > `);
|
|
508
|
-
if (enableAns.toLowerCase() !== "y") {
|
|
509
|
-
prompt.close();
|
|
510
|
-
log("未启用共享。你可以稍后在 openclaw.json 中手动配置。");
|
|
511
|
-
return;
|
|
512
|
-
}
|
|
513
|
-
|
|
514
|
-
console.log(`
|
|
515
|
-
${BOLD}请选择你的角色 / Choose your role:${RESET}
|
|
516
|
-
${GREEN}1)${RESET} 创建团队 (Hub) — 成为团队管理员,其他人连接你
|
|
517
|
-
${GREEN}2)${RESET} 加入团队 (Client) — 连接到已有的 Hub
|
|
518
|
-
`);
|
|
519
|
-
|
|
520
|
-
const roleAns = await prompt.ask(` 请输入 1 或 2 / Enter 1 or 2 > `);
|
|
521
|
-
|
|
522
|
-
let sharingConfig;
|
|
523
|
-
|
|
524
|
-
if (roleAns === "1") {
|
|
525
|
-
console.log(`\n ${CYAN}${BOLD}── Hub 设置 / Hub Setup ──${RESET}\n`);
|
|
526
|
-
|
|
527
|
-
const teamName = (await prompt.ask(` 团队名称 / Team name (默认: My Team) > `)) || "My Team";
|
|
528
|
-
const portStr = (await prompt.ask(` Hub 端口 / Hub port (默认: 18800) > `)) || "18800";
|
|
529
|
-
const port = parseInt(portStr, 10) || 18800;
|
|
530
|
-
const teamToken = generateTeamToken();
|
|
531
|
-
|
|
532
|
-
sharingConfig = {
|
|
533
|
-
enabled: true,
|
|
534
|
-
role: "hub",
|
|
535
|
-
hub: { port, teamName, teamToken },
|
|
536
|
-
};
|
|
537
|
-
|
|
538
|
-
const localIPs = getLocalIPs();
|
|
539
|
-
const displayIP = localIPs.length > 0 ? localIPs[0].address : "<your-ip>";
|
|
540
|
-
|
|
541
|
-
console.log(`
|
|
542
|
-
${GREEN}${BOLD} ┌────────────────────────────────────────────────────────────┐
|
|
543
|
-
│ ✔ Hub 配置完成!/ Hub configured! │
|
|
544
|
-
│ │
|
|
545
|
-
│ 请将以下信息分享给团队成员: │
|
|
546
|
-
│ Share this info with your team: │
|
|
547
|
-
│ │
|
|
548
|
-
│ ${CYAN}Hub 地址 / Address : ${displayIP}:${port}${GREEN}
|
|
549
|
-
│ ${CYAN}Team Token : ${teamToken}${GREEN}
|
|
550
|
-
│ │
|
|
551
|
-
│ 团队成员安装插件时选择 "加入团队" 并输入以上信息。 │
|
|
552
|
-
└────────────────────────────────────────────────────────────┘${RESET}
|
|
553
|
-
`);
|
|
554
|
-
|
|
555
|
-
if (localIPs.length > 1) {
|
|
556
|
-
log("检测到多个网络接口 / Multiple network interfaces:");
|
|
557
|
-
for (const ip of localIPs) {
|
|
558
|
-
log(` ${ip.name}: ${BOLD}${ip.address}:${port}${RESET}`);
|
|
559
|
-
}
|
|
560
|
-
}
|
|
561
|
-
|
|
562
|
-
} else if (roleAns === "2") {
|
|
563
|
-
console.log(`\n ${CYAN}${BOLD}── 加入团队 / Join Team ──${RESET}\n`);
|
|
564
|
-
|
|
565
|
-
const hubAddress = await prompt.ask(` Hub 地址 / Hub address (如 192.168.1.100:18800) > `);
|
|
566
|
-
if (!hubAddress) {
|
|
567
|
-
prompt.close();
|
|
568
|
-
warn("Hub 地址不能为空,跳过配置。");
|
|
569
|
-
return;
|
|
570
|
-
}
|
|
571
|
-
|
|
572
|
-
const teamToken = await prompt.ask(` Team Token (由 Hub 创建者提供 / from Hub creator) > `);
|
|
573
|
-
if (!teamToken) {
|
|
574
|
-
prompt.close();
|
|
575
|
-
warn("Team Token 不能为空,跳过配置。");
|
|
576
|
-
return;
|
|
577
|
-
}
|
|
578
|
-
|
|
579
|
-
const username = (await prompt.ask(` 你的用户名 / Your username (默认: ${os.userInfo().username}) > `)) || os.userInfo().username;
|
|
580
455
|
|
|
581
|
-
|
|
582
|
-
log(`正在加入团队 / Joining team at: ${BOLD}${hubUrl}${RESET} ...`);
|
|
583
|
-
|
|
584
|
-
let userToken = "";
|
|
585
|
-
let joinOk = false;
|
|
586
|
-
|
|
587
|
-
try {
|
|
588
|
-
const http = require("http");
|
|
589
|
-
const https = require("https");
|
|
590
|
-
const joinResult = await new Promise((resolve, reject) => {
|
|
591
|
-
const postData = JSON.stringify({ teamToken, username, deviceName: os.hostname() });
|
|
592
|
-
const url = new URL(`${hubUrl}/api/v1/hub/join`);
|
|
593
|
-
const mod = url.protocol === "https:" ? https : http;
|
|
594
|
-
const reqObj = mod.request({
|
|
595
|
-
hostname: url.hostname, port: url.port, path: url.pathname,
|
|
596
|
-
method: "POST",
|
|
597
|
-
headers: { "Content-Type": "application/json", "Content-Length": Buffer.byteLength(postData) },
|
|
598
|
-
timeout: 8000,
|
|
599
|
-
}, (resp) => {
|
|
600
|
-
let data = "";
|
|
601
|
-
resp.on("data", (c) => { data += c; });
|
|
602
|
-
resp.on("end", () => {
|
|
603
|
-
try { resolve({ status: resp.statusCode, body: JSON.parse(data) }); }
|
|
604
|
-
catch { resolve({ status: resp.statusCode, body: data }); }
|
|
605
|
-
});
|
|
606
|
-
});
|
|
607
|
-
reqObj.on("error", reject);
|
|
608
|
-
reqObj.on("timeout", () => { reqObj.destroy(); reject(new Error("timeout")); });
|
|
609
|
-
reqObj.write(postData);
|
|
610
|
-
reqObj.end();
|
|
611
|
-
});
|
|
612
|
-
|
|
613
|
-
if (joinResult.status === 200 && joinResult.body.userToken) {
|
|
614
|
-
userToken = joinResult.body.userToken;
|
|
615
|
-
joinOk = true;
|
|
616
|
-
ok(`加入成功!/ Joined successfully! 用户: ${BOLD}${username}${RESET}`);
|
|
617
|
-
} else if (joinResult.status === 403) {
|
|
618
|
-
prompt.close();
|
|
619
|
-
fail("Team Token 无效 / Invalid Team Token");
|
|
620
|
-
return;
|
|
621
|
-
} else {
|
|
622
|
-
warn(`Hub 返回 / Hub responded: ${joinResult.status} ${JSON.stringify(joinResult.body)}`);
|
|
623
|
-
log("配置将被保存,gateway 启动时会用 Team Token 自动重试加入。");
|
|
624
|
-
}
|
|
625
|
-
} catch (e) {
|
|
626
|
-
warn(`无法连接 Hub / Cannot reach Hub: ${e.message}`);
|
|
627
|
-
log("配置将被保存,gateway 启动时会用 Team Token 自动重试加入。");
|
|
628
|
-
}
|
|
629
|
-
|
|
630
|
-
sharingConfig = {
|
|
631
|
-
enabled: true,
|
|
632
|
-
role: "client",
|
|
633
|
-
client: { hubAddress, teamToken },
|
|
634
|
-
};
|
|
635
|
-
if (userToken) sharingConfig.client.userToken = userToken;
|
|
636
|
-
|
|
637
|
-
const statusMsg = joinOk
|
|
638
|
-
? `已加入团队,重启 gateway 即生效`
|
|
639
|
-
: `Hub 暂不可达,gateway 启动时会自动加入`;
|
|
640
|
-
console.log(`
|
|
641
|
-
${GREEN}${BOLD} ┌────────────────────────────────────────────────────────────┐
|
|
642
|
-
│ ✔ Client 配置完成!/ Client configured! │
|
|
643
|
-
│ ${CYAN}Hub: ${hubAddress}${GREEN}
|
|
644
|
-
│ ${CYAN}${statusMsg}${GREEN}
|
|
645
|
-
└────────────────────────────────────────────────────────────┘${RESET}
|
|
646
|
-
`);
|
|
647
|
-
|
|
648
|
-
} else {
|
|
649
|
-
prompt.close();
|
|
650
|
-
warn(`无效选择 "${roleAns}",跳过配置。你可以稍后在 openclaw.json 中手动配置。`);
|
|
651
|
-
return;
|
|
652
|
-
}
|
|
653
|
-
|
|
654
|
-
prompt.close();
|
|
655
|
-
|
|
656
|
-
try {
|
|
657
|
-
if (!cfg.plugins) cfg.plugins = {};
|
|
658
|
-
if (!cfg.plugins.entries) cfg.plugins.entries = {};
|
|
659
|
-
if (!cfg.plugins.entries["memos-local-openclaw-plugin"]) {
|
|
660
|
-
cfg.plugins.entries["memos-local-openclaw-plugin"] = { enabled: true };
|
|
661
|
-
}
|
|
662
|
-
const entry = cfg.plugins.entries["memos-local-openclaw-plugin"];
|
|
663
|
-
if (!entry.config) entry.config = {};
|
|
664
|
-
entry.config.sharing = sharingConfig;
|
|
665
|
-
|
|
666
|
-
const backup = cfgPath + ".bak-" + Date.now();
|
|
667
|
-
fs.copyFileSync(cfgPath, backup);
|
|
668
|
-
fs.writeFileSync(cfgPath, JSON.stringify(cfg, null, 2) + "\n", "utf-8");
|
|
669
|
-
ok(`配置已写入 / Config saved: ${DIM}~/.openclaw/openclaw.json${RESET}`);
|
|
670
|
-
log(`备份 / Backup: ${DIM}${backup}${RESET}`);
|
|
671
|
-
} catch (e) {
|
|
672
|
-
fail(`写入配置失败 / Config write failed: ${e.message}`);
|
|
673
|
-
warn("请手动编辑 ~/.openclaw/openclaw.json 添加 sharing 配置。");
|
|
674
|
-
}
|
|
675
|
-
}
|
|
676
|
-
|
|
677
|
-
(async () => {
|
|
678
|
-
try {
|
|
679
|
-
await setupSharingWizard();
|
|
680
|
-
} catch (e) {
|
|
681
|
-
warn(`Setup wizard error: ${e.message}`);
|
|
682
|
-
}
|
|
683
|
-
|
|
684
|
-
console.log(`
|
|
685
|
-
${GREEN}${BOLD} ┌──────────────────────────────────────────────────┐
|
|
686
|
-
│ ✔ Setup complete! │
|
|
687
|
-
│ │
|
|
688
|
-
│ Restart gateway: │
|
|
689
|
-
│ ${CYAN}openclaw gateway stop && openclaw gateway start${GREEN} │
|
|
690
|
-
└──────────────────────────────────────────────────┘${RESET}
|
|
691
|
-
`);
|
|
692
|
-
process.exit(0);
|
|
693
|
-
})();
|
|
456
|
+
process.exit(0);
|
|
@@ -5,13 +5,13 @@ description: "Use the MemOS Local memory system to search and use the user's pas
|
|
|
5
5
|
|
|
6
6
|
# MemOS Local Memory — Agent Guide
|
|
7
7
|
|
|
8
|
-
This skill describes how to use the MemOS memory tools so you can reliably search and use the user's long-term conversation history,
|
|
8
|
+
This skill describes how to use the MemOS memory tools so you can reliably search and use the user's long-term conversation history, share knowledge across agents, and discover public skills.
|
|
9
9
|
|
|
10
10
|
## How memory is provided each turn
|
|
11
11
|
|
|
12
12
|
- **Automatic recall (hook):** At the start of each turn, the system runs a memory search using the user's current message and injects relevant past memories into your context. You do not need to call any tool for that.
|
|
13
13
|
- **When that is not enough:** If the user's message is very long, vague, or the automatic search returns **no memories**, you should **generate your own short, focused query** and call `memory_search` yourself.
|
|
14
|
-
- **Memory isolation:** Each agent can only see its own
|
|
14
|
+
- **Memory isolation:** Each agent can only see its own memories and memories marked as `public`. Other agents' private memories are invisible to you.
|
|
15
15
|
|
|
16
16
|
## Tools — what they do and when to call
|
|
17
17
|
|
|
@@ -89,30 +89,6 @@ This skill describes how to use the MemOS memory tools so you can reliably searc
|
|
|
89
89
|
- **Parameters:**
|
|
90
90
|
- `skillId` (string, **required**) — The skill ID to unpublish.
|
|
91
91
|
|
|
92
|
-
### network_memory_detail
|
|
93
|
-
|
|
94
|
-
- **What it does:** Fetches the full content behind a Hub search hit.
|
|
95
|
-
- **When to call:** A `memory_search` result came from the Hub and you need the full shared memory content.
|
|
96
|
-
- **Parameters:** `remoteHitId`.
|
|
97
|
-
|
|
98
|
-
### task_share / task_unshare
|
|
99
|
-
|
|
100
|
-
- **What they do:** Share a local task to the Hub, or remove it later.
|
|
101
|
-
- **When to call:** A task is valuable to your group or to the whole team and should be discoverable via shared search.
|
|
102
|
-
- **Parameters:** `taskId`, plus sharing visibility/scope when required.
|
|
103
|
-
|
|
104
|
-
### network_skill_pull
|
|
105
|
-
|
|
106
|
-
- **What it does:** Pulls a Hub-shared skill bundle down into local storage.
|
|
107
|
-
- **When to call:** `skill_search` found a useful Hub skill and you want to use it locally or offline.
|
|
108
|
-
- **Parameters:** `skillId`.
|
|
109
|
-
|
|
110
|
-
### network_team_info
|
|
111
|
-
|
|
112
|
-
- **What it does:** Returns current Hub connection information, user, role, and groups.
|
|
113
|
-
- **When to call:** You need to confirm whether team sharing is configured or which groups the current client belongs to.
|
|
114
|
-
- **Parameters:** none.
|
|
115
|
-
|
|
116
92
|
### memory_timeline
|
|
117
93
|
|
|
118
94
|
- **What it does:** Expand context around a memory search hit. Pass the `chunkId` from a search result to read the surrounding conversation messages.
|
package/src/capture/index.ts
CHANGED
|
@@ -70,6 +70,7 @@ export function captureMessages(
|
|
|
70
70
|
if (role === "user") {
|
|
71
71
|
content = stripInboundMetadata(content);
|
|
72
72
|
} else {
|
|
73
|
+
content = stripThinkingTags(content);
|
|
73
74
|
content = stripEvidenceWrappers(content, evidenceTag);
|
|
74
75
|
}
|
|
75
76
|
if (!content.trim()) continue;
|
|
@@ -149,6 +150,13 @@ export function stripInboundMetadata(text: string): string {
|
|
|
149
150
|
return stripEnvelopePrefix(result.join("\n")).trim();
|
|
150
151
|
}
|
|
151
152
|
|
|
153
|
+
/** Strip <think…>…</think⟩ blocks emitted by DeepSeek-style reasoning models. */
|
|
154
|
+
const THINKING_TAG_RE = /<think[\s>][\s\S]*?<\/think>\s*/gi;
|
|
155
|
+
|
|
156
|
+
function stripThinkingTags(text: string): string {
|
|
157
|
+
return text.replace(THINKING_TAG_RE, "");
|
|
158
|
+
}
|
|
159
|
+
|
|
152
160
|
function stripEnvelopePrefix(text: string): string {
|
|
153
161
|
return text.replace(ENVELOPE_PREFIX_RE, "");
|
|
154
162
|
}
|
package/src/config.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import * as path from "path";
|
|
2
|
-
import { DEFAULTS, type MemosLocalConfig, type PluginContext, type Logger
|
|
3
|
-
import { OpenClawAPIClient, type HostModelsConfig } from "./openclaw-api";
|
|
2
|
+
import { DEFAULTS, type MemosLocalConfig, type PluginContext, type Logger } from "./types";
|
|
4
3
|
|
|
5
4
|
const ENV_RE = /\$\{([A-Z_][A-Z0-9_]*)\}/g;
|
|
6
5
|
|
|
@@ -21,24 +20,6 @@ function deepResolveEnv<T>(obj: T): T {
|
|
|
21
20
|
return obj;
|
|
22
21
|
}
|
|
23
22
|
|
|
24
|
-
function resolveProviderFallback<T extends { provider?: string; capabilities?: unknown }>(
|
|
25
|
-
config: T | undefined,
|
|
26
|
-
fallbackProvider: T["provider"],
|
|
27
|
-
enabled: boolean,
|
|
28
|
-
): T | undefined {
|
|
29
|
-
if (!config) {
|
|
30
|
-
return enabled
|
|
31
|
-
? ({ provider: fallbackProvider } as T)
|
|
32
|
-
: undefined;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
if (config.provider == null && enabled) {
|
|
36
|
-
return { ...config, provider: fallbackProvider };
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
return config;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
23
|
export function resolveConfig(raw: Partial<MemosLocalConfig> | undefined, stateDir: string): MemosLocalConfig {
|
|
43
24
|
const cfg = deepResolveEnv(raw ?? {});
|
|
44
25
|
|
|
@@ -46,11 +27,6 @@ export function resolveConfig(raw: Partial<MemosLocalConfig> | undefined, stateD
|
|
|
46
27
|
const telemetryEnabled =
|
|
47
28
|
cfg.telemetry?.enabled ??
|
|
48
29
|
(telemetryEnvVar === "false" || telemetryEnvVar === "0" ? false : true);
|
|
49
|
-
const sharingCapabilities = {
|
|
50
|
-
hostEmbedding: cfg.sharing?.capabilities?.hostEmbedding ?? false,
|
|
51
|
-
hostCompletion: cfg.sharing?.capabilities?.hostCompletion ?? false,
|
|
52
|
-
hostSkill: cfg.sharing?.capabilities?.hostSkill ?? false,
|
|
53
|
-
};
|
|
54
30
|
|
|
55
31
|
return {
|
|
56
32
|
...cfg,
|
|
@@ -75,64 +51,7 @@ export function resolveConfig(raw: Partial<MemosLocalConfig> | undefined, stateD
|
|
|
75
51
|
},
|
|
76
52
|
telemetry: {
|
|
77
53
|
enabled: telemetryEnabled,
|
|
78
|
-
posthogApiKey: cfg.telemetry?.posthogApiKey ?? process.env.POSTHOG_API_KEY ?? "",
|
|
79
|
-
posthogHost: cfg.telemetry?.posthogHost ?? process.env.POSTHOG_HOST ?? "",
|
|
80
54
|
},
|
|
81
|
-
summarizer: (() => {
|
|
82
|
-
const summarizerConfig = resolveProviderFallback<SummarizerConfig>(
|
|
83
|
-
cfg.summarizer,
|
|
84
|
-
"openclaw",
|
|
85
|
-
sharingCapabilities.hostCompletion,
|
|
86
|
-
);
|
|
87
|
-
return summarizerConfig
|
|
88
|
-
? {
|
|
89
|
-
...summarizerConfig,
|
|
90
|
-
capabilities: sharingCapabilities,
|
|
91
|
-
}
|
|
92
|
-
: undefined;
|
|
93
|
-
})(),
|
|
94
|
-
embedding: (() => {
|
|
95
|
-
const embeddingConfig = resolveProviderFallback<EmbeddingConfig>(
|
|
96
|
-
cfg.embedding,
|
|
97
|
-
"openclaw",
|
|
98
|
-
sharingCapabilities.hostEmbedding,
|
|
99
|
-
);
|
|
100
|
-
return embeddingConfig
|
|
101
|
-
? {
|
|
102
|
-
...embeddingConfig,
|
|
103
|
-
capabilities: sharingCapabilities,
|
|
104
|
-
}
|
|
105
|
-
: undefined;
|
|
106
|
-
})(),
|
|
107
|
-
skillEvolution: cfg.skillEvolution ? {
|
|
108
|
-
...cfg.skillEvolution,
|
|
109
|
-
summarizer: (() => {
|
|
110
|
-
const skSumCfg = resolveProviderFallback<SummarizerConfig>(
|
|
111
|
-
cfg.skillEvolution!.summarizer as SummarizerConfig | undefined,
|
|
112
|
-
"openclaw",
|
|
113
|
-
sharingCapabilities.hostSkill,
|
|
114
|
-
);
|
|
115
|
-
return skSumCfg
|
|
116
|
-
? { ...skSumCfg, capabilities: sharingCapabilities }
|
|
117
|
-
: undefined;
|
|
118
|
-
})(),
|
|
119
|
-
} : undefined,
|
|
120
|
-
sharing: (() => {
|
|
121
|
-
const role = cfg.sharing?.role ?? "client";
|
|
122
|
-
const enabled = cfg.sharing?.enabled ?? false;
|
|
123
|
-
const hub = role === "hub" ? {
|
|
124
|
-
port: cfg.sharing?.hub?.port ?? 18800,
|
|
125
|
-
teamName: cfg.sharing?.hub?.teamName ?? "",
|
|
126
|
-
teamToken: cfg.sharing?.hub?.teamToken ?? "",
|
|
127
|
-
} : { port: 18800, teamName: "", teamToken: "" };
|
|
128
|
-
const client = role === "client" ? {
|
|
129
|
-
hubAddress: cfg.sharing?.client?.hubAddress ?? "",
|
|
130
|
-
userToken: cfg.sharing?.client?.userToken ?? "",
|
|
131
|
-
teamToken: cfg.sharing?.client?.teamToken ?? "",
|
|
132
|
-
pendingUserId: cfg.sharing?.client?.pendingUserId ?? "",
|
|
133
|
-
} : { hubAddress: "", userToken: "", teamToken: "", pendingUserId: "" };
|
|
134
|
-
return { enabled, role, hub, client, capabilities: sharingCapabilities };
|
|
135
|
-
})(),
|
|
136
55
|
};
|
|
137
56
|
}
|
|
138
57
|
|
|
@@ -141,7 +60,6 @@ export function buildContext(
|
|
|
141
60
|
workspaceDir: string,
|
|
142
61
|
rawConfig: Partial<MemosLocalConfig> | undefined,
|
|
143
62
|
log?: Logger,
|
|
144
|
-
hostModels?: HostModelsConfig,
|
|
145
63
|
): PluginContext {
|
|
146
64
|
const defaultLog: Logger = {
|
|
147
65
|
debug: (...args) => console.debug("[memos-local]", ...args),
|
|
@@ -150,19 +68,10 @@ export function buildContext(
|
|
|
150
68
|
error: (...args) => console.error("[memos-local]", ...args),
|
|
151
69
|
};
|
|
152
70
|
|
|
153
|
-
const logger = log ?? defaultLog;
|
|
154
|
-
const config = resolveConfig(rawConfig, stateDir);
|
|
155
|
-
|
|
156
|
-
// Create OpenClawAPI instance if host capabilities are enabled
|
|
157
|
-
const openclawAPI = (config.sharing?.capabilities?.hostEmbedding || config.sharing?.capabilities?.hostCompletion || config.sharing?.capabilities?.hostSkill)
|
|
158
|
-
? new OpenClawAPIClient(logger, hostModels)
|
|
159
|
-
: undefined;
|
|
160
|
-
|
|
161
71
|
return {
|
|
162
72
|
stateDir,
|
|
163
73
|
workspaceDir,
|
|
164
|
-
config,
|
|
165
|
-
log:
|
|
166
|
-
openclawAPI,
|
|
74
|
+
config: resolveConfig(rawConfig, stateDir),
|
|
75
|
+
log: log ?? defaultLog,
|
|
167
76
|
};
|
|
168
77
|
}
|
package/src/embedding/index.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { EmbeddingConfig, Logger
|
|
1
|
+
import type { EmbeddingConfig, Logger } from "../types";
|
|
2
2
|
import { embedOpenAI } from "./providers/openai";
|
|
3
3
|
import { embedGemini } from "./providers/gemini";
|
|
4
4
|
import { embedCohere, embedCohereQuery } from "./providers/cohere";
|
|
@@ -11,13 +11,9 @@ export class Embedder {
|
|
|
11
11
|
constructor(
|
|
12
12
|
private cfg: EmbeddingConfig | undefined,
|
|
13
13
|
private log: Logger,
|
|
14
|
-
private openclawAPI?: OpenClawAPI,
|
|
15
14
|
) {}
|
|
16
15
|
|
|
17
16
|
get provider(): string {
|
|
18
|
-
if (this.cfg?.provider === "openclaw" && this.cfg.capabilities?.hostEmbedding !== true) {
|
|
19
|
-
return "local";
|
|
20
|
-
}
|
|
21
17
|
return this.cfg?.provider ?? "local";
|
|
22
18
|
}
|
|
23
19
|
|
|
@@ -85,20 +81,4 @@ export class Embedder {
|
|
|
85
81
|
throw err;
|
|
86
82
|
}
|
|
87
83
|
}
|
|
88
|
-
|
|
89
|
-
private async embedOpenClaw(texts: string[]): Promise<number[][]> {
|
|
90
|
-
if (!this.openclawAPI) {
|
|
91
|
-
throw new Error(
|
|
92
|
-
"OpenClaw API not available. Ensure sharing.capabilities.hostEmbedding is enabled in config."
|
|
93
|
-
);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
this.log.debug(`Calling OpenClaw embed API for ${texts.length} texts`);
|
|
97
|
-
const response = await this.openclawAPI.embed({
|
|
98
|
-
texts,
|
|
99
|
-
model: this.cfg?.model,
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
return response.embeddings;
|
|
103
|
-
}
|
|
104
84
|
}
|
package/src/index.ts
CHANGED
|
@@ -6,9 +6,8 @@ import { Embedder } from "./embedding";
|
|
|
6
6
|
import { IngestWorker } from "./ingest/worker";
|
|
7
7
|
import { RecallEngine } from "./recall/engine";
|
|
8
8
|
import { captureMessages } from "./capture";
|
|
9
|
-
import { createMemorySearchTool, createMemoryTimelineTool, createMemoryGetTool
|
|
9
|
+
import { createMemorySearchTool, createMemoryTimelineTool, createMemoryGetTool } from "./tools";
|
|
10
10
|
import type { MemosLocalConfig, ToolDefinition, Logger } from "./types";
|
|
11
|
-
import type { HostModelsConfig } from "./openclaw-api";
|
|
12
11
|
|
|
13
12
|
export interface MemosLocalPlugin {
|
|
14
13
|
id: string;
|
|
@@ -24,7 +23,6 @@ export interface PluginInitOptions {
|
|
|
24
23
|
workspaceDir?: string;
|
|
25
24
|
config?: Partial<MemosLocalConfig>;
|
|
26
25
|
log?: Logger;
|
|
27
|
-
hostModels?: HostModelsConfig;
|
|
28
26
|
}
|
|
29
27
|
|
|
30
28
|
/**
|
|
@@ -53,22 +51,21 @@ export interface PluginInitOptions {
|
|
|
53
51
|
export function initPlugin(opts: PluginInitOptions = {}): MemosLocalPlugin {
|
|
54
52
|
const stateDir = opts.stateDir ?? defaultStateDir();
|
|
55
53
|
const workspaceDir = opts.workspaceDir ?? process.cwd();
|
|
56
|
-
const ctx = buildContext(stateDir, workspaceDir, opts.config, opts.log
|
|
54
|
+
const ctx = buildContext(stateDir, workspaceDir, opts.config, opts.log);
|
|
57
55
|
|
|
58
56
|
ctx.log.info("Initializing memos-local plugin...");
|
|
59
57
|
|
|
60
58
|
ensureSqliteBinding(ctx.log);
|
|
61
59
|
|
|
62
60
|
const store = new SqliteStore(ctx.config.storage!.dbPath!, ctx.log);
|
|
63
|
-
const embedder = new Embedder(ctx.config.embedding, ctx.log
|
|
61
|
+
const embedder = new Embedder(ctx.config.embedding, ctx.log);
|
|
64
62
|
const worker = new IngestWorker(store, embedder, ctx);
|
|
65
63
|
const engine = new RecallEngine(store, embedder, ctx);
|
|
66
64
|
|
|
67
65
|
const tools: ToolDefinition[] = [
|
|
68
|
-
createMemorySearchTool(engine
|
|
66
|
+
createMemorySearchTool(engine),
|
|
69
67
|
createMemoryTimelineTool(store),
|
|
70
68
|
createMemoryGetTool(store),
|
|
71
|
-
createNetworkMemoryDetailTool(store, ctx),
|
|
72
69
|
];
|
|
73
70
|
|
|
74
71
|
ctx.log.info(`Plugin ready. DB: ${ctx.config.storage!.dbPath}, Embedding: ${embedder.provider}`);
|