openclaw-memory-alibaba-local 0.1.9-beta.21 → 0.1.9-beta.23
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/capture-state.ts +1 -2
- package/db.ts +2 -3
- package/index.ts +75 -94
- package/package.json +1 -1
- package/prompts.ts +5 -1
package/capture-state.ts
CHANGED
|
@@ -166,7 +166,6 @@ function getMessageRoleRaw(msg: unknown): string {
|
|
|
166
166
|
export function resolveRoleCountsForSession(
|
|
167
167
|
entry: CursorFileEntry | undefined,
|
|
168
168
|
messages: unknown[],
|
|
169
|
-
log: { info: (m: string) => void },
|
|
170
169
|
): { roleCounts: Record<string, number>; lastMessagesLength: number } {
|
|
171
170
|
if (isV2Entry(entry)) {
|
|
172
171
|
return {
|
|
@@ -176,7 +175,7 @@ export function resolveRoleCountsForSession(
|
|
|
176
175
|
}
|
|
177
176
|
if (isLegacyEntry(entry)) {
|
|
178
177
|
const end = Math.min(Math.max(0, entry.lastEndExclusive), messages.length);
|
|
179
|
-
log
|
|
178
|
+
console.log("[openclaw-memory-alibaba-local] migrated legacy full-context cursor to per-role counts");
|
|
180
179
|
return {
|
|
181
180
|
roleCounts: countRolesInMessagesPrefix(messages, end),
|
|
182
181
|
lastMessagesLength: end,
|
package/db.ts
CHANGED
|
@@ -1328,7 +1328,6 @@ export class MemoryDB {
|
|
|
1328
1328
|
agentId: string,
|
|
1329
1329
|
maxRows: number,
|
|
1330
1330
|
maxAgeMs: number,
|
|
1331
|
-
log?: { info: (m: string) => void },
|
|
1332
1331
|
): Promise<void> {
|
|
1333
1332
|
await this.ensureInitialized();
|
|
1334
1333
|
const a = sqlEscapeLiteral(agentId);
|
|
@@ -1343,7 +1342,7 @@ export class MemoryDB {
|
|
|
1343
1342
|
// 2. Count remaining; if over maxRows, trim oldest
|
|
1344
1343
|
const remaining = await this.table!.countRows(base);
|
|
1345
1344
|
if (remaining <= maxRows) {
|
|
1346
|
-
log
|
|
1345
|
+
console.log(`[openclaw-memory-alibaba-local] gcFullContext agent=${agentId} remaining=${remaining} (within limit)`);
|
|
1347
1346
|
return;
|
|
1348
1347
|
}
|
|
1349
1348
|
const excess = remaining - maxRows;
|
|
@@ -1357,6 +1356,6 @@ export class MemoryDB {
|
|
|
1357
1356
|
const cutoff = Number(oldest[excess - 1]!.createdAt);
|
|
1358
1357
|
await this.table!.delete(`${base} AND createdAt <= ${Math.floor(cutoff)}`);
|
|
1359
1358
|
}
|
|
1360
|
-
log
|
|
1359
|
+
console.log(`[openclaw-memory-alibaba-local] gcFullContext agent=${agentId} deleted ${excess} excess rows (was ${remaining}, cap ${maxRows})`);
|
|
1361
1360
|
}
|
|
1362
1361
|
}
|
package/index.ts
CHANGED
|
@@ -86,6 +86,13 @@ const MAX_AUTO_CAPTURE_REGEX = 3;
|
|
|
86
86
|
const MAX_AUTO_CAPTURE_LLM = Infinity;
|
|
87
87
|
const DEFAULT_IMPORTANCE = 0.7;
|
|
88
88
|
|
|
89
|
+
/** Strip markdown code fences (```json ... ```) that some LLMs wrap around JSON output. */
|
|
90
|
+
function stripMarkdownJsonFence(raw: string): string {
|
|
91
|
+
const trimmed = raw.trim();
|
|
92
|
+
const m = /^```(?:json)?\s*\n?([\s\S]*?)\n?```\s*$/.exec(trimmed);
|
|
93
|
+
return m ? m[1]!.trim() : trimmed;
|
|
94
|
+
}
|
|
95
|
+
|
|
89
96
|
async function embedQueryVectors(backend: EmbeddingBackend, text: string): Promise<number[][]> {
|
|
90
97
|
const t = text.trim();
|
|
91
98
|
if (!t) {
|
|
@@ -175,26 +182,22 @@ function getThresholdForCategory(cfg: MemoryConfig, category: MemoryCategory): n
|
|
|
175
182
|
return cfg.similarityThresholdSelfImproving;
|
|
176
183
|
}
|
|
177
184
|
|
|
178
|
-
/** 可选:给 LLM / 衰减诊断日志(与 OpenClaw api.logger 兼容,仅用 info)。 */
|
|
179
|
-
type MemoryDiagnosticLog = { info: (m: string) => void } | undefined;
|
|
180
|
-
|
|
181
185
|
/** 精简日志:仅记录 tag + prompt 字符数,不贴原文。 */
|
|
182
|
-
function logLlmCall(tag: string, promptChars: number
|
|
183
|
-
log
|
|
186
|
+
function logLlmCall(tag: string, promptChars: number): void {
|
|
187
|
+
console.log(`[openclaw-memory-alibaba-local] llm ${tag} prompt (${promptChars} chars)`);
|
|
184
188
|
}
|
|
185
189
|
|
|
186
190
|
/** 记录 merge 结果统计。 */
|
|
187
|
-
function logMergeResult(total: number, actions: ReadonlyArray<{ action: string }
|
|
188
|
-
if (!log) return;
|
|
191
|
+
function logMergeResult(total: number, actions: ReadonlyArray<{ action: string }>): void {
|
|
189
192
|
const counts: Record<string, number> = {};
|
|
190
193
|
for (const a of actions) counts[a.action] = (counts[a.action] ?? 0) + 1;
|
|
191
194
|
const parts = Object.entries(counts).map(([k, v]) => `${v} ${k}`).join(", ");
|
|
192
|
-
log
|
|
195
|
+
console.log(`[openclaw-memory-alibaba-local] batchMerge result: ${total} items → ${parts}`);
|
|
193
196
|
}
|
|
194
197
|
|
|
195
198
|
/** 记忆衰减为纯公式,不向模型发提示词;仍打日志避免与「冲突检测 LLM」混淆。 */
|
|
196
|
-
function logMemoryDecayNoLlm(phase: string,
|
|
197
|
-
log
|
|
199
|
+
function logMemoryDecayNoLlm(phase: string, detail: string): void {
|
|
200
|
+
console.log(`[openclaw-memory-alibaba-local] memoryDecay ${phase} (no LLM; formula-only) ${detail}`);
|
|
198
201
|
}
|
|
199
202
|
|
|
200
203
|
/** Apply time decay to recall results: effectiveScore = score * decay(createdAt). Returns new array sorted by effectiveScore desc. */
|
|
@@ -234,7 +237,6 @@ async function runRecall(
|
|
|
234
237
|
agentId: string,
|
|
235
238
|
queryVectors: number[][],
|
|
236
239
|
options: { limitUser: number; limitSelf: number; minScore: number },
|
|
237
|
-
log?: MemoryDiagnosticLog,
|
|
238
240
|
): Promise<MemorySearchResult[]> {
|
|
239
241
|
if (queryVectors.length === 0) {
|
|
240
242
|
return [];
|
|
@@ -271,7 +273,6 @@ async function runRecall(
|
|
|
271
273
|
);
|
|
272
274
|
logMemoryDecayNoLlm(
|
|
273
275
|
"vectorRecall",
|
|
274
|
-
log,
|
|
275
276
|
`strategy=${cfg.memoryDecayStrategy} halfLifeDays=${cfg.memoryDecayHalfLifeDays} agentId=${agentId} inputRows=${decayIn}`,
|
|
276
277
|
);
|
|
277
278
|
}
|
|
@@ -288,7 +289,6 @@ async function bm25SupplementRecall(
|
|
|
288
289
|
queryText: string,
|
|
289
290
|
vectorResults: MemorySearchResult[],
|
|
290
291
|
maxAdd: number,
|
|
291
|
-
log?: MemoryDiagnosticLog,
|
|
292
292
|
): Promise<MemorySearchResult[]> {
|
|
293
293
|
const q = queryText.trim();
|
|
294
294
|
if (q.length < 2 || maxAdd <= 0) {
|
|
@@ -353,7 +353,6 @@ async function bm25SupplementRecall(
|
|
|
353
353
|
ranked = applyMemoryDecay(ranked, Date.now(), cfg.memoryDecayStrategy, cfg.memoryDecayHalfLifeDays);
|
|
354
354
|
logMemoryDecayNoLlm(
|
|
355
355
|
"bm25Pool",
|
|
356
|
-
log,
|
|
357
356
|
`strategy=${cfg.memoryDecayStrategy} halfLifeDays=${cfg.memoryDecayHalfLifeDays} agentId=${agentId} inputRows=${decayIn}`,
|
|
358
357
|
);
|
|
359
358
|
}
|
|
@@ -379,12 +378,11 @@ async function runHybridRecall(
|
|
|
379
378
|
queryText: string,
|
|
380
379
|
queryVectors: number[][],
|
|
381
380
|
options: { limitUser: number; limitSelf: number; minScore: number },
|
|
382
|
-
log?: MemoryDiagnosticLog,
|
|
383
381
|
): Promise<MemorySearchResult[]> {
|
|
384
|
-
const vector = await runRecall(db, cfg, agentId, queryVectors, options
|
|
382
|
+
const vector = await runRecall(db, cfg, agentId, queryVectors, options);
|
|
385
383
|
const extra =
|
|
386
384
|
queryText.trim().length >= 2
|
|
387
|
-
? await bm25SupplementRecall(db, cfg, agentId, queryText, vector, RECALL_BM25_MAX
|
|
385
|
+
? await bm25SupplementRecall(db, cfg, agentId, queryText, vector, RECALL_BM25_MAX)
|
|
388
386
|
: [];
|
|
389
387
|
return [...vector, ...extra].slice(0, RECALL_FINAL_MAX);
|
|
390
388
|
}
|
|
@@ -434,7 +432,6 @@ async function extractUserMemoriesWithLLM(
|
|
|
434
432
|
llmConfig: LLMConfig,
|
|
435
433
|
userMessages: string[],
|
|
436
434
|
_maxExtractions = Infinity,
|
|
437
|
-
log?: MemoryDiagnosticLog,
|
|
438
435
|
): Promise<LLMExtractionItem[]> {
|
|
439
436
|
if (userMessages.length === 0) return [];
|
|
440
437
|
const combined = userMessages
|
|
@@ -444,7 +441,7 @@ async function extractUserMemoriesWithLLM(
|
|
|
444
441
|
|
|
445
442
|
const extractionPrompt = buildMemoryExtractionPrompt() + combined;
|
|
446
443
|
|
|
447
|
-
logLlmCall("memoryExtraction", extractionPrompt.length
|
|
444
|
+
logLlmCall("memoryExtraction", extractionPrompt.length);
|
|
448
445
|
|
|
449
446
|
const openai = new OpenAI({
|
|
450
447
|
apiKey: llmConfig.apiKey,
|
|
@@ -453,7 +450,7 @@ async function extractUserMemoriesWithLLM(
|
|
|
453
450
|
|
|
454
451
|
const parseExtractions = (raw: string): LLMExtractionItem[] => {
|
|
455
452
|
try {
|
|
456
|
-
const parsed = JSON.parse(raw) as {
|
|
453
|
+
const parsed = JSON.parse(stripMarkdownJsonFence(raw)) as {
|
|
457
454
|
extractions?: Array<{ text?: string }>;
|
|
458
455
|
};
|
|
459
456
|
const list = Array.isArray(parsed.extractions) ? parsed.extractions : [];
|
|
@@ -468,7 +465,7 @@ async function extractUserMemoriesWithLLM(
|
|
|
468
465
|
}
|
|
469
466
|
return out;
|
|
470
467
|
} catch (err: unknown) {
|
|
471
|
-
|
|
468
|
+
console.warn(`[openclaw-memory-alibaba-local] memoryExtraction JSON parse failed: ${err}`);
|
|
472
469
|
return [];
|
|
473
470
|
}
|
|
474
471
|
};
|
|
@@ -479,13 +476,13 @@ async function extractUserMemoriesWithLLM(
|
|
|
479
476
|
temperature: 0,
|
|
480
477
|
max_tokens: 8192,
|
|
481
478
|
}).catch((err: unknown) => {
|
|
482
|
-
|
|
479
|
+
console.warn(`[openclaw-memory-alibaba-local] memoryExtraction LLM call failed: ${err}`);
|
|
483
480
|
return null;
|
|
484
481
|
});
|
|
485
482
|
|
|
486
483
|
const raw = completion?.choices[0]?.message?.content?.trim() ?? "";
|
|
487
484
|
const items = parseExtractions(raw);
|
|
488
|
-
log
|
|
485
|
+
console.log(`[openclaw-memory-alibaba-local] memoryExtraction extracted ${items.length} items`);
|
|
489
486
|
return items;
|
|
490
487
|
}
|
|
491
488
|
|
|
@@ -534,11 +531,10 @@ async function extractSelfImprovingWithLLM(
|
|
|
534
531
|
llmConfig: LLMConfig,
|
|
535
532
|
conversationText: string,
|
|
536
533
|
maxExtractions = MAX_AUTO_CAPTURE_SELF_IMPROVING,
|
|
537
|
-
log?: MemoryDiagnosticLog,
|
|
538
534
|
): Promise<SelfImprovingExtractionItem[]> {
|
|
539
535
|
if (conversationText.length < 20) return [];
|
|
540
536
|
const prompt = SELF_IMPROVING_EXTRACTION_INSTRUCTIONS + "\n" + conversationText;
|
|
541
|
-
logLlmCall("selfImprovingExtraction", prompt.length
|
|
537
|
+
logLlmCall("selfImprovingExtraction", prompt.length);
|
|
542
538
|
const openai = new OpenAI({
|
|
543
539
|
apiKey: llmConfig.apiKey,
|
|
544
540
|
baseURL: llmConfig.baseUrl,
|
|
@@ -552,7 +548,7 @@ async function extractSelfImprovingWithLLM(
|
|
|
552
548
|
const raw = completion.choices[0]?.message?.content?.trim() ?? "";
|
|
553
549
|
const validCategories = new Set(SELF_IMPROVING_CATEGORIES);
|
|
554
550
|
try {
|
|
555
|
-
const parsed = JSON.parse(raw) as {
|
|
551
|
+
const parsed = JSON.parse(stripMarkdownJsonFence(raw)) as {
|
|
556
552
|
extractions?: Array<{ category?: string; text?: string; importance?: unknown }>;
|
|
557
553
|
};
|
|
558
554
|
const list = Array.isArray(parsed.extractions) ? parsed.extractions : [];
|
|
@@ -574,7 +570,7 @@ async function extractSelfImprovingWithLLM(
|
|
|
574
570
|
}
|
|
575
571
|
return out;
|
|
576
572
|
} catch (err: unknown) {
|
|
577
|
-
|
|
573
|
+
console.warn(`[openclaw-memory-alibaba-local] selfImprovingExtraction JSON parse failed: ${err}`);
|
|
578
574
|
return [];
|
|
579
575
|
}
|
|
580
576
|
}
|
|
@@ -597,7 +593,6 @@ async function mergeMemoriesWithLLM(
|
|
|
597
593
|
llmConfig: LLMConfig,
|
|
598
594
|
newItems: LLMExtractionItem[],
|
|
599
595
|
existingCandidates: MemorySearchResult[],
|
|
600
|
-
log?: MemoryDiagnosticLog,
|
|
601
596
|
): Promise<MergeAction[]> {
|
|
602
597
|
if (newItems.length === 0) return [];
|
|
603
598
|
|
|
@@ -624,7 +619,7 @@ async function mergeMemoriesWithLLM(
|
|
|
624
619
|
}));
|
|
625
620
|
|
|
626
621
|
const prompt = buildMemoryMergePrompt(newForPrompt, existingForPrompt);
|
|
627
|
-
logLlmCall("batchMerge", prompt.length
|
|
622
|
+
logLlmCall("batchMerge", prompt.length);
|
|
628
623
|
|
|
629
624
|
const openai = new OpenAI({
|
|
630
625
|
apiKey: llmConfig.apiKey,
|
|
@@ -643,7 +638,7 @@ async function mergeMemoriesWithLLM(
|
|
|
643
638
|
const allValidCategories = new Set(Object.keys(PROMPT_CATEGORY_TO_STORAGE));
|
|
644
639
|
|
|
645
640
|
try {
|
|
646
|
-
const parsed = JSON.parse(raw) as {
|
|
641
|
+
const parsed = JSON.parse(stripMarkdownJsonFence(raw)) as {
|
|
647
642
|
actions?: Array<{
|
|
648
643
|
index?: number;
|
|
649
644
|
action?: string;
|
|
@@ -714,7 +709,7 @@ async function mergeMemoriesWithLLM(
|
|
|
714
709
|
return result;
|
|
715
710
|
} catch (err: unknown) {
|
|
716
711
|
// On parse failure, fallback: insert everything
|
|
717
|
-
|
|
712
|
+
console.warn(`[openclaw-memory-alibaba-local] batchMerge JSON parse failed, fallback insert all: ${err}`);
|
|
718
713
|
return newItems.map((item) => ({
|
|
719
714
|
action: "insert" as const,
|
|
720
715
|
text: item.text,
|
|
@@ -899,7 +894,6 @@ async function runAgentEndCapture(
|
|
|
899
894
|
userId: string | null,
|
|
900
895
|
messages: unknown[],
|
|
901
896
|
lancedbDir: string,
|
|
902
|
-
log: { info: (m: string) => void; warn: (m: string) => void },
|
|
903
897
|
): Promise<void> {
|
|
904
898
|
if (messages.length === 0) {
|
|
905
899
|
return;
|
|
@@ -908,10 +902,10 @@ async function runAgentEndCapture(
|
|
|
908
902
|
const key = getFullContextCursorKey(agentId, sessionKey);
|
|
909
903
|
const map = loadAgentEndCursorMap(lancedbDir);
|
|
910
904
|
const entry = map[key];
|
|
911
|
-
let { roleCounts: saved, lastMessagesLength } = resolveRoleCountsForSession(entry, messages
|
|
905
|
+
let { roleCounts: saved, lastMessagesLength } = resolveRoleCountsForSession(entry, messages);
|
|
912
906
|
|
|
913
907
|
if (messages.length < lastMessagesLength) {
|
|
914
|
-
log
|
|
908
|
+
console.log("[openclaw-memory-alibaba-local] transcript shrank; reset per-role capture cursors");
|
|
915
909
|
saved = {};
|
|
916
910
|
}
|
|
917
911
|
|
|
@@ -971,7 +965,7 @@ async function runAgentEndCapture(
|
|
|
971
965
|
const batchId = randomUUID();
|
|
972
966
|
const sid = sessionKey;
|
|
973
967
|
|
|
974
|
-
log
|
|
968
|
+
console.log(`[openclaw-memory-alibaba-local] agentEndCapture fullRows=${fullRows.length} userTexts=${userRawTexts.length} uaLines=${uaLines.length}`);
|
|
975
969
|
|
|
976
970
|
if (fullRows.length > 0) {
|
|
977
971
|
await db.storeMany(
|
|
@@ -989,12 +983,12 @@ async function runAgentEndCapture(
|
|
|
989
983
|
})),
|
|
990
984
|
);
|
|
991
985
|
// GC: 删除超过 50000 条或超过 1 个月的全文记忆
|
|
992
|
-
await db.gcFullContext(agentId, 50_000, 30 * 24 * 60 * 60 * 1000
|
|
986
|
+
await db.gcFullContext(agentId, 50_000, 30 * 24 * 60 * 60 * 1000);
|
|
993
987
|
}
|
|
994
988
|
|
|
995
989
|
await Promise.all([
|
|
996
|
-
captureUserMemoryFromInboundTexts(cfg, db, backend, agentId, sid, userId, userRawTexts
|
|
997
|
-
captureSelfImprovingFromLines(cfg, db, backend, agentId, sid, userId, uaLines
|
|
990
|
+
captureUserMemoryFromInboundTexts(cfg, db, backend, agentId, sid, userId, userRawTexts),
|
|
991
|
+
captureSelfImprovingFromLines(cfg, db, backend, agentId, sid, userId, uaLines),
|
|
998
992
|
]);
|
|
999
993
|
|
|
1000
994
|
map[key] = {
|
|
@@ -1014,7 +1008,6 @@ async function captureUserMemoryFromInboundTexts(
|
|
|
1014
1008
|
sessionKey: string,
|
|
1015
1009
|
userId: string | null,
|
|
1016
1010
|
inboundTexts: string[],
|
|
1017
|
-
log: { info: (m: string) => void },
|
|
1018
1011
|
): Promise<void> {
|
|
1019
1012
|
if (inboundTexts.length === 0) {
|
|
1020
1013
|
return;
|
|
@@ -1044,7 +1037,6 @@ async function captureUserMemoryFromInboundTexts(
|
|
|
1044
1037
|
await storeOneCaptureItem(agentId, { ...item, text }, cfg, db, backend, {
|
|
1045
1038
|
userId,
|
|
1046
1039
|
sessionId: sessionKey,
|
|
1047
|
-
log,
|
|
1048
1040
|
});
|
|
1049
1041
|
}
|
|
1050
1042
|
return;
|
|
@@ -1058,9 +1050,8 @@ async function captureUserMemoryFromInboundTexts(
|
|
|
1058
1050
|
cfg.llm,
|
|
1059
1051
|
toSend,
|
|
1060
1052
|
MAX_AUTO_CAPTURE_LLM,
|
|
1061
|
-
log,
|
|
1062
1053
|
).catch((err: unknown) => {
|
|
1063
|
-
|
|
1054
|
+
console.warn(`[openclaw-memory-alibaba-local] memoryExtraction pipeline failed: ${err}`);
|
|
1064
1055
|
return [] as LLMExtractionItem[];
|
|
1065
1056
|
});
|
|
1066
1057
|
if (extractions.length === 0) return;
|
|
@@ -1083,15 +1074,14 @@ async function captureUserMemoryFromInboundTexts(
|
|
|
1083
1074
|
: [];
|
|
1084
1075
|
|
|
1085
1076
|
// 3. Call batch merge LLM
|
|
1086
|
-
log
|
|
1077
|
+
console.log(`[openclaw-memory-alibaba-local] batchMerge input: ${extractions.length} extractions, ${existingCandidates.length} existing candidates`);
|
|
1087
1078
|
const mergeActions = await mergeMemoriesWithLLM(
|
|
1088
1079
|
cfg.llm,
|
|
1089
1080
|
embeddingResults.map((r) => r.item),
|
|
1090
1081
|
existingCandidates,
|
|
1091
|
-
log,
|
|
1092
1082
|
).catch((err: unknown) => {
|
|
1093
1083
|
// Fallback: insert all
|
|
1094
|
-
|
|
1084
|
+
console.warn(`[openclaw-memory-alibaba-local] batchMerge LLM failed, fallback insert all: ${err}`);
|
|
1095
1085
|
return embeddingResults.map((r): MergeAction => ({
|
|
1096
1086
|
action: "insert" as const,
|
|
1097
1087
|
text: r.item.text,
|
|
@@ -1101,7 +1091,7 @@ async function captureUserMemoryFromInboundTexts(
|
|
|
1101
1091
|
});
|
|
1102
1092
|
|
|
1103
1093
|
// 4. Log & execute merge actions
|
|
1104
|
-
logMergeResult(extractions.length, mergeActions
|
|
1094
|
+
logMergeResult(extractions.length, mergeActions);
|
|
1105
1095
|
for (const action of mergeActions) {
|
|
1106
1096
|
if (action.action === "skip") continue;
|
|
1107
1097
|
|
|
@@ -1150,7 +1140,6 @@ async function captureUserMemoryFromInboundTexts(
|
|
|
1150
1140
|
await storeOneCaptureItem(agentId, { category: e.category, text, importance: e.importance }, cfg, db, backend, {
|
|
1151
1141
|
userId,
|
|
1152
1142
|
sessionId: sessionKey,
|
|
1153
|
-
log,
|
|
1154
1143
|
});
|
|
1155
1144
|
}
|
|
1156
1145
|
}
|
|
@@ -1164,7 +1153,6 @@ async function captureSelfImprovingFromLines(
|
|
|
1164
1153
|
sessionKey: string,
|
|
1165
1154
|
userId: string | null,
|
|
1166
1155
|
lines: string[],
|
|
1167
|
-
log: { info: (m: string) => void },
|
|
1168
1156
|
): Promise<void> {
|
|
1169
1157
|
if (!cfg.enableSelfImprovingMemory || lines.length === 0) {
|
|
1170
1158
|
return;
|
|
@@ -1185,9 +1173,8 @@ async function captureSelfImprovingFromLines(
|
|
|
1185
1173
|
cfg.llm,
|
|
1186
1174
|
combined,
|
|
1187
1175
|
MAX_AUTO_CAPTURE_SELF_IMPROVING,
|
|
1188
|
-
log,
|
|
1189
1176
|
).catch((err: unknown) => {
|
|
1190
|
-
|
|
1177
|
+
console.warn(`[openclaw-memory-alibaba-local] selfImprovingExtraction pipeline failed: ${err}`);
|
|
1191
1178
|
return [] as SelfImprovingExtractionItem[];
|
|
1192
1179
|
});
|
|
1193
1180
|
for (const e of extractions) {
|
|
@@ -1215,7 +1202,6 @@ async function captureSelfImprovingFromLines(
|
|
|
1215
1202
|
await storeOneCaptureItem(agentId, item, cfg, db, backend, {
|
|
1216
1203
|
userId,
|
|
1217
1204
|
sessionId: sessionKey,
|
|
1218
|
-
log,
|
|
1219
1205
|
});
|
|
1220
1206
|
}
|
|
1221
1207
|
}
|
|
@@ -1294,7 +1280,6 @@ async function storeOneCaptureItem(
|
|
|
1294
1280
|
sessionId?: string | null;
|
|
1295
1281
|
batchId?: string | null;
|
|
1296
1282
|
seqInBatch?: number | null;
|
|
1297
|
-
log?: { info: (m: string) => void };
|
|
1298
1283
|
},
|
|
1299
1284
|
): Promise<StoreOneResult> {
|
|
1300
1285
|
if (isFullContextStoredWithoutEmbedding(item.category)) {
|
|
@@ -1360,8 +1345,8 @@ const memoryPlugin = {
|
|
|
1360
1345
|
? createEmbeddingBackend(cfg.embedding)
|
|
1361
1346
|
: null;
|
|
1362
1347
|
if (embeddingBackendPromise) {
|
|
1363
|
-
|
|
1364
|
-
"openclaw-memory-alibaba-local
|
|
1348
|
+
console.log(
|
|
1349
|
+
"[openclaw-memory-alibaba-local] embedding backend load started (async; local node-llama-cpp may compile native code)",
|
|
1365
1350
|
);
|
|
1366
1351
|
}
|
|
1367
1352
|
|
|
@@ -1387,16 +1372,16 @@ const memoryPlugin = {
|
|
|
1387
1372
|
api.logger,
|
|
1388
1373
|
);
|
|
1389
1374
|
} else {
|
|
1390
|
-
|
|
1391
|
-
"openclaw-memory-alibaba-local
|
|
1375
|
+
console.warn(
|
|
1376
|
+
"[openclaw-memory-alibaba-local] registerGatewayMethod missing — memory admin WS RPC disabled",
|
|
1392
1377
|
);
|
|
1393
1378
|
}
|
|
1394
1379
|
|
|
1395
1380
|
if (typeof api.registerHttpRoute === "function") {
|
|
1396
1381
|
registerMemoryPanelRoutes(api.registerHttpRoute.bind(api), getMemoryAdminOpsContext, api.logger);
|
|
1397
1382
|
} else {
|
|
1398
|
-
|
|
1399
|
-
"openclaw-memory-alibaba-local
|
|
1383
|
+
console.warn(
|
|
1384
|
+
"[openclaw-memory-alibaba-local] registerHttpRoute missing — /plugins/memory HTML shell disabled",
|
|
1400
1385
|
);
|
|
1401
1386
|
}
|
|
1402
1387
|
|
|
@@ -1429,8 +1414,8 @@ const memoryPlugin = {
|
|
|
1429
1414
|
opts: { vectorDim: db.getEmbeddingVectorDim() },
|
|
1430
1415
|
};
|
|
1431
1416
|
ensureAdminWaitDone();
|
|
1432
|
-
|
|
1433
|
-
"openclaw-memory-alibaba-local
|
|
1417
|
+
console.log(
|
|
1418
|
+
"[openclaw-memory-alibaba-local] memory admin API unlocked (LanceDB open; local embedding may still be compiling)",
|
|
1434
1419
|
);
|
|
1435
1420
|
|
|
1436
1421
|
if (cfg.embedding && embeddingBackendPromise) {
|
|
@@ -1444,12 +1429,12 @@ const memoryPlugin = {
|
|
|
1444
1429
|
mode === "remote"
|
|
1445
1430
|
? cfg.embedding.model
|
|
1446
1431
|
: (cfg.embedding.modelPath?.trim() || "~/.openclaw/embedding_model/embeddinggemma-300M-Q8_0.gguf");
|
|
1447
|
-
|
|
1448
|
-
`openclaw-memory-alibaba-local
|
|
1432
|
+
console.log(
|
|
1433
|
+
`[openclaw-memory-alibaba-local] registered (db: ${resolvedDbPath}, table: ${LANCEDB_TABLE_NAME}, embedMode: ${mode}, model: ${modelHint}, vectorDim: ${backend.vectorDim})`,
|
|
1449
1434
|
);
|
|
1450
1435
|
} else {
|
|
1451
|
-
|
|
1452
|
-
"openclaw-memory-alibaba-local
|
|
1436
|
+
console.log(
|
|
1437
|
+
"[openclaw-memory-alibaba-local] registered without embedding (recall/store tools no-op; admin UI can still open LanceDB)",
|
|
1453
1438
|
);
|
|
1454
1439
|
}
|
|
1455
1440
|
|
|
@@ -1511,7 +1496,6 @@ const memoryPlugin = {
|
|
|
1511
1496
|
limitSelf,
|
|
1512
1497
|
minScore: RECALL_MIN_SCORE_RELAXED,
|
|
1513
1498
|
},
|
|
1514
|
-
api.logger,
|
|
1515
1499
|
);
|
|
1516
1500
|
|
|
1517
1501
|
// Respect the user-requested limit after hybrid recall (vector + BM25 may exceed it).
|
|
@@ -1627,7 +1611,6 @@ const memoryPlugin = {
|
|
|
1627
1611
|
const { action, entry } = await storeOneCaptureItem(agentId, item, cfg, db, backend, {
|
|
1628
1612
|
userId,
|
|
1629
1613
|
sessionId,
|
|
1630
|
-
log: api.logger,
|
|
1631
1614
|
});
|
|
1632
1615
|
const preview = text.length > 100 ? text.slice(0, 100) + "..." : text;
|
|
1633
1616
|
return {
|
|
@@ -1738,8 +1721,8 @@ const memoryPlugin = {
|
|
|
1738
1721
|
{ name: "memory_forget" },
|
|
1739
1722
|
);
|
|
1740
1723
|
} else {
|
|
1741
|
-
|
|
1742
|
-
"openclaw-memory-alibaba-local
|
|
1724
|
+
console.log(
|
|
1725
|
+
"[openclaw-memory-alibaba-local] autoRecall is false — memory_recall / memory_store / memory_forget tools not registered",
|
|
1743
1726
|
);
|
|
1744
1727
|
}
|
|
1745
1728
|
|
|
@@ -1753,8 +1736,8 @@ const memoryPlugin = {
|
|
|
1753
1736
|
try {
|
|
1754
1737
|
const extracted = extractUserQueryForRecall(event.prompt);
|
|
1755
1738
|
if (extracted.query.length < 5) {
|
|
1756
|
-
|
|
1757
|
-
`openclaw-memory-alibaba-local
|
|
1739
|
+
console.log(
|
|
1740
|
+
`[openclaw-memory-alibaba-local] recall skip (extracted query too short) rawLen=${event.prompt.length} queryLen=${extracted.query.length} removed=${extracted.removedLabels.join(",") || "none"}`,
|
|
1758
1741
|
);
|
|
1759
1742
|
return;
|
|
1760
1743
|
}
|
|
@@ -1778,17 +1761,16 @@ const memoryPlugin = {
|
|
|
1778
1761
|
limitSelf: cfg.enableSelfImprovingMemory ? RECALL_LIMIT_SELF : 0,
|
|
1779
1762
|
minScore: RECALL_MIN_SCORE_HOOK,
|
|
1780
1763
|
},
|
|
1781
|
-
api.logger,
|
|
1782
1764
|
);
|
|
1783
1765
|
const searchMs = Date.now() - tSearch0;
|
|
1784
1766
|
const totalMs = Date.now() - tRecall0;
|
|
1785
|
-
|
|
1786
|
-
`openclaw-memory-alibaba-local
|
|
1767
|
+
console.log(
|
|
1768
|
+
`[openclaw-memory-alibaba-local] recall timing embedMs=${embedMs} lancedbSearchMs=${searchMs} totalMs=${totalMs} results=${results.length} (vector≤${RECALL_VECTOR_MAX}+bm25≤${RECALL_BM25_MAX}, cap ${RECALL_FINAL_MAX})`,
|
|
1787
1769
|
);
|
|
1788
1770
|
if (results.length === 0) return;
|
|
1789
1771
|
|
|
1790
|
-
|
|
1791
|
-
`openclaw-memory-alibaba-local
|
|
1772
|
+
console.log(
|
|
1773
|
+
`[openclaw-memory-alibaba-local] injecting ${results.length} memories into context`,
|
|
1792
1774
|
);
|
|
1793
1775
|
return {
|
|
1794
1776
|
prependContext: formatRelevantMemoriesContext(
|
|
@@ -1817,7 +1799,7 @@ const memoryPlugin = {
|
|
|
1817
1799
|
),
|
|
1818
1800
|
};
|
|
1819
1801
|
} catch (err) {
|
|
1820
|
-
|
|
1802
|
+
console.warn(`[openclaw-memory-alibaba-local] recall failed: ${String(err)}`);
|
|
1821
1803
|
}
|
|
1822
1804
|
});
|
|
1823
1805
|
}
|
|
@@ -1835,8 +1817,8 @@ const memoryPlugin = {
|
|
|
1835
1817
|
const tCap0 = Date.now();
|
|
1836
1818
|
const storageSessionKey = resolveStorageSessionKey(ctx);
|
|
1837
1819
|
if (!storageSessionKey) {
|
|
1838
|
-
|
|
1839
|
-
"openclaw-memory-alibaba-local
|
|
1820
|
+
console.warn(
|
|
1821
|
+
"[openclaw-memory-alibaba-local] agent_end skip capture (no sessionKey/sessionId)",
|
|
1840
1822
|
);
|
|
1841
1823
|
return;
|
|
1842
1824
|
}
|
|
@@ -1852,13 +1834,12 @@ const memoryPlugin = {
|
|
|
1852
1834
|
userId,
|
|
1853
1835
|
event.messages,
|
|
1854
1836
|
resolvedDbPath,
|
|
1855
|
-
api.logger,
|
|
1856
1837
|
);
|
|
1857
|
-
|
|
1858
|
-
`openclaw-memory-alibaba-local
|
|
1838
|
+
console.log(
|
|
1839
|
+
`[openclaw-memory-alibaba-local] agent_end capture done totalHookMs=${Date.now() - tCap0} messages=${event.messages.length}`,
|
|
1859
1840
|
);
|
|
1860
1841
|
} catch (err) {
|
|
1861
|
-
|
|
1842
|
+
console.warn(`[openclaw-memory-alibaba-local] agent_end capture failed: ${String(err)}`);
|
|
1862
1843
|
}
|
|
1863
1844
|
});
|
|
1864
1845
|
}
|
|
@@ -1868,21 +1849,21 @@ const memoryPlugin = {
|
|
|
1868
1849
|
start: () => {
|
|
1869
1850
|
if (cfg.embedding) {
|
|
1870
1851
|
const em = cfg.embedding;
|
|
1871
|
-
|
|
1872
|
-
`openclaw-memory-alibaba-local
|
|
1852
|
+
console.log(
|
|
1853
|
+
`[openclaw-memory-alibaba-local] started (db: ${resolvedDbPath}, embedMode: ${em.mode}${em.mode === "remote" ? `, model: ${em.model}` : ""})`,
|
|
1873
1854
|
);
|
|
1874
1855
|
} else {
|
|
1875
|
-
|
|
1856
|
+
console.log("[openclaw-memory-alibaba-local] started (memory not configured)");
|
|
1876
1857
|
}
|
|
1877
1858
|
},
|
|
1878
1859
|
stop: async () => {
|
|
1879
1860
|
await backend?.close();
|
|
1880
1861
|
if (db) await db.close();
|
|
1881
|
-
|
|
1862
|
+
console.log("[openclaw-memory-alibaba-local] stopped");
|
|
1882
1863
|
},
|
|
1883
1864
|
});
|
|
1884
1865
|
} catch (err) {
|
|
1885
|
-
|
|
1866
|
+
console.error(`[openclaw-memory-alibaba-local] failed to initialize: ${String(err)}`);
|
|
1886
1867
|
const dimRaw = cfg.embedding ? embeddingVectorDim(cfg.embedding) : 0;
|
|
1887
1868
|
const fallbackDim = dimRaw > 0 ? dimRaw : 768;
|
|
1888
1869
|
try {
|
|
@@ -1898,28 +1879,28 @@ const memoryPlugin = {
|
|
|
1898
1879
|
api.registerService({
|
|
1899
1880
|
id: "openclaw-memory-alibaba-local",
|
|
1900
1881
|
start: () => {
|
|
1901
|
-
|
|
1902
|
-
"openclaw-memory-alibaba-local
|
|
1882
|
+
console.warn(
|
|
1883
|
+
"[openclaw-memory-alibaba-local] running in degraded mode (embedding failed; admin UI only)",
|
|
1903
1884
|
);
|
|
1904
1885
|
},
|
|
1905
1886
|
stop: async () => {
|
|
1906
1887
|
await backend?.close();
|
|
1907
1888
|
await dbDegraded.close();
|
|
1908
|
-
|
|
1889
|
+
console.log("[openclaw-memory-alibaba-local] stopped");
|
|
1909
1890
|
},
|
|
1910
1891
|
});
|
|
1911
|
-
|
|
1912
|
-
`openclaw-memory-alibaba-local
|
|
1892
|
+
console.warn(
|
|
1893
|
+
`[openclaw-memory-alibaba-local] /plugins/memory registered in degraded mode (vectorDim=${fallbackDim}); fix local embedding or switch to embedding.mode=remote`,
|
|
1913
1894
|
);
|
|
1914
1895
|
} catch (err2) {
|
|
1915
|
-
|
|
1896
|
+
console.error(`[openclaw-memory-alibaba-local] degraded admin registration failed: ${String(err2)}`);
|
|
1916
1897
|
}
|
|
1917
1898
|
}
|
|
1918
1899
|
} finally {
|
|
1919
1900
|
ensureAdminWaitDone();
|
|
1920
1901
|
}
|
|
1921
1902
|
})().catch((err) => {
|
|
1922
|
-
|
|
1903
|
+
console.error(`[openclaw-memory-alibaba-local] unexpected init failure: ${String(err)}`);
|
|
1923
1904
|
});
|
|
1924
1905
|
},
|
|
1925
1906
|
};
|
package/package.json
CHANGED
package/prompts.ts
CHANGED
|
@@ -193,7 +193,7 @@ Do NOT merge items that merely share the same person but cover different topics.
|
|
|
193
193
|
- **DELETE** (memoryId): A batch item directly contradicts and fully replaces a Store item. Delete the Store item; handle the batch item as INSERT.
|
|
194
194
|
- Only when info DIRECTLY contradicts (e.g. "moved to Shanghai" vs stored "lives in Beijing").
|
|
195
195
|
|
|
196
|
-
# Category
|
|
196
|
+
# Category & Relevance Filter
|
|
197
197
|
|
|
198
198
|
For every INSERT or UPDATE, assign a category based on content:
|
|
199
199
|
- **profile**: User identity (name, age, location, job, relationships, background)
|
|
@@ -203,6 +203,10 @@ For every INSERT or UPDATE, assign a category based on content:
|
|
|
203
203
|
|
|
204
204
|
Only memories about "User" → profile/preferences/decisions. Others → "fact".
|
|
205
205
|
|
|
206
|
+
**User-category filter**: For profile/preferences/decisions, only keep **durable personal information** — identity, traits, relationships, beliefs, preferences, life events, long-term goals. SKIP one-time operational requests, transient commands, debugging queries, or ephemeral task instructions (e.g. "User asked to run command X", "User requested to search logs", "User asked which files were viewed"). These reveal nothing lasting about the person.
|
|
207
|
+
|
|
208
|
+
**Fact-category**: ZERO information loss. All events, activities, and third-party info must be kept.
|
|
209
|
+
|
|
206
210
|
# Output format
|
|
207
211
|
|
|
208
212
|
Reply with ONLY a JSON object:
|