@elizaos/plugin-memory 1.0.5 → 1.0.7

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.
@@ -30,10 +30,13 @@ var __export = (target, all) => {
30
30
  var exports_index_node = {};
31
31
  __export(exports_index_node, {
32
32
  sessionSummaries: () => sessionSummaries,
33
+ recentMessagesProvider: () => recentMessagesProvider,
33
34
  memoryPlugin: () => memoryPlugin,
34
35
  memoryAccessLogs: () => memoryAccessLogs,
36
+ longTermMemoryProvider: () => longTermMemoryProvider,
35
37
  longTermMemories: () => longTermMemories,
36
38
  default: () => src_default,
39
+ contextSummaryProvider: () => contextSummaryProvider,
37
40
  MemoryService: () => MemoryService,
38
41
  LongTermMemoryCategory: () => LongTermMemoryCategory
39
42
  });
@@ -127,13 +130,13 @@ class MemoryService extends import_core.Service {
127
130
  this.lastExtractionCheckpoints = new Map;
128
131
  this.memoryConfig = {
129
132
  shortTermSummarizationThreshold: 16,
130
- shortTermRetainRecent: 10,
133
+ shortTermRetainRecent: 6,
131
134
  shortTermSummarizationInterval: 10,
132
135
  longTermExtractionEnabled: true,
133
136
  longTermVectorSearchEnabled: false,
134
- longTermConfidenceThreshold: 0.7,
135
- longTermExtractionThreshold: 20,
136
- longTermExtractionInterval: 5,
137
+ longTermConfidenceThreshold: 0.85,
138
+ longTermExtractionThreshold: 30,
139
+ longTermExtractionInterval: 10,
137
140
  summaryModelType: "TEXT_LARGE",
138
141
  summaryMaxTokens: 2500,
139
142
  summaryMaxNewMessages: 20
@@ -183,7 +186,7 @@ class MemoryService extends import_core.Service {
183
186
  if (extractionInterval) {
184
187
  this.memoryConfig.longTermExtractionInterval = parseInt(extractionInterval, 10);
185
188
  }
186
- import_core.logger.info({
189
+ import_core.logger.debug({
187
190
  summarizationThreshold: this.memoryConfig.shortTermSummarizationThreshold,
188
191
  summarizationInterval: this.memoryConfig.shortTermSummarizationInterval,
189
192
  maxNewMessages: this.memoryConfig.summaryMaxNewMessages,
@@ -540,6 +543,16 @@ ${items}`);
540
543
 
541
544
  // src/evaluators/summarization.ts
542
545
  var import_core2 = require("@elizaos/core");
546
+ async function getDialogueMessageCount(runtime, roomId) {
547
+ const messages = await runtime.getMemories({
548
+ tableName: "messages",
549
+ roomId,
550
+ count: 100,
551
+ unique: false
552
+ });
553
+ const dialogueMessages = messages.filter((msg) => !(msg.content?.type === "action_result" && msg.metadata?.type === "action_result") && (msg.metadata?.type === "agent_response_message" || msg.metadata?.type === "user_message"));
554
+ return dialogueMessages.length;
555
+ }
543
556
  var initialSummarizationTemplate = `# Task: Summarize Conversation
544
557
 
545
558
  You are analyzing a conversation to create a concise summary that captures the key points, topics, and important details.
@@ -627,26 +640,26 @@ var summarizationEvaluator = {
627
640
  return false;
628
641
  }
629
642
  const config = memoryService.getConfig();
630
- const currentMessageCount = await runtime.countMemories(message.roomId, false, "messages");
643
+ const currentDialogueCount = await getDialogueMessageCount(runtime, message.roomId);
631
644
  const existingSummary = await memoryService.getCurrentSessionSummary(message.roomId);
632
645
  if (!existingSummary) {
633
- const shouldSummarize = currentMessageCount >= config.shortTermSummarizationThreshold;
646
+ const shouldSummarize = currentDialogueCount >= config.shortTermSummarizationThreshold;
634
647
  import_core2.logger.debug({
635
648
  roomId: message.roomId,
636
- currentMessageCount,
649
+ currentDialogueCount,
637
650
  threshold: config.shortTermSummarizationThreshold,
638
651
  shouldSummarize,
639
652
  reason: "initial_summary_check"
640
653
  }, "Summarization validation check");
641
654
  return shouldSummarize;
642
655
  } else {
643
- const newMessageCount = currentMessageCount - existingSummary.lastMessageOffset;
644
- const shouldUpdate = newMessageCount >= config.shortTermSummarizationInterval;
656
+ const newDialogueCount = currentDialogueCount - existingSummary.lastMessageOffset;
657
+ const shouldUpdate = newDialogueCount >= config.shortTermSummarizationInterval;
645
658
  import_core2.logger.debug({
646
659
  roomId: message.roomId,
647
- currentMessageCount,
660
+ currentDialogueCount,
648
661
  lastOffset: existingSummary.lastMessageOffset,
649
- newMessageCount,
662
+ newDialogueCount,
650
663
  interval: config.shortTermSummarizationInterval,
651
664
  shouldUpdate,
652
665
  reason: "summary_update_check"
@@ -666,30 +679,31 @@ var summarizationEvaluator = {
666
679
  import_core2.logger.info(`Starting summarization for room ${roomId}`);
667
680
  const existingSummary = await memoryService.getCurrentSessionSummary(roomId);
668
681
  const lastOffset = existingSummary?.lastMessageOffset || 0;
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
- }
680
- const newMessages = await runtime.getMemories({
682
+ const allMessages = await runtime.getMemories({
681
683
  tableName: "messages",
682
684
  roomId,
683
- count: messagesToFetch,
684
- unique: false,
685
- start: lastOffset
685
+ count: 1000,
686
+ unique: false
686
687
  });
687
- if (newMessages.length === 0) {
688
- import_core2.logger.debug("No new messages retrieved");
688
+ const allDialogueMessages = allMessages.filter((msg) => !(msg.content?.type === "action_result" && msg.metadata?.type === "action_result") && (msg.metadata?.type === "agent_response_message" || msg.metadata?.type === "user_message"));
689
+ const totalDialogueCount = allDialogueMessages.length;
690
+ const newDialogueCount = totalDialogueCount - lastOffset;
691
+ if (newDialogueCount === 0) {
692
+ import_core2.logger.debug("No new dialogue messages to summarize");
689
693
  return;
690
694
  }
691
- const sortedMessages = newMessages.sort((a, b) => (a.createdAt || 0) - (b.createdAt || 0));
692
- const formattedMessages = sortedMessages.map((msg) => {
695
+ const maxNewMessages = config.summaryMaxNewMessages || 50;
696
+ const messagesToProcess = Math.min(newDialogueCount, maxNewMessages);
697
+ if (newDialogueCount > maxNewMessages) {
698
+ import_core2.logger.warn(`Capping new dialogue messages at ${maxNewMessages} (${newDialogueCount} available). Oldest messages will be skipped.`);
699
+ }
700
+ const sortedDialogueMessages = allDialogueMessages.sort((a, b) => (a.createdAt || 0) - (b.createdAt || 0));
701
+ const newDialogueMessages = sortedDialogueMessages.slice(lastOffset, lastOffset + messagesToProcess);
702
+ if (newDialogueMessages.length === 0) {
703
+ import_core2.logger.debug("No new dialogue messages retrieved after filtering");
704
+ return;
705
+ }
706
+ const formattedMessages = newDialogueMessages.map((msg) => {
693
707
  const sender = msg.entityId === runtime.agentId ? runtime.character.name : "User";
694
708
  return `${sender}: ${msg.content.text || "[non-text message]"}`;
695
709
  }).join(`
@@ -709,11 +723,16 @@ var summarizationEvaluator = {
709
723
  template
710
724
  });
711
725
  } else {
726
+ const initialMessages = sortedDialogueMessages.map((msg) => {
727
+ const sender = msg.entityId === runtime.agentId ? runtime.character.name : "User";
728
+ return `${sender}: ${msg.content.text || "[non-text message]"}`;
729
+ }).join(`
730
+ `);
712
731
  template = initialSummarizationTemplate;
713
732
  prompt = import_core2.composePromptFromState({
714
733
  state: {
715
734
  ...state,
716
- recentMessages: formattedMessages
735
+ recentMessages: initialMessages
717
736
  },
718
737
  template
719
738
  });
@@ -724,15 +743,15 @@ var summarizationEvaluator = {
724
743
  });
725
744
  const summaryResult = parseSummaryXML(response);
726
745
  import_core2.logger.info(`${existingSummary ? "Updated" : "Generated"} summary: ${summaryResult.summary.substring(0, 100)}...`);
727
- const newOffset = totalMessageCount;
728
- const firstMessage = sortedMessages[0];
729
- const lastMessage = sortedMessages[sortedMessages.length - 1];
746
+ const newOffset = lastOffset + newDialogueMessages.length;
747
+ const firstMessage = newDialogueMessages[0];
748
+ const lastMessage = newDialogueMessages[newDialogueMessages.length - 1];
730
749
  const startTime = existingSummary ? existingSummary.startTime : firstMessage?.createdAt && firstMessage.createdAt > 0 ? new Date(firstMessage.createdAt) : new Date;
731
750
  const endTime = lastMessage?.createdAt && lastMessage.createdAt > 0 ? new Date(lastMessage.createdAt) : new Date;
732
751
  if (existingSummary) {
733
752
  await memoryService.updateSessionSummary(existingSummary.id, roomId, {
734
753
  summary: summaryResult.summary,
735
- messageCount: existingSummary.messageCount + sortedMessages.length,
754
+ messageCount: existingSummary.messageCount + newDialogueMessages.length,
736
755
  lastMessageOffset: newOffset,
737
756
  endTime,
738
757
  topics: summaryResult.topics,
@@ -740,15 +759,15 @@ var summarizationEvaluator = {
740
759
  keyPoints: summaryResult.keyPoints
741
760
  }
742
761
  });
743
- import_core2.logger.info(`Updated summary for room ${roomId}: ${sortedMessages.length} new messages processed (offset: ${lastOffset} → ${newOffset})`);
762
+ import_core2.logger.info(`Updated summary for room ${roomId}: ${newDialogueMessages.length} new dialogue messages processed (offset: ${lastOffset} → ${newOffset})`);
744
763
  } else {
745
764
  await memoryService.storeSessionSummary({
746
765
  agentId: runtime.agentId,
747
766
  roomId,
748
767
  entityId: message.entityId !== runtime.agentId ? message.entityId : undefined,
749
768
  summary: summaryResult.summary,
750
- messageCount: sortedMessages.length,
751
- lastMessageOffset: newOffset,
769
+ messageCount: totalDialogueCount,
770
+ lastMessageOffset: totalDialogueCount,
752
771
  startTime,
753
772
  endTime,
754
773
  topics: summaryResult.topics,
@@ -756,7 +775,7 @@ var summarizationEvaluator = {
756
775
  keyPoints: summaryResult.keyPoints
757
776
  }
758
777
  });
759
- import_core2.logger.info(`Created new summary for room ${roomId}: ${sortedMessages.length} messages summarized (offset: 0 → ${newOffset})`);
778
+ import_core2.logger.info(`Created new summary for room ${roomId}: ${totalDialogueCount} dialogue messages summarized (offset: 0 → ${totalDialogueCount})`);
760
779
  }
761
780
  } catch (error) {
762
781
  import_core2.logger.error({ error }, "Error during summarization:");
@@ -771,21 +790,15 @@ var import_core3 = require("@elizaos/core");
771
790
  // src/types/index.ts
772
791
  var LongTermMemoryCategory;
773
792
  ((LongTermMemoryCategory2) => {
774
- LongTermMemoryCategory2["IDENTITY"] = "identity";
775
- LongTermMemoryCategory2["EXPERTISE"] = "expertise";
776
- LongTermMemoryCategory2["PROJECTS"] = "projects";
777
- LongTermMemoryCategory2["PREFERENCES"] = "preferences";
778
- LongTermMemoryCategory2["DATA_SOURCES"] = "data_sources";
779
- LongTermMemoryCategory2["GOALS"] = "goals";
780
- LongTermMemoryCategory2["CONSTRAINTS"] = "constraints";
781
- LongTermMemoryCategory2["DEFINITIONS"] = "definitions";
782
- LongTermMemoryCategory2["BEHAVIORAL_PATTERNS"] = "behavioral_patterns";
793
+ LongTermMemoryCategory2["EPISODIC"] = "episodic";
794
+ LongTermMemoryCategory2["SEMANTIC"] = "semantic";
795
+ LongTermMemoryCategory2["PROCEDURAL"] = "procedural";
783
796
  })(LongTermMemoryCategory ||= {});
784
797
 
785
798
  // src/evaluators/long-term-extraction.ts
786
- var extractionTemplate = `# Task: Extract Long-Term Memory
799
+ var extractionTemplate = `# Task: Extract Long-Term Memory (Strict Criteria)
787
800
 
788
- You are analyzing a conversation to extract ONLY the most important, persistent facts about the user that should be remembered long-term.
801
+ You are analyzing a conversation to extract ONLY the most critical, persistent information about the user using cognitive science memory categories.
789
802
 
790
803
  # Recent Messages
791
804
  {{recentMessages}}
@@ -793,66 +806,127 @@ You are analyzing a conversation to extract ONLY the most important, persistent
793
806
  # Current Long-Term Memories
794
807
  {{existingMemories}}
795
808
 
796
- # Memory Categories
797
- 1. **identity**: User's name, role, identity (e.g., "I'm a data scientist")
798
- 2. **expertise**: User's skills, knowledge domains, or unfamiliarity with topics
799
- 3. **projects**: Ongoing projects, past interactions, recurring topics
800
- 4. **preferences**: Communication style, format preferences, verbosity, etc.
801
- 5. **data_sources**: Frequently used files, databases, APIs
802
- 6. **goals**: Broader intentions (e.g., "preparing for interview")
803
- 7. **constraints**: User-defined rules or limitations
804
- 8. **definitions**: Custom terms, acronyms, glossaries
805
- 9. **behavioral_patterns**: How the user tends to interact
809
+ # Memory Categories (Based on Cognitive Science)
806
810
 
807
- # STRICT EXTRACTION CRITERIA
811
+ ## 1. EPISODIC Memory
812
+ Personal experiences and specific events with temporal/spatial context.
813
+ **Examples:**
814
+ - "User completed migration project from MongoDB to PostgreSQL in Q2 2024"
815
+ - "User encountered authentication bug in production on March 15th"
816
+ - "User had a negative experience with Docker networking in previous job"
808
817
 
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
818
+ **Requirements:**
819
+ - Must include WHO did WHAT, WHEN/WHERE
820
+ - Must be a specific, concrete event (not a pattern)
821
+ - Must have significant impact or relevance to future work
817
822
 
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
823
+ ## 2. SEMANTIC Memory
824
+ General facts, concepts, knowledge, and established truths about the user.
825
+ **Examples:**
826
+ - "User is a senior backend engineer with 8 years experience"
827
+ - "User specializes in distributed systems and microservices architecture"
828
+ - "User's primary programming language is TypeScript"
829
+ - "User works at Acme Corp as technical lead"
827
830
 
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
831
+ **Requirements:**
832
+ - Must be factual, timeless information
833
+ - Must be explicitly stated or demonstrated conclusively
834
+ - No speculation or inference from single instances
835
+ - Core identity, expertise, or knowledge only
833
836
 
834
- # Instructions
835
- Extract ONLY truly important NEW information that meets the strict criteria above. For each item:
836
- - Determine which category it belongs to
837
- - Write a clear, factual statement
838
- - Assess confidence (0.0 to 1.0) - BE CONSERVATIVE
839
- - Require strong evidence before extraction
837
+ ## 3. PROCEDURAL Memory
838
+ Skills, workflows, methodologies, and how-to knowledge.
839
+ **Examples:**
840
+ - "User follows strict TDD workflow: write tests first, then implementation"
841
+ - "User prefers git rebase over merge to maintain linear history"
842
+ - "User's debugging process: check logs → reproduce locally → binary search"
843
+ - "User always writes JSDoc comments before implementing functions"
840
844
 
841
- **When in doubt, DO NOT extract.** It's better to miss temporary information than to clutter long-term memory.
845
+ **Requirements:**
846
+ - Must describe HOW user does something
847
+ - Must be a repeated, consistent pattern (seen 3+ times or explicitly stated as standard practice)
848
+ - Must be a workflow, methodology, or skill application
849
+ - Not one-off preferences
842
850
 
843
- If there are no new long-term facts to extract, respond with <memories></memories>
851
+ # ULTRA-STRICT EXTRACTION CRITERIA
852
+
853
+ ## ✅ DO EXTRACT (Only These):
854
+
855
+ **EPISODIC:**
856
+ - Significant completed projects or milestones
857
+ - Important bugs, incidents, or problems encountered
858
+ - Major decisions made with lasting impact
859
+ - Formative experiences that shape future work
860
+
861
+ **SEMANTIC:**
862
+ - Professional identity (role, title, company)
863
+ - Core expertise and specializations (stated explicitly or demonstrated conclusively)
864
+ - Primary languages, frameworks, or tools (not exploratory use)
865
+ - Established facts about their work context
866
+
867
+ **PROCEDURAL:**
868
+ - Consistent workflows demonstrated 3+ times or explicitly stated
869
+ - Standard practices user always follows
870
+ - Methodology preferences with clear rationale
871
+ - Debugging, testing, or development processes
872
+
873
+ ## ❌ NEVER EXTRACT:
874
+
875
+ - **One-time requests or tasks** (e.g., "can you generate an image", "help me debug this")
876
+ - **Casual conversations** without lasting significance
877
+ - **Exploratory questions** (e.g., "how does X work?")
878
+ - **Temporary context** (current bug, today's task)
879
+ - **Preferences from single occurrence** (e.g., user asked for code once)
880
+ - **Social pleasantries** (thank you, greetings)
881
+ - **Testing or experimentation** (trying out a feature)
882
+ - **Common patterns everyone has** (likes clear explanations)
883
+ - **Situational information** (working on feature X today)
884
+ - **Opinions without persistence** (single complaint, isolated praise)
885
+ - **General knowledge** (not specific to user)
886
+
887
+ # Quality Gates (ALL Must Pass)
888
+
889
+ 1. **Significance Test**: Will this matter in 3+ months?
890
+ 2. **Specificity Test**: Is this concrete and actionable?
891
+ 3. **Evidence Test**: Is there strong evidence (3+ instances OR explicit self-identification)?
892
+ 4. **Uniqueness Test**: Is this specific to THIS user (not generic)?
893
+ 5. **Confidence Test**: Confidence must be >= 0.85 (be VERY conservative)
894
+ 6. **Non-Redundancy Test**: Does this add NEW information not in existing memories?
895
+
896
+ # Confidence Scoring (Be Conservative)
897
+
898
+ - **0.95-1.0**: User explicitly stated as core identity/practice AND demonstrated multiple times
899
+ - **0.85-0.94**: User explicitly stated OR consistently demonstrated 5+ times
900
+ - **0.75-0.84**: Strong pattern (3-4 instances) with supporting context
901
+ - **Below 0.75**: DO NOT EXTRACT (insufficient evidence)
902
+
903
+ # Critical Instructions
904
+
905
+ 1. **Default to NOT extracting** - When in doubt, skip it
906
+ 2. **Require overwhelming evidence** - One or two mentions is NOT enough
907
+ 3. **Focus on what's PERSISTENT** - Not what's temporary or situational
908
+ 4. **Verify against existing memories** - Don't duplicate or contradict
909
+ 5. **Maximum 2-3 extractions per run** - Quality over quantity
910
+
911
+ **If there are no qualifying facts (which is common), respond with <memories></memories>**
912
+
913
+ # Response Format
844
914
 
845
- Respond in this XML format:
846
915
  <memories>
847
916
  <memory>
848
- <category>identity</category>
849
- <content>User is a software engineer specializing in backend development</content>
917
+ <category>semantic</category>
918
+ <content>User is a senior TypeScript developer with 8 years of backend experience</content>
850
919
  <confidence>0.95</confidence>
851
920
  </memory>
852
921
  <memory>
853
- <category>preferences</category>
854
- <content>Prefers code examples over lengthy explanations</content>
855
- <confidence>0.85</confidence>
922
+ <category>procedural</category>
923
+ <content>User follows TDD workflow: writes tests before implementation, runs tests after each change</content>
924
+ <confidence>0.88</confidence>
925
+ </memory>
926
+ <memory>
927
+ <category>episodic</category>
928
+ <content>User led database migration from MongoDB to PostgreSQL for payment system in Q2 2024</content>
929
+ <confidence>0.92</confidence>
856
930
  </memory>
857
931
  </memories>`;
858
932
  function parseMemoryExtractionXML(xml) {
@@ -941,7 +1015,7 @@ var longTermExtractionEvaluator = {
941
1015
  const extractions = parseMemoryExtractionXML(response);
942
1016
  import_core3.logger.info(`Extracted ${extractions.length} long-term memories`);
943
1017
  for (const extraction of extractions) {
944
- if (extraction.confidence >= config.longTermConfidenceThreshold) {
1018
+ if (extraction.confidence >= Math.max(config.longTermConfidenceThreshold, 0.85)) {
945
1019
  await memoryService.storeLongTermMemory({
946
1020
  agentId: runtime.agentId,
947
1021
  entityId,
@@ -956,7 +1030,7 @@ var longTermExtractionEvaluator = {
956
1030
  });
957
1031
  import_core3.logger.info(`Stored long-term memory: [${extraction.category}] ${extraction.content.substring(0, 50)}...`);
958
1032
  } else {
959
- import_core3.logger.debug(`Skipped low-confidence memory: ${extraction.content} (confidence: ${extraction.confidence})`);
1033
+ import_core3.logger.debug(`Skipped low-confidence memory: ${extraction.content} (confidence: ${extraction.confidence}, threshold: ${Math.max(config.longTermConfidenceThreshold, 0.85)})`);
960
1034
  }
961
1035
  }
962
1036
  const currentMessageCount = await runtime.countMemories(roomId, false, "messages");
@@ -969,235 +1043,8 @@ var longTermExtractionEvaluator = {
969
1043
  examples: []
970
1044
  };
971
1045
 
972
- // src/providers/short-term-memory.ts
973
- var import_core4 = require("@elizaos/core");
974
- var shortTermMemoryProvider = {
975
- name: "SHORT_TERM_MEMORY",
976
- description: "Adaptive conversation context with smart summarization",
977
- position: 95,
978
- get: async (runtime, message, _state) => {
979
- try {
980
- const memoryService = runtime.getService("memory");
981
- if (!memoryService) {
982
- return {
983
- data: { summaries: [], recentMessages: [], mode: "disabled" },
984
- values: {},
985
- text: ""
986
- };
987
- }
988
- const { roomId } = message;
989
- const config = memoryService.getConfig();
990
- const totalMessageCount = await runtime.countMemories(roomId, false, "messages");
991
- if (totalMessageCount < config.shortTermSummarizationThreshold) {
992
- const conversationLength = runtime.getConversationLength();
993
- const [entitiesData, room, recentMessagesData] = await Promise.all([
994
- import_core4.getEntityDetails({ runtime, roomId }),
995
- runtime.getRoom(roomId),
996
- runtime.getMemories({
997
- tableName: "messages",
998
- roomId,
999
- count: conversationLength,
1000
- unique: false
1001
- })
1002
- ]);
1003
- const actionResultMessages = recentMessagesData.filter((msg) => msg.content?.type === "action_result" && msg.metadata?.type === "action_result");
1004
- const dialogueMessages = recentMessagesData.filter((msg) => !(msg.content?.type === "action_result" && msg.metadata?.type === "action_result"));
1005
- const isPostFormat = room?.type ? room.type === import_core4.ChannelType.FEED || room.type === import_core4.ChannelType.THREAD : false;
1006
- const [formattedRecentMessages, formattedRecentPosts] = await Promise.all([
1007
- import_core4.formatMessages({
1008
- messages: dialogueMessages,
1009
- entities: entitiesData
1010
- }),
1011
- import_core4.formatPosts({
1012
- messages: dialogueMessages,
1013
- entities: entitiesData,
1014
- conversationHeader: false
1015
- })
1016
- ]);
1017
- let actionResultsText = "";
1018
- if (actionResultMessages.length > 0) {
1019
- const groupedByRun = new Map;
1020
- for (const mem of actionResultMessages) {
1021
- const runId = String(mem.content?.runId || "unknown");
1022
- if (!groupedByRun.has(runId)) {
1023
- groupedByRun.set(runId, []);
1024
- }
1025
- groupedByRun.get(runId)?.push(mem);
1026
- }
1027
- const formattedActionResults = Array.from(groupedByRun.entries()).slice(-3).map(([runId, memories]) => {
1028
- const sortedMemories = memories.sort((a, b) => (a.createdAt || 0) - (b.createdAt || 0));
1029
- const thought = sortedMemories[0]?.content?.planThought || "";
1030
- const runText = sortedMemories.map((mem) => {
1031
- const actionName = mem.content?.actionName || "Unknown";
1032
- const status = mem.content?.actionStatus || "unknown";
1033
- const planStep = mem.content?.planStep || "";
1034
- const text5 = mem.content?.text || "";
1035
- const error = mem.content?.error || "";
1036
- let memText = ` - ${actionName} (${status})`;
1037
- if (planStep)
1038
- memText += ` [${planStep}]`;
1039
- if (error) {
1040
- memText += `: Error - ${error}`;
1041
- } else if (text5 && text5 !== `Executed action: ${actionName}`) {
1042
- memText += `: ${text5}`;
1043
- }
1044
- return memText;
1045
- }).join(`
1046
- `);
1047
- return `**Action Run ${runId.slice(0, 8)}**${thought ? ` - "${thought}"` : ""}
1048
- ${runText}`;
1049
- }).join(`
1050
-
1051
- `);
1052
- actionResultsText = formattedActionResults ? import_core4.addHeader("# Recent Action Executions", formattedActionResults) : "";
1053
- }
1054
- const recentPosts = formattedRecentPosts && formattedRecentPosts.length > 0 ? import_core4.addHeader("# Posts in Thread", formattedRecentPosts) : "";
1055
- const recentMessages = formattedRecentMessages && formattedRecentMessages.length > 0 ? import_core4.addHeader("# Conversation Messages", formattedRecentMessages) : "";
1056
- if (!recentPosts && !recentMessages && dialogueMessages.length === 0 && !message.content.text) {
1057
- return {
1058
- data: {
1059
- summaries: [],
1060
- recentMessages: [],
1061
- actionResults: [],
1062
- mode: "full_conversation"
1063
- },
1064
- values: {
1065
- recentMessage: "No recent message available."
1066
- },
1067
- text: "No recent messages available"
1068
- };
1069
- }
1070
- let recentMessage = "No recent message available.";
1071
- if (dialogueMessages.length > 0) {
1072
- const mostRecentMessage = [...dialogueMessages].sort((a, b) => (b.createdAt || 0) - (a.createdAt || 0))[0];
1073
- const formattedSingleMessage = import_core4.formatMessages({
1074
- messages: [mostRecentMessage],
1075
- entities: entitiesData
1076
- });
1077
- if (formattedSingleMessage) {
1078
- recentMessage = formattedSingleMessage;
1079
- }
1080
- }
1081
- const metaData = message.metadata;
1082
- const senderName = entitiesData.find((entity) => entity.id === message.entityId)?.names[0] || metaData?.entityName || "Unknown User";
1083
- const receivedMessageContent = message.content.text;
1084
- const hasReceivedMessage = !!receivedMessageContent?.trim();
1085
- const receivedMessageHeader = hasReceivedMessage ? import_core4.addHeader("# Received Message", `${senderName}: ${receivedMessageContent}`) : "";
1086
- const focusHeader = hasReceivedMessage ? import_core4.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.`) : "";
1087
- const text4 = [
1088
- isPostFormat ? recentPosts : recentMessages,
1089
- actionResultsText,
1090
- recentMessages || recentPosts || message.content.text ? receivedMessageHeader : "",
1091
- recentMessages || recentPosts || message.content.text ? focusHeader : ""
1092
- ].filter(Boolean).join(`
1093
-
1094
- `);
1095
- return {
1096
- data: {
1097
- summaries: [],
1098
- recentMessages: dialogueMessages,
1099
- actionResults: actionResultMessages,
1100
- mode: "full_conversation"
1101
- },
1102
- values: {
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 }
1111
- },
1112
- text: text4
1113
- };
1114
- } else {
1115
- const currentSummary = await memoryService.getCurrentSessionSummary(roomId);
1116
- const lastOffset = currentSummary?.lastMessageOffset || 0;
1117
- const unsummarizedMessages = await runtime.getMemories({
1118
- tableName: "messages",
1119
- roomId,
1120
- count: config.shortTermRetainRecent,
1121
- unique: false,
1122
- start: lastOffset
1123
- });
1124
- const entitiesData = await import_core4.getEntityDetails({ runtime, roomId });
1125
- const room = await runtime.getRoom(roomId);
1126
- const isPostFormat = room?.type ? room.type === import_core4.ChannelType.FEED || room.type === import_core4.ChannelType.THREAD : false;
1127
- let recentMessagesText = "";
1128
- if (unsummarizedMessages.length > 0) {
1129
- const dialogueMessages = unsummarizedMessages.filter((msg) => !(msg.content?.type === "action_result" && msg.metadata?.type === "action_result"));
1130
- if (isPostFormat) {
1131
- recentMessagesText = import_core4.formatPosts({
1132
- messages: dialogueMessages,
1133
- entities: entitiesData,
1134
- conversationHeader: false
1135
- });
1136
- } else {
1137
- recentMessagesText = import_core4.formatMessages({
1138
- messages: dialogueMessages,
1139
- entities: entitiesData
1140
- });
1141
- }
1142
- if (recentMessagesText) {
1143
- recentMessagesText = import_core4.addHeader("# Recent Messages", recentMessagesText);
1144
- }
1145
- }
1146
- let summaryText = "";
1147
- if (currentSummary) {
1148
- const messageRange = `${currentSummary.messageCount} messages`;
1149
- const timeRange = new Date(currentSummary.startTime).toLocaleDateString();
1150
- summaryText = `**Previous Conversation** (${messageRange}, ${timeRange})
1151
- `;
1152
- summaryText += currentSummary.summary;
1153
- if (currentSummary.topics && currentSummary.topics.length > 0) {
1154
- summaryText += `
1155
- *Topics: ${currentSummary.topics.join(", ")}*`;
1156
- }
1157
- summaryText = import_core4.addHeader("# Conversation Summary", summaryText);
1158
- }
1159
- const metaData = message.metadata;
1160
- const senderName = entitiesData.find((entity) => entity.id === message.entityId)?.names[0] || metaData?.entityName || "Unknown User";
1161
- const receivedMessageContent = message.content.text;
1162
- const hasReceivedMessage = !!receivedMessageContent?.trim();
1163
- const receivedMessageHeader = hasReceivedMessage ? import_core4.addHeader("# Received Message", `${senderName}: ${receivedMessageContent}`) : "";
1164
- const focusHeader = hasReceivedMessage ? import_core4.addHeader("# Focus your response", `You are replying to the above message from **${senderName}**. Keep your answer relevant to that message.`) : "";
1165
- const text4 = [
1166
- summaryText,
1167
- recentMessagesText,
1168
- hasReceivedMessage ? receivedMessageHeader : "",
1169
- hasReceivedMessage ? focusHeader : ""
1170
- ].filter(Boolean).join(`
1171
-
1172
- `);
1173
- return {
1174
- data: {
1175
- summaries: currentSummary ? [currentSummary] : [],
1176
- recentMessages: unsummarizedMessages,
1177
- mode: "summarized"
1178
- },
1179
- values: {
1180
- ...summaryText && { sessionSummaries: summaryText },
1181
- ...recentMessagesText && { recentMessages: recentMessagesText },
1182
- ...receivedMessageHeader && { receivedMessageHeader },
1183
- ...focusHeader && { focusHeader }
1184
- },
1185
- text: text4
1186
- };
1187
- }
1188
- } catch (error) {
1189
- import_core4.logger.error({ error }, "Error in shortTermMemoryProvider:");
1190
- return {
1191
- data: { summaries: [], recentMessages: [], mode: "error" },
1192
- values: {},
1193
- text: "Error retrieving conversation context."
1194
- };
1195
- }
1196
- }
1197
- };
1198
-
1199
1046
  // src/providers/long-term-memory.ts
1200
- var import_core5 = require("@elizaos/core");
1047
+ var import_core4 = require("@elizaos/core");
1201
1048
  var longTermMemoryProvider = {
1202
1049
  name: "LONG_TERM_MEMORY",
1203
1050
  description: "Persistent facts and preferences about the user",
@@ -1229,7 +1076,7 @@ var longTermMemoryProvider = {
1229
1076
  };
1230
1077
  }
1231
1078
  const formattedMemories = await memoryService.getFormattedLongTermMemories(entityId);
1232
- const text4 = import_core5.addHeader("# What I Know About You", formattedMemories);
1079
+ const text4 = import_core4.addHeader("# What I Know About You", formattedMemories);
1233
1080
  const categoryCounts = new Map;
1234
1081
  for (const memory of memories) {
1235
1082
  const count = categoryCounts.get(memory.category) || 0;
@@ -1248,7 +1095,7 @@ var longTermMemoryProvider = {
1248
1095
  text: text4
1249
1096
  };
1250
1097
  } catch (error) {
1251
- import_core5.logger.error({ error }, "Error in longTermMemoryProvider:");
1098
+ import_core4.logger.error({ error }, "Error in longTermMemoryProvider:");
1252
1099
  return {
1253
1100
  data: { memories: [] },
1254
1101
  values: { longTermMemories: "" },
@@ -1258,15 +1105,215 @@ var longTermMemoryProvider = {
1258
1105
  }
1259
1106
  };
1260
1107
 
1108
+ // src/providers/context-summary.ts
1109
+ var import_core5 = require("@elizaos/core");
1110
+ var contextSummaryProvider = {
1111
+ name: "SUMMARIZED_CONTEXT",
1112
+ description: "Provides summarized context from previous conversations",
1113
+ position: 96,
1114
+ get: async (runtime, message, _state) => {
1115
+ try {
1116
+ const memoryService = runtime.getService("memory");
1117
+ const { roomId } = message;
1118
+ if (!memoryService) {
1119
+ return {
1120
+ data: {
1121
+ summary: null
1122
+ },
1123
+ values: {
1124
+ sessionSummaries: "",
1125
+ sessionSummariesWithTopics: ""
1126
+ },
1127
+ text: ""
1128
+ };
1129
+ }
1130
+ const currentSummary = await memoryService.getCurrentSessionSummary(roomId);
1131
+ if (!currentSummary) {
1132
+ return {
1133
+ data: {
1134
+ summary: null
1135
+ },
1136
+ values: {
1137
+ sessionSummaries: "",
1138
+ sessionSummariesWithTopics: ""
1139
+ },
1140
+ text: ""
1141
+ };
1142
+ }
1143
+ const messageRange = `${currentSummary.messageCount} messages`;
1144
+ const timeRange = new Date(currentSummary.startTime).toLocaleDateString();
1145
+ let summaryOnly = `**Previous Conversation** (${messageRange}, ${timeRange})
1146
+ `;
1147
+ summaryOnly += currentSummary.summary;
1148
+ let summaryWithTopics = summaryOnly;
1149
+ if (currentSummary.topics && currentSummary.topics.length > 0) {
1150
+ summaryWithTopics += `
1151
+ *Topics: ${currentSummary.topics.join(", ")}*`;
1152
+ }
1153
+ const sessionSummaries2 = import_core5.addHeader("# Conversation Summary", summaryOnly);
1154
+ const sessionSummariesWithTopics = import_core5.addHeader("# Conversation Summary", summaryWithTopics);
1155
+ return {
1156
+ data: {
1157
+ summary: currentSummary
1158
+ },
1159
+ values: {
1160
+ sessionSummaries: sessionSummaries2,
1161
+ sessionSummariesWithTopics
1162
+ },
1163
+ text: sessionSummariesWithTopics
1164
+ };
1165
+ } catch (error) {
1166
+ import_core5.logger.error({ error }, "Error in contextSummaryProvider:");
1167
+ return {
1168
+ data: {
1169
+ summary: null
1170
+ },
1171
+ values: {
1172
+ sessionSummaries: "",
1173
+ sessionSummariesWithTopics: ""
1174
+ },
1175
+ text: ""
1176
+ };
1177
+ }
1178
+ }
1179
+ };
1180
+
1181
+ // src/providers/recent-messages.ts
1182
+ var import_core6 = require("@elizaos/core");
1183
+ var recentMessagesProvider = {
1184
+ name: "RECENT_MESSAGES",
1185
+ description: "Provides recent conversation messages with detailed context",
1186
+ position: 94,
1187
+ get: async (runtime, message, _state) => {
1188
+ try {
1189
+ const memoryService = runtime.getService("memory");
1190
+ const { roomId } = message;
1191
+ const config = memoryService?.getConfig() || {
1192
+ shortTermSummarizationThreshold: 16,
1193
+ shortTermRetainRecent: 6
1194
+ };
1195
+ const conversationLength = runtime.getConversationLength();
1196
+ let messagesToFetch = config.shortTermRetainRecent;
1197
+ let startOffset = 0;
1198
+ let hasSummary = false;
1199
+ if (memoryService) {
1200
+ const currentSummary = await memoryService.getCurrentSessionSummary(roomId);
1201
+ if (currentSummary) {
1202
+ hasSummary = true;
1203
+ startOffset = currentSummary.lastMessageOffset || 0;
1204
+ }
1205
+ }
1206
+ if (!hasSummary) {
1207
+ const allMessages = await runtime.getMemories({
1208
+ tableName: "messages",
1209
+ roomId,
1210
+ count: conversationLength,
1211
+ unique: false
1212
+ });
1213
+ const dialogueMessageCount = allMessages.filter((msg) => !(msg.content?.type === "action_result" && msg.metadata?.type === "action_result") && (msg.metadata?.type === "agent_response_message" || msg.metadata?.type === "user_message")).length;
1214
+ if (dialogueMessageCount < config.shortTermSummarizationThreshold) {
1215
+ messagesToFetch = conversationLength;
1216
+ }
1217
+ }
1218
+ const [entitiesData, room, recentMessagesData] = await Promise.all([
1219
+ import_core6.getEntityDetails({ runtime, roomId }),
1220
+ runtime.getRoom(roomId),
1221
+ runtime.getMemories({
1222
+ tableName: "messages",
1223
+ roomId,
1224
+ count: messagesToFetch,
1225
+ unique: false,
1226
+ start: startOffset
1227
+ })
1228
+ ]);
1229
+ const isPostFormat = room?.type ? room.type === import_core6.ChannelType.FEED || room.type === import_core6.ChannelType.THREAD : false;
1230
+ const dialogueMessages = recentMessagesData.filter((msg) => !(msg.content?.type === "action_result" && msg.metadata?.type === "action_result") && (msg.metadata?.type === "agent_response_message" || msg.metadata?.type === "user_message"));
1231
+ let recentMessagesText = "";
1232
+ if (dialogueMessages.length > 0) {
1233
+ if (isPostFormat) {
1234
+ recentMessagesText = import_core6.formatPosts({
1235
+ messages: dialogueMessages,
1236
+ entities: entitiesData,
1237
+ conversationHeader: false
1238
+ });
1239
+ } else {
1240
+ recentMessagesText = import_core6.formatMessages({
1241
+ messages: dialogueMessages,
1242
+ entities: entitiesData
1243
+ });
1244
+ }
1245
+ if (recentMessagesText) {
1246
+ recentMessagesText = import_core6.addHeader("# Recent Messages", recentMessagesText);
1247
+ }
1248
+ }
1249
+ const formatConversationLog = (messages, includeThoughts) => {
1250
+ return messages.sort((a, b) => (a.createdAt || 0) - (b.createdAt || 0)).map((msg) => {
1251
+ const entity = entitiesData.find((e) => e.id === msg.entityId);
1252
+ const entityName = entity?.names[0] || (msg.entityId === runtime.agentId ? runtime.character.name : "Unknown");
1253
+ const timestamp4 = msg.createdAt ? new Date(msg.createdAt).toLocaleString() : "Unknown time";
1254
+ const text5 = msg.content.text || "";
1255
+ const thought = includeThoughts && msg.content.internalMonologue ? `
1256
+ [Internal thought: ${msg.content.internalMonologue}]` : "";
1257
+ return `[${timestamp4}] ${entityName}: ${text5}${thought}`;
1258
+ }).join(`
1259
+ `);
1260
+ };
1261
+ const conversationLog = import_core6.addHeader("# Conversation Messages", formatConversationLog(dialogueMessages, false));
1262
+ const conversationLogWithAgentThoughts = import_core6.addHeader("# Conversation Messages", formatConversationLog(dialogueMessages, true));
1263
+ const metaData = message.metadata;
1264
+ const senderName = entitiesData.find((entity) => entity.id === message.entityId)?.names[0] || metaData?.entityName || "Unknown User";
1265
+ const receivedMessageContent = message.content.text;
1266
+ const hasReceivedMessage = !!receivedMessageContent?.trim();
1267
+ const receivedMessageHeader = hasReceivedMessage ? import_core6.addHeader("# Received Message", `${senderName}: ${receivedMessageContent}`) : "";
1268
+ const focusHeader = hasReceivedMessage ? import_core6.addHeader("# Focus your response", `You are replying to the above message from **${senderName}**. Keep your answer relevant to that message.`) : "";
1269
+ const text4 = [recentMessagesText, receivedMessageHeader, focusHeader].filter(Boolean).join(`
1270
+
1271
+ `);
1272
+ return {
1273
+ data: {
1274
+ messages: dialogueMessages
1275
+ },
1276
+ values: {
1277
+ recentMessages: recentMessagesText,
1278
+ conversationLog,
1279
+ conversationLogWithAgentThoughts,
1280
+ ...receivedMessageHeader && { receivedMessageHeader },
1281
+ ...focusHeader && { focusHeader }
1282
+ },
1283
+ text: text4
1284
+ };
1285
+ } catch (error) {
1286
+ import_core6.logger.error({ error }, "Error in recentMessagesProvider:");
1287
+ return {
1288
+ data: {
1289
+ messages: []
1290
+ },
1291
+ values: {
1292
+ recentMessages: "",
1293
+ conversationLog: "",
1294
+ conversationLogWithAgentThoughts: "",
1295
+ receivedMessageHeader: "",
1296
+ focusHeader: ""
1297
+ },
1298
+ text: ""
1299
+ };
1300
+ }
1301
+ }
1302
+ };
1303
+
1261
1304
  // src/index.ts
1262
1305
  var memoryPlugin = {
1263
1306
  name: "memory",
1264
1307
  description: "Advanced memory management with conversation summarization and long-term persistent memory",
1265
1308
  services: [MemoryService],
1266
1309
  evaluators: [summarizationEvaluator, longTermExtractionEvaluator],
1267
- providers: [longTermMemoryProvider, shortTermMemoryProvider],
1310
+ providers: [
1311
+ longTermMemoryProvider,
1312
+ contextSummaryProvider,
1313
+ recentMessagesProvider
1314
+ ],
1268
1315
  schema: exports_schemas
1269
1316
  };
1270
1317
  var src_default = memoryPlugin;
1271
1318
 
1272
- //# debugId=3C20A9F0BA14039464756E2164756E21
1319
+ //# debugId=D8A71511D9B322A664756E2164756E21