@elizaos/plugin-memory 1.0.4 → 1.0.6

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,
121
- shortTermRetainRecent: 10,
120
+ shortTermSummarizationThreshold: 16,
121
+ shortTermRetainRecent: 6,
122
+ shortTermSummarizationInterval: 10,
122
123
  longTermExtractionEnabled: true,
123
124
  longTermVectorSearchEnabled: false,
124
- longTermConfidenceThreshold: 0.7,
125
- longTermExtractionInterval: 5,
125
+ longTermConfidenceThreshold: 0.85,
126
+ longTermExtractionThreshold: 30,
127
+ longTermExtractionInterval: 10,
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,
@@ -709,21 +770,15 @@ import {
709
770
  // src/types/index.ts
710
771
  var LongTermMemoryCategory;
711
772
  ((LongTermMemoryCategory2) => {
712
- LongTermMemoryCategory2["IDENTITY"] = "identity";
713
- LongTermMemoryCategory2["EXPERTISE"] = "expertise";
714
- LongTermMemoryCategory2["PROJECTS"] = "projects";
715
- LongTermMemoryCategory2["PREFERENCES"] = "preferences";
716
- LongTermMemoryCategory2["DATA_SOURCES"] = "data_sources";
717
- LongTermMemoryCategory2["GOALS"] = "goals";
718
- LongTermMemoryCategory2["CONSTRAINTS"] = "constraints";
719
- LongTermMemoryCategory2["DEFINITIONS"] = "definitions";
720
- LongTermMemoryCategory2["BEHAVIORAL_PATTERNS"] = "behavioral_patterns";
773
+ LongTermMemoryCategory2["EPISODIC"] = "episodic";
774
+ LongTermMemoryCategory2["SEMANTIC"] = "semantic";
775
+ LongTermMemoryCategory2["PROCEDURAL"] = "procedural";
721
776
  })(LongTermMemoryCategory ||= {});
722
777
 
723
778
  // src/evaluators/long-term-extraction.ts
724
- var extractionTemplate = `# Task: Extract Long-Term Memory
779
+ var extractionTemplate = `# Task: Extract Long-Term Memory (Strict Criteria)
725
780
 
726
- You are analyzing a conversation to extract facts that should be remembered long-term about the user.
781
+ You are analyzing a conversation to extract ONLY the most critical, persistent information about the user using cognitive science memory categories.
727
782
 
728
783
  # Recent Messages
729
784
  {{recentMessages}}
@@ -731,37 +786,127 @@ You are analyzing a conversation to extract facts that should be remembered long
731
786
  # Current Long-Term Memories
732
787
  {{existingMemories}}
733
788
 
734
- # Memory Categories
735
- 1. **identity**: User's name, role, identity (e.g., "I'm a data scientist")
736
- 2. **expertise**: User's skills, knowledge domains, or unfamiliarity with topics
737
- 3. **projects**: Ongoing projects, past interactions, recurring topics
738
- 4. **preferences**: Communication style, format preferences, verbosity, etc.
739
- 5. **data_sources**: Frequently used files, databases, APIs
740
- 6. **goals**: Broader intentions (e.g., "preparing for interview")
741
- 7. **constraints**: User-defined rules or limitations
742
- 8. **definitions**: Custom terms, acronyms, glossaries
743
- 9. **behavioral_patterns**: How the user tends to interact
789
+ # Memory Categories (Based on Cognitive Science)
744
790
 
745
- # Instructions
746
- Extract any NEW information that should be remembered long-term. For each item:
747
- - Determine which category it belongs to
748
- - Write a clear, factual statement
749
- - Assess confidence (0.0 to 1.0)
750
- - Only include information explicitly stated or strongly implied
791
+ ## 1. EPISODIC Memory
792
+ Personal experiences and specific events with temporal/spatial context.
793
+ **Examples:**
794
+ - "User completed migration project from MongoDB to PostgreSQL in Q2 2024"
795
+ - "User encountered authentication bug in production on March 15th"
796
+ - "User had a negative experience with Docker networking in previous job"
751
797
 
752
- If there are no new long-term facts to extract, respond with <memories></memories>
798
+ **Requirements:**
799
+ - Must include WHO did WHAT, WHEN/WHERE
800
+ - Must be a specific, concrete event (not a pattern)
801
+ - Must have significant impact or relevance to future work
802
+
803
+ ## 2. SEMANTIC Memory
804
+ General facts, concepts, knowledge, and established truths about the user.
805
+ **Examples:**
806
+ - "User is a senior backend engineer with 8 years experience"
807
+ - "User specializes in distributed systems and microservices architecture"
808
+ - "User's primary programming language is TypeScript"
809
+ - "User works at Acme Corp as technical lead"
810
+
811
+ **Requirements:**
812
+ - Must be factual, timeless information
813
+ - Must be explicitly stated or demonstrated conclusively
814
+ - No speculation or inference from single instances
815
+ - Core identity, expertise, or knowledge only
816
+
817
+ ## 3. PROCEDURAL Memory
818
+ Skills, workflows, methodologies, and how-to knowledge.
819
+ **Examples:**
820
+ - "User follows strict TDD workflow: write tests first, then implementation"
821
+ - "User prefers git rebase over merge to maintain linear history"
822
+ - "User's debugging process: check logs → reproduce locally → binary search"
823
+ - "User always writes JSDoc comments before implementing functions"
824
+
825
+ **Requirements:**
826
+ - Must describe HOW user does something
827
+ - Must be a repeated, consistent pattern (seen 3+ times or explicitly stated as standard practice)
828
+ - Must be a workflow, methodology, or skill application
829
+ - Not one-off preferences
830
+
831
+ # ULTRA-STRICT EXTRACTION CRITERIA
832
+
833
+ ## ✅ DO EXTRACT (Only These):
834
+
835
+ **EPISODIC:**
836
+ - Significant completed projects or milestones
837
+ - Important bugs, incidents, or problems encountered
838
+ - Major decisions made with lasting impact
839
+ - Formative experiences that shape future work
840
+
841
+ **SEMANTIC:**
842
+ - Professional identity (role, title, company)
843
+ - Core expertise and specializations (stated explicitly or demonstrated conclusively)
844
+ - Primary languages, frameworks, or tools (not exploratory use)
845
+ - Established facts about their work context
846
+
847
+ **PROCEDURAL:**
848
+ - Consistent workflows demonstrated 3+ times or explicitly stated
849
+ - Standard practices user always follows
850
+ - Methodology preferences with clear rationale
851
+ - Debugging, testing, or development processes
852
+
853
+ ## ❌ NEVER EXTRACT:
854
+
855
+ - **One-time requests or tasks** (e.g., "can you generate an image", "help me debug this")
856
+ - **Casual conversations** without lasting significance
857
+ - **Exploratory questions** (e.g., "how does X work?")
858
+ - **Temporary context** (current bug, today's task)
859
+ - **Preferences from single occurrence** (e.g., user asked for code once)
860
+ - **Social pleasantries** (thank you, greetings)
861
+ - **Testing or experimentation** (trying out a feature)
862
+ - **Common patterns everyone has** (likes clear explanations)
863
+ - **Situational information** (working on feature X today)
864
+ - **Opinions without persistence** (single complaint, isolated praise)
865
+ - **General knowledge** (not specific to user)
866
+
867
+ # Quality Gates (ALL Must Pass)
868
+
869
+ 1. **Significance Test**: Will this matter in 3+ months?
870
+ 2. **Specificity Test**: Is this concrete and actionable?
871
+ 3. **Evidence Test**: Is there strong evidence (3+ instances OR explicit self-identification)?
872
+ 4. **Uniqueness Test**: Is this specific to THIS user (not generic)?
873
+ 5. **Confidence Test**: Confidence must be >= 0.85 (be VERY conservative)
874
+ 6. **Non-Redundancy Test**: Does this add NEW information not in existing memories?
875
+
876
+ # Confidence Scoring (Be Conservative)
877
+
878
+ - **0.95-1.0**: User explicitly stated as core identity/practice AND demonstrated multiple times
879
+ - **0.85-0.94**: User explicitly stated OR consistently demonstrated 5+ times
880
+ - **0.75-0.84**: Strong pattern (3-4 instances) with supporting context
881
+ - **Below 0.75**: DO NOT EXTRACT (insufficient evidence)
882
+
883
+ # Critical Instructions
884
+
885
+ 1. **Default to NOT extracting** - When in doubt, skip it
886
+ 2. **Require overwhelming evidence** - One or two mentions is NOT enough
887
+ 3. **Focus on what's PERSISTENT** - Not what's temporary or situational
888
+ 4. **Verify against existing memories** - Don't duplicate or contradict
889
+ 5. **Maximum 2-3 extractions per run** - Quality over quantity
890
+
891
+ **If there are no qualifying facts (which is common), respond with <memories></memories>**
892
+
893
+ # Response Format
753
894
 
754
- Respond in this XML format:
755
895
  <memories>
756
896
  <memory>
757
- <category>identity</category>
758
- <content>User is a software engineer specializing in backend development</content>
897
+ <category>semantic</category>
898
+ <content>User is a senior TypeScript developer with 8 years of backend experience</content>
759
899
  <confidence>0.95</confidence>
760
900
  </memory>
761
901
  <memory>
762
- <category>preferences</category>
763
- <content>Prefers code examples over lengthy explanations</content>
764
- <confidence>0.85</confidence>
902
+ <category>procedural</category>
903
+ <content>User follows TDD workflow: writes tests before implementation, runs tests after each change</content>
904
+ <confidence>0.88</confidence>
905
+ </memory>
906
+ <memory>
907
+ <category>episodic</category>
908
+ <content>User led database migration from MongoDB to PostgreSQL for payment system in Q2 2024</content>
909
+ <confidence>0.92</confidence>
765
910
  </memory>
766
911
  </memories>`;
767
912
  function parseMemoryExtractionXML(xml) {
@@ -850,7 +995,7 @@ var longTermExtractionEvaluator = {
850
995
  const extractions = parseMemoryExtractionXML(response);
851
996
  logger3.info(`Extracted ${extractions.length} long-term memories`);
852
997
  for (const extraction of extractions) {
853
- if (extraction.confidence >= config.longTermConfidenceThreshold) {
998
+ if (extraction.confidence >= Math.max(config.longTermConfidenceThreshold, 0.85)) {
854
999
  await memoryService.storeLongTermMemory({
855
1000
  agentId: runtime.agentId,
856
1001
  entityId,
@@ -865,7 +1010,7 @@ var longTermExtractionEvaluator = {
865
1010
  });
866
1011
  logger3.info(`Stored long-term memory: [${extraction.category}] ${extraction.content.substring(0, 50)}...`);
867
1012
  } else {
868
- logger3.debug(`Skipped low-confidence memory: ${extraction.content} (confidence: ${extraction.confidence})`);
1013
+ logger3.debug(`Skipped low-confidence memory: ${extraction.content} (confidence: ${extraction.confidence}, threshold: ${Math.max(config.longTermConfidenceThreshold, 0.85)})`);
869
1014
  }
870
1015
  }
871
1016
  const currentMessageCount = await runtime.countMemories(roomId, false, "messages");
@@ -887,26 +1032,31 @@ import {
887
1032
  getEntityDetails,
888
1033
  logger as logger4
889
1034
  } from "@elizaos/core";
1035
+ var getRecentInteractions = async (runtime, sourceEntityId, targetEntityId, excludeRoomId) => {
1036
+ const rooms = await runtime.getRoomsForParticipants([sourceEntityId, targetEntityId]);
1037
+ return runtime.getMemoriesByRoomIds({
1038
+ tableName: "messages",
1039
+ roomIds: rooms.filter((room) => room !== excludeRoomId),
1040
+ limit: 20
1041
+ });
1042
+ };
890
1043
  var shortTermMemoryProvider = {
891
1044
  name: "SHORT_TERM_MEMORY",
892
- description: "Adaptive conversation context with smart summarization",
1045
+ description: "Unified conversation context with smart summarization and interactions",
893
1046
  position: 95,
894
1047
  get: async (runtime, message, _state) => {
895
1048
  try {
896
1049
  const memoryService = runtime.getService("memory");
897
- if (!memoryService) {
898
- return {
899
- data: { summaries: [], recentMessages: [], mode: "disabled" },
900
- values: {},
901
- text: ""
902
- };
903
- }
904
1050
  const { roomId } = message;
905
- const config = memoryService.getConfig();
1051
+ const conversationLength = 16;
1052
+ const config = memoryService?.getConfig() || {
1053
+ shortTermSummarizationThreshold: 16,
1054
+ shortTermRetainRecent: 6
1055
+ };
906
1056
  const totalMessageCount = await runtime.countMemories(roomId, false, "messages");
907
- if (totalMessageCount < config.shortTermSummarizationThreshold) {
908
- const conversationLength = runtime.getConversationLength();
909
- const [entitiesData, room, recentMessagesData] = await Promise.all([
1057
+ const useSummarization = memoryService && totalMessageCount >= config.shortTermSummarizationThreshold;
1058
+ if (!useSummarization) {
1059
+ const [entitiesData, room, recentMessagesData, recentInteractionsData] = await Promise.all([
910
1060
  getEntityDetails({ runtime, roomId }),
911
1061
  runtime.getRoom(roomId),
912
1062
  runtime.getMemories({
@@ -914,7 +1064,8 @@ var shortTermMemoryProvider = {
914
1064
  roomId,
915
1065
  count: conversationLength,
916
1066
  unique: false
917
- })
1067
+ }),
1068
+ message.entityId !== runtime.agentId ? getRecentInteractions(runtime, message.entityId, runtime.agentId, roomId) : Promise.resolve([])
918
1069
  ]);
919
1070
  const actionResultMessages = recentMessagesData.filter((msg) => msg.content?.type === "action_result" && msg.metadata?.type === "action_result");
920
1071
  const dialogueMessages = recentMessagesData.filter((msg) => !(msg.content?.type === "action_result" && msg.metadata?.type === "action_result"));
@@ -930,6 +1081,20 @@ var shortTermMemoryProvider = {
930
1081
  conversationHeader: false
931
1082
  })
932
1083
  ]);
1084
+ const formatConversationLog = (messages, includeThoughts) => {
1085
+ return messages.sort((a, b) => (a.createdAt || 0) - (b.createdAt || 0)).map((msg) => {
1086
+ const entity = entitiesData.find((e) => e.id === msg.entityId);
1087
+ const entityName = entity?.names[0] || (msg.entityId === runtime.agentId ? runtime.character.name : "Unknown");
1088
+ const timestamp4 = msg.createdAt ? new Date(msg.createdAt).toLocaleString() : "Unknown time";
1089
+ const text5 = msg.content.text || "";
1090
+ const thought = includeThoughts && msg.content.internalMonologue ? `
1091
+ [Internal thought: ${msg.content.internalMonologue}]` : "";
1092
+ return `[${timestamp4}] ${entityName}: ${text5}${thought}`;
1093
+ }).join(`
1094
+ `);
1095
+ };
1096
+ const conversationLog = formatConversationLog(dialogueMessages, false);
1097
+ const conversationLogWithAgentThoughts = formatConversationLog(dialogueMessages, true);
933
1098
  let actionResultsText = "";
934
1099
  if (actionResultMessages.length > 0) {
935
1100
  const groupedByRun = new Map;
@@ -938,7 +1103,10 @@ var shortTermMemoryProvider = {
938
1103
  if (!groupedByRun.has(runId)) {
939
1104
  groupedByRun.set(runId, []);
940
1105
  }
941
- groupedByRun.get(runId)?.push(mem);
1106
+ const memories = groupedByRun.get(runId);
1107
+ if (memories) {
1108
+ memories.push(mem);
1109
+ }
942
1110
  }
943
1111
  const formattedActionResults = Array.from(groupedByRun.entries()).slice(-3).map(([runId, memories]) => {
944
1112
  const sortedMemories = memories.sort((a, b) => (a.createdAt || 0) - (b.createdAt || 0));
@@ -974,11 +1142,20 @@ ${runText}`;
974
1142
  data: {
975
1143
  summaries: [],
976
1144
  recentMessages: [],
1145
+ recentInteractions: [],
977
1146
  actionResults: [],
978
1147
  mode: "full_conversation"
979
1148
  },
980
1149
  values: {
981
- recentMessage: "No recent message available."
1150
+ recentPosts: "",
1151
+ recentMessages: "",
1152
+ recentMessageInteractions: "",
1153
+ recentPostInteractions: "",
1154
+ recentInteractions: "",
1155
+ recentActionResults: "",
1156
+ recentMessage: "No recent message available.",
1157
+ conversationLog: "",
1158
+ conversationLogWithAgentThoughts: ""
982
1159
  },
983
1160
  text: "No recent messages available"
984
1161
  };
@@ -1000,6 +1177,80 @@ ${runText}`;
1000
1177
  const hasReceivedMessage = !!receivedMessageContent?.trim();
1001
1178
  const receivedMessageHeader = hasReceivedMessage ? addHeader("# Received Message", `${senderName}: ${receivedMessageContent}`) : "";
1002
1179
  const focusHeader = hasReceivedMessage ? addHeader("# Focus your response", `You are replying to the above message from **${senderName}**. Keep your answer relevant to that message. Do not repeat earlier replies unless the sender asks again.`) : "";
1180
+ const interactionEntityMap = new Map;
1181
+ if (recentInteractionsData.length > 0) {
1182
+ const uniqueEntityIds = [
1183
+ ...new Set(recentInteractionsData.map((message2) => message2.entityId).filter((id) => id !== runtime.agentId))
1184
+ ];
1185
+ const uniqueEntityIdSet = new Set(uniqueEntityIds);
1186
+ const entitiesDataIdSet = new Set;
1187
+ entitiesData.forEach((entity) => {
1188
+ if (uniqueEntityIdSet.has(entity.id)) {
1189
+ interactionEntityMap.set(entity.id, entity);
1190
+ entitiesDataIdSet.add(entity.id);
1191
+ }
1192
+ });
1193
+ const remainingEntityIds = uniqueEntityIds.filter((id) => !entitiesDataIdSet.has(id));
1194
+ if (remainingEntityIds.length > 0) {
1195
+ const entities = await Promise.all(remainingEntityIds.map((entityId) => runtime.getEntityById(entityId)));
1196
+ entities.forEach((entity, index4) => {
1197
+ if (entity) {
1198
+ interactionEntityMap.set(remainingEntityIds[index4], entity);
1199
+ }
1200
+ });
1201
+ }
1202
+ }
1203
+ const getRecentMessageInteractions = async (recentInteractionsData2) => {
1204
+ const formattedInteractions = recentInteractionsData2.map((message2) => {
1205
+ const isSelf = message2.entityId === runtime.agentId;
1206
+ let sender;
1207
+ if (isSelf) {
1208
+ sender = runtime.character.name;
1209
+ } else {
1210
+ sender = interactionEntityMap.get(message2.entityId)?.metadata?.userName || "unknown";
1211
+ }
1212
+ return `${sender}: ${message2.content.text}`;
1213
+ });
1214
+ return formattedInteractions.join(`
1215
+ `);
1216
+ };
1217
+ const getRecentPostInteractions = async (recentInteractionsData2, entities) => {
1218
+ const combinedEntities = [...entities];
1219
+ const actorIds = new Set(entities.map((entity) => entity.id));
1220
+ for (const [id, entity] of interactionEntityMap.entries()) {
1221
+ if (!actorIds.has(id)) {
1222
+ combinedEntities.push(entity);
1223
+ }
1224
+ }
1225
+ const formattedInteractions = formatPosts({
1226
+ messages: recentInteractionsData2,
1227
+ entities: combinedEntities,
1228
+ conversationHeader: true
1229
+ });
1230
+ return formattedInteractions;
1231
+ };
1232
+ const [recentMessageInteractions, recentPostInteractions] = await Promise.all([
1233
+ getRecentMessageInteractions(recentInteractionsData),
1234
+ getRecentPostInteractions(recentInteractionsData, entitiesData)
1235
+ ]);
1236
+ const data = {
1237
+ summaries: [],
1238
+ recentMessages: dialogueMessages,
1239
+ recentInteractions: recentInteractionsData,
1240
+ actionResults: actionResultMessages,
1241
+ mode: "full_conversation"
1242
+ };
1243
+ const values = {
1244
+ recentPosts,
1245
+ recentMessages,
1246
+ recentMessageInteractions,
1247
+ recentPostInteractions,
1248
+ recentInteractions: isPostFormat ? recentPostInteractions : recentMessageInteractions,
1249
+ recentActionResults: actionResultsText,
1250
+ recentMessage,
1251
+ conversationLog,
1252
+ conversationLogWithAgentThoughts
1253
+ };
1003
1254
  const text4 = [
1004
1255
  isPostFormat ? recentPosts : recentMessages,
1005
1256
  actionResultsText,
@@ -1009,40 +1260,68 @@ ${runText}`;
1009
1260
 
1010
1261
  `);
1011
1262
  return {
1012
- data: {
1013
- summaries: [],
1014
- recentMessages: dialogueMessages,
1015
- actionResults: actionResultMessages,
1016
- mode: "full_conversation"
1017
- },
1018
- values: {
1019
- ...(isPostFormat ? recentPosts : recentMessages) && {
1020
- recentMessages: isPostFormat ? recentPosts : recentMessages
1021
- },
1022
- ...recentPosts && { recentPosts },
1023
- ...actionResultsText && { recentActionResults: actionResultsText },
1024
- ...recentMessage && { recentMessage },
1025
- ...receivedMessageHeader && { receivedMessageHeader },
1026
- ...focusHeader && { focusHeader }
1027
- },
1263
+ data,
1264
+ values,
1028
1265
  text: text4
1029
1266
  };
1030
1267
  } else {
1031
1268
  const currentSummary = await memoryService.getCurrentSessionSummary(roomId);
1032
1269
  const lastOffset = currentSummary?.lastMessageOffset || 0;
1033
- const unsummarizedMessages = await runtime.getMemories({
1034
- tableName: "messages",
1035
- roomId,
1036
- count: config.shortTermRetainRecent,
1037
- unique: false,
1038
- start: lastOffset
1039
- });
1040
- const entitiesData = await getEntityDetails({ runtime, roomId });
1041
- const room = await runtime.getRoom(roomId);
1270
+ const recentCount = config.shortTermRetainRecent;
1271
+ const [entitiesData, room, unsummarizedMessages, recentInteractionsData] = await Promise.all([
1272
+ getEntityDetails({ runtime, roomId }),
1273
+ runtime.getRoom(roomId),
1274
+ runtime.getMemories({
1275
+ tableName: "messages",
1276
+ roomId,
1277
+ count: recentCount,
1278
+ unique: false,
1279
+ start: lastOffset
1280
+ }),
1281
+ message.entityId !== runtime.agentId ? getRecentInteractions(runtime, message.entityId, runtime.agentId, roomId) : Promise.resolve([])
1282
+ ]);
1042
1283
  const isPostFormat = room?.type ? room.type === ChannelType.FEED || room.type === ChannelType.THREAD : false;
1284
+ const actionResultMessages = unsummarizedMessages.filter((msg) => msg.content?.type === "action_result" && msg.metadata?.type === "action_result");
1285
+ const dialogueMessages = unsummarizedMessages.filter((msg) => !(msg.content?.type === "action_result" && msg.metadata?.type === "action_result"));
1286
+ let actionResultsText = "";
1287
+ if (actionResultMessages.length > 0) {
1288
+ const groupedByRun = new Map;
1289
+ for (const mem of actionResultMessages) {
1290
+ const runId = String(mem.content?.runId || "unknown");
1291
+ if (!groupedByRun.has(runId)) {
1292
+ groupedByRun.set(runId, []);
1293
+ }
1294
+ groupedByRun.get(runId)?.push(mem);
1295
+ }
1296
+ const formattedActionResults = Array.from(groupedByRun.entries()).slice(-3).map(([runId, memories]) => {
1297
+ const sortedMemories = memories.sort((a, b) => (a.createdAt || 0) - (b.createdAt || 0));
1298
+ const thought = sortedMemories[0]?.content?.planThought || "";
1299
+ const runText = sortedMemories.map((mem) => {
1300
+ const actionName = mem.content?.actionName || "Unknown";
1301
+ const status = mem.content?.actionStatus || "unknown";
1302
+ const planStep = mem.content?.planStep || "";
1303
+ const text5 = mem.content?.text || "";
1304
+ const error = mem.content?.error || "";
1305
+ let memText = ` - ${actionName} (${status})`;
1306
+ if (planStep)
1307
+ memText += ` [${planStep}]`;
1308
+ if (error) {
1309
+ memText += `: Error - ${error}`;
1310
+ } else if (text5 && text5 !== `Executed action: ${actionName}`) {
1311
+ memText += `: ${text5}`;
1312
+ }
1313
+ return memText;
1314
+ }).join(`
1315
+ `);
1316
+ return `**Action Run ${runId.slice(0, 8)}**${thought ? ` - "${thought}"` : ""}
1317
+ ${runText}`;
1318
+ }).join(`
1319
+
1320
+ `);
1321
+ actionResultsText = formattedActionResults ? addHeader("# Recent Action Executions", formattedActionResults) : "";
1322
+ }
1043
1323
  let recentMessagesText = "";
1044
- if (unsummarizedMessages.length > 0) {
1045
- const dialogueMessages = unsummarizedMessages.filter((msg) => !(msg.content?.type === "action_result" && msg.metadata?.type === "action_result"));
1324
+ if (dialogueMessages.length > 0) {
1046
1325
  if (isPostFormat) {
1047
1326
  recentMessagesText = formatPosts({
1048
1327
  messages: dialogueMessages,
@@ -1059,6 +1338,31 @@ ${runText}`;
1059
1338
  recentMessagesText = addHeader("# Recent Messages", recentMessagesText);
1060
1339
  }
1061
1340
  }
1341
+ let recentMessage = "No recent message available.";
1342
+ if (dialogueMessages.length > 0) {
1343
+ const mostRecentMessage = [...dialogueMessages].sort((a, b) => (b.createdAt || 0) - (a.createdAt || 0))[0];
1344
+ const formattedSingleMessage = formatMessages({
1345
+ messages: [mostRecentMessage],
1346
+ entities: entitiesData
1347
+ });
1348
+ if (formattedSingleMessage) {
1349
+ recentMessage = formattedSingleMessage;
1350
+ }
1351
+ }
1352
+ const formatConversationLog = (messages, includeThoughts) => {
1353
+ return messages.sort((a, b) => (a.createdAt || 0) - (b.createdAt || 0)).map((msg) => {
1354
+ const entity = entitiesData.find((e) => e.id === msg.entityId);
1355
+ const entityName = entity?.names[0] || (msg.entityId === runtime.agentId ? runtime.character.name : "Unknown");
1356
+ const timestamp4 = msg.createdAt ? new Date(msg.createdAt).toLocaleString() : "Unknown time";
1357
+ const text5 = msg.content.text || "";
1358
+ const thought = includeThoughts && msg.content.internalMonologue ? `
1359
+ [Internal thought: ${msg.content.internalMonologue}]` : "";
1360
+ return `[${timestamp4}] ${entityName}: ${text5}${thought}`;
1361
+ }).join(`
1362
+ `);
1363
+ };
1364
+ const conversationLog = formatConversationLog(dialogueMessages, false);
1365
+ const conversationLogWithAgentThoughts = formatConversationLog(dialogueMessages, true);
1062
1366
  let summaryText = "";
1063
1367
  if (currentSummary) {
1064
1368
  const messageRange = `${currentSummary.messageCount} messages`;
@@ -1078,9 +1382,66 @@ ${runText}`;
1078
1382
  const hasReceivedMessage = !!receivedMessageContent?.trim();
1079
1383
  const receivedMessageHeader = hasReceivedMessage ? addHeader("# Received Message", `${senderName}: ${receivedMessageContent}`) : "";
1080
1384
  const focusHeader = hasReceivedMessage ? addHeader("# Focus your response", `You are replying to the above message from **${senderName}**. Keep your answer relevant to that message.`) : "";
1385
+ const interactionEntityMap = new Map;
1386
+ if (recentInteractionsData.length > 0) {
1387
+ const uniqueEntityIds = [
1388
+ ...new Set(recentInteractionsData.map((message2) => message2.entityId).filter((id) => id !== runtime.agentId))
1389
+ ];
1390
+ const uniqueEntityIdSet = new Set(uniqueEntityIds);
1391
+ const entitiesDataIdSet = new Set;
1392
+ entitiesData.forEach((entity) => {
1393
+ if (uniqueEntityIdSet.has(entity.id)) {
1394
+ interactionEntityMap.set(entity.id, entity);
1395
+ entitiesDataIdSet.add(entity.id);
1396
+ }
1397
+ });
1398
+ const remainingEntityIds = uniqueEntityIds.filter((id) => !entitiesDataIdSet.has(id));
1399
+ if (remainingEntityIds.length > 0) {
1400
+ const entities = await Promise.all(remainingEntityIds.map((entityId) => runtime.getEntityById(entityId)));
1401
+ entities.forEach((entity, index4) => {
1402
+ if (entity) {
1403
+ interactionEntityMap.set(remainingEntityIds[index4], entity);
1404
+ }
1405
+ });
1406
+ }
1407
+ }
1408
+ const getRecentMessageInteractions = async (recentInteractionsData2) => {
1409
+ const formattedInteractions = recentInteractionsData2.map((message2) => {
1410
+ const isSelf = message2.entityId === runtime.agentId;
1411
+ let sender;
1412
+ if (isSelf) {
1413
+ sender = runtime.character.name;
1414
+ } else {
1415
+ sender = interactionEntityMap.get(message2.entityId)?.metadata?.userName || "unknown";
1416
+ }
1417
+ return `${sender}: ${message2.content.text}`;
1418
+ });
1419
+ return formattedInteractions.join(`
1420
+ `);
1421
+ };
1422
+ const getRecentPostInteractions = async (recentInteractionsData2, entities) => {
1423
+ const combinedEntities = [...entities];
1424
+ const actorIds = new Set(entities.map((entity) => entity.id));
1425
+ for (const [id, entity] of interactionEntityMap.entries()) {
1426
+ if (!actorIds.has(id)) {
1427
+ combinedEntities.push(entity);
1428
+ }
1429
+ }
1430
+ const formattedInteractions = formatPosts({
1431
+ messages: recentInteractionsData2,
1432
+ entities: combinedEntities,
1433
+ conversationHeader: true
1434
+ });
1435
+ return formattedInteractions;
1436
+ };
1437
+ const [recentMessageInteractions, recentPostInteractions] = await Promise.all([
1438
+ getRecentMessageInteractions(recentInteractionsData),
1439
+ getRecentPostInteractions(recentInteractionsData, entitiesData)
1440
+ ]);
1081
1441
  const text4 = [
1082
1442
  summaryText,
1083
1443
  recentMessagesText,
1444
+ actionResultsText,
1084
1445
  hasReceivedMessage ? receivedMessageHeader : "",
1085
1446
  hasReceivedMessage ? focusHeader : ""
1086
1447
  ].filter(Boolean).join(`
@@ -1089,12 +1450,21 @@ ${runText}`;
1089
1450
  return {
1090
1451
  data: {
1091
1452
  summaries: currentSummary ? [currentSummary] : [],
1092
- recentMessages: unsummarizedMessages,
1453
+ recentMessages: dialogueMessages,
1454
+ recentInteractions: recentInteractionsData,
1455
+ actionResults: actionResultMessages,
1093
1456
  mode: "summarized"
1094
1457
  },
1095
1458
  values: {
1096
1459
  ...summaryText && { sessionSummaries: summaryText },
1097
1460
  ...recentMessagesText && { recentMessages: recentMessagesText },
1461
+ recentMessageInteractions,
1462
+ recentPostInteractions,
1463
+ recentInteractions: isPostFormat ? recentPostInteractions : recentMessageInteractions,
1464
+ ...actionResultsText && { recentActionResults: actionResultsText },
1465
+ recentMessage,
1466
+ conversationLog,
1467
+ conversationLogWithAgentThoughts,
1098
1468
  ...receivedMessageHeader && { receivedMessageHeader },
1099
1469
  ...focusHeader && { focusHeader }
1100
1470
  },
@@ -1104,8 +1474,23 @@ ${runText}`;
1104
1474
  } catch (error) {
1105
1475
  logger4.error({ error }, "Error in shortTermMemoryProvider:");
1106
1476
  return {
1107
- data: { summaries: [], recentMessages: [], mode: "error" },
1108
- values: {},
1477
+ data: {
1478
+ summaries: [],
1479
+ recentMessages: [],
1480
+ recentInteractions: [],
1481
+ actionResults: [],
1482
+ mode: "error"
1483
+ },
1484
+ values: {
1485
+ recentPosts: "",
1486
+ recentMessages: "",
1487
+ recentMessageInteractions: "",
1488
+ recentPostInteractions: "",
1489
+ recentInteractions: "",
1490
+ recentActionResults: "",
1491
+ conversationLog: "",
1492
+ conversationLogWithAgentThoughts: ""
1493
+ },
1109
1494
  text: "Error retrieving conversation context."
1110
1495
  };
1111
1496
  }
@@ -1197,4 +1582,4 @@ export {
1197
1582
  LongTermMemoryCategory
1198
1583
  };
1199
1584
 
1200
- //# debugId=C168790F41A1B4EE64756E2164756E21
1585
+ //# debugId=B1C29E71DE6182A064756E2164756E21