openclaw-amem 1.1.2 → 1.1.4
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 +1 -1
- package/dist/index.js +414 -279
- package/openclaw.plugin.json +2 -2
- package/package.json +8 -7
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# openclaw-amem
|
|
2
2
|
|
|
3
3
|
<p align="center">
|
|
4
|
-
<img src="https://
|
|
4
|
+
<img src="https://raw.githubusercontent.com/heichaowo/amem/main/docs/public/logo.webp" width="120" alt="A-MEM Logo" />
|
|
5
5
|
</p>
|
|
6
6
|
|
|
7
7
|
[](../../LICENSE)
|
package/dist/index.js
CHANGED
|
@@ -30,56 +30,24 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
30
30
|
));
|
|
31
31
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
32
32
|
|
|
33
|
-
// ../amem-core/
|
|
34
|
-
var dist_exports = {};
|
|
35
|
-
__export(dist_exports, {
|
|
36
|
-
addMemory: () => addMemory,
|
|
37
|
-
addNote: () => addNote,
|
|
38
|
-
checkQuality: () => checkQuality,
|
|
39
|
-
configure: () => configure,
|
|
40
|
-
consolidateMemories: () => consolidateMemories,
|
|
41
|
-
cosineSimilarity: () => cosineSimilarity,
|
|
42
|
-
countNotes: () => countNotes,
|
|
43
|
-
createStorageContext: () => createStorageContext,
|
|
44
|
-
deleteNote: () => deleteNote,
|
|
45
|
-
encode: () => encode,
|
|
46
|
-
ensureCollection: () => ensureCollection,
|
|
47
|
-
findByHash: () => findByHash,
|
|
48
|
-
generateReviewBatch: () => generateReviewBatch,
|
|
49
|
-
getDataDir: () => getDataDir,
|
|
50
|
-
getEvoCount: () => getEvoCount,
|
|
51
|
-
getNote: () => getNote,
|
|
52
|
-
getNotesByDatePrefix: () => getNotesByDatePrefix,
|
|
53
|
-
incrementEvoCount: () => incrementEvoCount,
|
|
54
|
-
invalidateNote: () => invalidateNote,
|
|
55
|
-
listMemories: () => listMemories,
|
|
56
|
-
listNotes: () => listNotes,
|
|
57
|
-
llmCall: () => llmCall,
|
|
58
|
-
llmConstructNote: () => llmConstructNote,
|
|
59
|
-
llmCrudDecision: () => llmCrudDecision,
|
|
60
|
-
llmEvolutionJudge: () => llmEvolutionJudge,
|
|
61
|
-
llmEvolveNote: () => llmEvolveNote,
|
|
62
|
-
llmShouldLink: () => llmShouldLink,
|
|
63
|
-
llmShouldMerge: () => llmShouldMerge,
|
|
64
|
-
mergeSimilarNotes: () => mergeSimilarNotes,
|
|
65
|
-
patchNotePayload: () => patchNotePayload,
|
|
66
|
-
queryByEmbedding: () => queryByEmbedding,
|
|
67
|
-
replaceLinkReferences: () => replaceLinkReferences,
|
|
68
|
-
resetCollectionReady: () => resetCollectionReady,
|
|
69
|
-
scanLowQuality: () => scanLowQuality,
|
|
70
|
-
searchMemory: () => searchMemory,
|
|
71
|
-
shouldRunEvolution: () => shouldRunEvolution,
|
|
72
|
-
t: () => t,
|
|
73
|
-
updateNote: () => updateNote,
|
|
74
|
-
updateNoteContent: () => updateNoteContent,
|
|
75
|
-
updateNoteLinks: () => updateNoteLinks
|
|
76
|
-
});
|
|
33
|
+
// ../amem-core/src/config.ts
|
|
77
34
|
function configure(opts) {
|
|
78
35
|
if (opts.dataDir) _dataDir = opts.dataDir;
|
|
79
36
|
}
|
|
80
37
|
function getDataDir() {
|
|
81
38
|
return _dataDir;
|
|
82
39
|
}
|
|
40
|
+
var os, path, _dataDir;
|
|
41
|
+
var init_config = __esm({
|
|
42
|
+
"../amem-core/src/config.ts"() {
|
|
43
|
+
"use strict";
|
|
44
|
+
os = __toESM(require("os"), 1);
|
|
45
|
+
path = __toESM(require("path"), 1);
|
|
46
|
+
_dataDir = process.env.AMEM_DATA_DIR || path.join(os.homedir(), ".amem");
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
// ../amem-core/src/embedding.ts
|
|
83
51
|
async function getExtractor() {
|
|
84
52
|
if (extractor) return extractor;
|
|
85
53
|
if (!pipeline) {
|
|
@@ -133,11 +101,28 @@ async function encode(text) {
|
|
|
133
101
|
}
|
|
134
102
|
throw new Error("Unexpected embedding output shape");
|
|
135
103
|
}
|
|
104
|
+
async function loadModel() {
|
|
105
|
+
await getExtractor();
|
|
106
|
+
}
|
|
107
|
+
function isModelLoaded() {
|
|
108
|
+
return extractor !== null;
|
|
109
|
+
}
|
|
136
110
|
function cosineSimilarity(a, b) {
|
|
137
111
|
let dot = 0;
|
|
138
112
|
for (let i = 0; i < a.length; i++) dot += a[i] * b[i];
|
|
139
113
|
return dot;
|
|
140
114
|
}
|
|
115
|
+
var pipeline, extractor, MODEL_NAME;
|
|
116
|
+
var init_embedding = __esm({
|
|
117
|
+
"../amem-core/src/embedding.ts"() {
|
|
118
|
+
"use strict";
|
|
119
|
+
pipeline = null;
|
|
120
|
+
extractor = null;
|
|
121
|
+
MODEL_NAME = "Xenova/paraphrase-multilingual-MiniLM-L12-v2";
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
// ../amem-core/src/evo-counter.ts
|
|
141
126
|
function counterFile() {
|
|
142
127
|
return process.env.AMEM_EVO_COUNTER_PATH || path2.join(getDataDir(), "amem_evo_cnt.json");
|
|
143
128
|
}
|
|
@@ -158,6 +143,199 @@ function shouldRunEvolution() {
|
|
|
158
143
|
const count = incrementEvoCount();
|
|
159
144
|
return count % EVO_THRESHOLD === 0;
|
|
160
145
|
}
|
|
146
|
+
var fs, path2, EVO_THRESHOLD;
|
|
147
|
+
var init_evo_counter = __esm({
|
|
148
|
+
"../amem-core/src/evo-counter.ts"() {
|
|
149
|
+
"use strict";
|
|
150
|
+
fs = __toESM(require("fs"), 1);
|
|
151
|
+
path2 = __toESM(require("path"), 1);
|
|
152
|
+
init_config();
|
|
153
|
+
EVO_THRESHOLD = 20;
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
// ../amem-core/src/prompts.ts
|
|
158
|
+
var LOCALE, en, zh, templates, t;
|
|
159
|
+
var init_prompts = __esm({
|
|
160
|
+
"../amem-core/src/prompts.ts"() {
|
|
161
|
+
"use strict";
|
|
162
|
+
LOCALE = process.env.AMEM_PROMPT_LOCALE === "zh" ? "zh" : "en";
|
|
163
|
+
en = {
|
|
164
|
+
crudDecision: (userText, assistantText, memoryList) => `You are a memory management agent. Analyze the conversation and decide what memory operations are needed.
|
|
165
|
+
|
|
166
|
+
## Conversation
|
|
167
|
+
|
|
168
|
+
User: ${userText}
|
|
169
|
+
Assistant: ${assistantText}
|
|
170
|
+
|
|
171
|
+
## Existing relevant memories (identified by integer idx)
|
|
172
|
+
|
|
173
|
+
${memoryList}
|
|
174
|
+
|
|
175
|
+
## Task
|
|
176
|
+
|
|
177
|
+
Extract only genuinely important long-term facts (decisions, preferences, account info, project status, key insights). Skip small talk, confirmations, and information already captured in existing memories.
|
|
178
|
+
|
|
179
|
+
## Operation types
|
|
180
|
+
- NEW: Extract a brand new fact not present in existing memories
|
|
181
|
+
- UPDATE: New information refines or supersedes an existing memory; specify existingIdx
|
|
182
|
+
- DELETE: An existing memory is outdated, contradicted, or wrong; specify existingIdx, fact = original content
|
|
183
|
+
- NONE: Nothing worth recording, or information already fully captured
|
|
184
|
+
|
|
185
|
+
## Output format
|
|
186
|
+
|
|
187
|
+
Return a JSON array. Each item:
|
|
188
|
+
{"action": "NEW"|"UPDATE"|"DELETE"|"NONE", "fact": "fact content", "existingIdx": integer or omit, "reason": "optional"}
|
|
189
|
+
|
|
190
|
+
Return at most 3 operations. If nothing is worth recording, return [].
|
|
191
|
+
Return only the JSON array, no other text.
|
|
192
|
+
|
|
193
|
+
Examples:
|
|
194
|
+
|
|
195
|
+
1. New preference:
|
|
196
|
+
[{"action": "NEW", "fact": "User prefers TypeScript over JavaScript", "reason": "Explicitly stated tech preference"}]
|
|
197
|
+
|
|
198
|
+
2. Updating an existing memory (idx 0 was "User is evaluating React and Vue"):
|
|
199
|
+
[{"action": "UPDATE", "fact": "User decided to use React (dropped Vue)", "existingIdx": 0, "reason": "Decision finalized, update evaluation status"}]
|
|
200
|
+
|
|
201
|
+
3. Conversation is just "Sure, thanks" / "Got it" with no new info:
|
|
202
|
+
[]`,
|
|
203
|
+
shouldMerge: (contentA, contentB) => `You are a memory deduplication assistant. Determine whether two memories express essentially the same information.
|
|
204
|
+
|
|
205
|
+
Memory A: ${contentA}
|
|
206
|
+
Memory B: ${contentB}
|
|
207
|
+
|
|
208
|
+
Rules:
|
|
209
|
+
- If both memories express the same core fact (possibly different wording or granularity), return:
|
|
210
|
+
{"shouldMerge": true, "merged": "Concise merged statement preserving key details from both, more complete than either alone"}
|
|
211
|
+
- If the memories are complementary, on different topics, or contain different specific facts, return:
|
|
212
|
+
{"shouldMerge": false}
|
|
213
|
+
|
|
214
|
+
Return only JSON, no other text.
|
|
215
|
+
|
|
216
|
+
Examples:
|
|
217
|
+
|
|
218
|
+
1. Should merge (different granularity):
|
|
219
|
+
A: "Project uses PostgreSQL"
|
|
220
|
+
B: "Project's primary database is PostgreSQL 16, deployed on AWS RDS"
|
|
221
|
+
-> {"shouldMerge": true, "merged": "Project uses PostgreSQL 16 as primary database, deployed on AWS RDS"}
|
|
222
|
+
|
|
223
|
+
2. Should NOT merge (complementary but distinct):
|
|
224
|
+
A: "User prefers VS Code"
|
|
225
|
+
B: "User's VS Code uses One Dark Pro theme"
|
|
226
|
+
-> {"shouldMerge": false}`,
|
|
227
|
+
evolutionJudge: (oldContent, newContent) => `You are a memory evolution judge. Analyze the relationship between an old and new memory and return JSON.
|
|
228
|
+
|
|
229
|
+
Old memory: ${oldContent}
|
|
230
|
+
New memory: ${newContent}
|
|
231
|
+
|
|
232
|
+
Classification rules:
|
|
233
|
+
|
|
234
|
+
- EVOLVE: New content deepens or updates the old memory (e.g. "Considering Next.js" -> "Decided on Next.js 14 App Router")
|
|
235
|
+
Return: {"type": "EVOLVE", "mergedContent": "Merged content preserving the evolution trajectory"}
|
|
236
|
+
|
|
237
|
+
- CONFLICT: Old and new information directly contradict each other on the same attribute (e.g. "Uses MySQL as primary DB" vs "Migrated to PostgreSQL")
|
|
238
|
+
Return: {"type": "CONFLICT"}
|
|
239
|
+
|
|
240
|
+
- EXPAND: New information supplements the old memory on the same topic (e.g. "Handles backend dev" + "Backend uses Go and gRPC")
|
|
241
|
+
Return: {"type": "EXPAND", "mergedContent": "Merged content integrating both pieces of information"}
|
|
242
|
+
|
|
243
|
+
- NEW: Completely unrelated information, no substantive connection to the old memory
|
|
244
|
+
Return: {"type": "NEW"}
|
|
245
|
+
|
|
246
|
+
Return only JSON, no other text.`
|
|
247
|
+
};
|
|
248
|
+
zh = {
|
|
249
|
+
crudDecision: (userText, assistantText, memoryList) => `\u4F60\u662F\u4E00\u4E2A\u8BB0\u5FC6\u7BA1\u7406 agent\uFF0C\u8D1F\u8D23\u5206\u6790\u5BF9\u8BDD\u5185\u5BB9\u5E76\u51B3\u5B9A\u5982\u4F55\u64CD\u4F5C\u8BB0\u5FC6\u5E93\u3002
|
|
250
|
+
|
|
251
|
+
## \u5BF9\u8BDD\u5185\u5BB9
|
|
252
|
+
|
|
253
|
+
\u7528\u6237\uFF1A${userText}
|
|
254
|
+
\u52A9\u624B\uFF1A${assistantText}
|
|
255
|
+
|
|
256
|
+
## \u5DF2\u6709\u76F8\u5173\u8BB0\u5FC6\uFF08\u7528\u6574\u6570 idx \u6807\u8BC6\uFF09
|
|
257
|
+
|
|
258
|
+
${memoryList}
|
|
259
|
+
|
|
260
|
+
## \u4EFB\u52A1
|
|
261
|
+
|
|
262
|
+
\u5206\u6790\u4E0A\u8FF0\u5BF9\u8BDD\uFF0C\u51B3\u5B9A\u9700\u8981\u54EA\u4E9B\u8BB0\u5FC6\u64CD\u4F5C\u3002\u53EA\u63D0\u53D6\u771F\u6B63\u91CD\u8981\u7684\u957F\u671F\u4E8B\u5B9E\uFF08\u51B3\u7B56\u3001\u504F\u597D\u3001\u8D26\u53F7\u4FE1\u606F\u3001\u9879\u76EE\u72B6\u6001\u3001\u5173\u952E\u6D1E\u5BDF\uFF09\u3002\u8DF3\u8FC7\u95F2\u804A\u3001\u786E\u8BA4\u8BED\u3001\u91CD\u590D\u4FE1\u606F\u3002
|
|
263
|
+
|
|
264
|
+
## \u64CD\u4F5C\u7C7B\u578B
|
|
265
|
+
- NEW\uFF1A\u63D0\u53D6\u5168\u65B0\u4E8B\u5B9E\uFF08\u5DF2\u6709\u8BB0\u5FC6\u4E2D\u6CA1\u6709\u7684\u4FE1\u606F\uFF09
|
|
266
|
+
- UPDATE\uFF1A\u65B0\u4FE1\u606F\u66F4\u65B0\u4E86\u67D0\u6761\u5DF2\u6709\u8BB0\u5FC6\uFF0C\u7528 existingIdx \u6307\u5B9A\u8981\u66F4\u65B0\u7684\u6761\u76EE
|
|
267
|
+
- DELETE\uFF1A\u67D0\u6761\u5DF2\u6709\u8BB0\u5FC6\u5DF2\u7ECF\u8FC7\u65F6\u3001\u53D1\u751F\u51B2\u7A81\u6216\u9519\u8BEF\uFF0C\u7528 existingIdx \u6307\u5B9A\uFF0Cfact \u586B\u539F\u5185\u5BB9
|
|
268
|
+
- NONE\uFF1A\u4E0D\u503C\u5F97\u8BB0\u5F55\u6216\u5DF2\u6709\u5B8C\u5168\u76F8\u540C\u7684\u4FE1\u606F
|
|
269
|
+
|
|
270
|
+
## \u8F93\u51FA\u683C\u5F0F
|
|
271
|
+
|
|
272
|
+
\u8FD4\u56DE JSON \u6570\u7EC4\uFF0C\u6BCF\u6761\u683C\u5F0F\uFF1A
|
|
273
|
+
{"action": "NEW"|"UPDATE"|"DELETE"|"NONE", "fact": "\u4E8B\u5B9E\u5185\u5BB9", "existingIdx": \u6574\u6570\u6216\u7701\u7565, "reason": "\u539F\u56E0\uFF08\u53EF\u9009\uFF09"}
|
|
274
|
+
|
|
275
|
+
\u6BCF\u6B21\u6700\u591A\u8FD4\u56DE 3 \u6761\u64CD\u4F5C\u3002\u5982\u679C\u6CA1\u6709\u503C\u5F97\u64CD\u4F5C\u7684\u5185\u5BB9\uFF0C\u8FD4\u56DE []\u3002
|
|
276
|
+
\u53EA\u8FD4\u56DE JSON \u6570\u7EC4\uFF0C\u4E0D\u8981\u4EFB\u4F55\u5176\u4ED6\u6587\u5B57\u3002
|
|
277
|
+
|
|
278
|
+
\u793A\u4F8B\uFF1A
|
|
279
|
+
|
|
280
|
+
1. \u63D0\u53D6\u65B0\u504F\u597D\uFF1A
|
|
281
|
+
[{"action": "NEW", "fact": "\u7528\u6237\u504F\u597D TypeScript \u800C\u975E JavaScript", "reason": "\u660E\u786E\u8868\u8FBE\u7684\u6280\u672F\u504F\u597D"}]
|
|
282
|
+
|
|
283
|
+
2. \u66F4\u65B0\u5DF2\u6709\u8BB0\u5FC6\uFF08idx 0 \u539F\u4E3A"\u7528\u6237\u6B63\u5728\u8BC4\u4F30 React \u548C Vue"\uFF09\uFF1A
|
|
284
|
+
[{"action": "UPDATE", "fact": "\u7528\u6237\u51B3\u5B9A\u4F7F\u7528 React\uFF08\u653E\u5F03\u4E86 Vue\uFF09", "existingIdx": 0, "reason": "\u51B3\u7B56\u5DF2\u660E\u786E\uFF0C\u66F4\u65B0\u8BC4\u4F30\u72B6\u6001"}]
|
|
285
|
+
|
|
286
|
+
3. \u5BF9\u8BDD\u4EC5\u4E3A"\u597D\u7684\uFF0C\u8C22\u8C22"/"\u6CA1\u95EE\u9898"\u7B49\u786E\u8BA4\u8BED\uFF0C\u65E0\u65B0\u4FE1\u606F\uFF1A
|
|
287
|
+
[]`,
|
|
288
|
+
shouldMerge: (contentA, contentB) => `\u4F60\u662F\u4E00\u4E2A\u8BB0\u5FC6\u53BB\u91CD\u52A9\u624B\uFF0C\u8D1F\u8D23\u5224\u65AD\u4E24\u6761\u8BB0\u5FC6\u662F\u5426\u8868\u8FBE\u4E86\u672C\u8D28\u76F8\u540C\u7684\u4FE1\u606F\u3002
|
|
289
|
+
|
|
290
|
+
\u8BB0\u5FC6A\uFF1A${contentA}
|
|
291
|
+
\u8BB0\u5FC6B\uFF1A${contentB}
|
|
292
|
+
|
|
293
|
+
\u5224\u65AD\u89C4\u5219\uFF1A
|
|
294
|
+
- \u5982\u679C\u4E24\u6761\u8BB0\u5FC6\u8868\u8FBE\u7684\u662F\u672C\u8D28\u76F8\u540C\u7684\u4FE1\u606F\uFF08\u53EF\u80FD\u63AA\u8F9E\u4E0D\u540C\u3001\u7C92\u5EA6\u4E0D\u540C\uFF0C\u4F46\u6838\u5FC3\u4E8B\u5B9E\u4E00\u81F4\uFF09\uFF0C\u8FD4\u56DE JSON\uFF1A
|
|
295
|
+
{"shouldMerge": true, "merged": "\u5408\u5E76\u540E\u7684\u7B80\u6D01\u8868\u8FF0\uFF0C\u4FDD\u7559\u4E24\u6761\u8BB0\u5FC6\u7684\u5173\u952E\u4FE1\u606F\uFF0C\u6BD4\u4EFB\u4F55\u4E00\u6761\u90FD\u66F4\u5B8C\u6574"}
|
|
296
|
+
- \u5982\u679C\u4E24\u6761\u8BB0\u5FC6\u662F\u4E92\u8865\u4FE1\u606F\u3001\u4E0D\u540C\u4E3B\u9898\u3001\u6216\u5305\u542B\u4E0D\u540C\u7684\u5177\u4F53\u4E8B\u5B9E\uFF0C\u8FD4\u56DE JSON\uFF1A
|
|
297
|
+
{"shouldMerge": false}
|
|
298
|
+
|
|
299
|
+
\u53EA\u8FD4\u56DE JSON\uFF0C\u4E0D\u8981\u4EFB\u4F55\u5176\u4ED6\u6587\u5B57\u3002
|
|
300
|
+
|
|
301
|
+
\u793A\u4F8B\uFF1A
|
|
302
|
+
|
|
303
|
+
1. \u5E94\u5408\u5E76\uFF08\u7C92\u5EA6\u4E0D\u540C\uFF09\uFF1A
|
|
304
|
+
A: "\u9879\u76EE\u4F7F\u7528 PostgreSQL \u6570\u636E\u5E93"
|
|
305
|
+
B: "\u9879\u76EE\u7684\u4E3B\u6570\u636E\u5E93\u662F PostgreSQL 16\uFF0C\u90E8\u7F72\u5728 AWS RDS \u4E0A"
|
|
306
|
+
\u2192 {"shouldMerge": true, "merged": "\u9879\u76EE\u4F7F\u7528 PostgreSQL 16 \u4F5C\u4E3A\u4E3B\u6570\u636E\u5E93\uFF0C\u90E8\u7F72\u5728 AWS RDS \u4E0A"}
|
|
307
|
+
|
|
308
|
+
2. \u4E0D\u5E94\u5408\u5E76\uFF08\u4E92\u8865\u4F46\u4E0D\u540C\uFF09\uFF1A
|
|
309
|
+
A: "\u7528\u6237\u559C\u6B22\u7528 VS Code"
|
|
310
|
+
B: "\u7528\u6237\u7684 VS Code \u4F7F\u7528 One Dark Pro \u4E3B\u9898"
|
|
311
|
+
\u2192 {"shouldMerge": false}`,
|
|
312
|
+
evolutionJudge: (oldContent, newContent) => `\u4F60\u662F\u4E00\u4E2A\u8BB0\u5FC6\u6F14\u5316\u5224\u65AD\u52A9\u624B\u3002\u5206\u6790\u4EE5\u4E0B\u4E24\u6761\u8BB0\u5FC6\u7684\u5173\u7CFB\u5E76\u8FD4\u56DE JSON\u3002
|
|
313
|
+
|
|
314
|
+
\u65E7\u8BB0\u5FC6\uFF1A${oldContent}
|
|
315
|
+
\u65B0\u8BB0\u5FC6\uFF1A${newContent}
|
|
316
|
+
|
|
317
|
+
\u5224\u65AD\u89C4\u5219\uFF1A
|
|
318
|
+
|
|
319
|
+
- EVOLVE\uFF1A\u65B0\u5185\u5BB9\u662F\u5BF9\u65E7\u8BB0\u5FC6\u7684\u6DF1\u5316/\u66F4\u65B0\uFF08\u5982\u300C\u6B63\u5728\u8003\u8651\u7528 Next.js\u300D\u2192\u300C\u51B3\u5B9A\u7528 Next.js 14 App Router\u300D\uFF09
|
|
320
|
+
\u8FD4\u56DE\uFF1A{"type": "EVOLVE", "mergedContent": "\u878D\u5408\u540E\u7684\u5B8C\u6574\u5185\u5BB9\uFF0C\u4FDD\u7559\u6F14\u5316\u8F68\u8FF9"}
|
|
321
|
+
|
|
322
|
+
- CONFLICT\uFF1A\u65B0\u65E7\u4FE1\u606F\u5728\u540C\u4E00\u5C5E\u6027\u4E0A\u76F4\u63A5\u77DB\u76FE\uFF08\u5982\u300C\u4F7F\u7528 MySQL \u4F5C\u4E3A\u4E3B\u6570\u636E\u5E93\u300Dvs\u300C\u5DF2\u8FC1\u79FB\u5230 PostgreSQL\u300D\uFF09
|
|
323
|
+
\u8FD4\u56DE\uFF1A{"type": "CONFLICT"}
|
|
324
|
+
|
|
325
|
+
- EXPAND\uFF1A\u65B0\u4FE1\u606F\u662F\u5BF9\u65E7\u8BB0\u5FC6\u540C\u4E00\u4E3B\u9898\u7684\u8865\u5145\u6269\u5C55\uFF08\u5982\u300C\u8D1F\u8D23\u540E\u7AEF\u5F00\u53D1\u300D+\u300C\u540E\u7AEF\u4F7F\u7528 Go \u548C gRPC\u300D\uFF09
|
|
326
|
+
\u8FD4\u56DE\uFF1A{"type": "EXPAND", "mergedContent": "\u5408\u5E76\u540E\u7684\u5B8C\u6574\u5185\u5BB9\uFF0C\u6574\u5408\u53CC\u65B9\u4FE1\u606F"}
|
|
327
|
+
|
|
328
|
+
- NEW\uFF1A\u5168\u65B0\u4FE1\u606F\uFF0C\u4E0E\u65E7\u8BB0\u5FC6\u65E0\u5B9E\u8D28\u5173\u8054\uFF08\u5982\u300C\u559C\u6B22 dark mode\u300Dvs\u300C\u4E0B\u5468\u8981\u53BB\u51FA\u5DEE\u300D\uFF09
|
|
329
|
+
\u8FD4\u56DE\uFF1A{"type": "NEW"}
|
|
330
|
+
|
|
331
|
+
\u53EA\u8FD4\u56DE JSON\uFF0C\u4E0D\u8981\u4EFB\u4F55\u5176\u4ED6\u6587\u5B57\u3002`
|
|
332
|
+
};
|
|
333
|
+
templates = { en, zh };
|
|
334
|
+
t = templates[LOCALE];
|
|
335
|
+
}
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
// ../amem-core/src/llm.ts
|
|
161
339
|
async function llmCall(prompt, maxTokens = 500) {
|
|
162
340
|
try {
|
|
163
341
|
const isThinking = MODEL.includes("gemini") || MODEL.includes("pro-agent");
|
|
@@ -381,24 +559,54 @@ ${linkedStr}`;
|
|
|
381
559
|
return { tags: null, context: null, shouldStrengthen: false, suggestedConnections: [], tagsToUpdate: [] };
|
|
382
560
|
}
|
|
383
561
|
}
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
562
|
+
var import_sdk, client, MODEL, VALID_CONFIDENCE, VALID_CATEGORIES, VALID_EVOLUTION_TYPES;
|
|
563
|
+
var init_llm = __esm({
|
|
564
|
+
"../amem-core/src/llm.ts"() {
|
|
565
|
+
"use strict";
|
|
566
|
+
import_sdk = __toESM(require("@anthropic-ai/sdk"), 1);
|
|
567
|
+
init_prompts();
|
|
568
|
+
client = new import_sdk.default({
|
|
569
|
+
...process.env.AMEM_LLM_API_KEY && { apiKey: process.env.AMEM_LLM_API_KEY },
|
|
570
|
+
...process.env.AMEM_LLM_BASE_URL && { baseURL: process.env.AMEM_LLM_BASE_URL }
|
|
571
|
+
});
|
|
572
|
+
MODEL = process.env.AMEM_LLM_MODEL ?? "claude-sonnet-4-6";
|
|
573
|
+
VALID_CONFIDENCE = /* @__PURE__ */ new Set(["high", "medium", "low"]);
|
|
574
|
+
VALID_CATEGORIES = /* @__PURE__ */ new Set([
|
|
575
|
+
"Technical",
|
|
576
|
+
"Business",
|
|
577
|
+
"Personal",
|
|
578
|
+
"Project",
|
|
579
|
+
"Research",
|
|
580
|
+
"System",
|
|
581
|
+
"General"
|
|
582
|
+
]);
|
|
583
|
+
VALID_EVOLUTION_TYPES = /* @__PURE__ */ new Set(["EVOLVE", "CONFLICT", "EXPAND", "NEW"]);
|
|
584
|
+
}
|
|
585
|
+
});
|
|
586
|
+
|
|
587
|
+
// ../amem-core/src/storage.ts
|
|
588
|
+
async function qdrant(method, path6, body) {
|
|
589
|
+
const res = await fetch(`${QDRANT_URL}${path6}`, {
|
|
590
|
+
method,
|
|
591
|
+
headers: { "Content-Type": "application/json" },
|
|
592
|
+
body: body ? JSON.stringify(body) : void 0
|
|
593
|
+
});
|
|
594
|
+
const data = await res.json();
|
|
595
|
+
if (!res.ok || data.status && data.status !== "ok" && data.status !== "acknowledged") {
|
|
596
|
+
throw new Error(`Qdrant ${method} ${path6} failed: ${data.error || JSON.stringify(data)}`);
|
|
597
|
+
}
|
|
598
|
+
return data.result;
|
|
599
|
+
}
|
|
600
|
+
async function pingQdrant() {
|
|
601
|
+
const res = await fetch(`${QDRANT_URL}/readyz`);
|
|
602
|
+
if (!res.ok) throw new Error(`Qdrant GET /readyz failed: ${res.status}`);
|
|
603
|
+
}
|
|
604
|
+
function resetCollectionReady() {
|
|
605
|
+
_collectionReady = false;
|
|
606
|
+
_collectionReadyMap.clear();
|
|
607
|
+
}
|
|
608
|
+
async function ensureCollection(collectionName) {
|
|
609
|
+
const col = collectionName || getCollection();
|
|
402
610
|
if (collectionName) {
|
|
403
611
|
if (_collectionReadyMap.get(col)) return;
|
|
404
612
|
} else {
|
|
@@ -776,6 +984,19 @@ async function patchNotePayload(id, fields) {
|
|
|
776
984
|
async function replaceLinkReferences(oldId, newId, agentId) {
|
|
777
985
|
return makeCrud(getCollection()).replaceLinkReferences(oldId, newId, agentId);
|
|
778
986
|
}
|
|
987
|
+
var QDRANT_URL, getCollection, VECTOR_DIM, _collectionReady, _collectionReadyMap;
|
|
988
|
+
var init_storage = __esm({
|
|
989
|
+
"../amem-core/src/storage.ts"() {
|
|
990
|
+
"use strict";
|
|
991
|
+
QDRANT_URL = "http://localhost:6333";
|
|
992
|
+
getCollection = () => process.env.AMEM_COLLECTION || "amem_notes";
|
|
993
|
+
VECTOR_DIM = 384;
|
|
994
|
+
_collectionReady = false;
|
|
995
|
+
_collectionReadyMap = /* @__PURE__ */ new Map();
|
|
996
|
+
}
|
|
997
|
+
});
|
|
998
|
+
|
|
999
|
+
// ../amem-core/src/memory.ts
|
|
779
1000
|
function getJieba() {
|
|
780
1001
|
if (!_jieba) _jieba = new import_jieba.Jieba();
|
|
781
1002
|
return _jieba;
|
|
@@ -1041,6 +1262,44 @@ async function addMemory(content, agentId = "main", opts) {
|
|
|
1041
1262
|
console.log(`[done] Note added: ${note.id}`);
|
|
1042
1263
|
return note.id;
|
|
1043
1264
|
}
|
|
1265
|
+
async function addEpisodic(content, agentId = "main", opts) {
|
|
1266
|
+
const scope = opts?.scope ?? "private";
|
|
1267
|
+
const ctx = opts?.storageCtx ?? defaultCtx();
|
|
1268
|
+
const quality = checkQuality(content);
|
|
1269
|
+
if (!quality.ok) {
|
|
1270
|
+
throw new Error(`[quality] \u5199\u5165\u62D2\u7EDD: ${quality.reason}`);
|
|
1271
|
+
}
|
|
1272
|
+
const embedding = await encode(content);
|
|
1273
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1274
|
+
const note = {
|
|
1275
|
+
id: (0, import_uuid.v4)(),
|
|
1276
|
+
content,
|
|
1277
|
+
timestamp: now,
|
|
1278
|
+
keywords: [],
|
|
1279
|
+
tags: [],
|
|
1280
|
+
context: "",
|
|
1281
|
+
embedding,
|
|
1282
|
+
links: [],
|
|
1283
|
+
agent_id: scope === "shared" ? "shared" : agentId,
|
|
1284
|
+
hash: (0, import_crypto.createHash)("md5").update(content).digest("hex"),
|
|
1285
|
+
retrieval_count: 0,
|
|
1286
|
+
last_accessed: now,
|
|
1287
|
+
evolution_history: [],
|
|
1288
|
+
category: "General",
|
|
1289
|
+
is_active: true,
|
|
1290
|
+
note_type: "memory",
|
|
1291
|
+
topics: [],
|
|
1292
|
+
pending_merge: false,
|
|
1293
|
+
conflict: false,
|
|
1294
|
+
ephemeral: quality.ephemeral,
|
|
1295
|
+
low_quality: false,
|
|
1296
|
+
owner: agentId,
|
|
1297
|
+
readers: scope === "shared" ? ["*"] : [agentId],
|
|
1298
|
+
writers: [agentId]
|
|
1299
|
+
};
|
|
1300
|
+
await ctx.addNote(note);
|
|
1301
|
+
return note.id;
|
|
1302
|
+
}
|
|
1044
1303
|
async function searchMemory(query, topK = 5, agentId = "main", opts) {
|
|
1045
1304
|
const useBfs = opts?.useBfs !== false;
|
|
1046
1305
|
const bfsSimThreshold = opts?.bfsSimThreshold ?? 0.25;
|
|
@@ -1361,6 +1620,26 @@ async function consolidateMemories(agentId, logger, storageCtx) {
|
|
|
1361
1620
|
log.info(`[Consolidation] Completed consolidation run. Merged ${mergedCount} pairs.`);
|
|
1362
1621
|
return mergedCount;
|
|
1363
1622
|
}
|
|
1623
|
+
var import_uuid, import_crypto, fs2, path3, import_jieba, _jieba, EPHEMERAL_SIGNALS;
|
|
1624
|
+
var init_memory = __esm({
|
|
1625
|
+
"../amem-core/src/memory.ts"() {
|
|
1626
|
+
"use strict";
|
|
1627
|
+
import_uuid = require("uuid");
|
|
1628
|
+
import_crypto = require("crypto");
|
|
1629
|
+
fs2 = __toESM(require("fs"), 1);
|
|
1630
|
+
path3 = __toESM(require("path"), 1);
|
|
1631
|
+
init_embedding();
|
|
1632
|
+
init_storage();
|
|
1633
|
+
init_llm();
|
|
1634
|
+
init_evo_counter();
|
|
1635
|
+
init_config();
|
|
1636
|
+
import_jieba = require("@node-rs/jieba");
|
|
1637
|
+
_jieba = null;
|
|
1638
|
+
EPHEMERAL_SIGNALS = ["\u5F85\u8DD1", "\u7B49\u786E\u8BA4", "\u6628\u65E5", "\u660E\u5929\u5B8C\u6210"];
|
|
1639
|
+
}
|
|
1640
|
+
});
|
|
1641
|
+
|
|
1642
|
+
// ../amem-core/src/quality.ts
|
|
1364
1643
|
async function scanLowQuality(agentId) {
|
|
1365
1644
|
const notes = await listNotes(agentId);
|
|
1366
1645
|
const now = Date.now();
|
|
@@ -1483,228 +1762,84 @@ async function generateReviewBatch(agentId, outputPath) {
|
|
|
1483
1762
|
fs3.writeFileSync(filePath, lines.join("\n"), "utf8");
|
|
1484
1763
|
return filePath;
|
|
1485
1764
|
}
|
|
1486
|
-
var
|
|
1487
|
-
var
|
|
1488
|
-
"../amem-core/
|
|
1765
|
+
var fs3, path4, LOCALE2, DEFAULT_OUTPUT_DIR;
|
|
1766
|
+
var init_quality = __esm({
|
|
1767
|
+
"../amem-core/src/quality.ts"() {
|
|
1489
1768
|
"use strict";
|
|
1490
|
-
os = __toESM(require("os"), 1);
|
|
1491
|
-
path = __toESM(require("path"), 1);
|
|
1492
|
-
fs = __toESM(require("fs"), 1);
|
|
1493
|
-
path2 = __toESM(require("path"), 1);
|
|
1494
|
-
import_sdk = __toESM(require("@anthropic-ai/sdk"), 1);
|
|
1495
|
-
import_uuid = require("uuid");
|
|
1496
|
-
import_crypto = require("crypto");
|
|
1497
|
-
fs2 = __toESM(require("fs"), 1);
|
|
1498
|
-
path3 = __toESM(require("path"), 1);
|
|
1499
|
-
import_jieba = require("@node-rs/jieba");
|
|
1500
1769
|
fs3 = __toESM(require("fs"), 1);
|
|
1501
1770
|
path4 = __toESM(require("path"), 1);
|
|
1502
|
-
|
|
1503
|
-
pipeline = null;
|
|
1504
|
-
extractor = null;
|
|
1505
|
-
MODEL_NAME = "Xenova/paraphrase-multilingual-MiniLM-L12-v2";
|
|
1506
|
-
EVO_THRESHOLD = 20;
|
|
1507
|
-
LOCALE = process.env.AMEM_PROMPT_LOCALE === "zh" ? "zh" : "en";
|
|
1508
|
-
en = {
|
|
1509
|
-
crudDecision: (userText, assistantText, memoryList) => `You are a memory management agent. Analyze the conversation and decide what memory operations are needed.
|
|
1510
|
-
|
|
1511
|
-
## Conversation
|
|
1512
|
-
|
|
1513
|
-
User: ${userText}
|
|
1514
|
-
Assistant: ${assistantText}
|
|
1515
|
-
|
|
1516
|
-
## Existing relevant memories (identified by integer idx)
|
|
1517
|
-
|
|
1518
|
-
${memoryList}
|
|
1519
|
-
|
|
1520
|
-
## Task
|
|
1521
|
-
|
|
1522
|
-
Extract only genuinely important long-term facts (decisions, preferences, account info, project status, key insights). Skip small talk, confirmations, and information already captured in existing memories.
|
|
1523
|
-
|
|
1524
|
-
## Operation types
|
|
1525
|
-
- NEW: Extract a brand new fact not present in existing memories
|
|
1526
|
-
- UPDATE: New information refines or supersedes an existing memory; specify existingIdx
|
|
1527
|
-
- DELETE: An existing memory is outdated, contradicted, or wrong; specify existingIdx, fact = original content
|
|
1528
|
-
- NONE: Nothing worth recording, or information already fully captured
|
|
1529
|
-
|
|
1530
|
-
## Output format
|
|
1531
|
-
|
|
1532
|
-
Return a JSON array. Each item:
|
|
1533
|
-
{"action": "NEW"|"UPDATE"|"DELETE"|"NONE", "fact": "fact content", "existingIdx": integer or omit, "reason": "optional"}
|
|
1534
|
-
|
|
1535
|
-
Return at most 3 operations. If nothing is worth recording, return [].
|
|
1536
|
-
Return only the JSON array, no other text.
|
|
1537
|
-
|
|
1538
|
-
Examples:
|
|
1539
|
-
|
|
1540
|
-
1. New preference:
|
|
1541
|
-
[{"action": "NEW", "fact": "User prefers TypeScript over JavaScript", "reason": "Explicitly stated tech preference"}]
|
|
1542
|
-
|
|
1543
|
-
2. Updating an existing memory (idx 0 was "User is evaluating React and Vue"):
|
|
1544
|
-
[{"action": "UPDATE", "fact": "User decided to use React (dropped Vue)", "existingIdx": 0, "reason": "Decision finalized, update evaluation status"}]
|
|
1545
|
-
|
|
1546
|
-
3. Conversation is just "Sure, thanks" / "Got it" with no new info:
|
|
1547
|
-
[]`,
|
|
1548
|
-
shouldMerge: (contentA, contentB) => `You are a memory deduplication assistant. Determine whether two memories express essentially the same information.
|
|
1549
|
-
|
|
1550
|
-
Memory A: ${contentA}
|
|
1551
|
-
Memory B: ${contentB}
|
|
1552
|
-
|
|
1553
|
-
Rules:
|
|
1554
|
-
- If both memories express the same core fact (possibly different wording or granularity), return:
|
|
1555
|
-
{"shouldMerge": true, "merged": "Concise merged statement preserving key details from both, more complete than either alone"}
|
|
1556
|
-
- If the memories are complementary, on different topics, or contain different specific facts, return:
|
|
1557
|
-
{"shouldMerge": false}
|
|
1558
|
-
|
|
1559
|
-
Return only JSON, no other text.
|
|
1560
|
-
|
|
1561
|
-
Examples:
|
|
1562
|
-
|
|
1563
|
-
1. Should merge (different granularity):
|
|
1564
|
-
A: "Project uses PostgreSQL"
|
|
1565
|
-
B: "Project's primary database is PostgreSQL 16, deployed on AWS RDS"
|
|
1566
|
-
-> {"shouldMerge": true, "merged": "Project uses PostgreSQL 16 as primary database, deployed on AWS RDS"}
|
|
1567
|
-
|
|
1568
|
-
2. Should NOT merge (complementary but distinct):
|
|
1569
|
-
A: "User prefers VS Code"
|
|
1570
|
-
B: "User's VS Code uses One Dark Pro theme"
|
|
1571
|
-
-> {"shouldMerge": false}`,
|
|
1572
|
-
evolutionJudge: (oldContent, newContent) => `You are a memory evolution judge. Analyze the relationship between an old and new memory and return JSON.
|
|
1573
|
-
|
|
1574
|
-
Old memory: ${oldContent}
|
|
1575
|
-
New memory: ${newContent}
|
|
1576
|
-
|
|
1577
|
-
Classification rules:
|
|
1578
|
-
|
|
1579
|
-
- EVOLVE: New content deepens or updates the old memory (e.g. "Considering Next.js" -> "Decided on Next.js 14 App Router")
|
|
1580
|
-
Return: {"type": "EVOLVE", "mergedContent": "Merged content preserving the evolution trajectory"}
|
|
1581
|
-
|
|
1582
|
-
- CONFLICT: Old and new information directly contradict each other on the same attribute (e.g. "Uses MySQL as primary DB" vs "Migrated to PostgreSQL")
|
|
1583
|
-
Return: {"type": "CONFLICT"}
|
|
1584
|
-
|
|
1585
|
-
- EXPAND: New information supplements the old memory on the same topic (e.g. "Handles backend dev" + "Backend uses Go and gRPC")
|
|
1586
|
-
Return: {"type": "EXPAND", "mergedContent": "Merged content integrating both pieces of information"}
|
|
1587
|
-
|
|
1588
|
-
- NEW: Completely unrelated information, no substantive connection to the old memory
|
|
1589
|
-
Return: {"type": "NEW"}
|
|
1590
|
-
|
|
1591
|
-
Return only JSON, no other text.`
|
|
1592
|
-
};
|
|
1593
|
-
zh = {
|
|
1594
|
-
crudDecision: (userText, assistantText, memoryList) => `\u4F60\u662F\u4E00\u4E2A\u8BB0\u5FC6\u7BA1\u7406 agent\uFF0C\u8D1F\u8D23\u5206\u6790\u5BF9\u8BDD\u5185\u5BB9\u5E76\u51B3\u5B9A\u5982\u4F55\u64CD\u4F5C\u8BB0\u5FC6\u5E93\u3002
|
|
1595
|
-
|
|
1596
|
-
## \u5BF9\u8BDD\u5185\u5BB9
|
|
1597
|
-
|
|
1598
|
-
\u7528\u6237\uFF1A${userText}
|
|
1599
|
-
\u52A9\u624B\uFF1A${assistantText}
|
|
1600
|
-
|
|
1601
|
-
## \u5DF2\u6709\u76F8\u5173\u8BB0\u5FC6\uFF08\u7528\u6574\u6570 idx \u6807\u8BC6\uFF09
|
|
1602
|
-
|
|
1603
|
-
${memoryList}
|
|
1604
|
-
|
|
1605
|
-
## \u4EFB\u52A1
|
|
1606
|
-
|
|
1607
|
-
\u5206\u6790\u4E0A\u8FF0\u5BF9\u8BDD\uFF0C\u51B3\u5B9A\u9700\u8981\u54EA\u4E9B\u8BB0\u5FC6\u64CD\u4F5C\u3002\u53EA\u63D0\u53D6\u771F\u6B63\u91CD\u8981\u7684\u957F\u671F\u4E8B\u5B9E\uFF08\u51B3\u7B56\u3001\u504F\u597D\u3001\u8D26\u53F7\u4FE1\u606F\u3001\u9879\u76EE\u72B6\u6001\u3001\u5173\u952E\u6D1E\u5BDF\uFF09\u3002\u8DF3\u8FC7\u95F2\u804A\u3001\u786E\u8BA4\u8BED\u3001\u91CD\u590D\u4FE1\u606F\u3002
|
|
1608
|
-
|
|
1609
|
-
## \u64CD\u4F5C\u7C7B\u578B
|
|
1610
|
-
- NEW\uFF1A\u63D0\u53D6\u5168\u65B0\u4E8B\u5B9E\uFF08\u5DF2\u6709\u8BB0\u5FC6\u4E2D\u6CA1\u6709\u7684\u4FE1\u606F\uFF09
|
|
1611
|
-
- UPDATE\uFF1A\u65B0\u4FE1\u606F\u66F4\u65B0\u4E86\u67D0\u6761\u5DF2\u6709\u8BB0\u5FC6\uFF0C\u7528 existingIdx \u6307\u5B9A\u8981\u66F4\u65B0\u7684\u6761\u76EE
|
|
1612
|
-
- DELETE\uFF1A\u67D0\u6761\u5DF2\u6709\u8BB0\u5FC6\u5DF2\u7ECF\u8FC7\u65F6\u3001\u53D1\u751F\u51B2\u7A81\u6216\u9519\u8BEF\uFF0C\u7528 existingIdx \u6307\u5B9A\uFF0Cfact \u586B\u539F\u5185\u5BB9
|
|
1613
|
-
- NONE\uFF1A\u4E0D\u503C\u5F97\u8BB0\u5F55\u6216\u5DF2\u6709\u5B8C\u5168\u76F8\u540C\u7684\u4FE1\u606F
|
|
1614
|
-
|
|
1615
|
-
## \u8F93\u51FA\u683C\u5F0F
|
|
1616
|
-
|
|
1617
|
-
\u8FD4\u56DE JSON \u6570\u7EC4\uFF0C\u6BCF\u6761\u683C\u5F0F\uFF1A
|
|
1618
|
-
{"action": "NEW"|"UPDATE"|"DELETE"|"NONE", "fact": "\u4E8B\u5B9E\u5185\u5BB9", "existingIdx": \u6574\u6570\u6216\u7701\u7565, "reason": "\u539F\u56E0\uFF08\u53EF\u9009\uFF09"}
|
|
1619
|
-
|
|
1620
|
-
\u6BCF\u6B21\u6700\u591A\u8FD4\u56DE 3 \u6761\u64CD\u4F5C\u3002\u5982\u679C\u6CA1\u6709\u503C\u5F97\u64CD\u4F5C\u7684\u5185\u5BB9\uFF0C\u8FD4\u56DE []\u3002
|
|
1621
|
-
\u53EA\u8FD4\u56DE JSON \u6570\u7EC4\uFF0C\u4E0D\u8981\u4EFB\u4F55\u5176\u4ED6\u6587\u5B57\u3002
|
|
1622
|
-
|
|
1623
|
-
\u793A\u4F8B\uFF1A
|
|
1624
|
-
|
|
1625
|
-
1. \u63D0\u53D6\u65B0\u504F\u597D\uFF1A
|
|
1626
|
-
[{"action": "NEW", "fact": "\u7528\u6237\u504F\u597D TypeScript \u800C\u975E JavaScript", "reason": "\u660E\u786E\u8868\u8FBE\u7684\u6280\u672F\u504F\u597D"}]
|
|
1627
|
-
|
|
1628
|
-
2. \u66F4\u65B0\u5DF2\u6709\u8BB0\u5FC6\uFF08idx 0 \u539F\u4E3A"\u7528\u6237\u6B63\u5728\u8BC4\u4F30 React \u548C Vue"\uFF09\uFF1A
|
|
1629
|
-
[{"action": "UPDATE", "fact": "\u7528\u6237\u51B3\u5B9A\u4F7F\u7528 React\uFF08\u653E\u5F03\u4E86 Vue\uFF09", "existingIdx": 0, "reason": "\u51B3\u7B56\u5DF2\u660E\u786E\uFF0C\u66F4\u65B0\u8BC4\u4F30\u72B6\u6001"}]
|
|
1630
|
-
|
|
1631
|
-
3. \u5BF9\u8BDD\u4EC5\u4E3A"\u597D\u7684\uFF0C\u8C22\u8C22"/"\u6CA1\u95EE\u9898"\u7B49\u786E\u8BA4\u8BED\uFF0C\u65E0\u65B0\u4FE1\u606F\uFF1A
|
|
1632
|
-
[]`,
|
|
1633
|
-
shouldMerge: (contentA, contentB) => `\u4F60\u662F\u4E00\u4E2A\u8BB0\u5FC6\u53BB\u91CD\u52A9\u624B\uFF0C\u8D1F\u8D23\u5224\u65AD\u4E24\u6761\u8BB0\u5FC6\u662F\u5426\u8868\u8FBE\u4E86\u672C\u8D28\u76F8\u540C\u7684\u4FE1\u606F\u3002
|
|
1634
|
-
|
|
1635
|
-
\u8BB0\u5FC6A\uFF1A${contentA}
|
|
1636
|
-
\u8BB0\u5FC6B\uFF1A${contentB}
|
|
1637
|
-
|
|
1638
|
-
\u5224\u65AD\u89C4\u5219\uFF1A
|
|
1639
|
-
- \u5982\u679C\u4E24\u6761\u8BB0\u5FC6\u8868\u8FBE\u7684\u662F\u672C\u8D28\u76F8\u540C\u7684\u4FE1\u606F\uFF08\u53EF\u80FD\u63AA\u8F9E\u4E0D\u540C\u3001\u7C92\u5EA6\u4E0D\u540C\uFF0C\u4F46\u6838\u5FC3\u4E8B\u5B9E\u4E00\u81F4\uFF09\uFF0C\u8FD4\u56DE JSON\uFF1A
|
|
1640
|
-
{"shouldMerge": true, "merged": "\u5408\u5E76\u540E\u7684\u7B80\u6D01\u8868\u8FF0\uFF0C\u4FDD\u7559\u4E24\u6761\u8BB0\u5FC6\u7684\u5173\u952E\u4FE1\u606F\uFF0C\u6BD4\u4EFB\u4F55\u4E00\u6761\u90FD\u66F4\u5B8C\u6574"}
|
|
1641
|
-
- \u5982\u679C\u4E24\u6761\u8BB0\u5FC6\u662F\u4E92\u8865\u4FE1\u606F\u3001\u4E0D\u540C\u4E3B\u9898\u3001\u6216\u5305\u542B\u4E0D\u540C\u7684\u5177\u4F53\u4E8B\u5B9E\uFF0C\u8FD4\u56DE JSON\uFF1A
|
|
1642
|
-
{"shouldMerge": false}
|
|
1643
|
-
|
|
1644
|
-
\u53EA\u8FD4\u56DE JSON\uFF0C\u4E0D\u8981\u4EFB\u4F55\u5176\u4ED6\u6587\u5B57\u3002
|
|
1645
|
-
|
|
1646
|
-
\u793A\u4F8B\uFF1A
|
|
1647
|
-
|
|
1648
|
-
1. \u5E94\u5408\u5E76\uFF08\u7C92\u5EA6\u4E0D\u540C\uFF09\uFF1A
|
|
1649
|
-
A: "\u9879\u76EE\u4F7F\u7528 PostgreSQL \u6570\u636E\u5E93"
|
|
1650
|
-
B: "\u9879\u76EE\u7684\u4E3B\u6570\u636E\u5E93\u662F PostgreSQL 16\uFF0C\u90E8\u7F72\u5728 AWS RDS \u4E0A"
|
|
1651
|
-
\u2192 {"shouldMerge": true, "merged": "\u9879\u76EE\u4F7F\u7528 PostgreSQL 16 \u4F5C\u4E3A\u4E3B\u6570\u636E\u5E93\uFF0C\u90E8\u7F72\u5728 AWS RDS \u4E0A"}
|
|
1652
|
-
|
|
1653
|
-
2. \u4E0D\u5E94\u5408\u5E76\uFF08\u4E92\u8865\u4F46\u4E0D\u540C\uFF09\uFF1A
|
|
1654
|
-
A: "\u7528\u6237\u559C\u6B22\u7528 VS Code"
|
|
1655
|
-
B: "\u7528\u6237\u7684 VS Code \u4F7F\u7528 One Dark Pro \u4E3B\u9898"
|
|
1656
|
-
\u2192 {"shouldMerge": false}`,
|
|
1657
|
-
evolutionJudge: (oldContent, newContent) => `\u4F60\u662F\u4E00\u4E2A\u8BB0\u5FC6\u6F14\u5316\u5224\u65AD\u52A9\u624B\u3002\u5206\u6790\u4EE5\u4E0B\u4E24\u6761\u8BB0\u5FC6\u7684\u5173\u7CFB\u5E76\u8FD4\u56DE JSON\u3002
|
|
1658
|
-
|
|
1659
|
-
\u65E7\u8BB0\u5FC6\uFF1A${oldContent}
|
|
1660
|
-
\u65B0\u8BB0\u5FC6\uFF1A${newContent}
|
|
1661
|
-
|
|
1662
|
-
\u5224\u65AD\u89C4\u5219\uFF1A
|
|
1663
|
-
|
|
1664
|
-
- EVOLVE\uFF1A\u65B0\u5185\u5BB9\u662F\u5BF9\u65E7\u8BB0\u5FC6\u7684\u6DF1\u5316/\u66F4\u65B0\uFF08\u5982\u300C\u6B63\u5728\u8003\u8651\u7528 Next.js\u300D\u2192\u300C\u51B3\u5B9A\u7528 Next.js 14 App Router\u300D\uFF09
|
|
1665
|
-
\u8FD4\u56DE\uFF1A{"type": "EVOLVE", "mergedContent": "\u878D\u5408\u540E\u7684\u5B8C\u6574\u5185\u5BB9\uFF0C\u4FDD\u7559\u6F14\u5316\u8F68\u8FF9"}
|
|
1666
|
-
|
|
1667
|
-
- CONFLICT\uFF1A\u65B0\u65E7\u4FE1\u606F\u5728\u540C\u4E00\u5C5E\u6027\u4E0A\u76F4\u63A5\u77DB\u76FE\uFF08\u5982\u300C\u4F7F\u7528 MySQL \u4F5C\u4E3A\u4E3B\u6570\u636E\u5E93\u300Dvs\u300C\u5DF2\u8FC1\u79FB\u5230 PostgreSQL\u300D\uFF09
|
|
1668
|
-
\u8FD4\u56DE\uFF1A{"type": "CONFLICT"}
|
|
1669
|
-
|
|
1670
|
-
- EXPAND\uFF1A\u65B0\u4FE1\u606F\u662F\u5BF9\u65E7\u8BB0\u5FC6\u540C\u4E00\u4E3B\u9898\u7684\u8865\u5145\u6269\u5C55\uFF08\u5982\u300C\u8D1F\u8D23\u540E\u7AEF\u5F00\u53D1\u300D+\u300C\u540E\u7AEF\u4F7F\u7528 Go \u548C gRPC\u300D\uFF09
|
|
1671
|
-
\u8FD4\u56DE\uFF1A{"type": "EXPAND", "mergedContent": "\u5408\u5E76\u540E\u7684\u5B8C\u6574\u5185\u5BB9\uFF0C\u6574\u5408\u53CC\u65B9\u4FE1\u606F"}
|
|
1672
|
-
|
|
1673
|
-
- NEW\uFF1A\u5168\u65B0\u4FE1\u606F\uFF0C\u4E0E\u65E7\u8BB0\u5FC6\u65E0\u5B9E\u8D28\u5173\u8054\uFF08\u5982\u300C\u559C\u6B22 dark mode\u300Dvs\u300C\u4E0B\u5468\u8981\u53BB\u51FA\u5DEE\u300D\uFF09
|
|
1674
|
-
\u8FD4\u56DE\uFF1A{"type": "NEW"}
|
|
1675
|
-
|
|
1676
|
-
\u53EA\u8FD4\u56DE JSON\uFF0C\u4E0D\u8981\u4EFB\u4F55\u5176\u4ED6\u6587\u5B57\u3002`
|
|
1677
|
-
};
|
|
1678
|
-
templates = { en, zh };
|
|
1679
|
-
t = templates[LOCALE];
|
|
1680
|
-
client = new import_sdk.default({
|
|
1681
|
-
...process.env.AMEM_LLM_API_KEY && { apiKey: process.env.AMEM_LLM_API_KEY },
|
|
1682
|
-
...process.env.AMEM_LLM_BASE_URL && { baseURL: process.env.AMEM_LLM_BASE_URL }
|
|
1683
|
-
});
|
|
1684
|
-
MODEL = process.env.AMEM_LLM_MODEL ?? "claude-sonnet-4-6";
|
|
1685
|
-
VALID_CONFIDENCE = /* @__PURE__ */ new Set(["high", "medium", "low"]);
|
|
1686
|
-
VALID_CATEGORIES = /* @__PURE__ */ new Set([
|
|
1687
|
-
"Technical",
|
|
1688
|
-
"Business",
|
|
1689
|
-
"Personal",
|
|
1690
|
-
"Project",
|
|
1691
|
-
"Research",
|
|
1692
|
-
"System",
|
|
1693
|
-
"General"
|
|
1694
|
-
]);
|
|
1695
|
-
VALID_EVOLUTION_TYPES = /* @__PURE__ */ new Set(["EVOLVE", "CONFLICT", "EXPAND", "NEW"]);
|
|
1696
|
-
QDRANT_URL = "http://localhost:6333";
|
|
1697
|
-
getCollection = () => process.env.AMEM_COLLECTION || "amem_notes";
|
|
1698
|
-
VECTOR_DIM = 384;
|
|
1699
|
-
_collectionReady = false;
|
|
1700
|
-
_collectionReadyMap = /* @__PURE__ */ new Map();
|
|
1701
|
-
_jieba = null;
|
|
1702
|
-
EPHEMERAL_SIGNALS = ["\u5F85\u8DD1", "\u7B49\u786E\u8BA4", "\u6628\u65E5", "\u660E\u5929\u5B8C\u6210"];
|
|
1771
|
+
init_storage();
|
|
1703
1772
|
LOCALE2 = process.env.AMEM_PROMPT_LOCALE === "zh" ? "zh" : "en";
|
|
1704
1773
|
DEFAULT_OUTPUT_DIR = process.env.AMEM_REVIEW_DIR || process.cwd();
|
|
1705
1774
|
}
|
|
1706
1775
|
});
|
|
1707
1776
|
|
|
1777
|
+
// ../amem-core/src/index.ts
|
|
1778
|
+
var src_exports = {};
|
|
1779
|
+
__export(src_exports, {
|
|
1780
|
+
addEpisodic: () => addEpisodic,
|
|
1781
|
+
addMemory: () => addMemory,
|
|
1782
|
+
addNote: () => addNote,
|
|
1783
|
+
bm25Score: () => bm25Score,
|
|
1784
|
+
buildBM25: () => buildBM25,
|
|
1785
|
+
checkQuality: () => checkQuality,
|
|
1786
|
+
configure: () => configure,
|
|
1787
|
+
consolidateMemories: () => consolidateMemories,
|
|
1788
|
+
cosineSimilarity: () => cosineSimilarity,
|
|
1789
|
+
countNotes: () => countNotes,
|
|
1790
|
+
createStorageContext: () => createStorageContext,
|
|
1791
|
+
deleteNote: () => deleteNote,
|
|
1792
|
+
encode: () => encode,
|
|
1793
|
+
ensureCollection: () => ensureCollection,
|
|
1794
|
+
findByHash: () => findByHash,
|
|
1795
|
+
generateReviewBatch: () => generateReviewBatch,
|
|
1796
|
+
getDataDir: () => getDataDir,
|
|
1797
|
+
getEvoCount: () => getEvoCount,
|
|
1798
|
+
getNote: () => getNote,
|
|
1799
|
+
getNotesByDatePrefix: () => getNotesByDatePrefix,
|
|
1800
|
+
incrementEvoCount: () => incrementEvoCount,
|
|
1801
|
+
invalidateNote: () => invalidateNote,
|
|
1802
|
+
isModelLoaded: () => isModelLoaded,
|
|
1803
|
+
listMemories: () => listMemories,
|
|
1804
|
+
listNotes: () => listNotes,
|
|
1805
|
+
llmCall: () => llmCall,
|
|
1806
|
+
llmConstructNote: () => llmConstructNote,
|
|
1807
|
+
llmCrudDecision: () => llmCrudDecision,
|
|
1808
|
+
llmEvolutionJudge: () => llmEvolutionJudge,
|
|
1809
|
+
llmEvolveNote: () => llmEvolveNote,
|
|
1810
|
+
llmShouldLink: () => llmShouldLink,
|
|
1811
|
+
llmShouldMerge: () => llmShouldMerge,
|
|
1812
|
+
loadModel: () => loadModel,
|
|
1813
|
+
mergeSimilarNotes: () => mergeSimilarNotes,
|
|
1814
|
+
patchNotePayload: () => patchNotePayload,
|
|
1815
|
+
pingQdrant: () => pingQdrant,
|
|
1816
|
+
queryByEmbedding: () => queryByEmbedding,
|
|
1817
|
+
replaceLinkReferences: () => replaceLinkReferences,
|
|
1818
|
+
resetCollectionReady: () => resetCollectionReady,
|
|
1819
|
+
rrfMerge: () => rrfMerge,
|
|
1820
|
+
scanLowQuality: () => scanLowQuality,
|
|
1821
|
+
searchMemory: () => searchMemory,
|
|
1822
|
+
shouldRunEvolution: () => shouldRunEvolution,
|
|
1823
|
+
simpleTokenize: () => simpleTokenize,
|
|
1824
|
+
t: () => t,
|
|
1825
|
+
updateNote: () => updateNote,
|
|
1826
|
+
updateNoteContent: () => updateNoteContent,
|
|
1827
|
+
updateNoteLinks: () => updateNoteLinks
|
|
1828
|
+
});
|
|
1829
|
+
var init_src = __esm({
|
|
1830
|
+
"../amem-core/src/index.ts"() {
|
|
1831
|
+
"use strict";
|
|
1832
|
+
init_config();
|
|
1833
|
+
init_embedding();
|
|
1834
|
+
init_evo_counter();
|
|
1835
|
+
init_llm();
|
|
1836
|
+
init_memory();
|
|
1837
|
+
init_prompts();
|
|
1838
|
+
init_quality();
|
|
1839
|
+
init_storage();
|
|
1840
|
+
}
|
|
1841
|
+
});
|
|
1842
|
+
|
|
1708
1843
|
// src/index.ts
|
|
1709
1844
|
var index_exports = {};
|
|
1710
1845
|
__export(index_exports, {
|
|
@@ -1733,7 +1868,7 @@ module.exports = __toCommonJS(index_exports);
|
|
|
1733
1868
|
var os2 = __toESM(require("os"));
|
|
1734
1869
|
var path5 = __toESM(require("path"));
|
|
1735
1870
|
var import_plugin_entry = require("openclaw/plugin-sdk/plugin-entry");
|
|
1736
|
-
|
|
1871
|
+
init_src();
|
|
1737
1872
|
var import_crypto2 = require("crypto");
|
|
1738
1873
|
|
|
1739
1874
|
// src/hook-liveness.ts
|
|
@@ -1762,7 +1897,7 @@ function hookNeverFiredWarning(now = Date.now()) {
|
|
|
1762
1897
|
}
|
|
1763
1898
|
|
|
1764
1899
|
// src/index.ts
|
|
1765
|
-
|
|
1900
|
+
init_src();
|
|
1766
1901
|
var _config = {};
|
|
1767
1902
|
function register(api) {
|
|
1768
1903
|
const logger = api.logger;
|
|
@@ -2110,7 +2245,7 @@ ${text}${hookWarning}` }],
|
|
|
2110
2245
|
id: r.id,
|
|
2111
2246
|
content: r.content
|
|
2112
2247
|
}));
|
|
2113
|
-
const { llmCrudDecision: llmCrudDecision2 } = await Promise.resolve().then(() => (
|
|
2248
|
+
const { llmCrudDecision: llmCrudDecision2 } = await Promise.resolve().then(() => (init_src(), src_exports));
|
|
2114
2249
|
const operations = await llmCrudDecision2(
|
|
2115
2250
|
userText,
|
|
2116
2251
|
assistantText,
|
package/openclaw.plugin.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"id": "openclaw-amem",
|
|
3
3
|
"name": "Memory (A-MEM v2)",
|
|
4
|
-
"description": "
|
|
5
|
-
"version": "1.1.
|
|
4
|
+
"description": "OpenClaw memory plugin implementing A-MEM — memories evolve, not just accumulate. Graph linking, hybrid retrieval, LLM-driven evolution. No Python.",
|
|
5
|
+
"version": "1.1.4",
|
|
6
6
|
"kind": "memory",
|
|
7
7
|
"openclaw": {
|
|
8
8
|
"compat": {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "openclaw-amem",
|
|
3
|
-
"version": "1.1.
|
|
4
|
-
"description": "A-MEM
|
|
3
|
+
"version": "1.1.4",
|
|
4
|
+
"description": "OpenClaw memory plugin implementing A-MEM — memories evolve, not just accumulate. Graph linking, hybrid retrieval, LLM-driven evolution. No Python.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"openclaw": {
|
|
@@ -16,23 +16,23 @@
|
|
|
16
16
|
}
|
|
17
17
|
},
|
|
18
18
|
"dependencies": {
|
|
19
|
-
"@anthropic-ai/sdk": "^0.
|
|
20
|
-
"@huggingface/transformers": "^
|
|
19
|
+
"@anthropic-ai/sdk": "^0.110.0",
|
|
20
|
+
"@huggingface/transformers": "^4.2.0",
|
|
21
21
|
"@node-rs/jieba": "^2.0.1",
|
|
22
22
|
"@qdrant/js-client-rest": "^1.18.0",
|
|
23
|
-
"@types/uuid": "^
|
|
23
|
+
"@types/uuid": "^11.0.0",
|
|
24
24
|
"uuid": "^14.0.0"
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
27
|
"@eslint/js": "^10.0.1",
|
|
28
|
+
"@types/node": "^26.1.1",
|
|
28
29
|
"eslint": "^10.4.1",
|
|
29
30
|
"prettier": "^3.8.3",
|
|
30
31
|
"tsup": "^8.4.0",
|
|
31
32
|
"tsx": "^4.21.0",
|
|
32
33
|
"typescript": "^5.9.3",
|
|
33
34
|
"typescript-eslint": "^8.60.1",
|
|
34
|
-
"vitest": "^4.1.
|
|
35
|
-
"amem-core": "0.1.0"
|
|
35
|
+
"vitest": "^4.1.10"
|
|
36
36
|
},
|
|
37
37
|
"optionalDependencies": {
|
|
38
38
|
"@node-rs/jieba-darwin-arm64": "^2.0.1",
|
|
@@ -68,6 +68,7 @@
|
|
|
68
68
|
"scripts": {
|
|
69
69
|
"build": "tsup src/index.ts --format cjs --out-dir dist",
|
|
70
70
|
"dev": "tsup src/index.ts --format cjs --watch",
|
|
71
|
+
"typecheck": "tsc --noEmit",
|
|
71
72
|
"lint": "eslint src",
|
|
72
73
|
"format": "prettier --check \"src/**/*.ts\"",
|
|
73
74
|
"format:fix": "prettier --write \"src/**/*.ts\"",
|