@elizaos/plugin-experience 2.0.0-alpha.2 → 2.0.0-alpha.4
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/dist/node/index.node.js +152 -169
- package/dist/node/index.node.js.map +5 -5
- package/dist/node/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +11 -3
- package/LICENSE +0 -21
package/dist/node/index.node.js
CHANGED
|
@@ -368,7 +368,7 @@ var experienceEvaluator = {
|
|
|
368
368
|
const messageCount = Number.parseInt(currentCount, 10);
|
|
369
369
|
const newMessageCount = messageCount + 1;
|
|
370
370
|
await runtime.setCache(lastExtractionKey, newMessageCount.toString());
|
|
371
|
-
const shouldExtract = newMessageCount %
|
|
371
|
+
const shouldExtract = newMessageCount % 25 === 0;
|
|
372
372
|
if (shouldExtract) {
|
|
373
373
|
logger2.info(`[experienceEvaluator] Triggering experience extraction after ${newMessageCount} messages`);
|
|
374
374
|
}
|
|
@@ -391,21 +391,14 @@ var experienceEvaluator = {
|
|
|
391
391
|
return;
|
|
392
392
|
}
|
|
393
393
|
const conversationContext = recentMessages.map((m) => m.content.text).filter(Boolean).join(" ");
|
|
394
|
-
const existingExperiences = await experienceService.queryExperiences({
|
|
395
|
-
query: conversationContext,
|
|
396
|
-
limit: 10,
|
|
397
|
-
minConfidence: 0.7
|
|
398
|
-
});
|
|
399
|
-
const existingExperiencesText = existingExperiences.length > 0 ? existingExperiences.map((exp) => `- ${exp.learning}`).join(`
|
|
400
|
-
`) : "None";
|
|
401
394
|
const extractionPrompt = composePrompt({
|
|
402
395
|
state: {
|
|
403
396
|
conversation_context: conversationContext,
|
|
404
|
-
existing_experiences:
|
|
397
|
+
existing_experiences: "None"
|
|
405
398
|
},
|
|
406
399
|
template: EXTRACT_EXPERIENCES_TEMPLATE
|
|
407
400
|
});
|
|
408
|
-
const response = await runtime.useModel(ModelType.
|
|
401
|
+
const response = await runtime.useModel(ModelType.TEXT_SMALL, {
|
|
409
402
|
prompt: extractionPrompt
|
|
410
403
|
});
|
|
411
404
|
const experiences = parseExtractedExperiences(response);
|
|
@@ -420,6 +413,19 @@ var experienceEvaluator = {
|
|
|
420
413
|
if (!exp.learning || typeof exp.confidence !== "number" || exp.confidence < threshold) {
|
|
421
414
|
continue;
|
|
422
415
|
}
|
|
416
|
+
const similar = await experienceService.findSimilarExperiences(exp.learning, 1);
|
|
417
|
+
if (similar.length > 0) {
|
|
418
|
+
const existingLearning = similar[0].learning.toLowerCase();
|
|
419
|
+
const newLearning = exp.learning.toLowerCase();
|
|
420
|
+
const existingWords = new Set(existingLearning.split(/\s+/).filter((w) => w.length > 3));
|
|
421
|
+
const newWords = new Set(newLearning.split(/\s+/).filter((w) => w.length > 3));
|
|
422
|
+
const overlap = [...newWords].filter((w) => existingWords.has(w)).length;
|
|
423
|
+
const union = new Set([...existingWords, ...newWords]).size;
|
|
424
|
+
if (union > 0 && overlap / union > 0.6) {
|
|
425
|
+
logger2.debug(`[experienceEvaluator] Skipping duplicate experience: "${exp.learning.substring(0, 80)}..."`);
|
|
426
|
+
continue;
|
|
427
|
+
}
|
|
428
|
+
}
|
|
423
429
|
const normalizedType = typeof exp.type === "string" ? exp.type.toUpperCase() : "";
|
|
424
430
|
const experienceType = experienceTypeMap[normalizedType] ?? "learning" /* LEARNING */;
|
|
425
431
|
const experienceTag = experienceType;
|
|
@@ -756,35 +762,28 @@ class ExperienceService extends Service {
|
|
|
756
762
|
experiences = new Map;
|
|
757
763
|
experiencesByDomain = new Map;
|
|
758
764
|
experiencesByType = new Map;
|
|
759
|
-
|
|
765
|
+
dirtyExperiences = new Set;
|
|
766
|
+
persistTimer = null;
|
|
760
767
|
decayManager;
|
|
761
768
|
relationshipManager;
|
|
762
769
|
constructor(runtime) {
|
|
763
770
|
super(runtime);
|
|
764
771
|
this.decayManager = new ConfidenceDecayManager;
|
|
765
772
|
this.relationshipManager = new ExperienceRelationshipManager;
|
|
766
|
-
const max = getNumberSetting2(runtime, "MAX_EXPERIENCES", this.maxExperiences);
|
|
767
|
-
if (Number.isFinite(max) && max > 0) {
|
|
768
|
-
this.maxExperiences = Math.floor(max);
|
|
769
|
-
}
|
|
770
773
|
this.loadExperiences();
|
|
774
|
+
this.persistTimer = setInterval(() => {
|
|
775
|
+
this.persistDirtyExperiences();
|
|
776
|
+
}, 60000);
|
|
771
777
|
}
|
|
772
778
|
static async start(runtime) {
|
|
773
779
|
const service = new ExperienceService(runtime);
|
|
774
780
|
return service;
|
|
775
781
|
}
|
|
776
|
-
setMaxExperiences(maxExperiences) {
|
|
777
|
-
if (!Number.isFinite(maxExperiences) || maxExperiences <= 0)
|
|
778
|
-
return;
|
|
779
|
-
this.maxExperiences = Math.floor(maxExperiences);
|
|
780
|
-
}
|
|
781
782
|
async loadExperiences() {
|
|
782
|
-
const
|
|
783
|
+
const memories = await this.runtime.getMemories({
|
|
783
784
|
entityId: this.runtime.agentId,
|
|
784
|
-
|
|
785
|
-
tableName: "memories"
|
|
785
|
+
tableName: "experiences"
|
|
786
786
|
});
|
|
787
|
-
const memories = allMemories.filter((m) => m.content.type === "experience");
|
|
788
787
|
for (const memory of memories) {
|
|
789
788
|
const experienceData = memory.content.data;
|
|
790
789
|
if (experienceData?.id) {
|
|
@@ -836,9 +835,19 @@ class ExperienceService extends Service {
|
|
|
836
835
|
}
|
|
837
836
|
async recordExperience(experienceData) {
|
|
838
837
|
const embeddingText = `${experienceData.context} ${experienceData.action} ${experienceData.result} ${experienceData.learning}`;
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
838
|
+
let embedding;
|
|
839
|
+
try {
|
|
840
|
+
const result = await this.runtime.useModel(ModelType2.TEXT_EMBEDDING, {
|
|
841
|
+
text: embeddingText
|
|
842
|
+
});
|
|
843
|
+
if (Array.isArray(result) && result.length > 0 && result.some((v) => v !== 0)) {
|
|
844
|
+
embedding = result;
|
|
845
|
+
} else {
|
|
846
|
+
logger4.warn("[ExperienceService] Embedding model returned empty/zero vector, storing without embedding");
|
|
847
|
+
}
|
|
848
|
+
} catch (err) {
|
|
849
|
+
logger4.warn(`[ExperienceService] Embedding generation failed, storing without embedding: ${err}`);
|
|
850
|
+
}
|
|
842
851
|
const now = Date.now();
|
|
843
852
|
const experience = {
|
|
844
853
|
id: uuidv4(),
|
|
@@ -883,9 +892,6 @@ class ExperienceService extends Service {
|
|
|
883
892
|
strength: 0.8
|
|
884
893
|
});
|
|
885
894
|
}
|
|
886
|
-
if (this.experiences.size > this.maxExperiences) {
|
|
887
|
-
await this.pruneOldExperiences();
|
|
888
|
-
}
|
|
889
895
|
logger4.info(`[ExperienceService] Recorded experience: ${experience.id} (${experience.type})`);
|
|
890
896
|
return experience;
|
|
891
897
|
}
|
|
@@ -915,7 +921,6 @@ class ExperienceService extends Service {
|
|
|
915
921
|
updatedAt: experience.updatedAt,
|
|
916
922
|
accessCount: experience.accessCount,
|
|
917
923
|
lastAccessedAt: experience.lastAccessedAt,
|
|
918
|
-
embedding: experience.embedding,
|
|
919
924
|
relatedExperiences: experience.relatedExperiences,
|
|
920
925
|
supersedes: experience.supersedes,
|
|
921
926
|
previousBelief: experience.previousBelief,
|
|
@@ -926,88 +931,43 @@ class ExperienceService extends Service {
|
|
|
926
931
|
};
|
|
927
932
|
await this.runtime.createMemory(memory, "experiences", true);
|
|
928
933
|
}
|
|
934
|
+
async persistDirtyExperiences() {
|
|
935
|
+
if (this.dirtyExperiences.size === 0)
|
|
936
|
+
return;
|
|
937
|
+
const toSave = Array.from(this.dirtyExperiences);
|
|
938
|
+
this.dirtyExperiences.clear();
|
|
939
|
+
let saved = 0;
|
|
940
|
+
for (const id of toSave) {
|
|
941
|
+
const exp = this.experiences.get(id);
|
|
942
|
+
if (exp) {
|
|
943
|
+
try {
|
|
944
|
+
await this.saveExperienceToMemory(exp);
|
|
945
|
+
saved++;
|
|
946
|
+
} catch {
|
|
947
|
+
this.dirtyExperiences.add(id);
|
|
948
|
+
}
|
|
949
|
+
}
|
|
950
|
+
}
|
|
951
|
+
if (saved > 0) {
|
|
952
|
+
logger4.debug(`[ExperienceService] Persisted ${saved} dirty experiences`);
|
|
953
|
+
}
|
|
954
|
+
}
|
|
929
955
|
async queryExperiences(query) {
|
|
930
956
|
let results = [];
|
|
957
|
+
const limit = query.limit || 10;
|
|
931
958
|
if (query.query) {
|
|
932
|
-
const
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
candidates = candidates.filter((exp) => types.includes(exp.type));
|
|
937
|
-
}
|
|
938
|
-
if (query.outcome) {
|
|
939
|
-
candidates = candidates.filter((exp) => exp.outcome === query.outcome);
|
|
940
|
-
}
|
|
941
|
-
if (query.domain) {
|
|
942
|
-
const domains = Array.isArray(query.domain) ? query.domain : [query.domain];
|
|
943
|
-
candidates = candidates.filter((exp) => domains.includes(exp.domain));
|
|
944
|
-
}
|
|
945
|
-
if (query.tags && query.tags.length > 0) {
|
|
946
|
-
candidates = candidates.filter((exp) => query.tags?.some((tag) => exp.tags.includes(tag)));
|
|
947
|
-
}
|
|
948
|
-
if (query.minConfidence !== undefined) {
|
|
949
|
-
const minConfidence = query.minConfidence;
|
|
950
|
-
candidates = candidates.filter((exp) => {
|
|
951
|
-
const decayedConfidence = this.decayManager.getDecayedConfidence(exp);
|
|
952
|
-
return decayedConfidence >= minConfidence;
|
|
953
|
-
});
|
|
954
|
-
}
|
|
955
|
-
if (query.minImportance !== undefined) {
|
|
956
|
-
const minImportance = query.minImportance;
|
|
957
|
-
candidates = candidates.filter((exp) => exp.importance >= minImportance);
|
|
958
|
-
}
|
|
959
|
-
if (query.timeRange) {
|
|
960
|
-
candidates = candidates.filter((exp) => {
|
|
961
|
-
if (query.timeRange?.start && exp.createdAt < query.timeRange?.start)
|
|
962
|
-
return false;
|
|
963
|
-
if (query.timeRange?.end && exp.createdAt > query.timeRange?.end)
|
|
964
|
-
return false;
|
|
965
|
-
return true;
|
|
966
|
-
});
|
|
967
|
-
}
|
|
968
|
-
results = candidates;
|
|
959
|
+
const hasFilters = !!(query.type || query.outcome || query.domain || query.tags && query.tags.length > 0 || query.minConfidence !== undefined || query.minImportance !== undefined || query.timeRange);
|
|
960
|
+
const fetchLimit = hasFilters ? Math.max(limit * 5, 50) : limit;
|
|
961
|
+
const candidates = this.applyFilters(await this.findSimilarExperiences(query.query, fetchLimit), query);
|
|
962
|
+
results = candidates.slice(0, limit);
|
|
969
963
|
} else {
|
|
970
|
-
|
|
971
|
-
if (query.type) {
|
|
972
|
-
const types = Array.isArray(query.type) ? query.type : [query.type];
|
|
973
|
-
candidates = candidates.filter((exp) => types.includes(exp.type));
|
|
974
|
-
}
|
|
975
|
-
if (query.outcome) {
|
|
976
|
-
candidates = candidates.filter((exp) => exp.outcome === query.outcome);
|
|
977
|
-
}
|
|
978
|
-
if (query.domain) {
|
|
979
|
-
const domains = Array.isArray(query.domain) ? query.domain : [query.domain];
|
|
980
|
-
candidates = candidates.filter((exp) => domains.includes(exp.domain));
|
|
981
|
-
}
|
|
982
|
-
if (query.tags && query.tags.length > 0) {
|
|
983
|
-
candidates = candidates.filter((exp) => query.tags?.some((tag) => exp.tags.includes(tag)));
|
|
984
|
-
}
|
|
985
|
-
if (query.minConfidence !== undefined) {
|
|
986
|
-
const minConfidence = query.minConfidence;
|
|
987
|
-
candidates = candidates.filter((exp) => {
|
|
988
|
-
const decayedConfidence = this.decayManager.getDecayedConfidence(exp);
|
|
989
|
-
return decayedConfidence >= minConfidence;
|
|
990
|
-
});
|
|
991
|
-
}
|
|
992
|
-
if (query.minImportance !== undefined) {
|
|
993
|
-
const minImportance = query.minImportance;
|
|
994
|
-
candidates = candidates.filter((exp) => exp.importance >= minImportance);
|
|
995
|
-
}
|
|
996
|
-
if (query.timeRange) {
|
|
997
|
-
candidates = candidates.filter((exp) => {
|
|
998
|
-
if (query.timeRange?.start && exp.createdAt < query.timeRange?.start)
|
|
999
|
-
return false;
|
|
1000
|
-
if (query.timeRange?.end && exp.createdAt > query.timeRange?.end)
|
|
1001
|
-
return false;
|
|
1002
|
-
return true;
|
|
1003
|
-
});
|
|
1004
|
-
}
|
|
964
|
+
const candidates = this.applyFilters(Array.from(this.experiences.values()), query);
|
|
1005
965
|
candidates.sort((a, b) => {
|
|
1006
966
|
const scoreA = this.decayManager.getDecayedConfidence(a) * a.importance;
|
|
1007
967
|
const scoreB = this.decayManager.getDecayedConfidence(b) * b.importance;
|
|
1008
968
|
return scoreB - scoreA;
|
|
1009
969
|
});
|
|
1010
|
-
results = candidates.slice(0,
|
|
970
|
+
results = candidates.slice(0, limit);
|
|
1011
971
|
}
|
|
1012
972
|
if (query.includeRelated) {
|
|
1013
973
|
const relatedIds = new Set;
|
|
@@ -1024,31 +984,96 @@ class ExperienceService extends Service {
|
|
|
1024
984
|
for (const exp of results) {
|
|
1025
985
|
exp.accessCount++;
|
|
1026
986
|
exp.lastAccessedAt = Date.now();
|
|
987
|
+
this.dirtyExperiences.add(exp.id);
|
|
1027
988
|
}
|
|
1028
989
|
return results;
|
|
1029
990
|
}
|
|
991
|
+
applyFilters(candidates, query) {
|
|
992
|
+
let filtered = candidates;
|
|
993
|
+
if (query.type) {
|
|
994
|
+
const types = Array.isArray(query.type) ? query.type : [query.type];
|
|
995
|
+
filtered = filtered.filter((e) => types.includes(e.type));
|
|
996
|
+
}
|
|
997
|
+
if (query.outcome) {
|
|
998
|
+
filtered = filtered.filter((e) => e.outcome === query.outcome);
|
|
999
|
+
}
|
|
1000
|
+
if (query.domain) {
|
|
1001
|
+
const domains = Array.isArray(query.domain) ? query.domain : [query.domain];
|
|
1002
|
+
filtered = filtered.filter((e) => domains.includes(e.domain));
|
|
1003
|
+
}
|
|
1004
|
+
if (query.tags && query.tags.length > 0) {
|
|
1005
|
+
filtered = filtered.filter((e) => query.tags?.some((t) => e.tags.includes(t)));
|
|
1006
|
+
}
|
|
1007
|
+
if (query.minConfidence !== undefined) {
|
|
1008
|
+
const min = query.minConfidence;
|
|
1009
|
+
filtered = filtered.filter((e) => this.decayManager.getDecayedConfidence(e) >= min);
|
|
1010
|
+
}
|
|
1011
|
+
if (query.minImportance !== undefined) {
|
|
1012
|
+
const min = query.minImportance;
|
|
1013
|
+
filtered = filtered.filter((e) => e.importance >= min);
|
|
1014
|
+
}
|
|
1015
|
+
if (query.timeRange) {
|
|
1016
|
+
const { start, end } = query.timeRange;
|
|
1017
|
+
filtered = filtered.filter((e) => {
|
|
1018
|
+
if (start && e.createdAt < start)
|
|
1019
|
+
return false;
|
|
1020
|
+
if (end && e.createdAt > end)
|
|
1021
|
+
return false;
|
|
1022
|
+
return true;
|
|
1023
|
+
});
|
|
1024
|
+
}
|
|
1025
|
+
return filtered;
|
|
1026
|
+
}
|
|
1030
1027
|
async findSimilarExperiences(text, limit = 5) {
|
|
1031
1028
|
if (!text || this.experiences.size === 0) {
|
|
1032
1029
|
return [];
|
|
1033
1030
|
}
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
const similarity = this.cosineSimilarity(queryEmbedding, experience.embedding);
|
|
1041
|
-
similarities.push({ experience, similarity });
|
|
1031
|
+
let queryEmbedding;
|
|
1032
|
+
try {
|
|
1033
|
+
queryEmbedding = await this.runtime.useModel(ModelType2.TEXT_EMBEDDING, { text });
|
|
1034
|
+
if (!Array.isArray(queryEmbedding) || queryEmbedding.length === 0 || queryEmbedding.every((v) => v === 0)) {
|
|
1035
|
+
logger4.warn("[ExperienceService] Query embedding is empty/zero, falling back to recency sort");
|
|
1036
|
+
return this.fallbackSort(limit);
|
|
1042
1037
|
}
|
|
1038
|
+
} catch {
|
|
1039
|
+
logger4.warn("[ExperienceService] Query embedding failed, falling back to recency sort");
|
|
1040
|
+
return this.fallbackSort(limit);
|
|
1043
1041
|
}
|
|
1044
|
-
|
|
1045
|
-
const
|
|
1042
|
+
const SIMILARITY_FLOOR = 0.05;
|
|
1043
|
+
const scored = [];
|
|
1044
|
+
const now = Date.now();
|
|
1045
|
+
for (const experience of this.experiences.values()) {
|
|
1046
|
+
if (!experience.embedding)
|
|
1047
|
+
continue;
|
|
1048
|
+
const similarity = this.cosineSimilarity(queryEmbedding, experience.embedding);
|
|
1049
|
+
if (similarity < SIMILARITY_FLOOR)
|
|
1050
|
+
continue;
|
|
1051
|
+
const decayedConfidence = this.decayManager.getDecayedConfidence(experience);
|
|
1052
|
+
const ageDays = Math.max(0, (now - experience.createdAt) / (24 * 60 * 60 * 1000));
|
|
1053
|
+
const recencyFactor = 1 / (1 + ageDays / 30);
|
|
1054
|
+
const accessFactor = Math.min(1, Math.log2(experience.accessCount + 1) / Math.log2(10));
|
|
1055
|
+
const qualityScore = decayedConfidence * 0.45 + experience.importance * 0.35 + recencyFactor * 0.12 + accessFactor * 0.08;
|
|
1056
|
+
const rerankScore = similarity * 0.7 + qualityScore * 0.3;
|
|
1057
|
+
scored.push({ experience, score: rerankScore });
|
|
1058
|
+
}
|
|
1059
|
+
scored.sort((a, b) => b.score - a.score);
|
|
1060
|
+
const results = scored.slice(0, limit).map((item) => item.experience);
|
|
1046
1061
|
for (const exp of results) {
|
|
1047
1062
|
exp.accessCount++;
|
|
1048
|
-
exp.lastAccessedAt =
|
|
1063
|
+
exp.lastAccessedAt = now;
|
|
1064
|
+
this.dirtyExperiences.add(exp.id);
|
|
1049
1065
|
}
|
|
1050
1066
|
return results;
|
|
1051
1067
|
}
|
|
1068
|
+
fallbackSort(limit) {
|
|
1069
|
+
const all = Array.from(this.experiences.values());
|
|
1070
|
+
all.sort((a, b) => {
|
|
1071
|
+
const sa = this.decayManager.getDecayedConfidence(a) * a.importance;
|
|
1072
|
+
const sb = this.decayManager.getDecayedConfidence(b) * b.importance;
|
|
1073
|
+
return sb - sa;
|
|
1074
|
+
});
|
|
1075
|
+
return all.slice(0, limit);
|
|
1076
|
+
}
|
|
1052
1077
|
async analyzeExperiences(domain, type) {
|
|
1053
1078
|
const experiences = await this.queryExperiences({
|
|
1054
1079
|
domain: domain ? [domain] : undefined,
|
|
@@ -1176,63 +1201,26 @@ class ExperienceService extends Service {
|
|
|
1176
1201
|
}
|
|
1177
1202
|
return recommendations.slice(0, 5);
|
|
1178
1203
|
}
|
|
1179
|
-
async pruneOldExperiences() {
|
|
1180
|
-
if (this.experiences.size <= this.maxExperiences) {
|
|
1181
|
-
return;
|
|
1182
|
-
}
|
|
1183
|
-
const experienceArray = Array.from(this.experiences.values());
|
|
1184
|
-
experienceArray.sort((a, b) => {
|
|
1185
|
-
if (a.importance !== b.importance) {
|
|
1186
|
-
return a.importance - b.importance;
|
|
1187
|
-
}
|
|
1188
|
-
if (a.accessCount !== b.accessCount) {
|
|
1189
|
-
return a.accessCount - b.accessCount;
|
|
1190
|
-
}
|
|
1191
|
-
return a.createdAt - b.createdAt;
|
|
1192
|
-
});
|
|
1193
|
-
const toRemove = experienceArray.slice(0, experienceArray.length - this.maxExperiences);
|
|
1194
|
-
let removedCount = 0;
|
|
1195
|
-
for (const experience of toRemove) {
|
|
1196
|
-
this.experiences.delete(experience.id);
|
|
1197
|
-
const domainSet = this.experiencesByDomain.get(experience.domain);
|
|
1198
|
-
if (domainSet) {
|
|
1199
|
-
domainSet.delete(experience.id);
|
|
1200
|
-
if (domainSet.size === 0) {
|
|
1201
|
-
this.experiencesByDomain.delete(experience.domain);
|
|
1202
|
-
}
|
|
1203
|
-
}
|
|
1204
|
-
const typeSet = this.experiencesByType.get(experience.type);
|
|
1205
|
-
if (typeSet) {
|
|
1206
|
-
typeSet.delete(experience.id);
|
|
1207
|
-
if (typeSet.size === 0) {
|
|
1208
|
-
this.experiencesByType.delete(experience.type);
|
|
1209
|
-
}
|
|
1210
|
-
}
|
|
1211
|
-
removedCount++;
|
|
1212
|
-
}
|
|
1213
|
-
logger4.info(`[ExperienceService] Pruned ${removedCount} old experiences`);
|
|
1214
|
-
}
|
|
1215
1204
|
async stop() {
|
|
1216
1205
|
logger4.info("[ExperienceService] Stopping...");
|
|
1206
|
+
if (this.persistTimer) {
|
|
1207
|
+
clearInterval(this.persistTimer);
|
|
1208
|
+
this.persistTimer = null;
|
|
1209
|
+
}
|
|
1217
1210
|
const experiencesToSave = Array.from(this.experiences.values());
|
|
1218
1211
|
let savedCount = 0;
|
|
1219
1212
|
for (const experience of experiencesToSave) {
|
|
1220
|
-
|
|
1221
|
-
|
|
1213
|
+
try {
|
|
1214
|
+
await this.saveExperienceToMemory(experience);
|
|
1215
|
+
savedCount++;
|
|
1216
|
+
} catch (err) {
|
|
1217
|
+
logger4.warn(`[ExperienceService] Failed to save experience ${experience.id}: ${err}`);
|
|
1218
|
+
}
|
|
1222
1219
|
}
|
|
1220
|
+
this.dirtyExperiences.clear();
|
|
1223
1221
|
logger4.info(`[ExperienceService] Saved ${savedCount} experiences`);
|
|
1224
1222
|
}
|
|
1225
1223
|
}
|
|
1226
|
-
function getNumberSetting2(runtime, key, fallback) {
|
|
1227
|
-
const value = runtime.getSetting(key);
|
|
1228
|
-
if (typeof value === "number")
|
|
1229
|
-
return value;
|
|
1230
|
-
if (typeof value === "string") {
|
|
1231
|
-
const parsed = Number.parseFloat(value);
|
|
1232
|
-
return Number.isFinite(parsed) ? parsed : fallback;
|
|
1233
|
-
}
|
|
1234
|
-
return fallback;
|
|
1235
|
-
}
|
|
1236
1224
|
|
|
1237
1225
|
// index.ts
|
|
1238
1226
|
var experiencePlugin = {
|
|
@@ -1244,14 +1232,9 @@ var experiencePlugin = {
|
|
|
1244
1232
|
evaluators: [experienceEvaluator],
|
|
1245
1233
|
async init(config, runtime) {
|
|
1246
1234
|
logger5.info("[ExperiencePlugin] Initializing experience learning system");
|
|
1247
|
-
const maxExperiences = parseOptionalNumber(config.MAX_EXPERIENCES, 1e4);
|
|
1248
1235
|
const autoRecordThreshold = parseOptionalNumber(config.AUTO_RECORD_THRESHOLD, 0.7);
|
|
1249
|
-
runtime.setSetting("MAX_EXPERIENCES", maxExperiences.toString());
|
|
1250
1236
|
runtime.setSetting("AUTO_RECORD_THRESHOLD", autoRecordThreshold.toString());
|
|
1251
|
-
const experienceService = runtime.getService("EXPERIENCE");
|
|
1252
|
-
experienceService?.setMaxExperiences(maxExperiences);
|
|
1253
1237
|
logger5.info(`[ExperiencePlugin] Configuration:
|
|
1254
|
-
- MAX_EXPERIENCES: ${maxExperiences}
|
|
1255
1238
|
- AUTO_RECORD_THRESHOLD: ${autoRecordThreshold}`);
|
|
1256
1239
|
}
|
|
1257
1240
|
};
|
|
@@ -1271,4 +1254,4 @@ export {
|
|
|
1271
1254
|
ExperienceService
|
|
1272
1255
|
};
|
|
1273
1256
|
|
|
1274
|
-
//# debugId=
|
|
1257
|
+
//# debugId=19BED8D33D8C8ECD64756E2164756E21
|