openclaw-memory-alibaba-local 1.0.11 → 1.0.13
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/db.ts +35 -17
- package/index.ts +23 -13
- package/package.json +1 -1
package/db.ts
CHANGED
|
@@ -510,7 +510,7 @@ export class MemoryDB {
|
|
|
510
510
|
});
|
|
511
511
|
if (hasFts) {
|
|
512
512
|
_ftsIndexExists = true;
|
|
513
|
-
console.
|
|
513
|
+
console.debug("[openclaw-memory-alibaba-local] text FTS index already exists");
|
|
514
514
|
return;
|
|
515
515
|
}
|
|
516
516
|
} catch {
|
|
@@ -519,13 +519,13 @@ export class MemoryDB {
|
|
|
519
519
|
|
|
520
520
|
// Create FTS index (no minimum row requirement)
|
|
521
521
|
try {
|
|
522
|
-
console.
|
|
522
|
+
console.debug("[openclaw-memory-alibaba-local] creating FTS index on text column...");
|
|
523
523
|
const lancedb = await loadLanceDB();
|
|
524
524
|
await this.table.createIndex("text", {
|
|
525
525
|
config: (lancedb as any).Index.fts(),
|
|
526
526
|
});
|
|
527
527
|
_ftsIndexExists = true;
|
|
528
|
-
console.
|
|
528
|
+
console.debug("[openclaw-memory-alibaba-local] text FTS index created successfully");
|
|
529
529
|
} catch (e) {
|
|
530
530
|
console.warn("[openclaw-memory-alibaba-local] createIndex(text FTS) failed:", String(e));
|
|
531
531
|
_ftsIndexExists = false;
|
|
@@ -610,32 +610,38 @@ export class MemoryDB {
|
|
|
610
610
|
});
|
|
611
611
|
if (hasVecIdx) {
|
|
612
612
|
_vectorIndexExists = true;
|
|
613
|
-
console.
|
|
613
|
+
console.debug("[openclaw-memory-alibaba-local] vector ANN index already exists");
|
|
614
614
|
return;
|
|
615
615
|
}
|
|
616
616
|
} catch {
|
|
617
617
|
// listIndices not supported or failed; continue to try creating
|
|
618
618
|
}
|
|
619
619
|
|
|
620
|
-
// Check row count; IVF_PQ requires ≥256 training rows
|
|
621
|
-
|
|
620
|
+
// Check row count; IVF_PQ requires ≥256 training rows.
|
|
621
|
+
// Exclude full_context_* categories (zero-vector placeholders, no real embeddings).
|
|
622
|
+
let vectorRowCount: number;
|
|
622
623
|
try {
|
|
623
|
-
|
|
624
|
+
const excludeCats = [FULL_CONTEXT_MEMORY, ...FULL_CONTEXT_SOURCE_CATEGORIES]
|
|
625
|
+
.map((c) => `'${sqlEscapeLiteral(String(c))}'`)
|
|
626
|
+
.join(", ");
|
|
627
|
+
const totalRows = await this.table.countRows();
|
|
628
|
+
const fullContextRows = await this.table.countRows(`category IN (${excludeCats})`);
|
|
629
|
+
vectorRowCount = totalRows - fullContextRows;
|
|
624
630
|
} catch {
|
|
625
631
|
return; // cannot determine; skip
|
|
626
632
|
}
|
|
627
|
-
if (
|
|
633
|
+
if (vectorRowCount < VECTOR_INDEX_MIN_ROWS) {
|
|
628
634
|
_vectorIndexExists = false;
|
|
629
|
-
console.
|
|
630
|
-
`[openclaw-memory-alibaba-local] vector ANN index skipped: ${
|
|
635
|
+
console.debug(
|
|
636
|
+
`[openclaw-memory-alibaba-local] vector ANN index skipped: ${vectorRowCount} vector rows < ${VECTOR_INDEX_MIN_ROWS} minimum`,
|
|
631
637
|
);
|
|
632
638
|
return;
|
|
633
639
|
}
|
|
634
640
|
|
|
635
641
|
// Create IVF_PQ index
|
|
636
642
|
try {
|
|
637
|
-
console.
|
|
638
|
-
`[openclaw-memory-alibaba-local] creating IVF_PQ vector index (${
|
|
643
|
+
console.debug(
|
|
644
|
+
`[openclaw-memory-alibaba-local] creating IVF_PQ vector index (${vectorRowCount} vector rows, dim=${this.vectorDim})...`,
|
|
639
645
|
);
|
|
640
646
|
const lancedb = await loadLanceDB();
|
|
641
647
|
await this.table.createIndex("vector", {
|
|
@@ -1300,9 +1306,21 @@ export class MemoryDB {
|
|
|
1300
1306
|
throw new Error(`Invalid memory ID format: ${id}`);
|
|
1301
1307
|
}
|
|
1302
1308
|
await this.ensureInitialized();
|
|
1309
|
+
await this.refreshToLatest();
|
|
1303
1310
|
const pred = `id = '${sqlEscapeLiteral(id)}' AND agentId = '${sqlEscapeLiteral(agentId)}'`;
|
|
1311
|
+
// Verify row exists before delete
|
|
1312
|
+
const before = await this.table!.countRows(pred);
|
|
1304
1313
|
await this.table!.delete(pred);
|
|
1305
|
-
|
|
1314
|
+
await this.refreshToLatest();
|
|
1315
|
+
const after = await this.table!.countRows(pred);
|
|
1316
|
+
if (before > 0 && after === 0) {
|
|
1317
|
+
console.log(`[openclaw-memory-alibaba-local] db.delete OK id=${id} (${before} row(s) removed)`);
|
|
1318
|
+
} else if (before === 0) {
|
|
1319
|
+
console.warn(`[openclaw-memory-alibaba-local] db.delete MISS id=${id} (row not found before delete)`);
|
|
1320
|
+
} else {
|
|
1321
|
+
console.warn(`[openclaw-memory-alibaba-local] db.delete FAIL id=${id} (before=${before} after=${after})`);
|
|
1322
|
+
}
|
|
1323
|
+
return before > 0 && after === 0;
|
|
1306
1324
|
}
|
|
1307
1325
|
|
|
1308
1326
|
async close(): Promise<void> {
|
|
@@ -1369,7 +1387,7 @@ export class MemoryDB {
|
|
|
1369
1387
|
// 2. Count remaining; if over maxRows, trim oldest
|
|
1370
1388
|
const remaining = await this.table!.countRows(base);
|
|
1371
1389
|
if (remaining <= maxRows) {
|
|
1372
|
-
console.
|
|
1390
|
+
console.debug(`[openclaw-memory-alibaba-local] gcFullContext agent=${agentId} remaining=${remaining} (within limit)`);
|
|
1373
1391
|
return;
|
|
1374
1392
|
}
|
|
1375
1393
|
const excess = remaining - maxRows;
|
|
@@ -1383,7 +1401,7 @@ export class MemoryDB {
|
|
|
1383
1401
|
const cutoff = Number(oldest[excess - 1]!.createdAt);
|
|
1384
1402
|
await this.table!.delete(`${base} AND createdAt <= ${Math.floor(cutoff)}`);
|
|
1385
1403
|
}
|
|
1386
|
-
console.
|
|
1404
|
+
console.debug(`[openclaw-memory-alibaba-local] gcFullContext agent=${agentId} deleted ${excess} excess rows (was ${remaining}, cap ${maxRows})`);
|
|
1387
1405
|
}
|
|
1388
1406
|
|
|
1389
1407
|
/**
|
|
@@ -1435,7 +1453,7 @@ export class MemoryDB {
|
|
|
1435
1453
|
const afterSoft = await this.table!.countRows(base);
|
|
1436
1454
|
const softDeleted = count - afterSoft;
|
|
1437
1455
|
if (softDeleted > 0) {
|
|
1438
|
-
console.
|
|
1456
|
+
console.debug(`[openclaw-memory-alibaba-local] gcWorldFact agent=${agentId} phase1: deleted ${softDeleted} old+low-importance rows (was ${count}, now ${afterSoft})`);
|
|
1439
1457
|
}
|
|
1440
1458
|
count = afterSoft;
|
|
1441
1459
|
}
|
|
@@ -1452,7 +1470,7 @@ export class MemoryDB {
|
|
|
1452
1470
|
const cutoff = Number(oldest[excess - 1]!.createdAt);
|
|
1453
1471
|
await this.table!.delete(`${base} AND createdAt <= ${Math.floor(cutoff)}`);
|
|
1454
1472
|
}
|
|
1455
|
-
console.
|
|
1473
|
+
console.debug(`[openclaw-memory-alibaba-local] gcWorldFact agent=${agentId} phase2: deleted ${excess} excess rows (was ${count}, cap ${hardMaxRows})`);
|
|
1456
1474
|
}
|
|
1457
1475
|
}
|
|
1458
1476
|
}
|
package/index.ts
CHANGED
|
@@ -190,7 +190,7 @@ function getThresholdForCategory(cfg: MemoryConfig, category: MemoryCategory): n
|
|
|
190
190
|
|
|
191
191
|
/** 精简日志:仅记录 tag + prompt 字符数,不贴原文。 */
|
|
192
192
|
function logLlmCall(tag: string, promptChars: number): void {
|
|
193
|
-
console.
|
|
193
|
+
console.debug(`[openclaw-memory-alibaba-local] llm ${tag} prompt (${promptChars} chars)`);
|
|
194
194
|
}
|
|
195
195
|
|
|
196
196
|
/** 记录 userImageExtraction 结果统计。 */
|
|
@@ -198,12 +198,12 @@ function logUserImageResult(total: number, actions: ReadonlyArray<{ action: stri
|
|
|
198
198
|
const counts: Record<string, number> = {};
|
|
199
199
|
for (const a of actions) counts[a.action] = (counts[a.action] ?? 0) + 1;
|
|
200
200
|
const parts = Object.entries(counts).map(([k, v]) => `${v} ${k}`).join(", ");
|
|
201
|
-
console.
|
|
201
|
+
console.debug(`[openclaw-memory-alibaba-local] userImageExtraction result: ${total} items → ${parts}`);
|
|
202
202
|
}
|
|
203
203
|
|
|
204
204
|
/** 记忆衰减为纯公式,不向模型发提示词;仍打日志避免与「冲突检测 LLM」混淆。 */
|
|
205
205
|
function logMemoryDecayNoLlm(phase: string, detail: string): void {
|
|
206
|
-
console.
|
|
206
|
+
console.debug(`[openclaw-memory-alibaba-local] memoryDecay ${phase} (no LLM; formula-only) ${detail}`);
|
|
207
207
|
}
|
|
208
208
|
|
|
209
209
|
// ---- Embedding-based clustering utilities ----
|
|
@@ -556,7 +556,7 @@ async function extractUserMemoriesWithLLM(
|
|
|
556
556
|
|
|
557
557
|
const raw = completion?.choices[0]?.message?.content?.trim() ?? "";
|
|
558
558
|
const items = parseExtractions(raw);
|
|
559
|
-
console.
|
|
559
|
+
console.debug(`[openclaw-memory-alibaba-local] memoryExtraction extracted ${items.length} items`);
|
|
560
560
|
return items;
|
|
561
561
|
}
|
|
562
562
|
|
|
@@ -1101,7 +1101,7 @@ async function runAgentEndCapture(
|
|
|
1101
1101
|
let { roleCounts: saved, lastMessagesLength } = resolveRoleCountsForSession(entry, messages);
|
|
1102
1102
|
|
|
1103
1103
|
if (messages.length < lastMessagesLength) {
|
|
1104
|
-
console.
|
|
1104
|
+
console.debug("[openclaw-memory-alibaba-local] transcript shrank; reset per-role capture cursors");
|
|
1105
1105
|
saved = {};
|
|
1106
1106
|
}
|
|
1107
1107
|
|
|
@@ -1118,7 +1118,7 @@ async function runAgentEndCapture(
|
|
|
1118
1118
|
}
|
|
1119
1119
|
map[key] = { version: 2, roleCounts: { ...running }, lastMessagesLength: messages.length };
|
|
1120
1120
|
saveAgentEndCursorMap(lancedbDir, map);
|
|
1121
|
-
console.
|
|
1121
|
+
console.debug(
|
|
1122
1122
|
`[openclaw-memory-alibaba-local] agent_end cursor-only advance (non-user trigger) messages=${messages.length}`,
|
|
1123
1123
|
);
|
|
1124
1124
|
return;
|
|
@@ -1180,7 +1180,7 @@ async function runAgentEndCapture(
|
|
|
1180
1180
|
const batchId = randomUUID();
|
|
1181
1181
|
const sid = sessionKey;
|
|
1182
1182
|
|
|
1183
|
-
console.
|
|
1183
|
+
console.debug(`[openclaw-memory-alibaba-local] agentEndCapture fullRows=${fullRows.length} userTexts=${userRawTexts.length} uaLines=${uaLines.length}`);
|
|
1184
1184
|
|
|
1185
1185
|
if (fullRows.length > 0) {
|
|
1186
1186
|
await db.storeMany(
|
|
@@ -1328,13 +1328,13 @@ async function captureUserMemoryFromInboundTexts(
|
|
|
1328
1328
|
}
|
|
1329
1329
|
}
|
|
1330
1330
|
const existingCandidates = [...candidateMap.values()].sort((a, b) => b.score - a.score);
|
|
1331
|
-
console.
|
|
1331
|
+
console.debug(`[openclaw-memory-alibaba-local] worldImageExtraction recall: ${embeddingResults.length} items × ${PER_ITEM_RECALL} = raw ${embeddingResults.length * PER_ITEM_RECALL}, deduped ${existingCandidates.length}, minScore=${recallMinScore}`);
|
|
1332
1332
|
if (existingCandidates.length > 0) {
|
|
1333
|
-
console.
|
|
1333
|
+
console.debug(`[openclaw-memory-alibaba-local] worldImageExtraction recall found ${existingCandidates.length} candidates: ${existingCandidates.map((c) => `[${c.score.toFixed(3)}] ${c.entry.text.slice(0, 60)}`).join(" | ")}`);
|
|
1334
1334
|
}
|
|
1335
1335
|
|
|
1336
1336
|
// 3. LLM CRUD decision
|
|
1337
|
-
console.
|
|
1337
|
+
console.debug(`[openclaw-memory-alibaba-local] worldImageExtraction input: ${eventItems.length} event items, ${existingCandidates.length} existing candidates`);
|
|
1338
1338
|
const worldActions = await extractWorldImageWithLLM(
|
|
1339
1339
|
cfg.llm,
|
|
1340
1340
|
embeddingResults.map((r) => r.item),
|
|
@@ -1432,16 +1432,16 @@ async function captureUserMemoryFromInboundTexts(
|
|
|
1432
1432
|
// 2. Recall top-10 similar existing memories for ALL new extractions (agentId global, USER_MEMORY scope)
|
|
1433
1433
|
const allVectors = embeddingResults.flatMap((r) => r.vectors);
|
|
1434
1434
|
const recallMinScore = Math.max(0.5, cfg.similarityThresholdUserMemory - 0.35);
|
|
1435
|
-
console.
|
|
1435
|
+
console.debug(`[openclaw-memory-alibaba-local] userImageExtraction recall: ${allVectors.length} query vectors, minScore=${recallMinScore}`);
|
|
1436
1436
|
const existingCandidates = allVectors.length > 0
|
|
1437
1437
|
? await db.searchMerged(agentId, allVectors, 10, recallMinScore, [...USER_MEMORY_CATEGORIES])
|
|
1438
1438
|
: [];
|
|
1439
1439
|
if (existingCandidates.length > 0) {
|
|
1440
|
-
console.
|
|
1440
|
+
console.debug(`[openclaw-memory-alibaba-local] userImageExtraction recall found ${existingCandidates.length} candidates: ${existingCandidates.map((c) => `[${c.score.toFixed(3)}] ${c.entry.text.slice(0, 60)}`).join(" | ")}`);
|
|
1441
1441
|
}
|
|
1442
1442
|
|
|
1443
1443
|
// 3. Call user image extraction LLM
|
|
1444
|
-
console.
|
|
1444
|
+
console.debug(`[openclaw-memory-alibaba-local] userImageExtraction input: ${userItems.length} user items (${eventItems.length} event items bypassed), ${existingCandidates.length} existing candidates`);
|
|
1445
1445
|
const userImageActions = await extractUserImageWithLLM(
|
|
1446
1446
|
cfg.llm,
|
|
1447
1447
|
embeddingResults.map((r) => r.item),
|
|
@@ -2209,6 +2209,16 @@ const memoryPlugin = {
|
|
|
2209
2209
|
});
|
|
2210
2210
|
if (isBootstrapSession) {
|
|
2211
2211
|
console.log("[openclaw-memory-alibaba-local] agent_end skip capture (system/bootstrap session)");
|
|
2212
|
+
// Advance cursor past bootstrap messages so the next agent_end won't re-process them.
|
|
2213
|
+
try {
|
|
2214
|
+
const storageSessionKey = resolveStorageSessionKey(ctx);
|
|
2215
|
+
if (storageSessionKey) {
|
|
2216
|
+
const agentId = resolveAgentIdForMemory(ctx);
|
|
2217
|
+
await runAgentEndCapture(cfg, db, backend, agentId, storageSessionKey, null, event.messages, resolvedDbPath, /* cursorOnly */ true);
|
|
2218
|
+
}
|
|
2219
|
+
} catch (e) {
|
|
2220
|
+
console.warn("[openclaw-memory-alibaba-local] agent_end bootstrap cursor advance failed:", String(e));
|
|
2221
|
+
}
|
|
2212
2222
|
return;
|
|
2213
2223
|
}
|
|
2214
2224
|
}
|