@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/cjs/index.node.cjs
CHANGED
|
@@ -126,14 +126,17 @@ class MemoryService extends import_core.Service {
|
|
|
126
126
|
this.sessionMessageCounts = new Map;
|
|
127
127
|
this.lastExtractionCheckpoints = new Map;
|
|
128
128
|
this.memoryConfig = {
|
|
129
|
-
shortTermSummarizationThreshold:
|
|
129
|
+
shortTermSummarizationThreshold: 16,
|
|
130
130
|
shortTermRetainRecent: 10,
|
|
131
|
+
shortTermSummarizationInterval: 10,
|
|
131
132
|
longTermExtractionEnabled: true,
|
|
132
133
|
longTermVectorSearchEnabled: false,
|
|
133
134
|
longTermConfidenceThreshold: 0.7,
|
|
135
|
+
longTermExtractionThreshold: 20,
|
|
134
136
|
longTermExtractionInterval: 5,
|
|
135
137
|
summaryModelType: "TEXT_LARGE",
|
|
136
|
-
summaryMaxTokens: 2500
|
|
138
|
+
summaryMaxTokens: 2500,
|
|
139
|
+
summaryMaxNewMessages: 20
|
|
137
140
|
};
|
|
138
141
|
}
|
|
139
142
|
static async start(runtime) {
|
|
@@ -154,6 +157,14 @@ class MemoryService extends import_core.Service {
|
|
|
154
157
|
if (retainRecent) {
|
|
155
158
|
this.memoryConfig.shortTermRetainRecent = parseInt(retainRecent, 10);
|
|
156
159
|
}
|
|
160
|
+
const summarizationInterval = runtime.getSetting("MEMORY_SUMMARIZATION_INTERVAL");
|
|
161
|
+
if (summarizationInterval) {
|
|
162
|
+
this.memoryConfig.shortTermSummarizationInterval = parseInt(summarizationInterval, 10);
|
|
163
|
+
}
|
|
164
|
+
const maxNewMessages = runtime.getSetting("MEMORY_MAX_NEW_MESSAGES");
|
|
165
|
+
if (maxNewMessages) {
|
|
166
|
+
this.memoryConfig.summaryMaxNewMessages = parseInt(maxNewMessages, 10);
|
|
167
|
+
}
|
|
157
168
|
const longTermEnabled = runtime.getSetting("MEMORY_LONG_TERM_ENABLED");
|
|
158
169
|
if (longTermEnabled === "false") {
|
|
159
170
|
this.memoryConfig.longTermExtractionEnabled = false;
|
|
@@ -164,10 +175,21 @@ class MemoryService extends import_core.Service {
|
|
|
164
175
|
if (confidenceThreshold) {
|
|
165
176
|
this.memoryConfig.longTermConfidenceThreshold = parseFloat(confidenceThreshold);
|
|
166
177
|
}
|
|
178
|
+
const extractionThreshold = runtime.getSetting("MEMORY_EXTRACTION_THRESHOLD");
|
|
179
|
+
if (extractionThreshold) {
|
|
180
|
+
this.memoryConfig.longTermExtractionThreshold = parseInt(extractionThreshold, 10);
|
|
181
|
+
}
|
|
182
|
+
const extractionInterval = runtime.getSetting("MEMORY_EXTRACTION_INTERVAL");
|
|
183
|
+
if (extractionInterval) {
|
|
184
|
+
this.memoryConfig.longTermExtractionInterval = parseInt(extractionInterval, 10);
|
|
185
|
+
}
|
|
167
186
|
import_core.logger.info({
|
|
168
187
|
summarizationThreshold: this.memoryConfig.shortTermSummarizationThreshold,
|
|
188
|
+
summarizationInterval: this.memoryConfig.shortTermSummarizationInterval,
|
|
189
|
+
maxNewMessages: this.memoryConfig.summaryMaxNewMessages,
|
|
169
190
|
retainRecent: this.memoryConfig.shortTermRetainRecent,
|
|
170
191
|
longTermEnabled: this.memoryConfig.longTermExtractionEnabled,
|
|
192
|
+
extractionThreshold: this.memoryConfig.longTermExtractionThreshold,
|
|
171
193
|
extractionInterval: this.memoryConfig.longTermExtractionInterval,
|
|
172
194
|
confidenceThreshold: this.memoryConfig.longTermConfidenceThreshold
|
|
173
195
|
}, "MemoryService initialized");
|
|
@@ -228,14 +250,26 @@ class MemoryService extends import_core.Service {
|
|
|
228
250
|
}
|
|
229
251
|
}
|
|
230
252
|
async shouldRunExtraction(entityId, roomId, currentMessageCount) {
|
|
253
|
+
const threshold = this.memoryConfig.longTermExtractionThreshold;
|
|
231
254
|
const interval = this.memoryConfig.longTermExtractionInterval;
|
|
255
|
+
if (currentMessageCount < threshold) {
|
|
256
|
+
import_core.logger.debug({
|
|
257
|
+
entityId,
|
|
258
|
+
roomId,
|
|
259
|
+
currentMessageCount,
|
|
260
|
+
threshold,
|
|
261
|
+
shouldRun: false
|
|
262
|
+
}, "Extraction check: below threshold");
|
|
263
|
+
return false;
|
|
264
|
+
}
|
|
232
265
|
const lastCheckpoint = await this.getLastExtractionCheckpoint(entityId, roomId);
|
|
233
266
|
const currentCheckpoint = Math.floor(currentMessageCount / interval) * interval;
|
|
234
|
-
const shouldRun = currentMessageCount >=
|
|
267
|
+
const shouldRun = currentMessageCount >= threshold && currentCheckpoint > lastCheckpoint;
|
|
235
268
|
import_core.logger.debug({
|
|
236
269
|
entityId,
|
|
237
270
|
roomId,
|
|
238
271
|
currentMessageCount,
|
|
272
|
+
threshold,
|
|
239
273
|
interval,
|
|
240
274
|
lastCheckpoint,
|
|
241
275
|
currentCheckpoint,
|
|
@@ -303,7 +337,7 @@ class MemoryService extends import_core.Service {
|
|
|
303
337
|
accessCount: row.accessCount
|
|
304
338
|
}));
|
|
305
339
|
}
|
|
306
|
-
async updateLongTermMemory(id, updates) {
|
|
340
|
+
async updateLongTermMemory(id, entityId, updates) {
|
|
307
341
|
const db = this.getDb();
|
|
308
342
|
const updateData = {
|
|
309
343
|
updatedAt: new Date
|
|
@@ -326,13 +360,13 @@ class MemoryService extends import_core.Service {
|
|
|
326
360
|
if (updates.accessCount !== undefined) {
|
|
327
361
|
updateData.accessCount = updates.accessCount;
|
|
328
362
|
}
|
|
329
|
-
await db.update(longTermMemories).set(updateData).where(import_drizzle_orm4.eq(longTermMemories.id, id));
|
|
330
|
-
import_core.logger.info(`Updated long-term memory: ${id}`);
|
|
363
|
+
await db.update(longTermMemories).set(updateData).where(import_drizzle_orm4.and(import_drizzle_orm4.eq(longTermMemories.id, id), import_drizzle_orm4.eq(longTermMemories.agentId, this.runtime.agentId), import_drizzle_orm4.eq(longTermMemories.entityId, entityId)));
|
|
364
|
+
import_core.logger.info(`Updated long-term memory: ${id} for entity ${entityId}`);
|
|
331
365
|
}
|
|
332
|
-
async deleteLongTermMemory(id) {
|
|
366
|
+
async deleteLongTermMemory(id, entityId) {
|
|
333
367
|
const db = this.getDb();
|
|
334
|
-
await db.delete(longTermMemories).where(import_drizzle_orm4.eq(longTermMemories.id, id));
|
|
335
|
-
import_core.logger.info(`Deleted long-term memory: ${id}`);
|
|
368
|
+
await db.delete(longTermMemories).where(import_drizzle_orm4.and(import_drizzle_orm4.eq(longTermMemories.id, id), import_drizzle_orm4.eq(longTermMemories.agentId, this.runtime.agentId), import_drizzle_orm4.eq(longTermMemories.entityId, entityId)));
|
|
369
|
+
import_core.logger.info(`Deleted long-term memory: ${id} for entity ${entityId}`);
|
|
336
370
|
}
|
|
337
371
|
async getCurrentSessionSummary(roomId) {
|
|
338
372
|
const db = this.getDb();
|
|
@@ -387,7 +421,7 @@ class MemoryService extends import_core.Service {
|
|
|
387
421
|
import_core.logger.info(`Stored session summary for room ${newSummary.roomId}`);
|
|
388
422
|
return newSummary;
|
|
389
423
|
}
|
|
390
|
-
async updateSessionSummary(id, updates) {
|
|
424
|
+
async updateSessionSummary(id, roomId, updates) {
|
|
391
425
|
const db = this.getDb();
|
|
392
426
|
const updateData = {
|
|
393
427
|
updatedAt: new Date
|
|
@@ -413,8 +447,8 @@ class MemoryService extends import_core.Service {
|
|
|
413
447
|
if (updates.embedding !== undefined) {
|
|
414
448
|
updateData.embedding = updates.embedding;
|
|
415
449
|
}
|
|
416
|
-
await db.update(sessionSummaries).set(updateData).where(import_drizzle_orm4.eq(sessionSummaries.id, id));
|
|
417
|
-
import_core.logger.info(`Updated session summary: ${id}`);
|
|
450
|
+
await db.update(sessionSummaries).set(updateData).where(import_drizzle_orm4.and(import_drizzle_orm4.eq(sessionSummaries.id, id), import_drizzle_orm4.eq(sessionSummaries.agentId, this.runtime.agentId), import_drizzle_orm4.eq(sessionSummaries.roomId, roomId)));
|
|
451
|
+
import_core.logger.info(`Updated session summary: ${id} for room ${roomId}`);
|
|
418
452
|
}
|
|
419
453
|
async getSessionSummaries(roomId, limit = 5) {
|
|
420
454
|
const db = this.getDb();
|
|
@@ -594,14 +628,31 @@ var summarizationEvaluator = {
|
|
|
594
628
|
}
|
|
595
629
|
const config = memoryService.getConfig();
|
|
596
630
|
const currentMessageCount = await runtime.countMemories(message.roomId, false, "messages");
|
|
597
|
-
const
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
631
|
+
const existingSummary = await memoryService.getCurrentSessionSummary(message.roomId);
|
|
632
|
+
if (!existingSummary) {
|
|
633
|
+
const shouldSummarize = currentMessageCount >= config.shortTermSummarizationThreshold;
|
|
634
|
+
import_core2.logger.debug({
|
|
635
|
+
roomId: message.roomId,
|
|
636
|
+
currentMessageCount,
|
|
637
|
+
threshold: config.shortTermSummarizationThreshold,
|
|
638
|
+
shouldSummarize,
|
|
639
|
+
reason: "initial_summary_check"
|
|
640
|
+
}, "Summarization validation check");
|
|
641
|
+
return shouldSummarize;
|
|
642
|
+
} else {
|
|
643
|
+
const newMessageCount = currentMessageCount - existingSummary.lastMessageOffset;
|
|
644
|
+
const shouldUpdate = newMessageCount >= config.shortTermSummarizationInterval;
|
|
645
|
+
import_core2.logger.debug({
|
|
646
|
+
roomId: message.roomId,
|
|
647
|
+
currentMessageCount,
|
|
648
|
+
lastOffset: existingSummary.lastMessageOffset,
|
|
649
|
+
newMessageCount,
|
|
650
|
+
interval: config.shortTermSummarizationInterval,
|
|
651
|
+
shouldUpdate,
|
|
652
|
+
reason: "summary_update_check"
|
|
653
|
+
}, "Summarization validation check");
|
|
654
|
+
return shouldUpdate;
|
|
655
|
+
}
|
|
605
656
|
},
|
|
606
657
|
handler: async (runtime, message) => {
|
|
607
658
|
const memoryService = runtime.getService("memory");
|
|
@@ -616,15 +667,25 @@ var summarizationEvaluator = {
|
|
|
616
667
|
const existingSummary = await memoryService.getCurrentSessionSummary(roomId);
|
|
617
668
|
const lastOffset = existingSummary?.lastMessageOffset || 0;
|
|
618
669
|
const totalMessageCount = await runtime.countMemories(roomId, false, "messages");
|
|
670
|
+
const newMessageCount = totalMessageCount - lastOffset;
|
|
671
|
+
const maxNewMessages = config.summaryMaxNewMessages || 50;
|
|
672
|
+
const messagesToFetch = Math.min(newMessageCount, maxNewMessages);
|
|
673
|
+
if (messagesToFetch === 0) {
|
|
674
|
+
import_core2.logger.debug("No new messages to summarize");
|
|
675
|
+
return;
|
|
676
|
+
}
|
|
677
|
+
if (newMessageCount > maxNewMessages) {
|
|
678
|
+
import_core2.logger.warn(`Capping new messages at ${maxNewMessages} (${newMessageCount} available). Oldest messages will be skipped.`);
|
|
679
|
+
}
|
|
619
680
|
const newMessages = await runtime.getMemories({
|
|
620
681
|
tableName: "messages",
|
|
621
682
|
roomId,
|
|
622
|
-
count:
|
|
683
|
+
count: messagesToFetch,
|
|
623
684
|
unique: false,
|
|
624
685
|
start: lastOffset
|
|
625
686
|
});
|
|
626
687
|
if (newMessages.length === 0) {
|
|
627
|
-
import_core2.logger.debug("No new messages
|
|
688
|
+
import_core2.logger.debug("No new messages retrieved");
|
|
628
689
|
return;
|
|
629
690
|
}
|
|
630
691
|
const sortedMessages = newMessages.sort((a, b) => (a.createdAt || 0) - (b.createdAt || 0));
|
|
@@ -669,7 +730,7 @@ var summarizationEvaluator = {
|
|
|
669
730
|
const startTime = existingSummary ? existingSummary.startTime : firstMessage?.createdAt && firstMessage.createdAt > 0 ? new Date(firstMessage.createdAt) : new Date;
|
|
670
731
|
const endTime = lastMessage?.createdAt && lastMessage.createdAt > 0 ? new Date(lastMessage.createdAt) : new Date;
|
|
671
732
|
if (existingSummary) {
|
|
672
|
-
await memoryService.updateSessionSummary(existingSummary.id, {
|
|
733
|
+
await memoryService.updateSessionSummary(existingSummary.id, roomId, {
|
|
673
734
|
summary: summaryResult.summary,
|
|
674
735
|
messageCount: existingSummary.messageCount + sortedMessages.length,
|
|
675
736
|
lastMessageOffset: newOffset,
|
|
@@ -724,7 +785,7 @@ var LongTermMemoryCategory;
|
|
|
724
785
|
// src/evaluators/long-term-extraction.ts
|
|
725
786
|
var extractionTemplate = `# Task: Extract Long-Term Memory
|
|
726
787
|
|
|
727
|
-
You are analyzing a conversation to extract facts that should be remembered long-term
|
|
788
|
+
You are analyzing a conversation to extract ONLY the most important, persistent facts about the user that should be remembered long-term.
|
|
728
789
|
|
|
729
790
|
# Recent Messages
|
|
730
791
|
{{recentMessages}}
|
|
@@ -743,12 +804,41 @@ You are analyzing a conversation to extract facts that should be remembered long
|
|
|
743
804
|
8. **definitions**: Custom terms, acronyms, glossaries
|
|
744
805
|
9. **behavioral_patterns**: How the user tends to interact
|
|
745
806
|
|
|
807
|
+
# STRICT EXTRACTION CRITERIA
|
|
808
|
+
|
|
809
|
+
**DO EXTRACT** - Facts that are:
|
|
810
|
+
- Explicitly stated personal information (name, role, profession)
|
|
811
|
+
- Repeated patterns across multiple conversations (3+ occurrences)
|
|
812
|
+
- Core preferences stated with clear emphasis ("I always prefer...", "I never want...")
|
|
813
|
+
- Important ongoing projects or goals mentioned multiple times
|
|
814
|
+
- Persistent technical constraints or requirements
|
|
815
|
+
- Domain expertise demonstrated consistently
|
|
816
|
+
- Custom terminology the user defines and uses repeatedly
|
|
817
|
+
|
|
818
|
+
**DO NOT EXTRACT** - Facts that are:
|
|
819
|
+
- One-time requests or isolated tasks (e.g., "generate an image or similar")
|
|
820
|
+
- Single interactions without pattern repetition
|
|
821
|
+
- Casual preferences from single occurrences
|
|
822
|
+
- Testing or exploratory questions
|
|
823
|
+
- Temporary context or transient information
|
|
824
|
+
- General courtesy or social patterns (greetings, thank yous)
|
|
825
|
+
- Random or playful requests that don't indicate lasting preference
|
|
826
|
+
- Information that could change or is situational
|
|
827
|
+
|
|
828
|
+
# Quality Standards
|
|
829
|
+
- **Confidence threshold**: Only extract if confidence >= 0.8
|
|
830
|
+
- **Persistence required**: Must see evidence across multiple messages or strong explicit statement
|
|
831
|
+
- **Meaningful value**: Would this fact improve future interactions weeks from now?
|
|
832
|
+
- **Not redundant**: Avoid if existing memories already cover this information
|
|
833
|
+
|
|
746
834
|
# Instructions
|
|
747
|
-
Extract
|
|
835
|
+
Extract ONLY truly important NEW information that meets the strict criteria above. For each item:
|
|
748
836
|
- Determine which category it belongs to
|
|
749
837
|
- Write a clear, factual statement
|
|
750
|
-
- Assess confidence (0.0 to 1.0)
|
|
751
|
-
-
|
|
838
|
+
- Assess confidence (0.0 to 1.0) - BE CONSERVATIVE
|
|
839
|
+
- Require strong evidence before extraction
|
|
840
|
+
|
|
841
|
+
**When in doubt, DO NOT extract.** It's better to miss temporary information than to clutter long-term memory.
|
|
752
842
|
|
|
753
843
|
If there are no new long-term facts to extract, respond with <memories></memories>
|
|
754
844
|
|
|
@@ -891,7 +981,7 @@ var shortTermMemoryProvider = {
|
|
|
891
981
|
if (!memoryService) {
|
|
892
982
|
return {
|
|
893
983
|
data: { summaries: [], recentMessages: [], mode: "disabled" },
|
|
894
|
-
values: {
|
|
984
|
+
values: {},
|
|
895
985
|
text: ""
|
|
896
986
|
};
|
|
897
987
|
}
|
|
@@ -972,9 +1062,7 @@ ${runText}`;
|
|
|
972
1062
|
mode: "full_conversation"
|
|
973
1063
|
},
|
|
974
1064
|
values: {
|
|
975
|
-
|
|
976
|
-
recentMessages: "",
|
|
977
|
-
recentActionResults: ""
|
|
1065
|
+
recentMessage: "No recent message available."
|
|
978
1066
|
},
|
|
979
1067
|
text: "No recent messages available"
|
|
980
1068
|
};
|
|
@@ -1012,10 +1100,14 @@ ${runText}`;
|
|
|
1012
1100
|
mode: "full_conversation"
|
|
1013
1101
|
},
|
|
1014
1102
|
values: {
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1103
|
+
...(isPostFormat ? recentPosts : recentMessages) && {
|
|
1104
|
+
recentMessages: isPostFormat ? recentPosts : recentMessages
|
|
1105
|
+
},
|
|
1106
|
+
...recentPosts && { recentPosts },
|
|
1107
|
+
...actionResultsText && { recentActionResults: actionResultsText },
|
|
1108
|
+
...recentMessage && { recentMessage },
|
|
1109
|
+
...receivedMessageHeader && { receivedMessageHeader },
|
|
1110
|
+
...focusHeader && { focusHeader }
|
|
1019
1111
|
},
|
|
1020
1112
|
text: text4
|
|
1021
1113
|
};
|
|
@@ -1085,8 +1177,10 @@ ${runText}`;
|
|
|
1085
1177
|
mode: "summarized"
|
|
1086
1178
|
},
|
|
1087
1179
|
values: {
|
|
1088
|
-
sessionSummaries: summaryText,
|
|
1089
|
-
recentMessages: recentMessagesText
|
|
1180
|
+
...summaryText && { sessionSummaries: summaryText },
|
|
1181
|
+
...recentMessagesText && { recentMessages: recentMessagesText },
|
|
1182
|
+
...receivedMessageHeader && { receivedMessageHeader },
|
|
1183
|
+
...focusHeader && { focusHeader }
|
|
1090
1184
|
},
|
|
1091
1185
|
text: text4
|
|
1092
1186
|
};
|
|
@@ -1095,7 +1189,7 @@ ${runText}`;
|
|
|
1095
1189
|
import_core4.logger.error({ error }, "Error in shortTermMemoryProvider:");
|
|
1096
1190
|
return {
|
|
1097
1191
|
data: { summaries: [], recentMessages: [], mode: "error" },
|
|
1098
|
-
values: {
|
|
1192
|
+
values: {},
|
|
1099
1193
|
text: "Error retrieving conversation context."
|
|
1100
1194
|
};
|
|
1101
1195
|
}
|
|
@@ -1175,4 +1269,4 @@ var memoryPlugin = {
|
|
|
1175
1269
|
};
|
|
1176
1270
|
var src_default = memoryPlugin;
|
|
1177
1271
|
|
|
1178
|
-
//# debugId=
|
|
1272
|
+
//# debugId=3C20A9F0BA14039464756E2164756E21
|