@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.
@@ -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: 5,
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 >= interval && currentCheckpoint > lastCheckpoint;
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 shouldSummarize = currentMessageCount >= config.shortTermSummarizationThreshold;
593
- logger2.debug({
594
- roomId: message.roomId,
595
- currentMessageCount,
596
- threshold: config.shortTermSummarizationThreshold,
597
- shouldSummarize
598
- }, "Summarization validation check");
599
- return shouldSummarize;
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: config.shortTermSummarizationThreshold,
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 to summarize");
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 about the user.
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 any NEW information that should be remembered long-term. For each item:
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
- - Only include information explicitly stated or strongly implied
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: { sessionSummaries: "", recentMessages: "" },
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
- sessionSummaries: "",
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
- sessionSummaries: "",
1022
- recentMessages: isPostFormat ? recentPosts : recentMessages,
1023
- recentActionResults: actionResultsText,
1024
- recentMessage
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: { sessionSummaries: "", recentMessages: "" },
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=F2E3A5D3351D51D164756E2164756E21
1290
+ //# debugId=374CC1B0E70335CE64756E2164756E21