openclaw-memory-alibaba-local 1.0.13 → 1.0.14
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/index.ts +22 -29
- package/package.json +1 -1
- package/prompts.ts +5 -3
package/index.ts
CHANGED
|
@@ -181,13 +181,6 @@ function formatRelevantMemoriesContext(
|
|
|
181
181
|
].join("\n");
|
|
182
182
|
}
|
|
183
183
|
|
|
184
|
-
function getThresholdForCategory(cfg: MemoryConfig, category: MemoryCategory): number {
|
|
185
|
-
if (isUserMemoryCategory(category) || isFullContextSourceCategory(category) || category === FULL_CONTEXT_MEMORY) {
|
|
186
|
-
return cfg.similarityThresholdUserMemory;
|
|
187
|
-
}
|
|
188
|
-
return cfg.similarityThresholdSelfImproving;
|
|
189
|
-
}
|
|
190
|
-
|
|
191
184
|
/** 精简日志:仅记录 tag + prompt 字符数,不贴原文。 */
|
|
192
185
|
function logLlmCall(tag: string, promptChars: number): void {
|
|
193
186
|
console.debug(`[openclaw-memory-alibaba-local] llm ${tag} prompt (${promptChars} chars)`);
|
|
@@ -1182,6 +1175,16 @@ async function runAgentEndCapture(
|
|
|
1182
1175
|
|
|
1183
1176
|
console.debug(`[openclaw-memory-alibaba-local] agentEndCapture fullRows=${fullRows.length} userTexts=${userRawTexts.length} uaLines=${uaLines.length}`);
|
|
1184
1177
|
|
|
1178
|
+
// Save cursor BEFORE extraction so that a failure in extraction/storage
|
|
1179
|
+
// does not leave the cursor un-advanced, which would cause duplicate
|
|
1180
|
+
// full_context rows on retry.
|
|
1181
|
+
map[key] = {
|
|
1182
|
+
version: 2,
|
|
1183
|
+
roleCounts: { ...running },
|
|
1184
|
+
lastMessagesLength: messages.length,
|
|
1185
|
+
};
|
|
1186
|
+
saveAgentEndCursorMap(lancedbDir, map);
|
|
1187
|
+
|
|
1185
1188
|
if (fullRows.length > 0) {
|
|
1186
1189
|
await db.storeMany(
|
|
1187
1190
|
agentId,
|
|
@@ -1205,13 +1208,6 @@ async function runAgentEndCapture(
|
|
|
1205
1208
|
captureUserMemoryFromInboundTexts(cfg, db, backend, agentId, sid, userId, userRawTexts),
|
|
1206
1209
|
captureSelfImprovingFromLines(cfg, db, backend, agentId, sid, userId, uaLines),
|
|
1207
1210
|
]);
|
|
1208
|
-
|
|
1209
|
-
map[key] = {
|
|
1210
|
-
version: 2,
|
|
1211
|
-
roleCounts: { ...running },
|
|
1212
|
-
lastMessagesLength: messages.length,
|
|
1213
|
-
};
|
|
1214
|
-
saveAgentEndCursorMap(lancedbDir, map);
|
|
1215
1211
|
}
|
|
1216
1212
|
|
|
1217
1213
|
/** User memory from raw user message texts (agent_end user delta). */
|
|
@@ -1274,8 +1270,10 @@ async function captureUserMemoryFromInboundTexts(
|
|
|
1274
1270
|
// ---- Always split: User-related items vs event items ----
|
|
1275
1271
|
const userItems: LLMExtractionItem[] = [];
|
|
1276
1272
|
const eventItems: LLMExtractionItem[] = [];
|
|
1273
|
+
// Match both English "User" and Chinese "用户" to correctly route user preferences
|
|
1274
|
+
const USER_SUBJECT_RE = /\bUser\b|用户/;
|
|
1277
1275
|
for (const item of extractions) {
|
|
1278
|
-
if (
|
|
1276
|
+
if (USER_SUBJECT_RE.test(item.text)) {
|
|
1279
1277
|
userItems.push(item);
|
|
1280
1278
|
} else {
|
|
1281
1279
|
eventItems.push(item);
|
|
@@ -1646,21 +1644,16 @@ async function storeOneCaptureItem(
|
|
|
1646
1644
|
if (vectors.length === 0) {
|
|
1647
1645
|
throw new Error("openclaw-memory-alibaba-local: encodeForStorage returned no vectors");
|
|
1648
1646
|
}
|
|
1649
|
-
const threshold = getThresholdForCategory(cfg, item.category);
|
|
1650
1647
|
const dedupCategories = getDedupCategories(item.category);
|
|
1651
1648
|
const rows = buildChunkRows(item, vectors, options);
|
|
1652
1649
|
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
}
|
|
1661
|
-
|
|
1662
|
-
// With conflict_process: simple similarity-based dedup (batch merge handles LLM dedup for user memory)
|
|
1663
|
-
const recallMinScore = Math.max(0.5, threshold - 0.35);
|
|
1650
|
+
// Guard against near-exact duplicates only (score >= 0.92).
|
|
1651
|
+
// Lower thresholds (e.g. 0.65) would incorrectly treat similar-but-different
|
|
1652
|
+
// items as duplicates (e.g. "likes apples" vs "likes fish").
|
|
1653
|
+
// Semantic dedup for lower-similarity candidates is handled by the LLM CRUD
|
|
1654
|
+
// pipeline (userPipeline / eventPipeline) when memory_duplication_conflict_process is on.
|
|
1655
|
+
const NEAR_EXACT_THRESHOLD = 0.92;
|
|
1656
|
+
const recallMinScore = Math.max(0.5, NEAR_EXACT_THRESHOLD - 0.15);
|
|
1664
1657
|
const candidates = await db.searchMerged(
|
|
1665
1658
|
agentId,
|
|
1666
1659
|
vectors,
|
|
@@ -1668,11 +1661,11 @@ async function storeOneCaptureItem(
|
|
|
1668
1661
|
recallMinScore,
|
|
1669
1662
|
[...dedupCategories],
|
|
1670
1663
|
);
|
|
1671
|
-
if (candidates.length > 0 && candidates[0]!.score >=
|
|
1664
|
+
if (candidates.length > 0 && candidates[0]!.score >= NEAR_EXACT_THRESHOLD) {
|
|
1672
1665
|
await deleteSimilarLogicalMemory(db, agentId, options?.sessionId, candidates[0]!);
|
|
1673
1666
|
}
|
|
1674
1667
|
const stored = await db.storeMany(agentId, rows);
|
|
1675
|
-
return { action: candidates.length > 0 && candidates[0]!.score >=
|
|
1668
|
+
return { action: candidates.length > 0 && candidates[0]!.score >= NEAR_EXACT_THRESHOLD ? "updated" : "created", entry: stored[0]! };
|
|
1676
1669
|
}
|
|
1677
1670
|
|
|
1678
1671
|
// ---------------------------------------------------------------------------
|
package/package.json
CHANGED
package/prompts.ts
CHANGED
|
@@ -205,8 +205,9 @@ Only INSERT or UPDATE information that reveals something lasting about the User:
|
|
|
205
205
|
|
|
206
206
|
# Refinement Principles
|
|
207
207
|
1. **Prefer the richer version**: When a batch item and a Store item describe the same topic, keep whichever has the most information. If the batch adds new details, UPDATE to include them.
|
|
208
|
-
2. **High cohesion**: Only merge entries about the exact same topic. Entries about different topics stay separate.
|
|
209
|
-
3. **
|
|
208
|
+
2. **High cohesion**: Only merge entries about the exact same specific topic. Entries about different topics stay separate.
|
|
209
|
+
3. **Multiple preferences coexist**: Different concrete items under the same category are NOT duplicates. For example, "User likes apples" and "User likes fish" are two separate preferences — INSERT both, do NOT UPDATE or DELETE one for the other. Only UPDATE/DELETE when the new item truly contradicts or refines the old one (e.g. "User no longer likes apples" replaces "User likes apples").
|
|
210
|
+
4. **Strip date prefixes**: Input text may contain [date] or [as of ...] prefixes — remove them from the output text. User profile memories are evergreen and should not carry temporal tags.
|
|
210
211
|
|
|
211
212
|
# Actions (one per batch index)
|
|
212
213
|
- **INSERT**: New lasting personal info not in Store.
|
|
@@ -270,7 +271,8 @@ Only INSERT or UPDATE information that captures a concrete, verifiable fact or e
|
|
|
270
271
|
1. **Prefer the richer version**: When a batch item and a Store item describe the same topic, keep whichever has the most information. If the batch is richer, DELETE the old Store item and INSERT the batch item. If they are roughly equal, UPDATE to merge details.
|
|
271
272
|
2. **Preserve temporal markers**: Keep [as of ...] or [date] prefixes — world facts are time-sensitive.
|
|
272
273
|
3. **High cohesion**: Only merge entries about the exact same event or fact. Different events stay separate even if related.
|
|
273
|
-
4. **
|
|
274
|
+
4. **Multiple items coexist**: Different concrete items under the same category are NOT duplicates. For example, "likes apples" and "likes fish" are two separate facts — INSERT both. Only DELETE when the new item truly contradicts the old one (e.g. a corrected outcome).
|
|
275
|
+
5. **Contradiction = replace**: If a batch item directly contradicts a Store item (e.g. different outcome), DELETE the old item and INSERT the new one.
|
|
274
276
|
|
|
275
277
|
# Actions (one per batch index)
|
|
276
278
|
- **INSERT**: New world fact not in Store.
|