@elizaos/plugin-memory 1.0.5 → 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.
- package/README.md +58 -34
- package/dist/browser/index.browser.js +148 -77
- package/dist/browser/index.browser.js.map +6 -6
- package/dist/cjs/index.node.cjs +405 -110
- package/dist/cjs/index.node.js.map +6 -6
- package/dist/node/index.node.js +405 -110
- package/dist/node/index.node.js.map +6 -6
- package/dist/providers/short-term-memory.d.ts +8 -6
- package/dist/types/index.d.ts +9 -10
- package/package.json +1 -1
package/dist/cjs/index.node.cjs
CHANGED
|
@@ -127,13 +127,13 @@ class MemoryService extends import_core.Service {
|
|
|
127
127
|
this.lastExtractionCheckpoints = new Map;
|
|
128
128
|
this.memoryConfig = {
|
|
129
129
|
shortTermSummarizationThreshold: 16,
|
|
130
|
-
shortTermRetainRecent:
|
|
130
|
+
shortTermRetainRecent: 6,
|
|
131
131
|
shortTermSummarizationInterval: 10,
|
|
132
132
|
longTermExtractionEnabled: true,
|
|
133
133
|
longTermVectorSearchEnabled: false,
|
|
134
|
-
longTermConfidenceThreshold: 0.
|
|
135
|
-
longTermExtractionThreshold:
|
|
136
|
-
longTermExtractionInterval:
|
|
134
|
+
longTermConfidenceThreshold: 0.85,
|
|
135
|
+
longTermExtractionThreshold: 30,
|
|
136
|
+
longTermExtractionInterval: 10,
|
|
137
137
|
summaryModelType: "TEXT_LARGE",
|
|
138
138
|
summaryMaxTokens: 2500,
|
|
139
139
|
summaryMaxNewMessages: 20
|
|
@@ -771,21 +771,15 @@ var import_core3 = require("@elizaos/core");
|
|
|
771
771
|
// src/types/index.ts
|
|
772
772
|
var LongTermMemoryCategory;
|
|
773
773
|
((LongTermMemoryCategory2) => {
|
|
774
|
-
LongTermMemoryCategory2["
|
|
775
|
-
LongTermMemoryCategory2["
|
|
776
|
-
LongTermMemoryCategory2["
|
|
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";
|
|
774
|
+
LongTermMemoryCategory2["EPISODIC"] = "episodic";
|
|
775
|
+
LongTermMemoryCategory2["SEMANTIC"] = "semantic";
|
|
776
|
+
LongTermMemoryCategory2["PROCEDURAL"] = "procedural";
|
|
783
777
|
})(LongTermMemoryCategory ||= {});
|
|
784
778
|
|
|
785
779
|
// src/evaluators/long-term-extraction.ts
|
|
786
|
-
var extractionTemplate = `# Task: Extract Long-Term Memory
|
|
780
|
+
var extractionTemplate = `# Task: Extract Long-Term Memory (Strict Criteria)
|
|
787
781
|
|
|
788
|
-
You are analyzing a conversation to extract ONLY the most
|
|
782
|
+
You are analyzing a conversation to extract ONLY the most critical, persistent information about the user using cognitive science memory categories.
|
|
789
783
|
|
|
790
784
|
# Recent Messages
|
|
791
785
|
{{recentMessages}}
|
|
@@ -793,66 +787,127 @@ You are analyzing a conversation to extract ONLY the most important, persistent
|
|
|
793
787
|
# Current Long-Term Memories
|
|
794
788
|
{{existingMemories}}
|
|
795
789
|
|
|
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
|
|
790
|
+
# Memory Categories (Based on Cognitive Science)
|
|
806
791
|
|
|
807
|
-
|
|
792
|
+
## 1. EPISODIC Memory
|
|
793
|
+
Personal experiences and specific events with temporal/spatial context.
|
|
794
|
+
**Examples:**
|
|
795
|
+
- "User completed migration project from MongoDB to PostgreSQL in Q2 2024"
|
|
796
|
+
- "User encountered authentication bug in production on March 15th"
|
|
797
|
+
- "User had a negative experience with Docker networking in previous job"
|
|
808
798
|
|
|
809
|
-
**
|
|
810
|
-
-
|
|
811
|
-
-
|
|
812
|
-
-
|
|
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
|
|
799
|
+
**Requirements:**
|
|
800
|
+
- Must include WHO did WHAT, WHEN/WHERE
|
|
801
|
+
- Must be a specific, concrete event (not a pattern)
|
|
802
|
+
- Must have significant impact or relevance to future work
|
|
817
803
|
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
-
|
|
822
|
-
-
|
|
823
|
-
-
|
|
824
|
-
-
|
|
825
|
-
- Random or playful requests that don't indicate lasting preference
|
|
826
|
-
- Information that could change or is situational
|
|
804
|
+
## 2. SEMANTIC Memory
|
|
805
|
+
General facts, concepts, knowledge, and established truths about the user.
|
|
806
|
+
**Examples:**
|
|
807
|
+
- "User is a senior backend engineer with 8 years experience"
|
|
808
|
+
- "User specializes in distributed systems and microservices architecture"
|
|
809
|
+
- "User's primary programming language is TypeScript"
|
|
810
|
+
- "User works at Acme Corp as technical lead"
|
|
827
811
|
|
|
828
|
-
|
|
829
|
-
-
|
|
830
|
-
-
|
|
831
|
-
-
|
|
832
|
-
-
|
|
812
|
+
**Requirements:**
|
|
813
|
+
- Must be factual, timeless information
|
|
814
|
+
- Must be explicitly stated or demonstrated conclusively
|
|
815
|
+
- No speculation or inference from single instances
|
|
816
|
+
- Core identity, expertise, or knowledge only
|
|
833
817
|
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
-
|
|
838
|
-
-
|
|
839
|
-
-
|
|
818
|
+
## 3. PROCEDURAL Memory
|
|
819
|
+
Skills, workflows, methodologies, and how-to knowledge.
|
|
820
|
+
**Examples:**
|
|
821
|
+
- "User follows strict TDD workflow: write tests first, then implementation"
|
|
822
|
+
- "User prefers git rebase over merge to maintain linear history"
|
|
823
|
+
- "User's debugging process: check logs → reproduce locally → binary search"
|
|
824
|
+
- "User always writes JSDoc comments before implementing functions"
|
|
840
825
|
|
|
841
|
-
**
|
|
826
|
+
**Requirements:**
|
|
827
|
+
- Must describe HOW user does something
|
|
828
|
+
- Must be a repeated, consistent pattern (seen 3+ times or explicitly stated as standard practice)
|
|
829
|
+
- Must be a workflow, methodology, or skill application
|
|
830
|
+
- Not one-off preferences
|
|
842
831
|
|
|
843
|
-
|
|
832
|
+
# ULTRA-STRICT EXTRACTION CRITERIA
|
|
833
|
+
|
|
834
|
+
## ✅ DO EXTRACT (Only These):
|
|
835
|
+
|
|
836
|
+
**EPISODIC:**
|
|
837
|
+
- Significant completed projects or milestones
|
|
838
|
+
- Important bugs, incidents, or problems encountered
|
|
839
|
+
- Major decisions made with lasting impact
|
|
840
|
+
- Formative experiences that shape future work
|
|
841
|
+
|
|
842
|
+
**SEMANTIC:**
|
|
843
|
+
- Professional identity (role, title, company)
|
|
844
|
+
- Core expertise and specializations (stated explicitly or demonstrated conclusively)
|
|
845
|
+
- Primary languages, frameworks, or tools (not exploratory use)
|
|
846
|
+
- Established facts about their work context
|
|
847
|
+
|
|
848
|
+
**PROCEDURAL:**
|
|
849
|
+
- Consistent workflows demonstrated 3+ times or explicitly stated
|
|
850
|
+
- Standard practices user always follows
|
|
851
|
+
- Methodology preferences with clear rationale
|
|
852
|
+
- Debugging, testing, or development processes
|
|
853
|
+
|
|
854
|
+
## ❌ NEVER EXTRACT:
|
|
855
|
+
|
|
856
|
+
- **One-time requests or tasks** (e.g., "can you generate an image", "help me debug this")
|
|
857
|
+
- **Casual conversations** without lasting significance
|
|
858
|
+
- **Exploratory questions** (e.g., "how does X work?")
|
|
859
|
+
- **Temporary context** (current bug, today's task)
|
|
860
|
+
- **Preferences from single occurrence** (e.g., user asked for code once)
|
|
861
|
+
- **Social pleasantries** (thank you, greetings)
|
|
862
|
+
- **Testing or experimentation** (trying out a feature)
|
|
863
|
+
- **Common patterns everyone has** (likes clear explanations)
|
|
864
|
+
- **Situational information** (working on feature X today)
|
|
865
|
+
- **Opinions without persistence** (single complaint, isolated praise)
|
|
866
|
+
- **General knowledge** (not specific to user)
|
|
867
|
+
|
|
868
|
+
# Quality Gates (ALL Must Pass)
|
|
869
|
+
|
|
870
|
+
1. **Significance Test**: Will this matter in 3+ months?
|
|
871
|
+
2. **Specificity Test**: Is this concrete and actionable?
|
|
872
|
+
3. **Evidence Test**: Is there strong evidence (3+ instances OR explicit self-identification)?
|
|
873
|
+
4. **Uniqueness Test**: Is this specific to THIS user (not generic)?
|
|
874
|
+
5. **Confidence Test**: Confidence must be >= 0.85 (be VERY conservative)
|
|
875
|
+
6. **Non-Redundancy Test**: Does this add NEW information not in existing memories?
|
|
876
|
+
|
|
877
|
+
# Confidence Scoring (Be Conservative)
|
|
878
|
+
|
|
879
|
+
- **0.95-1.0**: User explicitly stated as core identity/practice AND demonstrated multiple times
|
|
880
|
+
- **0.85-0.94**: User explicitly stated OR consistently demonstrated 5+ times
|
|
881
|
+
- **0.75-0.84**: Strong pattern (3-4 instances) with supporting context
|
|
882
|
+
- **Below 0.75**: DO NOT EXTRACT (insufficient evidence)
|
|
883
|
+
|
|
884
|
+
# Critical Instructions
|
|
885
|
+
|
|
886
|
+
1. **Default to NOT extracting** - When in doubt, skip it
|
|
887
|
+
2. **Require overwhelming evidence** - One or two mentions is NOT enough
|
|
888
|
+
3. **Focus on what's PERSISTENT** - Not what's temporary or situational
|
|
889
|
+
4. **Verify against existing memories** - Don't duplicate or contradict
|
|
890
|
+
5. **Maximum 2-3 extractions per run** - Quality over quantity
|
|
891
|
+
|
|
892
|
+
**If there are no qualifying facts (which is common), respond with <memories></memories>**
|
|
893
|
+
|
|
894
|
+
# Response Format
|
|
844
895
|
|
|
845
|
-
Respond in this XML format:
|
|
846
896
|
<memories>
|
|
847
897
|
<memory>
|
|
848
|
-
<category>
|
|
849
|
-
<content>User is a
|
|
898
|
+
<category>semantic</category>
|
|
899
|
+
<content>User is a senior TypeScript developer with 8 years of backend experience</content>
|
|
850
900
|
<confidence>0.95</confidence>
|
|
851
901
|
</memory>
|
|
852
902
|
<memory>
|
|
853
|
-
<category>
|
|
854
|
-
<content>
|
|
855
|
-
<confidence>0.
|
|
903
|
+
<category>procedural</category>
|
|
904
|
+
<content>User follows TDD workflow: writes tests before implementation, runs tests after each change</content>
|
|
905
|
+
<confidence>0.88</confidence>
|
|
906
|
+
</memory>
|
|
907
|
+
<memory>
|
|
908
|
+
<category>episodic</category>
|
|
909
|
+
<content>User led database migration from MongoDB to PostgreSQL for payment system in Q2 2024</content>
|
|
910
|
+
<confidence>0.92</confidence>
|
|
856
911
|
</memory>
|
|
857
912
|
</memories>`;
|
|
858
913
|
function parseMemoryExtractionXML(xml) {
|
|
@@ -941,7 +996,7 @@ var longTermExtractionEvaluator = {
|
|
|
941
996
|
const extractions = parseMemoryExtractionXML(response);
|
|
942
997
|
import_core3.logger.info(`Extracted ${extractions.length} long-term memories`);
|
|
943
998
|
for (const extraction of extractions) {
|
|
944
|
-
if (extraction.confidence >= config.longTermConfidenceThreshold) {
|
|
999
|
+
if (extraction.confidence >= Math.max(config.longTermConfidenceThreshold, 0.85)) {
|
|
945
1000
|
await memoryService.storeLongTermMemory({
|
|
946
1001
|
agentId: runtime.agentId,
|
|
947
1002
|
entityId,
|
|
@@ -956,7 +1011,7 @@ var longTermExtractionEvaluator = {
|
|
|
956
1011
|
});
|
|
957
1012
|
import_core3.logger.info(`Stored long-term memory: [${extraction.category}] ${extraction.content.substring(0, 50)}...`);
|
|
958
1013
|
} else {
|
|
959
|
-
import_core3.logger.debug(`Skipped low-confidence memory: ${extraction.content} (confidence: ${extraction.confidence})`);
|
|
1014
|
+
import_core3.logger.debug(`Skipped low-confidence memory: ${extraction.content} (confidence: ${extraction.confidence}, threshold: ${Math.max(config.longTermConfidenceThreshold, 0.85)})`);
|
|
960
1015
|
}
|
|
961
1016
|
}
|
|
962
1017
|
const currentMessageCount = await runtime.countMemories(roomId, false, "messages");
|
|
@@ -971,26 +1026,31 @@ var longTermExtractionEvaluator = {
|
|
|
971
1026
|
|
|
972
1027
|
// src/providers/short-term-memory.ts
|
|
973
1028
|
var import_core4 = require("@elizaos/core");
|
|
1029
|
+
var getRecentInteractions = async (runtime, sourceEntityId, targetEntityId, excludeRoomId) => {
|
|
1030
|
+
const rooms = await runtime.getRoomsForParticipants([sourceEntityId, targetEntityId]);
|
|
1031
|
+
return runtime.getMemoriesByRoomIds({
|
|
1032
|
+
tableName: "messages",
|
|
1033
|
+
roomIds: rooms.filter((room) => room !== excludeRoomId),
|
|
1034
|
+
limit: 20
|
|
1035
|
+
});
|
|
1036
|
+
};
|
|
974
1037
|
var shortTermMemoryProvider = {
|
|
975
1038
|
name: "SHORT_TERM_MEMORY",
|
|
976
|
-
description: "
|
|
1039
|
+
description: "Unified conversation context with smart summarization and interactions",
|
|
977
1040
|
position: 95,
|
|
978
1041
|
get: async (runtime, message, _state) => {
|
|
979
1042
|
try {
|
|
980
1043
|
const memoryService = runtime.getService("memory");
|
|
981
|
-
if (!memoryService) {
|
|
982
|
-
return {
|
|
983
|
-
data: { summaries: [], recentMessages: [], mode: "disabled" },
|
|
984
|
-
values: {},
|
|
985
|
-
text: ""
|
|
986
|
-
};
|
|
987
|
-
}
|
|
988
1044
|
const { roomId } = message;
|
|
989
|
-
const
|
|
1045
|
+
const conversationLength = 16;
|
|
1046
|
+
const config = memoryService?.getConfig() || {
|
|
1047
|
+
shortTermSummarizationThreshold: 16,
|
|
1048
|
+
shortTermRetainRecent: 6
|
|
1049
|
+
};
|
|
990
1050
|
const totalMessageCount = await runtime.countMemories(roomId, false, "messages");
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
const [entitiesData, room, recentMessagesData] = await Promise.all([
|
|
1051
|
+
const useSummarization = memoryService && totalMessageCount >= config.shortTermSummarizationThreshold;
|
|
1052
|
+
if (!useSummarization) {
|
|
1053
|
+
const [entitiesData, room, recentMessagesData, recentInteractionsData] = await Promise.all([
|
|
994
1054
|
import_core4.getEntityDetails({ runtime, roomId }),
|
|
995
1055
|
runtime.getRoom(roomId),
|
|
996
1056
|
runtime.getMemories({
|
|
@@ -998,7 +1058,8 @@ var shortTermMemoryProvider = {
|
|
|
998
1058
|
roomId,
|
|
999
1059
|
count: conversationLength,
|
|
1000
1060
|
unique: false
|
|
1001
|
-
})
|
|
1061
|
+
}),
|
|
1062
|
+
message.entityId !== runtime.agentId ? getRecentInteractions(runtime, message.entityId, runtime.agentId, roomId) : Promise.resolve([])
|
|
1002
1063
|
]);
|
|
1003
1064
|
const actionResultMessages = recentMessagesData.filter((msg) => msg.content?.type === "action_result" && msg.metadata?.type === "action_result");
|
|
1004
1065
|
const dialogueMessages = recentMessagesData.filter((msg) => !(msg.content?.type === "action_result" && msg.metadata?.type === "action_result"));
|
|
@@ -1014,6 +1075,20 @@ var shortTermMemoryProvider = {
|
|
|
1014
1075
|
conversationHeader: false
|
|
1015
1076
|
})
|
|
1016
1077
|
]);
|
|
1078
|
+
const formatConversationLog = (messages, includeThoughts) => {
|
|
1079
|
+
return messages.sort((a, b) => (a.createdAt || 0) - (b.createdAt || 0)).map((msg) => {
|
|
1080
|
+
const entity = entitiesData.find((e) => e.id === msg.entityId);
|
|
1081
|
+
const entityName = entity?.names[0] || (msg.entityId === runtime.agentId ? runtime.character.name : "Unknown");
|
|
1082
|
+
const timestamp4 = msg.createdAt ? new Date(msg.createdAt).toLocaleString() : "Unknown time";
|
|
1083
|
+
const text5 = msg.content.text || "";
|
|
1084
|
+
const thought = includeThoughts && msg.content.internalMonologue ? `
|
|
1085
|
+
[Internal thought: ${msg.content.internalMonologue}]` : "";
|
|
1086
|
+
return `[${timestamp4}] ${entityName}: ${text5}${thought}`;
|
|
1087
|
+
}).join(`
|
|
1088
|
+
`);
|
|
1089
|
+
};
|
|
1090
|
+
const conversationLog = formatConversationLog(dialogueMessages, false);
|
|
1091
|
+
const conversationLogWithAgentThoughts = formatConversationLog(dialogueMessages, true);
|
|
1017
1092
|
let actionResultsText = "";
|
|
1018
1093
|
if (actionResultMessages.length > 0) {
|
|
1019
1094
|
const groupedByRun = new Map;
|
|
@@ -1022,7 +1097,10 @@ var shortTermMemoryProvider = {
|
|
|
1022
1097
|
if (!groupedByRun.has(runId)) {
|
|
1023
1098
|
groupedByRun.set(runId, []);
|
|
1024
1099
|
}
|
|
1025
|
-
groupedByRun.get(runId)
|
|
1100
|
+
const memories = groupedByRun.get(runId);
|
|
1101
|
+
if (memories) {
|
|
1102
|
+
memories.push(mem);
|
|
1103
|
+
}
|
|
1026
1104
|
}
|
|
1027
1105
|
const formattedActionResults = Array.from(groupedByRun.entries()).slice(-3).map(([runId, memories]) => {
|
|
1028
1106
|
const sortedMemories = memories.sort((a, b) => (a.createdAt || 0) - (b.createdAt || 0));
|
|
@@ -1058,11 +1136,20 @@ ${runText}`;
|
|
|
1058
1136
|
data: {
|
|
1059
1137
|
summaries: [],
|
|
1060
1138
|
recentMessages: [],
|
|
1139
|
+
recentInteractions: [],
|
|
1061
1140
|
actionResults: [],
|
|
1062
1141
|
mode: "full_conversation"
|
|
1063
1142
|
},
|
|
1064
1143
|
values: {
|
|
1065
|
-
|
|
1144
|
+
recentPosts: "",
|
|
1145
|
+
recentMessages: "",
|
|
1146
|
+
recentMessageInteractions: "",
|
|
1147
|
+
recentPostInteractions: "",
|
|
1148
|
+
recentInteractions: "",
|
|
1149
|
+
recentActionResults: "",
|
|
1150
|
+
recentMessage: "No recent message available.",
|
|
1151
|
+
conversationLog: "",
|
|
1152
|
+
conversationLogWithAgentThoughts: ""
|
|
1066
1153
|
},
|
|
1067
1154
|
text: "No recent messages available"
|
|
1068
1155
|
};
|
|
@@ -1084,6 +1171,80 @@ ${runText}`;
|
|
|
1084
1171
|
const hasReceivedMessage = !!receivedMessageContent?.trim();
|
|
1085
1172
|
const receivedMessageHeader = hasReceivedMessage ? import_core4.addHeader("# Received Message", `${senderName}: ${receivedMessageContent}`) : "";
|
|
1086
1173
|
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.`) : "";
|
|
1174
|
+
const interactionEntityMap = new Map;
|
|
1175
|
+
if (recentInteractionsData.length > 0) {
|
|
1176
|
+
const uniqueEntityIds = [
|
|
1177
|
+
...new Set(recentInteractionsData.map((message2) => message2.entityId).filter((id) => id !== runtime.agentId))
|
|
1178
|
+
];
|
|
1179
|
+
const uniqueEntityIdSet = new Set(uniqueEntityIds);
|
|
1180
|
+
const entitiesDataIdSet = new Set;
|
|
1181
|
+
entitiesData.forEach((entity) => {
|
|
1182
|
+
if (uniqueEntityIdSet.has(entity.id)) {
|
|
1183
|
+
interactionEntityMap.set(entity.id, entity);
|
|
1184
|
+
entitiesDataIdSet.add(entity.id);
|
|
1185
|
+
}
|
|
1186
|
+
});
|
|
1187
|
+
const remainingEntityIds = uniqueEntityIds.filter((id) => !entitiesDataIdSet.has(id));
|
|
1188
|
+
if (remainingEntityIds.length > 0) {
|
|
1189
|
+
const entities = await Promise.all(remainingEntityIds.map((entityId) => runtime.getEntityById(entityId)));
|
|
1190
|
+
entities.forEach((entity, index4) => {
|
|
1191
|
+
if (entity) {
|
|
1192
|
+
interactionEntityMap.set(remainingEntityIds[index4], entity);
|
|
1193
|
+
}
|
|
1194
|
+
});
|
|
1195
|
+
}
|
|
1196
|
+
}
|
|
1197
|
+
const getRecentMessageInteractions = async (recentInteractionsData2) => {
|
|
1198
|
+
const formattedInteractions = recentInteractionsData2.map((message2) => {
|
|
1199
|
+
const isSelf = message2.entityId === runtime.agentId;
|
|
1200
|
+
let sender;
|
|
1201
|
+
if (isSelf) {
|
|
1202
|
+
sender = runtime.character.name;
|
|
1203
|
+
} else {
|
|
1204
|
+
sender = interactionEntityMap.get(message2.entityId)?.metadata?.userName || "unknown";
|
|
1205
|
+
}
|
|
1206
|
+
return `${sender}: ${message2.content.text}`;
|
|
1207
|
+
});
|
|
1208
|
+
return formattedInteractions.join(`
|
|
1209
|
+
`);
|
|
1210
|
+
};
|
|
1211
|
+
const getRecentPostInteractions = async (recentInteractionsData2, entities) => {
|
|
1212
|
+
const combinedEntities = [...entities];
|
|
1213
|
+
const actorIds = new Set(entities.map((entity) => entity.id));
|
|
1214
|
+
for (const [id, entity] of interactionEntityMap.entries()) {
|
|
1215
|
+
if (!actorIds.has(id)) {
|
|
1216
|
+
combinedEntities.push(entity);
|
|
1217
|
+
}
|
|
1218
|
+
}
|
|
1219
|
+
const formattedInteractions = import_core4.formatPosts({
|
|
1220
|
+
messages: recentInteractionsData2,
|
|
1221
|
+
entities: combinedEntities,
|
|
1222
|
+
conversationHeader: true
|
|
1223
|
+
});
|
|
1224
|
+
return formattedInteractions;
|
|
1225
|
+
};
|
|
1226
|
+
const [recentMessageInteractions, recentPostInteractions] = await Promise.all([
|
|
1227
|
+
getRecentMessageInteractions(recentInteractionsData),
|
|
1228
|
+
getRecentPostInteractions(recentInteractionsData, entitiesData)
|
|
1229
|
+
]);
|
|
1230
|
+
const data = {
|
|
1231
|
+
summaries: [],
|
|
1232
|
+
recentMessages: dialogueMessages,
|
|
1233
|
+
recentInteractions: recentInteractionsData,
|
|
1234
|
+
actionResults: actionResultMessages,
|
|
1235
|
+
mode: "full_conversation"
|
|
1236
|
+
};
|
|
1237
|
+
const values = {
|
|
1238
|
+
recentPosts,
|
|
1239
|
+
recentMessages,
|
|
1240
|
+
recentMessageInteractions,
|
|
1241
|
+
recentPostInteractions,
|
|
1242
|
+
recentInteractions: isPostFormat ? recentPostInteractions : recentMessageInteractions,
|
|
1243
|
+
recentActionResults: actionResultsText,
|
|
1244
|
+
recentMessage,
|
|
1245
|
+
conversationLog,
|
|
1246
|
+
conversationLogWithAgentThoughts
|
|
1247
|
+
};
|
|
1087
1248
|
const text4 = [
|
|
1088
1249
|
isPostFormat ? recentPosts : recentMessages,
|
|
1089
1250
|
actionResultsText,
|
|
@@ -1093,40 +1254,68 @@ ${runText}`;
|
|
|
1093
1254
|
|
|
1094
1255
|
`);
|
|
1095
1256
|
return {
|
|
1096
|
-
data
|
|
1097
|
-
|
|
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
|
-
},
|
|
1257
|
+
data,
|
|
1258
|
+
values,
|
|
1112
1259
|
text: text4
|
|
1113
1260
|
};
|
|
1114
1261
|
} else {
|
|
1115
1262
|
const currentSummary = await memoryService.getCurrentSessionSummary(roomId);
|
|
1116
1263
|
const lastOffset = currentSummary?.lastMessageOffset || 0;
|
|
1117
|
-
const
|
|
1118
|
-
|
|
1119
|
-
roomId,
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1264
|
+
const recentCount = config.shortTermRetainRecent;
|
|
1265
|
+
const [entitiesData, room, unsummarizedMessages, recentInteractionsData] = await Promise.all([
|
|
1266
|
+
import_core4.getEntityDetails({ runtime, roomId }),
|
|
1267
|
+
runtime.getRoom(roomId),
|
|
1268
|
+
runtime.getMemories({
|
|
1269
|
+
tableName: "messages",
|
|
1270
|
+
roomId,
|
|
1271
|
+
count: recentCount,
|
|
1272
|
+
unique: false,
|
|
1273
|
+
start: lastOffset
|
|
1274
|
+
}),
|
|
1275
|
+
message.entityId !== runtime.agentId ? getRecentInteractions(runtime, message.entityId, runtime.agentId, roomId) : Promise.resolve([])
|
|
1276
|
+
]);
|
|
1126
1277
|
const isPostFormat = room?.type ? room.type === import_core4.ChannelType.FEED || room.type === import_core4.ChannelType.THREAD : false;
|
|
1278
|
+
const actionResultMessages = unsummarizedMessages.filter((msg) => msg.content?.type === "action_result" && msg.metadata?.type === "action_result");
|
|
1279
|
+
const dialogueMessages = unsummarizedMessages.filter((msg) => !(msg.content?.type === "action_result" && msg.metadata?.type === "action_result"));
|
|
1280
|
+
let actionResultsText = "";
|
|
1281
|
+
if (actionResultMessages.length > 0) {
|
|
1282
|
+
const groupedByRun = new Map;
|
|
1283
|
+
for (const mem of actionResultMessages) {
|
|
1284
|
+
const runId = String(mem.content?.runId || "unknown");
|
|
1285
|
+
if (!groupedByRun.has(runId)) {
|
|
1286
|
+
groupedByRun.set(runId, []);
|
|
1287
|
+
}
|
|
1288
|
+
groupedByRun.get(runId)?.push(mem);
|
|
1289
|
+
}
|
|
1290
|
+
const formattedActionResults = Array.from(groupedByRun.entries()).slice(-3).map(([runId, memories]) => {
|
|
1291
|
+
const sortedMemories = memories.sort((a, b) => (a.createdAt || 0) - (b.createdAt || 0));
|
|
1292
|
+
const thought = sortedMemories[0]?.content?.planThought || "";
|
|
1293
|
+
const runText = sortedMemories.map((mem) => {
|
|
1294
|
+
const actionName = mem.content?.actionName || "Unknown";
|
|
1295
|
+
const status = mem.content?.actionStatus || "unknown";
|
|
1296
|
+
const planStep = mem.content?.planStep || "";
|
|
1297
|
+
const text5 = mem.content?.text || "";
|
|
1298
|
+
const error = mem.content?.error || "";
|
|
1299
|
+
let memText = ` - ${actionName} (${status})`;
|
|
1300
|
+
if (planStep)
|
|
1301
|
+
memText += ` [${planStep}]`;
|
|
1302
|
+
if (error) {
|
|
1303
|
+
memText += `: Error - ${error}`;
|
|
1304
|
+
} else if (text5 && text5 !== `Executed action: ${actionName}`) {
|
|
1305
|
+
memText += `: ${text5}`;
|
|
1306
|
+
}
|
|
1307
|
+
return memText;
|
|
1308
|
+
}).join(`
|
|
1309
|
+
`);
|
|
1310
|
+
return `**Action Run ${runId.slice(0, 8)}**${thought ? ` - "${thought}"` : ""}
|
|
1311
|
+
${runText}`;
|
|
1312
|
+
}).join(`
|
|
1313
|
+
|
|
1314
|
+
`);
|
|
1315
|
+
actionResultsText = formattedActionResults ? import_core4.addHeader("# Recent Action Executions", formattedActionResults) : "";
|
|
1316
|
+
}
|
|
1127
1317
|
let recentMessagesText = "";
|
|
1128
|
-
if (
|
|
1129
|
-
const dialogueMessages = unsummarizedMessages.filter((msg) => !(msg.content?.type === "action_result" && msg.metadata?.type === "action_result"));
|
|
1318
|
+
if (dialogueMessages.length > 0) {
|
|
1130
1319
|
if (isPostFormat) {
|
|
1131
1320
|
recentMessagesText = import_core4.formatPosts({
|
|
1132
1321
|
messages: dialogueMessages,
|
|
@@ -1143,6 +1332,31 @@ ${runText}`;
|
|
|
1143
1332
|
recentMessagesText = import_core4.addHeader("# Recent Messages", recentMessagesText);
|
|
1144
1333
|
}
|
|
1145
1334
|
}
|
|
1335
|
+
let recentMessage = "No recent message available.";
|
|
1336
|
+
if (dialogueMessages.length > 0) {
|
|
1337
|
+
const mostRecentMessage = [...dialogueMessages].sort((a, b) => (b.createdAt || 0) - (a.createdAt || 0))[0];
|
|
1338
|
+
const formattedSingleMessage = import_core4.formatMessages({
|
|
1339
|
+
messages: [mostRecentMessage],
|
|
1340
|
+
entities: entitiesData
|
|
1341
|
+
});
|
|
1342
|
+
if (formattedSingleMessage) {
|
|
1343
|
+
recentMessage = formattedSingleMessage;
|
|
1344
|
+
}
|
|
1345
|
+
}
|
|
1346
|
+
const formatConversationLog = (messages, includeThoughts) => {
|
|
1347
|
+
return messages.sort((a, b) => (a.createdAt || 0) - (b.createdAt || 0)).map((msg) => {
|
|
1348
|
+
const entity = entitiesData.find((e) => e.id === msg.entityId);
|
|
1349
|
+
const entityName = entity?.names[0] || (msg.entityId === runtime.agentId ? runtime.character.name : "Unknown");
|
|
1350
|
+
const timestamp4 = msg.createdAt ? new Date(msg.createdAt).toLocaleString() : "Unknown time";
|
|
1351
|
+
const text5 = msg.content.text || "";
|
|
1352
|
+
const thought = includeThoughts && msg.content.internalMonologue ? `
|
|
1353
|
+
[Internal thought: ${msg.content.internalMonologue}]` : "";
|
|
1354
|
+
return `[${timestamp4}] ${entityName}: ${text5}${thought}`;
|
|
1355
|
+
}).join(`
|
|
1356
|
+
`);
|
|
1357
|
+
};
|
|
1358
|
+
const conversationLog = formatConversationLog(dialogueMessages, false);
|
|
1359
|
+
const conversationLogWithAgentThoughts = formatConversationLog(dialogueMessages, true);
|
|
1146
1360
|
let summaryText = "";
|
|
1147
1361
|
if (currentSummary) {
|
|
1148
1362
|
const messageRange = `${currentSummary.messageCount} messages`;
|
|
@@ -1162,9 +1376,66 @@ ${runText}`;
|
|
|
1162
1376
|
const hasReceivedMessage = !!receivedMessageContent?.trim();
|
|
1163
1377
|
const receivedMessageHeader = hasReceivedMessage ? import_core4.addHeader("# Received Message", `${senderName}: ${receivedMessageContent}`) : "";
|
|
1164
1378
|
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.`) : "";
|
|
1379
|
+
const interactionEntityMap = new Map;
|
|
1380
|
+
if (recentInteractionsData.length > 0) {
|
|
1381
|
+
const uniqueEntityIds = [
|
|
1382
|
+
...new Set(recentInteractionsData.map((message2) => message2.entityId).filter((id) => id !== runtime.agentId))
|
|
1383
|
+
];
|
|
1384
|
+
const uniqueEntityIdSet = new Set(uniqueEntityIds);
|
|
1385
|
+
const entitiesDataIdSet = new Set;
|
|
1386
|
+
entitiesData.forEach((entity) => {
|
|
1387
|
+
if (uniqueEntityIdSet.has(entity.id)) {
|
|
1388
|
+
interactionEntityMap.set(entity.id, entity);
|
|
1389
|
+
entitiesDataIdSet.add(entity.id);
|
|
1390
|
+
}
|
|
1391
|
+
});
|
|
1392
|
+
const remainingEntityIds = uniqueEntityIds.filter((id) => !entitiesDataIdSet.has(id));
|
|
1393
|
+
if (remainingEntityIds.length > 0) {
|
|
1394
|
+
const entities = await Promise.all(remainingEntityIds.map((entityId) => runtime.getEntityById(entityId)));
|
|
1395
|
+
entities.forEach((entity, index4) => {
|
|
1396
|
+
if (entity) {
|
|
1397
|
+
interactionEntityMap.set(remainingEntityIds[index4], entity);
|
|
1398
|
+
}
|
|
1399
|
+
});
|
|
1400
|
+
}
|
|
1401
|
+
}
|
|
1402
|
+
const getRecentMessageInteractions = async (recentInteractionsData2) => {
|
|
1403
|
+
const formattedInteractions = recentInteractionsData2.map((message2) => {
|
|
1404
|
+
const isSelf = message2.entityId === runtime.agentId;
|
|
1405
|
+
let sender;
|
|
1406
|
+
if (isSelf) {
|
|
1407
|
+
sender = runtime.character.name;
|
|
1408
|
+
} else {
|
|
1409
|
+
sender = interactionEntityMap.get(message2.entityId)?.metadata?.userName || "unknown";
|
|
1410
|
+
}
|
|
1411
|
+
return `${sender}: ${message2.content.text}`;
|
|
1412
|
+
});
|
|
1413
|
+
return formattedInteractions.join(`
|
|
1414
|
+
`);
|
|
1415
|
+
};
|
|
1416
|
+
const getRecentPostInteractions = async (recentInteractionsData2, entities) => {
|
|
1417
|
+
const combinedEntities = [...entities];
|
|
1418
|
+
const actorIds = new Set(entities.map((entity) => entity.id));
|
|
1419
|
+
for (const [id, entity] of interactionEntityMap.entries()) {
|
|
1420
|
+
if (!actorIds.has(id)) {
|
|
1421
|
+
combinedEntities.push(entity);
|
|
1422
|
+
}
|
|
1423
|
+
}
|
|
1424
|
+
const formattedInteractions = import_core4.formatPosts({
|
|
1425
|
+
messages: recentInteractionsData2,
|
|
1426
|
+
entities: combinedEntities,
|
|
1427
|
+
conversationHeader: true
|
|
1428
|
+
});
|
|
1429
|
+
return formattedInteractions;
|
|
1430
|
+
};
|
|
1431
|
+
const [recentMessageInteractions, recentPostInteractions] = await Promise.all([
|
|
1432
|
+
getRecentMessageInteractions(recentInteractionsData),
|
|
1433
|
+
getRecentPostInteractions(recentInteractionsData, entitiesData)
|
|
1434
|
+
]);
|
|
1165
1435
|
const text4 = [
|
|
1166
1436
|
summaryText,
|
|
1167
1437
|
recentMessagesText,
|
|
1438
|
+
actionResultsText,
|
|
1168
1439
|
hasReceivedMessage ? receivedMessageHeader : "",
|
|
1169
1440
|
hasReceivedMessage ? focusHeader : ""
|
|
1170
1441
|
].filter(Boolean).join(`
|
|
@@ -1173,12 +1444,21 @@ ${runText}`;
|
|
|
1173
1444
|
return {
|
|
1174
1445
|
data: {
|
|
1175
1446
|
summaries: currentSummary ? [currentSummary] : [],
|
|
1176
|
-
recentMessages:
|
|
1447
|
+
recentMessages: dialogueMessages,
|
|
1448
|
+
recentInteractions: recentInteractionsData,
|
|
1449
|
+
actionResults: actionResultMessages,
|
|
1177
1450
|
mode: "summarized"
|
|
1178
1451
|
},
|
|
1179
1452
|
values: {
|
|
1180
1453
|
...summaryText && { sessionSummaries: summaryText },
|
|
1181
1454
|
...recentMessagesText && { recentMessages: recentMessagesText },
|
|
1455
|
+
recentMessageInteractions,
|
|
1456
|
+
recentPostInteractions,
|
|
1457
|
+
recentInteractions: isPostFormat ? recentPostInteractions : recentMessageInteractions,
|
|
1458
|
+
...actionResultsText && { recentActionResults: actionResultsText },
|
|
1459
|
+
recentMessage,
|
|
1460
|
+
conversationLog,
|
|
1461
|
+
conversationLogWithAgentThoughts,
|
|
1182
1462
|
...receivedMessageHeader && { receivedMessageHeader },
|
|
1183
1463
|
...focusHeader && { focusHeader }
|
|
1184
1464
|
},
|
|
@@ -1188,8 +1468,23 @@ ${runText}`;
|
|
|
1188
1468
|
} catch (error) {
|
|
1189
1469
|
import_core4.logger.error({ error }, "Error in shortTermMemoryProvider:");
|
|
1190
1470
|
return {
|
|
1191
|
-
data: {
|
|
1192
|
-
|
|
1471
|
+
data: {
|
|
1472
|
+
summaries: [],
|
|
1473
|
+
recentMessages: [],
|
|
1474
|
+
recentInteractions: [],
|
|
1475
|
+
actionResults: [],
|
|
1476
|
+
mode: "error"
|
|
1477
|
+
},
|
|
1478
|
+
values: {
|
|
1479
|
+
recentPosts: "",
|
|
1480
|
+
recentMessages: "",
|
|
1481
|
+
recentMessageInteractions: "",
|
|
1482
|
+
recentPostInteractions: "",
|
|
1483
|
+
recentInteractions: "",
|
|
1484
|
+
recentActionResults: "",
|
|
1485
|
+
conversationLog: "",
|
|
1486
|
+
conversationLogWithAgentThoughts: ""
|
|
1487
|
+
},
|
|
1193
1488
|
text: "Error retrieving conversation context."
|
|
1194
1489
|
};
|
|
1195
1490
|
}
|
|
@@ -1269,4 +1564,4 @@ var memoryPlugin = {
|
|
|
1269
1564
|
};
|
|
1270
1565
|
var src_default = memoryPlugin;
|
|
1271
1566
|
|
|
1272
|
-
//# debugId=
|
|
1567
|
+
//# debugId=A3C66779A69339CA64756E2164756E21
|