@memtensor/memos-local-openclaw-plugin 1.0.2-beta.3 → 1.0.2-beta.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/dist/capture/index.d.ts.map +1 -1
- package/dist/capture/index.js +41 -1
- package/dist/capture/index.js.map +1 -1
- package/dist/embedding/index.d.ts.map +1 -1
- package/dist/embedding/index.js +20 -7
- package/dist/embedding/index.js.map +1 -1
- package/dist/ingest/providers/anthropic.d.ts.map +1 -1
- package/dist/ingest/providers/anthropic.js +39 -25
- package/dist/ingest/providers/anthropic.js.map +1 -1
- package/dist/ingest/providers/bedrock.d.ts.map +1 -1
- package/dist/ingest/providers/bedrock.js +39 -25
- package/dist/ingest/providers/bedrock.js.map +1 -1
- package/dist/ingest/providers/gemini.d.ts.map +1 -1
- package/dist/ingest/providers/gemini.js +39 -25
- package/dist/ingest/providers/gemini.js.map +1 -1
- package/dist/ingest/providers/index.d.ts +19 -0
- package/dist/ingest/providers/index.d.ts.map +1 -1
- package/dist/ingest/providers/index.js +98 -10
- package/dist/ingest/providers/index.js.map +1 -1
- package/dist/ingest/providers/openai.d.ts.map +1 -1
- package/dist/ingest/providers/openai.js +39 -25
- package/dist/ingest/providers/openai.js.map +1 -1
- package/dist/ingest/worker.d.ts.map +1 -1
- package/dist/ingest/worker.js +8 -14
- package/dist/ingest/worker.js.map +1 -1
- package/dist/skill/bundled-memory-guide.d.ts +1 -1
- package/dist/skill/bundled-memory-guide.d.ts.map +1 -1
- package/dist/skill/bundled-memory-guide.js +9 -0
- package/dist/skill/bundled-memory-guide.js.map +1 -1
- package/dist/storage/sqlite.d.ts +14 -0
- package/dist/storage/sqlite.d.ts.map +1 -1
- package/dist/storage/sqlite.js +42 -0
- package/dist/storage/sqlite.js.map +1 -1
- package/dist/viewer/html.d.ts +1 -1
- package/dist/viewer/html.d.ts.map +1 -1
- package/dist/viewer/html.js +276 -51
- package/dist/viewer/html.js.map +1 -1
- package/dist/viewer/server.d.ts +4 -0
- package/dist/viewer/server.d.ts.map +1 -1
- package/dist/viewer/server.js +152 -27
- package/dist/viewer/server.js.map +1 -1
- package/index.ts +38 -85
- package/package.json +2 -1
- package/src/capture/index.ts +56 -1
- package/src/embedding/index.ts +13 -7
- package/src/ingest/providers/anthropic.ts +39 -25
- package/src/ingest/providers/bedrock.ts +39 -25
- package/src/ingest/providers/gemini.ts +39 -25
- package/src/ingest/providers/index.ts +112 -9
- package/src/ingest/providers/openai.ts +39 -25
- package/src/ingest/worker.ts +8 -15
- package/src/skill/bundled-memory-guide.ts +9 -0
- package/src/storage/sqlite.ts +49 -0
- package/src/viewer/html.ts +275 -50
- package/src/viewer/server.ts +143 -32
package/dist/viewer/server.js
CHANGED
|
@@ -19,6 +19,11 @@ const engine_1 = require("../recall/engine");
|
|
|
19
19
|
const evolver_1 = require("../skill/evolver");
|
|
20
20
|
const html_1 = require("./html");
|
|
21
21
|
const uuid_1 = require("uuid");
|
|
22
|
+
function normalizeTimestamp(ts) {
|
|
23
|
+
if (ts < 1e12)
|
|
24
|
+
return ts * 1000;
|
|
25
|
+
return ts;
|
|
26
|
+
}
|
|
22
27
|
class ViewerServer {
|
|
23
28
|
server = null;
|
|
24
29
|
store;
|
|
@@ -30,6 +35,15 @@ class ViewerServer {
|
|
|
30
35
|
auth;
|
|
31
36
|
ctx;
|
|
32
37
|
static SESSION_TTL = 24 * 60 * 60 * 1000;
|
|
38
|
+
static PLUGIN_VERSION = (() => {
|
|
39
|
+
try {
|
|
40
|
+
const pkgPath = node_path_1.default.resolve(__dirname, "../../package.json");
|
|
41
|
+
return JSON.parse(node_fs_1.default.readFileSync(pkgPath, "utf-8")).version ?? "unknown";
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
return "unknown";
|
|
45
|
+
}
|
|
46
|
+
})();
|
|
33
47
|
resetToken;
|
|
34
48
|
migrationRunning = false;
|
|
35
49
|
migrationAbort = false;
|
|
@@ -66,10 +80,28 @@ class ViewerServer {
|
|
|
66
80
|
this.server.listen(this.port, "127.0.0.1", () => {
|
|
67
81
|
const addr = this.server.address();
|
|
68
82
|
const actualPort = typeof addr === "object" && addr ? addr.port : this.port;
|
|
83
|
+
this.autoCleanupPolluted();
|
|
69
84
|
resolve(`http://127.0.0.1:${actualPort}`);
|
|
70
85
|
});
|
|
71
86
|
});
|
|
72
87
|
}
|
|
88
|
+
autoCleanupPolluted() {
|
|
89
|
+
try {
|
|
90
|
+
const polluted = this.store.findPollutedUserChunks();
|
|
91
|
+
let deleted = 0;
|
|
92
|
+
for (const { id } of polluted) {
|
|
93
|
+
if (this.store.deleteChunk(id))
|
|
94
|
+
deleted++;
|
|
95
|
+
}
|
|
96
|
+
const fixed = this.store.fixMixedUserChunks();
|
|
97
|
+
if (deleted > 0 || fixed > 0) {
|
|
98
|
+
this.log.info(`Auto-cleanup: removed ${deleted} polluted chunks, fixed ${fixed} mixed user+assistant chunks`);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
catch (err) {
|
|
102
|
+
this.log.warn(`Auto-cleanup failed: ${err}`);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
73
105
|
stop() {
|
|
74
106
|
this.server?.close();
|
|
75
107
|
this.server = null;
|
|
@@ -212,12 +244,16 @@ class ViewerServer {
|
|
|
212
244
|
this.handleSaveConfig(req, res);
|
|
213
245
|
else if (p === "/api/test-model" && req.method === "POST")
|
|
214
246
|
this.handleTestModel(req, res);
|
|
247
|
+
else if (p === "/api/model-health" && req.method === "GET")
|
|
248
|
+
this.serveModelHealth(res);
|
|
215
249
|
else if (p === "/api/fallback-model" && req.method === "GET")
|
|
216
250
|
this.serveFallbackModel(res);
|
|
217
251
|
else if (p === "/api/update-check" && req.method === "GET")
|
|
218
252
|
this.handleUpdateCheck(res);
|
|
219
253
|
else if (p === "/api/auth/logout" && req.method === "POST")
|
|
220
254
|
this.handleLogout(req, res);
|
|
255
|
+
else if (p === "/api/cleanup-polluted" && req.method === "POST")
|
|
256
|
+
this.handleCleanupPolluted(res);
|
|
221
257
|
else if (p === "/api/migrate/scan" && req.method === "GET")
|
|
222
258
|
this.handleMigrateScan(res);
|
|
223
259
|
else if (p === "/api/migrate/start" && req.method === "POST")
|
|
@@ -345,7 +381,7 @@ class ViewerServer {
|
|
|
345
381
|
// ─── Pages ───
|
|
346
382
|
serveViewer(res) {
|
|
347
383
|
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8", "Cache-Control": "no-store, no-cache, must-revalidate, max-age=0", "Pragma": "no-cache", "Expires": "0" });
|
|
348
|
-
res.end(html_1.viewerHTML);
|
|
384
|
+
res.end((0, html_1.viewerHTML)(ViewerServer.PLUGIN_VERSION));
|
|
349
385
|
}
|
|
350
386
|
// ─── Data APIs ───
|
|
351
387
|
serveMemories(res, url) {
|
|
@@ -491,7 +527,15 @@ class ViewerServer {
|
|
|
491
527
|
const total = db.prepare("SELECT COUNT(*) as count FROM chunks").get();
|
|
492
528
|
const sessions = db.prepare("SELECT COUNT(DISTINCT session_key) as count FROM chunks").get();
|
|
493
529
|
const roles = db.prepare("SELECT role, COUNT(*) as count FROM chunks GROUP BY role").all();
|
|
494
|
-
const timeRange = db.prepare("SELECT MIN(created_at) as earliest, MAX(created_at) as latest FROM chunks").get();
|
|
530
|
+
const timeRange = db.prepare("SELECT MIN(created_at) as earliest, MAX(created_at) as latest FROM chunks WHERE dedup_status = 'active'").get();
|
|
531
|
+
const MIN_VALID_TS = 1704067200000; // 2024-01-01
|
|
532
|
+
if (timeRange.earliest != null && timeRange.earliest < MIN_VALID_TS) {
|
|
533
|
+
timeRange.earliest = db.prepare("SELECT MIN(created_at) as v FROM chunks WHERE dedup_status = 'active' AND created_at >= ?").get(MIN_VALID_TS);
|
|
534
|
+
timeRange.earliest = timeRange.earliest?.v ?? null;
|
|
535
|
+
}
|
|
536
|
+
if (timeRange.latest != null && timeRange.latest < MIN_VALID_TS) {
|
|
537
|
+
timeRange.latest = null;
|
|
538
|
+
}
|
|
495
539
|
let embCount = 0;
|
|
496
540
|
try {
|
|
497
541
|
embCount = db.prepare("SELECT COUNT(*) as count FROM embeddings").get().count;
|
|
@@ -541,6 +585,8 @@ class ViewerServer {
|
|
|
541
585
|
}
|
|
542
586
|
const role = url.searchParams.get("role") ?? undefined;
|
|
543
587
|
const kind = url.searchParams.get("kind") ?? undefined;
|
|
588
|
+
const session = url.searchParams.get("session") ?? undefined;
|
|
589
|
+
const owner = url.searchParams.get("owner") ?? undefined;
|
|
544
590
|
const dateFrom = url.searchParams.get("dateFrom") ?? undefined;
|
|
545
591
|
const dateTo = url.searchParams.get("dateTo") ?? undefined;
|
|
546
592
|
const passesFilter = (r) => {
|
|
@@ -548,35 +594,71 @@ class ViewerServer {
|
|
|
548
594
|
return false;
|
|
549
595
|
if (kind && r.kind !== kind)
|
|
550
596
|
return false;
|
|
597
|
+
if (session && r.session_key !== session)
|
|
598
|
+
return false;
|
|
599
|
+
if (owner && r.owner !== owner)
|
|
600
|
+
return false;
|
|
551
601
|
if (dateFrom && r.created_at < new Date(dateFrom).getTime())
|
|
552
602
|
return false;
|
|
553
603
|
if (dateTo && r.created_at > new Date(dateTo).getTime())
|
|
554
604
|
return false;
|
|
555
605
|
return true;
|
|
556
606
|
};
|
|
607
|
+
const ftsFilters = [];
|
|
608
|
+
const likeFilters = [];
|
|
609
|
+
const sqlParams = [];
|
|
610
|
+
if (session) {
|
|
611
|
+
ftsFilters.push("c.session_key = ?");
|
|
612
|
+
likeFilters.push("session_key = ?");
|
|
613
|
+
sqlParams.push(session);
|
|
614
|
+
}
|
|
615
|
+
if (owner) {
|
|
616
|
+
ftsFilters.push("c.owner = ?");
|
|
617
|
+
likeFilters.push("owner = ?");
|
|
618
|
+
sqlParams.push(owner);
|
|
619
|
+
}
|
|
620
|
+
const ftsWhere = ftsFilters.length > 0 ? " AND " + ftsFilters.join(" AND ") : "";
|
|
621
|
+
const likeWhere = likeFilters.length > 0 ? " AND " + likeFilters.join(" AND ") : "";
|
|
557
622
|
const db = this.store.db;
|
|
558
623
|
let ftsResults = [];
|
|
559
624
|
try {
|
|
560
|
-
ftsResults = db.prepare(
|
|
625
|
+
ftsResults = db.prepare(`SELECT c.* FROM chunks_fts f JOIN chunks c ON f.rowid = c.rowid WHERE chunks_fts MATCH ?${ftsWhere} ORDER BY rank LIMIT 100`).all(q, ...sqlParams).filter(passesFilter);
|
|
561
626
|
}
|
|
562
627
|
catch { /* FTS syntax error, fall through */ }
|
|
563
628
|
if (ftsResults.length === 0) {
|
|
564
|
-
|
|
629
|
+
try {
|
|
630
|
+
ftsResults = db.prepare(`SELECT * FROM chunks WHERE (content LIKE ? OR summary LIKE ?)${likeWhere} ORDER BY created_at DESC LIMIT 100`).all(`%${q}%`, `%${q}%`, ...sqlParams).filter(passesFilter);
|
|
631
|
+
}
|
|
632
|
+
catch (err) {
|
|
633
|
+
this.log.warn(`LIKE search failed: ${err}`);
|
|
634
|
+
}
|
|
565
635
|
}
|
|
566
636
|
const SEMANTIC_THRESHOLD = 0.64;
|
|
637
|
+
const VECTOR_TIMEOUT_MS = 8000;
|
|
567
638
|
let vectorResults = [];
|
|
568
639
|
let scoreMap = new Map();
|
|
569
640
|
try {
|
|
570
|
-
const
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
641
|
+
const vecPromise = (async () => {
|
|
642
|
+
const queryVec = await this.embedder.embedQuery(q);
|
|
643
|
+
return (0, vector_1.vectorSearch)(this.store, queryVec, 40);
|
|
644
|
+
})();
|
|
645
|
+
const hits = await Promise.race([
|
|
646
|
+
vecPromise,
|
|
647
|
+
new Promise((resolve) => setTimeout(() => resolve(null), VECTOR_TIMEOUT_MS)),
|
|
648
|
+
]);
|
|
649
|
+
if (hits) {
|
|
650
|
+
scoreMap = new Map(hits.map(h => [h.chunkId, h.score]));
|
|
651
|
+
const hitIds = new Set(hits.filter(h => h.score >= SEMANTIC_THRESHOLD).map(h => h.chunkId));
|
|
652
|
+
if (hitIds.size > 0) {
|
|
653
|
+
const placeholders = [...hitIds].map(() => "?").join(",");
|
|
654
|
+
const rows = db.prepare(`SELECT * FROM chunks WHERE id IN (${placeholders})${likeWhere}`).all(...hitIds, ...sqlParams).filter(passesFilter);
|
|
655
|
+
rows.forEach((r) => { r._vscore = scoreMap.get(r.id) ?? 0; });
|
|
656
|
+
rows.sort((a, b) => (b._vscore ?? 0) - (a._vscore ?? 0));
|
|
657
|
+
vectorResults = rows;
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
else {
|
|
661
|
+
this.log.warn("Vector search timed out, returning FTS results only");
|
|
580
662
|
}
|
|
581
663
|
}
|
|
582
664
|
catch (err) {
|
|
@@ -1080,8 +1162,8 @@ class ViewerServer {
|
|
|
1080
1162
|
return;
|
|
1081
1163
|
}
|
|
1082
1164
|
if (type === "embedding") {
|
|
1083
|
-
await this.testEmbeddingModel(provider, model, endpoint, apiKey);
|
|
1084
|
-
this.jsonResponse(res, { ok: true, detail: `${provider}/${model}
|
|
1165
|
+
const dims = await this.testEmbeddingModel(provider, model, endpoint, apiKey);
|
|
1166
|
+
this.jsonResponse(res, { ok: true, detail: `${provider}/${model}`, dimensions: dims });
|
|
1085
1167
|
}
|
|
1086
1168
|
else {
|
|
1087
1169
|
await this.testChatModel(provider, model, endpoint, apiKey);
|
|
@@ -1095,6 +1177,9 @@ class ViewerServer {
|
|
|
1095
1177
|
}
|
|
1096
1178
|
});
|
|
1097
1179
|
}
|
|
1180
|
+
serveModelHealth(res) {
|
|
1181
|
+
this.jsonResponse(res, { models: providers_1.modelHealth.getAll() });
|
|
1182
|
+
}
|
|
1098
1183
|
serveFallbackModel(res) {
|
|
1099
1184
|
try {
|
|
1100
1185
|
const cfgPath = this.getOpenClawConfigPath();
|
|
@@ -1177,7 +1262,7 @@ class ViewerServer {
|
|
|
1177
1262
|
}
|
|
1178
1263
|
async testEmbeddingModel(provider, model, endpoint, apiKey) {
|
|
1179
1264
|
if (provider === "local") {
|
|
1180
|
-
return;
|
|
1265
|
+
return 384;
|
|
1181
1266
|
}
|
|
1182
1267
|
const baseUrl = (endpoint || "https://api.openai.com/v1").replace(/\/+$/, "");
|
|
1183
1268
|
const embUrl = baseUrl.endsWith("/embeddings") ? baseUrl : `${baseUrl}/embeddings`;
|
|
@@ -1190,39 +1275,59 @@ class ViewerServer {
|
|
|
1190
1275
|
const resp = await fetch(baseUrl.replace(/\/v\d+.*/, "/v2/embed"), {
|
|
1191
1276
|
method: "POST",
|
|
1192
1277
|
headers,
|
|
1193
|
-
body: JSON.stringify({ texts: ["test"], model: model || "embed-english-v3.0", input_type: "search_query", embedding_types: ["float"] }),
|
|
1278
|
+
body: JSON.stringify({ texts: ["test embedding vector"], model: model || "embed-english-v3.0", input_type: "search_query", embedding_types: ["float"] }),
|
|
1194
1279
|
signal: AbortSignal.timeout(15_000),
|
|
1195
1280
|
});
|
|
1196
1281
|
if (!resp.ok) {
|
|
1197
1282
|
const txt = await resp.text();
|
|
1198
1283
|
throw new Error(`Cohere embed ${resp.status}: ${txt}`);
|
|
1199
1284
|
}
|
|
1200
|
-
|
|
1285
|
+
const json = await resp.json();
|
|
1286
|
+
const vecs = json?.embeddings?.float;
|
|
1287
|
+
if (!Array.isArray(vecs) || vecs.length === 0 || !Array.isArray(vecs[0]) || vecs[0].length === 0) {
|
|
1288
|
+
throw new Error("Cohere returned empty embedding vector");
|
|
1289
|
+
}
|
|
1290
|
+
return vecs[0].length;
|
|
1201
1291
|
}
|
|
1202
1292
|
if (provider === "gemini") {
|
|
1203
1293
|
const url = `https://generativelanguage.googleapis.com/v1/models/${model || "text-embedding-004"}:embedContent?key=${apiKey}`;
|
|
1204
1294
|
const resp = await fetch(url, {
|
|
1205
1295
|
method: "POST",
|
|
1206
1296
|
headers: { "Content-Type": "application/json" },
|
|
1207
|
-
body: JSON.stringify({ content: { parts: [{ text: "test" }] } }),
|
|
1297
|
+
body: JSON.stringify({ content: { parts: [{ text: "test embedding vector" }] } }),
|
|
1208
1298
|
signal: AbortSignal.timeout(15_000),
|
|
1209
1299
|
});
|
|
1210
1300
|
if (!resp.ok) {
|
|
1211
1301
|
const txt = await resp.text();
|
|
1212
1302
|
throw new Error(`Gemini embed ${resp.status}: ${txt}`);
|
|
1213
1303
|
}
|
|
1214
|
-
|
|
1304
|
+
const json = await resp.json();
|
|
1305
|
+
const vec = json?.embedding?.values;
|
|
1306
|
+
if (!Array.isArray(vec) || vec.length === 0) {
|
|
1307
|
+
throw new Error("Gemini returned empty embedding vector");
|
|
1308
|
+
}
|
|
1309
|
+
return vec.length;
|
|
1215
1310
|
}
|
|
1216
1311
|
const resp = await fetch(embUrl, {
|
|
1217
1312
|
method: "POST",
|
|
1218
1313
|
headers,
|
|
1219
|
-
body: JSON.stringify({ input: ["test"], model: model || "text-embedding-3-small" }),
|
|
1314
|
+
body: JSON.stringify({ input: ["test embedding vector"], model: model || "text-embedding-3-small" }),
|
|
1220
1315
|
signal: AbortSignal.timeout(15_000),
|
|
1221
1316
|
});
|
|
1222
1317
|
if (!resp.ok) {
|
|
1223
1318
|
const txt = await resp.text();
|
|
1224
1319
|
throw new Error(`${resp.status}: ${txt}`);
|
|
1225
1320
|
}
|
|
1321
|
+
const json = await resp.json();
|
|
1322
|
+
const data = json?.data;
|
|
1323
|
+
if (!Array.isArray(data) || data.length === 0) {
|
|
1324
|
+
throw new Error("API returned no embedding data");
|
|
1325
|
+
}
|
|
1326
|
+
const vec = data[0]?.embedding;
|
|
1327
|
+
if (!Array.isArray(vec) || vec.length === 0) {
|
|
1328
|
+
throw new Error(`API returned empty embedding vector (got ${JSON.stringify(vec)?.slice(0, 100)})`);
|
|
1329
|
+
}
|
|
1330
|
+
return vec.length;
|
|
1226
1331
|
}
|
|
1227
1332
|
async testChatModel(provider, model, endpoint, apiKey) {
|
|
1228
1333
|
const baseUrl = (endpoint || "https://api.openai.com/v1").replace(/\/+$/, "");
|
|
@@ -1291,6 +1396,28 @@ class ViewerServer {
|
|
|
1291
1396
|
const home = process.env.HOME || process.env.USERPROFILE || "";
|
|
1292
1397
|
return node_path_1.default.join(home, ".openclaw");
|
|
1293
1398
|
}
|
|
1399
|
+
handleCleanupPolluted(res) {
|
|
1400
|
+
try {
|
|
1401
|
+
const polluted = this.store.findPollutedUserChunks();
|
|
1402
|
+
let deleted = 0;
|
|
1403
|
+
for (const { id, reason } of polluted) {
|
|
1404
|
+
if (this.store.deleteChunk(id)) {
|
|
1405
|
+
deleted++;
|
|
1406
|
+
this.log.info(`Cleaned polluted chunk ${id}: ${reason}`);
|
|
1407
|
+
}
|
|
1408
|
+
}
|
|
1409
|
+
const fixed = this.store.fixMixedUserChunks();
|
|
1410
|
+
this.log.info(`Cleanup: removed ${deleted} polluted, fixed ${fixed} mixed chunks`);
|
|
1411
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
1412
|
+
res.end(JSON.stringify({ deleted, fixed, total: polluted.length }));
|
|
1413
|
+
}
|
|
1414
|
+
catch (err) {
|
|
1415
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
1416
|
+
this.log.error(`handleCleanupPolluted error: ${msg}`);
|
|
1417
|
+
res.writeHead(500, { "Content-Type": "application/json" });
|
|
1418
|
+
res.end(JSON.stringify({ error: msg }));
|
|
1419
|
+
}
|
|
1420
|
+
}
|
|
1294
1421
|
handleMigrateScan(res) {
|
|
1295
1422
|
try {
|
|
1296
1423
|
const ocHome = this.getOpenClawHome();
|
|
@@ -1540,7 +1667,6 @@ class ViewerServer {
|
|
|
1540
1667
|
let totalErrors = 0;
|
|
1541
1668
|
const cfgPath = this.getOpenClawConfigPath();
|
|
1542
1669
|
let summarizerCfg;
|
|
1543
|
-
let strongCfg;
|
|
1544
1670
|
try {
|
|
1545
1671
|
const raw = JSON.parse(node_fs_1.default.readFileSync(cfgPath, "utf-8"));
|
|
1546
1672
|
const pluginCfg = raw?.plugins?.entries?.["memos-local-openclaw-plugin"]?.config ??
|
|
@@ -1548,10 +1674,9 @@ class ViewerServer {
|
|
|
1548
1674
|
raw?.plugins?.entries?.["memos-lite-openclaw-plugin"]?.config ??
|
|
1549
1675
|
raw?.plugins?.entries?.["memos-lite"]?.config ?? {};
|
|
1550
1676
|
summarizerCfg = pluginCfg.summarizer;
|
|
1551
|
-
strongCfg = pluginCfg.skillEvolution?.summarizer;
|
|
1552
1677
|
}
|
|
1553
1678
|
catch { /* no config */ }
|
|
1554
|
-
const summarizer = new providers_1.Summarizer(summarizerCfg, this.log
|
|
1679
|
+
const summarizer = new providers_1.Summarizer(summarizerCfg, this.log);
|
|
1555
1680
|
// Phase 1: Import SQLite memory chunks
|
|
1556
1681
|
if (importSqlite) {
|
|
1557
1682
|
const memoryDir = node_path_1.default.join(ocHome, "memory");
|
|
@@ -1670,8 +1795,8 @@ class ViewerServer {
|
|
|
1670
1795
|
mergeCount: 0,
|
|
1671
1796
|
lastHitAt: null,
|
|
1672
1797
|
mergeHistory: "[]",
|
|
1673
|
-
createdAt: row.updated_at
|
|
1674
|
-
updatedAt: row.updated_at
|
|
1798
|
+
createdAt: normalizeTimestamp(row.updated_at),
|
|
1799
|
+
updatedAt: normalizeTimestamp(row.updated_at),
|
|
1675
1800
|
};
|
|
1676
1801
|
this.store.insertChunk(chunk);
|
|
1677
1802
|
if (embedding && dedupStatus === "active") {
|