@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/node/index.node.js
CHANGED
|
@@ -118,13 +118,13 @@ class MemoryService extends Service {
|
|
|
118
118
|
this.lastExtractionCheckpoints = new Map;
|
|
119
119
|
this.memoryConfig = {
|
|
120
120
|
shortTermSummarizationThreshold: 16,
|
|
121
|
-
shortTermRetainRecent:
|
|
121
|
+
shortTermRetainRecent: 6,
|
|
122
122
|
shortTermSummarizationInterval: 10,
|
|
123
123
|
longTermExtractionEnabled: true,
|
|
124
124
|
longTermVectorSearchEnabled: false,
|
|
125
|
-
longTermConfidenceThreshold: 0.
|
|
126
|
-
longTermExtractionThreshold:
|
|
127
|
-
longTermExtractionInterval:
|
|
125
|
+
longTermConfidenceThreshold: 0.85,
|
|
126
|
+
longTermExtractionThreshold: 30,
|
|
127
|
+
longTermExtractionInterval: 10,
|
|
128
128
|
summaryModelType: "TEXT_LARGE",
|
|
129
129
|
summaryMaxTokens: 2500,
|
|
130
130
|
summaryMaxNewMessages: 20
|
|
@@ -770,21 +770,15 @@ import {
|
|
|
770
770
|
// src/types/index.ts
|
|
771
771
|
var LongTermMemoryCategory;
|
|
772
772
|
((LongTermMemoryCategory2) => {
|
|
773
|
-
LongTermMemoryCategory2["
|
|
774
|
-
LongTermMemoryCategory2["
|
|
775
|
-
LongTermMemoryCategory2["
|
|
776
|
-
LongTermMemoryCategory2["PREFERENCES"] = "preferences";
|
|
777
|
-
LongTermMemoryCategory2["DATA_SOURCES"] = "data_sources";
|
|
778
|
-
LongTermMemoryCategory2["GOALS"] = "goals";
|
|
779
|
-
LongTermMemoryCategory2["CONSTRAINTS"] = "constraints";
|
|
780
|
-
LongTermMemoryCategory2["DEFINITIONS"] = "definitions";
|
|
781
|
-
LongTermMemoryCategory2["BEHAVIORAL_PATTERNS"] = "behavioral_patterns";
|
|
773
|
+
LongTermMemoryCategory2["EPISODIC"] = "episodic";
|
|
774
|
+
LongTermMemoryCategory2["SEMANTIC"] = "semantic";
|
|
775
|
+
LongTermMemoryCategory2["PROCEDURAL"] = "procedural";
|
|
782
776
|
})(LongTermMemoryCategory ||= {});
|
|
783
777
|
|
|
784
778
|
// src/evaluators/long-term-extraction.ts
|
|
785
|
-
var extractionTemplate = `# Task: Extract Long-Term Memory
|
|
779
|
+
var extractionTemplate = `# Task: Extract Long-Term Memory (Strict Criteria)
|
|
786
780
|
|
|
787
|
-
You are analyzing a conversation to extract ONLY the most
|
|
781
|
+
You are analyzing a conversation to extract ONLY the most critical, persistent information about the user using cognitive science memory categories.
|
|
788
782
|
|
|
789
783
|
# Recent Messages
|
|
790
784
|
{{recentMessages}}
|
|
@@ -792,66 +786,127 @@ You are analyzing a conversation to extract ONLY the most important, persistent
|
|
|
792
786
|
# Current Long-Term Memories
|
|
793
787
|
{{existingMemories}}
|
|
794
788
|
|
|
795
|
-
# Memory Categories
|
|
796
|
-
1. **identity**: User's name, role, identity (e.g., "I'm a data scientist")
|
|
797
|
-
2. **expertise**: User's skills, knowledge domains, or unfamiliarity with topics
|
|
798
|
-
3. **projects**: Ongoing projects, past interactions, recurring topics
|
|
799
|
-
4. **preferences**: Communication style, format preferences, verbosity, etc.
|
|
800
|
-
5. **data_sources**: Frequently used files, databases, APIs
|
|
801
|
-
6. **goals**: Broader intentions (e.g., "preparing for interview")
|
|
802
|
-
7. **constraints**: User-defined rules or limitations
|
|
803
|
-
8. **definitions**: Custom terms, acronyms, glossaries
|
|
804
|
-
9. **behavioral_patterns**: How the user tends to interact
|
|
789
|
+
# Memory Categories (Based on Cognitive Science)
|
|
805
790
|
|
|
806
|
-
|
|
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"
|
|
807
797
|
|
|
808
|
-
**
|
|
809
|
-
-
|
|
810
|
-
-
|
|
811
|
-
-
|
|
812
|
-
- Important ongoing projects or goals mentioned multiple times
|
|
813
|
-
- Persistent technical constraints or requirements
|
|
814
|
-
- Domain expertise demonstrated consistently
|
|
815
|
-
- Custom terminology the user defines and uses repeatedly
|
|
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
|
|
816
802
|
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
-
|
|
821
|
-
-
|
|
822
|
-
-
|
|
823
|
-
-
|
|
824
|
-
- Random or playful requests that don't indicate lasting preference
|
|
825
|
-
- Information that could change or is situational
|
|
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"
|
|
826
810
|
|
|
827
|
-
|
|
828
|
-
-
|
|
829
|
-
-
|
|
830
|
-
-
|
|
831
|
-
-
|
|
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
|
|
832
816
|
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
-
|
|
837
|
-
-
|
|
838
|
-
-
|
|
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"
|
|
839
824
|
|
|
840
|
-
**
|
|
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
|
|
841
830
|
|
|
842
|
-
|
|
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
|
|
843
894
|
|
|
844
|
-
Respond in this XML format:
|
|
845
895
|
<memories>
|
|
846
896
|
<memory>
|
|
847
|
-
<category>
|
|
848
|
-
<content>User is a
|
|
897
|
+
<category>semantic</category>
|
|
898
|
+
<content>User is a senior TypeScript developer with 8 years of backend experience</content>
|
|
849
899
|
<confidence>0.95</confidence>
|
|
850
900
|
</memory>
|
|
851
901
|
<memory>
|
|
852
|
-
<category>
|
|
853
|
-
<content>
|
|
854
|
-
<confidence>0.
|
|
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>
|
|
855
910
|
</memory>
|
|
856
911
|
</memories>`;
|
|
857
912
|
function parseMemoryExtractionXML(xml) {
|
|
@@ -940,7 +995,7 @@ var longTermExtractionEvaluator = {
|
|
|
940
995
|
const extractions = parseMemoryExtractionXML(response);
|
|
941
996
|
logger3.info(`Extracted ${extractions.length} long-term memories`);
|
|
942
997
|
for (const extraction of extractions) {
|
|
943
|
-
if (extraction.confidence >= config.longTermConfidenceThreshold) {
|
|
998
|
+
if (extraction.confidence >= Math.max(config.longTermConfidenceThreshold, 0.85)) {
|
|
944
999
|
await memoryService.storeLongTermMemory({
|
|
945
1000
|
agentId: runtime.agentId,
|
|
946
1001
|
entityId,
|
|
@@ -955,7 +1010,7 @@ var longTermExtractionEvaluator = {
|
|
|
955
1010
|
});
|
|
956
1011
|
logger3.info(`Stored long-term memory: [${extraction.category}] ${extraction.content.substring(0, 50)}...`);
|
|
957
1012
|
} else {
|
|
958
|
-
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)})`);
|
|
959
1014
|
}
|
|
960
1015
|
}
|
|
961
1016
|
const currentMessageCount = await runtime.countMemories(roomId, false, "messages");
|
|
@@ -977,26 +1032,31 @@ import {
|
|
|
977
1032
|
getEntityDetails,
|
|
978
1033
|
logger as logger4
|
|
979
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
|
+
};
|
|
980
1043
|
var shortTermMemoryProvider = {
|
|
981
1044
|
name: "SHORT_TERM_MEMORY",
|
|
982
|
-
description: "
|
|
1045
|
+
description: "Unified conversation context with smart summarization and interactions",
|
|
983
1046
|
position: 95,
|
|
984
1047
|
get: async (runtime, message, _state) => {
|
|
985
1048
|
try {
|
|
986
1049
|
const memoryService = runtime.getService("memory");
|
|
987
|
-
if (!memoryService) {
|
|
988
|
-
return {
|
|
989
|
-
data: { summaries: [], recentMessages: [], mode: "disabled" },
|
|
990
|
-
values: {},
|
|
991
|
-
text: ""
|
|
992
|
-
};
|
|
993
|
-
}
|
|
994
1050
|
const { roomId } = message;
|
|
995
|
-
const
|
|
1051
|
+
const conversationLength = 16;
|
|
1052
|
+
const config = memoryService?.getConfig() || {
|
|
1053
|
+
shortTermSummarizationThreshold: 16,
|
|
1054
|
+
shortTermRetainRecent: 6
|
|
1055
|
+
};
|
|
996
1056
|
const totalMessageCount = await runtime.countMemories(roomId, false, "messages");
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
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([
|
|
1000
1060
|
getEntityDetails({ runtime, roomId }),
|
|
1001
1061
|
runtime.getRoom(roomId),
|
|
1002
1062
|
runtime.getMemories({
|
|
@@ -1004,7 +1064,8 @@ var shortTermMemoryProvider = {
|
|
|
1004
1064
|
roomId,
|
|
1005
1065
|
count: conversationLength,
|
|
1006
1066
|
unique: false
|
|
1007
|
-
})
|
|
1067
|
+
}),
|
|
1068
|
+
message.entityId !== runtime.agentId ? getRecentInteractions(runtime, message.entityId, runtime.agentId, roomId) : Promise.resolve([])
|
|
1008
1069
|
]);
|
|
1009
1070
|
const actionResultMessages = recentMessagesData.filter((msg) => msg.content?.type === "action_result" && msg.metadata?.type === "action_result");
|
|
1010
1071
|
const dialogueMessages = recentMessagesData.filter((msg) => !(msg.content?.type === "action_result" && msg.metadata?.type === "action_result"));
|
|
@@ -1020,6 +1081,20 @@ var shortTermMemoryProvider = {
|
|
|
1020
1081
|
conversationHeader: false
|
|
1021
1082
|
})
|
|
1022
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);
|
|
1023
1098
|
let actionResultsText = "";
|
|
1024
1099
|
if (actionResultMessages.length > 0) {
|
|
1025
1100
|
const groupedByRun = new Map;
|
|
@@ -1028,7 +1103,10 @@ var shortTermMemoryProvider = {
|
|
|
1028
1103
|
if (!groupedByRun.has(runId)) {
|
|
1029
1104
|
groupedByRun.set(runId, []);
|
|
1030
1105
|
}
|
|
1031
|
-
groupedByRun.get(runId)
|
|
1106
|
+
const memories = groupedByRun.get(runId);
|
|
1107
|
+
if (memories) {
|
|
1108
|
+
memories.push(mem);
|
|
1109
|
+
}
|
|
1032
1110
|
}
|
|
1033
1111
|
const formattedActionResults = Array.from(groupedByRun.entries()).slice(-3).map(([runId, memories]) => {
|
|
1034
1112
|
const sortedMemories = memories.sort((a, b) => (a.createdAt || 0) - (b.createdAt || 0));
|
|
@@ -1064,11 +1142,20 @@ ${runText}`;
|
|
|
1064
1142
|
data: {
|
|
1065
1143
|
summaries: [],
|
|
1066
1144
|
recentMessages: [],
|
|
1145
|
+
recentInteractions: [],
|
|
1067
1146
|
actionResults: [],
|
|
1068
1147
|
mode: "full_conversation"
|
|
1069
1148
|
},
|
|
1070
1149
|
values: {
|
|
1071
|
-
|
|
1150
|
+
recentPosts: "",
|
|
1151
|
+
recentMessages: "",
|
|
1152
|
+
recentMessageInteractions: "",
|
|
1153
|
+
recentPostInteractions: "",
|
|
1154
|
+
recentInteractions: "",
|
|
1155
|
+
recentActionResults: "",
|
|
1156
|
+
recentMessage: "No recent message available.",
|
|
1157
|
+
conversationLog: "",
|
|
1158
|
+
conversationLogWithAgentThoughts: ""
|
|
1072
1159
|
},
|
|
1073
1160
|
text: "No recent messages available"
|
|
1074
1161
|
};
|
|
@@ -1090,6 +1177,80 @@ ${runText}`;
|
|
|
1090
1177
|
const hasReceivedMessage = !!receivedMessageContent?.trim();
|
|
1091
1178
|
const receivedMessageHeader = hasReceivedMessage ? addHeader("# Received Message", `${senderName}: ${receivedMessageContent}`) : "";
|
|
1092
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
|
+
};
|
|
1093
1254
|
const text4 = [
|
|
1094
1255
|
isPostFormat ? recentPosts : recentMessages,
|
|
1095
1256
|
actionResultsText,
|
|
@@ -1099,40 +1260,68 @@ ${runText}`;
|
|
|
1099
1260
|
|
|
1100
1261
|
`);
|
|
1101
1262
|
return {
|
|
1102
|
-
data
|
|
1103
|
-
|
|
1104
|
-
recentMessages: dialogueMessages,
|
|
1105
|
-
actionResults: actionResultMessages,
|
|
1106
|
-
mode: "full_conversation"
|
|
1107
|
-
},
|
|
1108
|
-
values: {
|
|
1109
|
-
...(isPostFormat ? recentPosts : recentMessages) && {
|
|
1110
|
-
recentMessages: isPostFormat ? recentPosts : recentMessages
|
|
1111
|
-
},
|
|
1112
|
-
...recentPosts && { recentPosts },
|
|
1113
|
-
...actionResultsText && { recentActionResults: actionResultsText },
|
|
1114
|
-
...recentMessage && { recentMessage },
|
|
1115
|
-
...receivedMessageHeader && { receivedMessageHeader },
|
|
1116
|
-
...focusHeader && { focusHeader }
|
|
1117
|
-
},
|
|
1263
|
+
data,
|
|
1264
|
+
values,
|
|
1118
1265
|
text: text4
|
|
1119
1266
|
};
|
|
1120
1267
|
} else {
|
|
1121
1268
|
const currentSummary = await memoryService.getCurrentSessionSummary(roomId);
|
|
1122
1269
|
const lastOffset = currentSummary?.lastMessageOffset || 0;
|
|
1123
|
-
const
|
|
1124
|
-
|
|
1125
|
-
roomId,
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
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
|
+
]);
|
|
1132
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
|
+
}
|
|
1133
1323
|
let recentMessagesText = "";
|
|
1134
|
-
if (
|
|
1135
|
-
const dialogueMessages = unsummarizedMessages.filter((msg) => !(msg.content?.type === "action_result" && msg.metadata?.type === "action_result"));
|
|
1324
|
+
if (dialogueMessages.length > 0) {
|
|
1136
1325
|
if (isPostFormat) {
|
|
1137
1326
|
recentMessagesText = formatPosts({
|
|
1138
1327
|
messages: dialogueMessages,
|
|
@@ -1149,6 +1338,31 @@ ${runText}`;
|
|
|
1149
1338
|
recentMessagesText = addHeader("# Recent Messages", recentMessagesText);
|
|
1150
1339
|
}
|
|
1151
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);
|
|
1152
1366
|
let summaryText = "";
|
|
1153
1367
|
if (currentSummary) {
|
|
1154
1368
|
const messageRange = `${currentSummary.messageCount} messages`;
|
|
@@ -1168,9 +1382,66 @@ ${runText}`;
|
|
|
1168
1382
|
const hasReceivedMessage = !!receivedMessageContent?.trim();
|
|
1169
1383
|
const receivedMessageHeader = hasReceivedMessage ? addHeader("# Received Message", `${senderName}: ${receivedMessageContent}`) : "";
|
|
1170
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
|
+
]);
|
|
1171
1441
|
const text4 = [
|
|
1172
1442
|
summaryText,
|
|
1173
1443
|
recentMessagesText,
|
|
1444
|
+
actionResultsText,
|
|
1174
1445
|
hasReceivedMessage ? receivedMessageHeader : "",
|
|
1175
1446
|
hasReceivedMessage ? focusHeader : ""
|
|
1176
1447
|
].filter(Boolean).join(`
|
|
@@ -1179,12 +1450,21 @@ ${runText}`;
|
|
|
1179
1450
|
return {
|
|
1180
1451
|
data: {
|
|
1181
1452
|
summaries: currentSummary ? [currentSummary] : [],
|
|
1182
|
-
recentMessages:
|
|
1453
|
+
recentMessages: dialogueMessages,
|
|
1454
|
+
recentInteractions: recentInteractionsData,
|
|
1455
|
+
actionResults: actionResultMessages,
|
|
1183
1456
|
mode: "summarized"
|
|
1184
1457
|
},
|
|
1185
1458
|
values: {
|
|
1186
1459
|
...summaryText && { sessionSummaries: summaryText },
|
|
1187
1460
|
...recentMessagesText && { recentMessages: recentMessagesText },
|
|
1461
|
+
recentMessageInteractions,
|
|
1462
|
+
recentPostInteractions,
|
|
1463
|
+
recentInteractions: isPostFormat ? recentPostInteractions : recentMessageInteractions,
|
|
1464
|
+
...actionResultsText && { recentActionResults: actionResultsText },
|
|
1465
|
+
recentMessage,
|
|
1466
|
+
conversationLog,
|
|
1467
|
+
conversationLogWithAgentThoughts,
|
|
1188
1468
|
...receivedMessageHeader && { receivedMessageHeader },
|
|
1189
1469
|
...focusHeader && { focusHeader }
|
|
1190
1470
|
},
|
|
@@ -1194,8 +1474,23 @@ ${runText}`;
|
|
|
1194
1474
|
} catch (error) {
|
|
1195
1475
|
logger4.error({ error }, "Error in shortTermMemoryProvider:");
|
|
1196
1476
|
return {
|
|
1197
|
-
data: {
|
|
1198
|
-
|
|
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
|
+
},
|
|
1199
1494
|
text: "Error retrieving conversation context."
|
|
1200
1495
|
};
|
|
1201
1496
|
}
|
|
@@ -1287,4 +1582,4 @@ export {
|
|
|
1287
1582
|
LongTermMemoryCategory
|
|
1288
1583
|
};
|
|
1289
1584
|
|
|
1290
|
-
//# debugId=
|
|
1585
|
+
//# debugId=B1C29E71DE6182A064756E2164756E21
|