@elizaos/plugin-memory 1.0.3 → 1.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +30 -13
- package/dist/browser/index.browser.js +49 -20
- package/dist/browser/index.browser.js.map +7 -7
- package/dist/cjs/index.node.cjs +133 -39
- package/dist/cjs/index.node.js.map +7 -7
- package/dist/evaluators/summarization.d.ts +13 -6
- package/dist/node/index.node.js +133 -39
- package/dist/node/index.node.js.map +7 -7
- package/dist/services/memory-service.d.ts +6 -3
- package/dist/types/index.d.ts +3 -0
- package/package.json +1 -1
package/dist/node/index.node.js
CHANGED
|
@@ -117,14 +117,17 @@ class MemoryService extends Service {
|
|
|
117
117
|
this.sessionMessageCounts = new Map;
|
|
118
118
|
this.lastExtractionCheckpoints = new Map;
|
|
119
119
|
this.memoryConfig = {
|
|
120
|
-
shortTermSummarizationThreshold:
|
|
120
|
+
shortTermSummarizationThreshold: 16,
|
|
121
121
|
shortTermRetainRecent: 10,
|
|
122
|
+
shortTermSummarizationInterval: 10,
|
|
122
123
|
longTermExtractionEnabled: true,
|
|
123
124
|
longTermVectorSearchEnabled: false,
|
|
124
125
|
longTermConfidenceThreshold: 0.7,
|
|
126
|
+
longTermExtractionThreshold: 20,
|
|
125
127
|
longTermExtractionInterval: 5,
|
|
126
128
|
summaryModelType: "TEXT_LARGE",
|
|
127
|
-
summaryMaxTokens: 2500
|
|
129
|
+
summaryMaxTokens: 2500,
|
|
130
|
+
summaryMaxNewMessages: 20
|
|
128
131
|
};
|
|
129
132
|
}
|
|
130
133
|
static async start(runtime) {
|
|
@@ -145,6 +148,14 @@ class MemoryService extends Service {
|
|
|
145
148
|
if (retainRecent) {
|
|
146
149
|
this.memoryConfig.shortTermRetainRecent = parseInt(retainRecent, 10);
|
|
147
150
|
}
|
|
151
|
+
const summarizationInterval = runtime.getSetting("MEMORY_SUMMARIZATION_INTERVAL");
|
|
152
|
+
if (summarizationInterval) {
|
|
153
|
+
this.memoryConfig.shortTermSummarizationInterval = parseInt(summarizationInterval, 10);
|
|
154
|
+
}
|
|
155
|
+
const maxNewMessages = runtime.getSetting("MEMORY_MAX_NEW_MESSAGES");
|
|
156
|
+
if (maxNewMessages) {
|
|
157
|
+
this.memoryConfig.summaryMaxNewMessages = parseInt(maxNewMessages, 10);
|
|
158
|
+
}
|
|
148
159
|
const longTermEnabled = runtime.getSetting("MEMORY_LONG_TERM_ENABLED");
|
|
149
160
|
if (longTermEnabled === "false") {
|
|
150
161
|
this.memoryConfig.longTermExtractionEnabled = false;
|
|
@@ -155,10 +166,21 @@ class MemoryService extends Service {
|
|
|
155
166
|
if (confidenceThreshold) {
|
|
156
167
|
this.memoryConfig.longTermConfidenceThreshold = parseFloat(confidenceThreshold);
|
|
157
168
|
}
|
|
169
|
+
const extractionThreshold = runtime.getSetting("MEMORY_EXTRACTION_THRESHOLD");
|
|
170
|
+
if (extractionThreshold) {
|
|
171
|
+
this.memoryConfig.longTermExtractionThreshold = parseInt(extractionThreshold, 10);
|
|
172
|
+
}
|
|
173
|
+
const extractionInterval = runtime.getSetting("MEMORY_EXTRACTION_INTERVAL");
|
|
174
|
+
if (extractionInterval) {
|
|
175
|
+
this.memoryConfig.longTermExtractionInterval = parseInt(extractionInterval, 10);
|
|
176
|
+
}
|
|
158
177
|
logger.info({
|
|
159
178
|
summarizationThreshold: this.memoryConfig.shortTermSummarizationThreshold,
|
|
179
|
+
summarizationInterval: this.memoryConfig.shortTermSummarizationInterval,
|
|
180
|
+
maxNewMessages: this.memoryConfig.summaryMaxNewMessages,
|
|
160
181
|
retainRecent: this.memoryConfig.shortTermRetainRecent,
|
|
161
182
|
longTermEnabled: this.memoryConfig.longTermExtractionEnabled,
|
|
183
|
+
extractionThreshold: this.memoryConfig.longTermExtractionThreshold,
|
|
162
184
|
extractionInterval: this.memoryConfig.longTermExtractionInterval,
|
|
163
185
|
confidenceThreshold: this.memoryConfig.longTermConfidenceThreshold
|
|
164
186
|
}, "MemoryService initialized");
|
|
@@ -219,14 +241,26 @@ class MemoryService extends Service {
|
|
|
219
241
|
}
|
|
220
242
|
}
|
|
221
243
|
async shouldRunExtraction(entityId, roomId, currentMessageCount) {
|
|
244
|
+
const threshold = this.memoryConfig.longTermExtractionThreshold;
|
|
222
245
|
const interval = this.memoryConfig.longTermExtractionInterval;
|
|
246
|
+
if (currentMessageCount < threshold) {
|
|
247
|
+
logger.debug({
|
|
248
|
+
entityId,
|
|
249
|
+
roomId,
|
|
250
|
+
currentMessageCount,
|
|
251
|
+
threshold,
|
|
252
|
+
shouldRun: false
|
|
253
|
+
}, "Extraction check: below threshold");
|
|
254
|
+
return false;
|
|
255
|
+
}
|
|
223
256
|
const lastCheckpoint = await this.getLastExtractionCheckpoint(entityId, roomId);
|
|
224
257
|
const currentCheckpoint = Math.floor(currentMessageCount / interval) * interval;
|
|
225
|
-
const shouldRun = currentMessageCount >=
|
|
258
|
+
const shouldRun = currentMessageCount >= threshold && currentCheckpoint > lastCheckpoint;
|
|
226
259
|
logger.debug({
|
|
227
260
|
entityId,
|
|
228
261
|
roomId,
|
|
229
262
|
currentMessageCount,
|
|
263
|
+
threshold,
|
|
230
264
|
interval,
|
|
231
265
|
lastCheckpoint,
|
|
232
266
|
currentCheckpoint,
|
|
@@ -294,7 +328,7 @@ class MemoryService extends Service {
|
|
|
294
328
|
accessCount: row.accessCount
|
|
295
329
|
}));
|
|
296
330
|
}
|
|
297
|
-
async updateLongTermMemory(id, updates) {
|
|
331
|
+
async updateLongTermMemory(id, entityId, updates) {
|
|
298
332
|
const db = this.getDb();
|
|
299
333
|
const updateData = {
|
|
300
334
|
updatedAt: new Date
|
|
@@ -317,13 +351,13 @@ class MemoryService extends Service {
|
|
|
317
351
|
if (updates.accessCount !== undefined) {
|
|
318
352
|
updateData.accessCount = updates.accessCount;
|
|
319
353
|
}
|
|
320
|
-
await db.update(longTermMemories).set(updateData).where(eq(longTermMemories.id, id));
|
|
321
|
-
logger.info(`Updated long-term memory: ${id}`);
|
|
354
|
+
await db.update(longTermMemories).set(updateData).where(and(eq(longTermMemories.id, id), eq(longTermMemories.agentId, this.runtime.agentId), eq(longTermMemories.entityId, entityId)));
|
|
355
|
+
logger.info(`Updated long-term memory: ${id} for entity ${entityId}`);
|
|
322
356
|
}
|
|
323
|
-
async deleteLongTermMemory(id) {
|
|
357
|
+
async deleteLongTermMemory(id, entityId) {
|
|
324
358
|
const db = this.getDb();
|
|
325
|
-
await db.delete(longTermMemories).where(eq(longTermMemories.id, id));
|
|
326
|
-
logger.info(`Deleted long-term memory: ${id}`);
|
|
359
|
+
await db.delete(longTermMemories).where(and(eq(longTermMemories.id, id), eq(longTermMemories.agentId, this.runtime.agentId), eq(longTermMemories.entityId, entityId)));
|
|
360
|
+
logger.info(`Deleted long-term memory: ${id} for entity ${entityId}`);
|
|
327
361
|
}
|
|
328
362
|
async getCurrentSessionSummary(roomId) {
|
|
329
363
|
const db = this.getDb();
|
|
@@ -378,7 +412,7 @@ class MemoryService extends Service {
|
|
|
378
412
|
logger.info(`Stored session summary for room ${newSummary.roomId}`);
|
|
379
413
|
return newSummary;
|
|
380
414
|
}
|
|
381
|
-
async updateSessionSummary(id, updates) {
|
|
415
|
+
async updateSessionSummary(id, roomId, updates) {
|
|
382
416
|
const db = this.getDb();
|
|
383
417
|
const updateData = {
|
|
384
418
|
updatedAt: new Date
|
|
@@ -404,8 +438,8 @@ class MemoryService extends Service {
|
|
|
404
438
|
if (updates.embedding !== undefined) {
|
|
405
439
|
updateData.embedding = updates.embedding;
|
|
406
440
|
}
|
|
407
|
-
await db.update(sessionSummaries).set(updateData).where(eq(sessionSummaries.id, id));
|
|
408
|
-
logger.info(`Updated session summary: ${id}`);
|
|
441
|
+
await db.update(sessionSummaries).set(updateData).where(and(eq(sessionSummaries.id, id), eq(sessionSummaries.agentId, this.runtime.agentId), eq(sessionSummaries.roomId, roomId)));
|
|
442
|
+
logger.info(`Updated session summary: ${id} for room ${roomId}`);
|
|
409
443
|
}
|
|
410
444
|
async getSessionSummaries(roomId, limit = 5) {
|
|
411
445
|
const db = this.getDb();
|
|
@@ -589,14 +623,31 @@ var summarizationEvaluator = {
|
|
|
589
623
|
}
|
|
590
624
|
const config = memoryService.getConfig();
|
|
591
625
|
const currentMessageCount = await runtime.countMemories(message.roomId, false, "messages");
|
|
592
|
-
const
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
626
|
+
const existingSummary = await memoryService.getCurrentSessionSummary(message.roomId);
|
|
627
|
+
if (!existingSummary) {
|
|
628
|
+
const shouldSummarize = currentMessageCount >= config.shortTermSummarizationThreshold;
|
|
629
|
+
logger2.debug({
|
|
630
|
+
roomId: message.roomId,
|
|
631
|
+
currentMessageCount,
|
|
632
|
+
threshold: config.shortTermSummarizationThreshold,
|
|
633
|
+
shouldSummarize,
|
|
634
|
+
reason: "initial_summary_check"
|
|
635
|
+
}, "Summarization validation check");
|
|
636
|
+
return shouldSummarize;
|
|
637
|
+
} else {
|
|
638
|
+
const newMessageCount = currentMessageCount - existingSummary.lastMessageOffset;
|
|
639
|
+
const shouldUpdate = newMessageCount >= config.shortTermSummarizationInterval;
|
|
640
|
+
logger2.debug({
|
|
641
|
+
roomId: message.roomId,
|
|
642
|
+
currentMessageCount,
|
|
643
|
+
lastOffset: existingSummary.lastMessageOffset,
|
|
644
|
+
newMessageCount,
|
|
645
|
+
interval: config.shortTermSummarizationInterval,
|
|
646
|
+
shouldUpdate,
|
|
647
|
+
reason: "summary_update_check"
|
|
648
|
+
}, "Summarization validation check");
|
|
649
|
+
return shouldUpdate;
|
|
650
|
+
}
|
|
600
651
|
},
|
|
601
652
|
handler: async (runtime, message) => {
|
|
602
653
|
const memoryService = runtime.getService("memory");
|
|
@@ -611,15 +662,25 @@ var summarizationEvaluator = {
|
|
|
611
662
|
const existingSummary = await memoryService.getCurrentSessionSummary(roomId);
|
|
612
663
|
const lastOffset = existingSummary?.lastMessageOffset || 0;
|
|
613
664
|
const totalMessageCount = await runtime.countMemories(roomId, false, "messages");
|
|
665
|
+
const newMessageCount = totalMessageCount - lastOffset;
|
|
666
|
+
const maxNewMessages = config.summaryMaxNewMessages || 50;
|
|
667
|
+
const messagesToFetch = Math.min(newMessageCount, maxNewMessages);
|
|
668
|
+
if (messagesToFetch === 0) {
|
|
669
|
+
logger2.debug("No new messages to summarize");
|
|
670
|
+
return;
|
|
671
|
+
}
|
|
672
|
+
if (newMessageCount > maxNewMessages) {
|
|
673
|
+
logger2.warn(`Capping new messages at ${maxNewMessages} (${newMessageCount} available). Oldest messages will be skipped.`);
|
|
674
|
+
}
|
|
614
675
|
const newMessages = await runtime.getMemories({
|
|
615
676
|
tableName: "messages",
|
|
616
677
|
roomId,
|
|
617
|
-
count:
|
|
678
|
+
count: messagesToFetch,
|
|
618
679
|
unique: false,
|
|
619
680
|
start: lastOffset
|
|
620
681
|
});
|
|
621
682
|
if (newMessages.length === 0) {
|
|
622
|
-
logger2.debug("No new messages
|
|
683
|
+
logger2.debug("No new messages retrieved");
|
|
623
684
|
return;
|
|
624
685
|
}
|
|
625
686
|
const sortedMessages = newMessages.sort((a, b) => (a.createdAt || 0) - (b.createdAt || 0));
|
|
@@ -664,7 +725,7 @@ var summarizationEvaluator = {
|
|
|
664
725
|
const startTime = existingSummary ? existingSummary.startTime : firstMessage?.createdAt && firstMessage.createdAt > 0 ? new Date(firstMessage.createdAt) : new Date;
|
|
665
726
|
const endTime = lastMessage?.createdAt && lastMessage.createdAt > 0 ? new Date(lastMessage.createdAt) : new Date;
|
|
666
727
|
if (existingSummary) {
|
|
667
|
-
await memoryService.updateSessionSummary(existingSummary.id, {
|
|
728
|
+
await memoryService.updateSessionSummary(existingSummary.id, roomId, {
|
|
668
729
|
summary: summaryResult.summary,
|
|
669
730
|
messageCount: existingSummary.messageCount + sortedMessages.length,
|
|
670
731
|
lastMessageOffset: newOffset,
|
|
@@ -723,7 +784,7 @@ var LongTermMemoryCategory;
|
|
|
723
784
|
// src/evaluators/long-term-extraction.ts
|
|
724
785
|
var extractionTemplate = `# Task: Extract Long-Term Memory
|
|
725
786
|
|
|
726
|
-
You are analyzing a conversation to extract facts that should be remembered long-term
|
|
787
|
+
You are analyzing a conversation to extract ONLY the most important, persistent facts about the user that should be remembered long-term.
|
|
727
788
|
|
|
728
789
|
# Recent Messages
|
|
729
790
|
{{recentMessages}}
|
|
@@ -742,12 +803,41 @@ You are analyzing a conversation to extract facts that should be remembered long
|
|
|
742
803
|
8. **definitions**: Custom terms, acronyms, glossaries
|
|
743
804
|
9. **behavioral_patterns**: How the user tends to interact
|
|
744
805
|
|
|
806
|
+
# STRICT EXTRACTION CRITERIA
|
|
807
|
+
|
|
808
|
+
**DO EXTRACT** - Facts that are:
|
|
809
|
+
- Explicitly stated personal information (name, role, profession)
|
|
810
|
+
- Repeated patterns across multiple conversations (3+ occurrences)
|
|
811
|
+
- Core preferences stated with clear emphasis ("I always prefer...", "I never want...")
|
|
812
|
+
- Important ongoing projects or goals mentioned multiple times
|
|
813
|
+
- Persistent technical constraints or requirements
|
|
814
|
+
- Domain expertise demonstrated consistently
|
|
815
|
+
- Custom terminology the user defines and uses repeatedly
|
|
816
|
+
|
|
817
|
+
**DO NOT EXTRACT** - Facts that are:
|
|
818
|
+
- One-time requests or isolated tasks (e.g., "generate an image or similar")
|
|
819
|
+
- Single interactions without pattern repetition
|
|
820
|
+
- Casual preferences from single occurrences
|
|
821
|
+
- Testing or exploratory questions
|
|
822
|
+
- Temporary context or transient information
|
|
823
|
+
- General courtesy or social patterns (greetings, thank yous)
|
|
824
|
+
- Random or playful requests that don't indicate lasting preference
|
|
825
|
+
- Information that could change or is situational
|
|
826
|
+
|
|
827
|
+
# Quality Standards
|
|
828
|
+
- **Confidence threshold**: Only extract if confidence >= 0.8
|
|
829
|
+
- **Persistence required**: Must see evidence across multiple messages or strong explicit statement
|
|
830
|
+
- **Meaningful value**: Would this fact improve future interactions weeks from now?
|
|
831
|
+
- **Not redundant**: Avoid if existing memories already cover this information
|
|
832
|
+
|
|
745
833
|
# Instructions
|
|
746
|
-
Extract
|
|
834
|
+
Extract ONLY truly important NEW information that meets the strict criteria above. For each item:
|
|
747
835
|
- Determine which category it belongs to
|
|
748
836
|
- Write a clear, factual statement
|
|
749
|
-
- Assess confidence (0.0 to 1.0)
|
|
750
|
-
-
|
|
837
|
+
- Assess confidence (0.0 to 1.0) - BE CONSERVATIVE
|
|
838
|
+
- Require strong evidence before extraction
|
|
839
|
+
|
|
840
|
+
**When in doubt, DO NOT extract.** It's better to miss temporary information than to clutter long-term memory.
|
|
751
841
|
|
|
752
842
|
If there are no new long-term facts to extract, respond with <memories></memories>
|
|
753
843
|
|
|
@@ -897,7 +987,7 @@ var shortTermMemoryProvider = {
|
|
|
897
987
|
if (!memoryService) {
|
|
898
988
|
return {
|
|
899
989
|
data: { summaries: [], recentMessages: [], mode: "disabled" },
|
|
900
|
-
values: {
|
|
990
|
+
values: {},
|
|
901
991
|
text: ""
|
|
902
992
|
};
|
|
903
993
|
}
|
|
@@ -978,9 +1068,7 @@ ${runText}`;
|
|
|
978
1068
|
mode: "full_conversation"
|
|
979
1069
|
},
|
|
980
1070
|
values: {
|
|
981
|
-
|
|
982
|
-
recentMessages: "",
|
|
983
|
-
recentActionResults: ""
|
|
1071
|
+
recentMessage: "No recent message available."
|
|
984
1072
|
},
|
|
985
1073
|
text: "No recent messages available"
|
|
986
1074
|
};
|
|
@@ -1018,10 +1106,14 @@ ${runText}`;
|
|
|
1018
1106
|
mode: "full_conversation"
|
|
1019
1107
|
},
|
|
1020
1108
|
values: {
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1109
|
+
...(isPostFormat ? recentPosts : recentMessages) && {
|
|
1110
|
+
recentMessages: isPostFormat ? recentPosts : recentMessages
|
|
1111
|
+
},
|
|
1112
|
+
...recentPosts && { recentPosts },
|
|
1113
|
+
...actionResultsText && { recentActionResults: actionResultsText },
|
|
1114
|
+
...recentMessage && { recentMessage },
|
|
1115
|
+
...receivedMessageHeader && { receivedMessageHeader },
|
|
1116
|
+
...focusHeader && { focusHeader }
|
|
1025
1117
|
},
|
|
1026
1118
|
text: text4
|
|
1027
1119
|
};
|
|
@@ -1091,8 +1183,10 @@ ${runText}`;
|
|
|
1091
1183
|
mode: "summarized"
|
|
1092
1184
|
},
|
|
1093
1185
|
values: {
|
|
1094
|
-
sessionSummaries: summaryText,
|
|
1095
|
-
recentMessages: recentMessagesText
|
|
1186
|
+
...summaryText && { sessionSummaries: summaryText },
|
|
1187
|
+
...recentMessagesText && { recentMessages: recentMessagesText },
|
|
1188
|
+
...receivedMessageHeader && { receivedMessageHeader },
|
|
1189
|
+
...focusHeader && { focusHeader }
|
|
1096
1190
|
},
|
|
1097
1191
|
text: text4
|
|
1098
1192
|
};
|
|
@@ -1101,7 +1195,7 @@ ${runText}`;
|
|
|
1101
1195
|
logger4.error({ error }, "Error in shortTermMemoryProvider:");
|
|
1102
1196
|
return {
|
|
1103
1197
|
data: { summaries: [], recentMessages: [], mode: "error" },
|
|
1104
|
-
values: {
|
|
1198
|
+
values: {},
|
|
1105
1199
|
text: "Error retrieving conversation context."
|
|
1106
1200
|
};
|
|
1107
1201
|
}
|
|
@@ -1193,4 +1287,4 @@ export {
|
|
|
1193
1287
|
LongTermMemoryCategory
|
|
1194
1288
|
};
|
|
1195
1289
|
|
|
1196
|
-
//# debugId=
|
|
1290
|
+
//# debugId=374CC1B0E70335CE64756E2164756E21
|