@elizaos/plugin-memory 1.1.2 → 2.0.0-alpha

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.
Files changed (43) hide show
  1. package/dist/evaluators/index.d.ts +3 -0
  2. package/dist/evaluators/index.d.ts.map +1 -0
  3. package/dist/evaluators/long-term-extraction.d.ts +1 -6
  4. package/dist/evaluators/long-term-extraction.d.ts.map +1 -0
  5. package/dist/evaluators/summarization.d.ts +1 -28
  6. package/dist/evaluators/summarization.d.ts.map +1 -0
  7. package/dist/generated/prompts/typescript/prompts.d.ts +16 -0
  8. package/dist/generated/prompts/typescript/prompts.d.ts.map +1 -0
  9. package/dist/index.d.ts +7 -38
  10. package/dist/index.d.ts.map +1 -0
  11. package/dist/{node/index.node.js → index.js} +931 -980
  12. package/dist/index.js.map +20 -0
  13. package/dist/providers/context-summary.d.ts +2 -11
  14. package/dist/providers/context-summary.d.ts.map +1 -0
  15. package/dist/providers/index.d.ts +3 -0
  16. package/dist/providers/index.d.ts.map +1 -0
  17. package/dist/providers/long-term-memory.d.ts +2 -16
  18. package/dist/providers/long-term-memory.d.ts.map +1 -0
  19. package/dist/schemas/index.d.ts +4 -9
  20. package/dist/schemas/index.d.ts.map +1 -0
  21. package/dist/schemas/long-term-memories.d.ts +1 -4
  22. package/dist/schemas/long-term-memories.d.ts.map +1 -0
  23. package/dist/schemas/memory-access-logs.d.ts +20 -58
  24. package/dist/schemas/memory-access-logs.d.ts.map +1 -0
  25. package/dist/schemas/session-summaries.d.ts +1 -4
  26. package/dist/schemas/session-summaries.d.ts.map +1 -0
  27. package/dist/services/memory-service.d.ts +7 -75
  28. package/dist/services/memory-service.d.ts.map +1 -0
  29. package/dist/types/index.d.ts +5 -26
  30. package/dist/types/index.d.ts.map +1 -0
  31. package/package.json +45 -48
  32. package/README.md +0 -335
  33. package/dist/actions/remember.d.ts +0 -11
  34. package/dist/browser/index.browser.js +0 -205
  35. package/dist/browser/index.browser.js.map +0 -19
  36. package/dist/browser/index.d.ts +0 -2
  37. package/dist/cjs/index.d.ts +0 -2
  38. package/dist/cjs/index.node.cjs +0 -1168
  39. package/dist/cjs/index.node.js.map +0 -19
  40. package/dist/index.browser.d.ts +0 -2
  41. package/dist/index.node.d.ts +0 -2
  42. package/dist/node/index.d.ts +0 -2
  43. package/dist/node/index.node.js.map +0 -19
@@ -9,536 +9,15 @@ var __export = (target, all) => {
9
9
  });
10
10
  };
11
11
 
12
- // src/services/memory-service.ts
12
+ // src/evaluators/long-term-extraction.ts
13
13
  import {
14
- Service,
15
- logger
14
+ composePromptFromState,
15
+ logger,
16
+ ModelType
16
17
  } from "@elizaos/core";
17
- import { eq, and, desc, sql as sql4, cosineDistance, gte } from "drizzle-orm";
18
18
 
19
- // src/schemas/index.ts
20
- var exports_schemas = {};
21
- __export(exports_schemas, {
22
- sessionSummaries: () => sessionSummaries,
23
- memoryAccessLogs: () => memoryAccessLogs,
24
- longTermMemories: () => longTermMemories
25
- });
26
-
27
- // src/schemas/long-term-memories.ts
28
- import { sql } from "drizzle-orm";
29
- import {
30
- pgTable,
31
- text,
32
- integer,
33
- jsonb,
34
- real,
35
- index,
36
- varchar,
37
- timestamp
38
- } from "drizzle-orm/pg-core";
39
- var longTermMemories = pgTable("long_term_memories", {
40
- id: varchar("id", { length: 36 }).primaryKey(),
41
- agentId: varchar("agent_id", { length: 36 }).notNull(),
42
- entityId: varchar("entity_id", { length: 36 }).notNull(),
43
- category: text("category").notNull(),
44
- content: text("content").notNull(),
45
- metadata: jsonb("metadata"),
46
- embedding: real("embedding").array(),
47
- confidence: real("confidence").default(1),
48
- source: text("source"),
49
- createdAt: timestamp("created_at").default(sql`now()`).notNull(),
50
- updatedAt: timestamp("updated_at").default(sql`now()`).notNull(),
51
- lastAccessedAt: timestamp("last_accessed_at"),
52
- accessCount: integer("access_count").default(0)
53
- }, (table) => ({
54
- agentEntityIdx: index("long_term_memories_agent_entity_idx").on(table.agentId, table.entityId),
55
- categoryIdx: index("long_term_memories_category_idx").on(table.category),
56
- confidenceIdx: index("long_term_memories_confidence_idx").on(table.confidence),
57
- createdAtIdx: index("long_term_memories_created_at_idx").on(table.createdAt)
58
- }));
59
- // src/schemas/session-summaries.ts
60
- import { sql as sql2 } from "drizzle-orm";
61
- import {
62
- pgTable as pgTable2,
63
- text as text2,
64
- integer as integer2,
65
- jsonb as jsonb2,
66
- real as real2,
67
- index as index2,
68
- varchar as varchar2,
69
- timestamp as timestamp2
70
- } from "drizzle-orm/pg-core";
71
- var sessionSummaries = pgTable2("session_summaries", {
72
- id: varchar2("id", { length: 36 }).primaryKey(),
73
- agentId: varchar2("agent_id", { length: 36 }).notNull(),
74
- roomId: varchar2("room_id", { length: 36 }).notNull(),
75
- entityId: varchar2("entity_id", { length: 36 }),
76
- summary: text2("summary").notNull(),
77
- messageCount: integer2("message_count").notNull(),
78
- lastMessageOffset: integer2("last_message_offset").notNull().default(0),
79
- startTime: timestamp2("start_time").notNull(),
80
- endTime: timestamp2("end_time").notNull(),
81
- topics: jsonb2("topics"),
82
- metadata: jsonb2("metadata"),
83
- embedding: real2("embedding").array(),
84
- createdAt: timestamp2("created_at").default(sql2`now()`).notNull(),
85
- updatedAt: timestamp2("updated_at").default(sql2`now()`).notNull()
86
- }, (table) => ({
87
- agentRoomIdx: index2("session_summaries_agent_room_idx").on(table.agentId, table.roomId),
88
- entityIdx: index2("session_summaries_entity_idx").on(table.entityId),
89
- startTimeIdx: index2("session_summaries_start_time_idx").on(table.startTime)
90
- }));
91
- // src/schemas/memory-access-logs.ts
92
- import { sql as sql3 } from "drizzle-orm";
93
- import { pgTable as pgTable3, text as text3, integer as integer3, real as real3, index as index3, varchar as varchar3, timestamp as timestamp3 } from "drizzle-orm/pg-core";
94
- var memoryAccessLogs = pgTable3("memory_access_logs", {
95
- id: varchar3("id", { length: 36 }).primaryKey(),
96
- agentId: varchar3("agent_id", { length: 36 }).notNull(),
97
- memoryId: varchar3("memory_id", { length: 36 }).notNull(),
98
- memoryType: text3("memory_type").notNull(),
99
- accessedAt: timestamp3("accessed_at").default(sql3`now()`).notNull(),
100
- roomId: varchar3("room_id", { length: 36 }),
101
- relevanceScore: real3("relevance_score"),
102
- wasUseful: integer3("was_useful")
103
- }, (table) => ({
104
- memoryIdx: index3("memory_access_logs_memory_idx").on(table.memoryId),
105
- agentIdx: index3("memory_access_logs_agent_idx").on(table.agentId),
106
- accessedAtIdx: index3("memory_access_logs_accessed_at_idx").on(table.accessedAt)
107
- }));
108
- // src/services/memory-service.ts
109
- class MemoryService extends Service {
110
- static serviceType = "memory";
111
- sessionMessageCounts;
112
- memoryConfig;
113
- lastExtractionCheckpoints;
114
- capabilityDescription = "Advanced memory management with short-term summarization and long-term persistent facts";
115
- constructor(runtime) {
116
- super(runtime);
117
- this.sessionMessageCounts = new Map;
118
- this.lastExtractionCheckpoints = new Map;
119
- this.memoryConfig = {
120
- shortTermSummarizationThreshold: 16,
121
- shortTermRetainRecent: 6,
122
- shortTermSummarizationInterval: 10,
123
- longTermExtractionEnabled: true,
124
- longTermVectorSearchEnabled: false,
125
- longTermConfidenceThreshold: 0.85,
126
- longTermExtractionThreshold: 30,
127
- longTermExtractionInterval: 10,
128
- summaryModelType: "TEXT_LARGE",
129
- summaryMaxTokens: 2500,
130
- summaryMaxNewMessages: 20
131
- };
132
- }
133
- static async start(runtime) {
134
- const service = new MemoryService(runtime);
135
- await service.initialize(runtime);
136
- return service;
137
- }
138
- async stop() {
139
- logger.info("MemoryService stopped");
140
- }
141
- async initialize(runtime) {
142
- this.runtime = runtime;
143
- const threshold = runtime.getSetting("MEMORY_SUMMARIZATION_THRESHOLD");
144
- if (threshold) {
145
- this.memoryConfig.shortTermSummarizationThreshold = parseInt(threshold, 10);
146
- }
147
- const retainRecent = runtime.getSetting("MEMORY_RETAIN_RECENT");
148
- if (retainRecent) {
149
- this.memoryConfig.shortTermRetainRecent = parseInt(retainRecent, 10);
150
- }
151
- const summarizationInterval = runtime.getSetting("MEMORY_SUMMARIZATION_INTERVAL");
152
- if (summarizationInterval) {
153
- this.memoryConfig.shortTermSummarizationInterval = parseInt(summarizationInterval, 10);
154
- }
155
- const maxNewMessages = runtime.getSetting("MEMORY_MAX_NEW_MESSAGES");
156
- if (maxNewMessages) {
157
- this.memoryConfig.summaryMaxNewMessages = parseInt(maxNewMessages, 10);
158
- }
159
- const longTermEnabled = runtime.getSetting("MEMORY_LONG_TERM_ENABLED");
160
- if (longTermEnabled === "false") {
161
- this.memoryConfig.longTermExtractionEnabled = false;
162
- } else if (longTermEnabled === "true") {
163
- this.memoryConfig.longTermExtractionEnabled = true;
164
- }
165
- const confidenceThreshold = runtime.getSetting("MEMORY_CONFIDENCE_THRESHOLD");
166
- if (confidenceThreshold) {
167
- this.memoryConfig.longTermConfidenceThreshold = parseFloat(confidenceThreshold);
168
- }
169
- const extractionThreshold = runtime.getSetting("MEMORY_EXTRACTION_THRESHOLD");
170
- if (extractionThreshold) {
171
- this.memoryConfig.longTermExtractionThreshold = parseInt(extractionThreshold, 10);
172
- }
173
- const extractionInterval = runtime.getSetting("MEMORY_EXTRACTION_INTERVAL");
174
- if (extractionInterval) {
175
- this.memoryConfig.longTermExtractionInterval = parseInt(extractionInterval, 10);
176
- }
177
- logger.debug({
178
- summarizationThreshold: this.memoryConfig.shortTermSummarizationThreshold,
179
- summarizationInterval: this.memoryConfig.shortTermSummarizationInterval,
180
- maxNewMessages: this.memoryConfig.summaryMaxNewMessages,
181
- retainRecent: this.memoryConfig.shortTermRetainRecent,
182
- longTermEnabled: this.memoryConfig.longTermExtractionEnabled,
183
- extractionThreshold: this.memoryConfig.longTermExtractionThreshold,
184
- extractionInterval: this.memoryConfig.longTermExtractionInterval,
185
- confidenceThreshold: this.memoryConfig.longTermConfidenceThreshold
186
- }, "MemoryService initialized");
187
- }
188
- getDb() {
189
- const db = this.runtime.db;
190
- if (!db) {
191
- throw new Error("Database not available");
192
- }
193
- return db;
194
- }
195
- getConfig() {
196
- return { ...this.memoryConfig };
197
- }
198
- updateConfig(updates) {
199
- this.memoryConfig = { ...this.memoryConfig, ...updates };
200
- }
201
- incrementMessageCount(roomId) {
202
- const current = this.sessionMessageCounts.get(roomId) || 0;
203
- const newCount = current + 1;
204
- this.sessionMessageCounts.set(roomId, newCount);
205
- return newCount;
206
- }
207
- resetMessageCount(roomId) {
208
- this.sessionMessageCounts.set(roomId, 0);
209
- }
210
- async shouldSummarize(roomId) {
211
- const count = await this.runtime.countMemories(roomId, false, "messages");
212
- return count >= this.memoryConfig.shortTermSummarizationThreshold;
213
- }
214
- getExtractionKey(entityId, roomId) {
215
- return `memory:extraction:${entityId}:${roomId}`;
216
- }
217
- async getLastExtractionCheckpoint(entityId, roomId) {
218
- const key = this.getExtractionKey(entityId, roomId);
219
- const cached = this.lastExtractionCheckpoints.get(key);
220
- if (cached !== undefined) {
221
- return cached;
222
- }
223
- try {
224
- const checkpoint = await this.runtime.getCache(key);
225
- const messageCount = checkpoint ?? 0;
226
- this.lastExtractionCheckpoints.set(key, messageCount);
227
- return messageCount;
228
- } catch (error) {
229
- logger.warn({ error }, "Failed to get extraction checkpoint from cache");
230
- return 0;
231
- }
232
- }
233
- async setLastExtractionCheckpoint(entityId, roomId, messageCount) {
234
- const key = this.getExtractionKey(entityId, roomId);
235
- this.lastExtractionCheckpoints.set(key, messageCount);
236
- try {
237
- await this.runtime.setCache(key, messageCount);
238
- logger.debug(`Set extraction checkpoint for ${entityId} in room ${roomId} at message count ${messageCount}`);
239
- } catch (error) {
240
- logger.error({ error }, "Failed to persist extraction checkpoint to cache");
241
- }
242
- }
243
- async shouldRunExtraction(entityId, roomId, currentMessageCount) {
244
- const threshold = this.memoryConfig.longTermExtractionThreshold;
245
- const interval = this.memoryConfig.longTermExtractionInterval;
246
- if (currentMessageCount < threshold) {
247
- return false;
248
- }
249
- const lastCheckpoint = await this.getLastExtractionCheckpoint(entityId, roomId);
250
- const currentCheckpoint = Math.floor(currentMessageCount / interval) * interval;
251
- const shouldRun = currentMessageCount >= threshold && currentCheckpoint > lastCheckpoint;
252
- logger.debug({
253
- entityId,
254
- roomId,
255
- currentMessageCount,
256
- threshold,
257
- interval,
258
- lastCheckpoint,
259
- currentCheckpoint,
260
- shouldRun
261
- }, "Extraction check");
262
- return shouldRun;
263
- }
264
- async storeLongTermMemory(memory) {
265
- const db = this.getDb();
266
- const id = crypto.randomUUID();
267
- const now = new Date;
268
- const newMemory = {
269
- id,
270
- createdAt: now,
271
- updatedAt: now,
272
- accessCount: 0,
273
- ...memory
274
- };
275
- try {
276
- await db.insert(longTermMemories).values({
277
- id: newMemory.id,
278
- agentId: newMemory.agentId,
279
- entityId: newMemory.entityId,
280
- category: newMemory.category,
281
- content: newMemory.content,
282
- metadata: newMemory.metadata || {},
283
- embedding: newMemory.embedding,
284
- confidence: newMemory.confidence,
285
- source: newMemory.source,
286
- accessCount: newMemory.accessCount,
287
- createdAt: now,
288
- updatedAt: now,
289
- lastAccessedAt: newMemory.lastAccessedAt
290
- });
291
- } catch (error) {
292
- logger.error({ error }, "Failed to store long-term memory");
293
- throw error;
294
- }
295
- logger.info(`Stored long-term memory: ${newMemory.category} for entity ${newMemory.entityId}`);
296
- return newMemory;
297
- }
298
- async getLongTermMemories(entityId, category, limit = 10) {
299
- const db = this.getDb();
300
- const conditions = [
301
- eq(longTermMemories.agentId, this.runtime.agentId),
302
- eq(longTermMemories.entityId, entityId)
303
- ];
304
- if (category) {
305
- conditions.push(eq(longTermMemories.category, category));
306
- }
307
- const results = await db.select().from(longTermMemories).where(and(...conditions)).orderBy(desc(longTermMemories.confidence), desc(longTermMemories.updatedAt)).limit(limit);
308
- return results.map((row) => ({
309
- id: row.id,
310
- agentId: row.agentId,
311
- entityId: row.entityId,
312
- category: row.category,
313
- content: row.content,
314
- metadata: row.metadata,
315
- embedding: row.embedding,
316
- confidence: row.confidence,
317
- source: row.source,
318
- createdAt: row.createdAt,
319
- updatedAt: row.updatedAt,
320
- lastAccessedAt: row.lastAccessedAt,
321
- accessCount: row.accessCount
322
- }));
323
- }
324
- async updateLongTermMemory(id, entityId, updates) {
325
- const db = this.getDb();
326
- const updateData = {
327
- updatedAt: new Date
328
- };
329
- if (updates.content !== undefined) {
330
- updateData.content = updates.content;
331
- }
332
- if (updates.metadata !== undefined) {
333
- updateData.metadata = updates.metadata;
334
- }
335
- if (updates.confidence !== undefined) {
336
- updateData.confidence = updates.confidence;
337
- }
338
- if (updates.embedding !== undefined) {
339
- updateData.embedding = updates.embedding;
340
- }
341
- if (updates.lastAccessedAt !== undefined) {
342
- updateData.lastAccessedAt = updates.lastAccessedAt;
343
- }
344
- if (updates.accessCount !== undefined) {
345
- updateData.accessCount = updates.accessCount;
346
- }
347
- await db.update(longTermMemories).set(updateData).where(and(eq(longTermMemories.id, id), eq(longTermMemories.agentId, this.runtime.agentId), eq(longTermMemories.entityId, entityId)));
348
- logger.info(`Updated long-term memory: ${id} for entity ${entityId}`);
349
- }
350
- async deleteLongTermMemory(id, entityId) {
351
- const db = this.getDb();
352
- await db.delete(longTermMemories).where(and(eq(longTermMemories.id, id), eq(longTermMemories.agentId, this.runtime.agentId), eq(longTermMemories.entityId, entityId)));
353
- logger.info(`Deleted long-term memory: ${id} for entity ${entityId}`);
354
- }
355
- async getCurrentSessionSummary(roomId) {
356
- const db = this.getDb();
357
- const results = await db.select().from(sessionSummaries).where(and(eq(sessionSummaries.agentId, this.runtime.agentId), eq(sessionSummaries.roomId, roomId))).orderBy(desc(sessionSummaries.updatedAt)).limit(1);
358
- if (results.length === 0) {
359
- return null;
360
- }
361
- const row = results[0];
362
- return {
363
- id: row.id,
364
- agentId: row.agentId,
365
- roomId: row.roomId,
366
- entityId: row.entityId,
367
- summary: row.summary,
368
- messageCount: row.messageCount,
369
- lastMessageOffset: row.lastMessageOffset,
370
- startTime: row.startTime,
371
- endTime: row.endTime,
372
- topics: row.topics || [],
373
- metadata: row.metadata,
374
- embedding: row.embedding,
375
- createdAt: row.createdAt,
376
- updatedAt: row.updatedAt
377
- };
378
- }
379
- async storeSessionSummary(summary) {
380
- const db = this.getDb();
381
- const id = crypto.randomUUID();
382
- const now = new Date;
383
- const newSummary = {
384
- id,
385
- createdAt: now,
386
- updatedAt: now,
387
- ...summary
388
- };
389
- await db.insert(sessionSummaries).values({
390
- id: newSummary.id,
391
- agentId: newSummary.agentId,
392
- roomId: newSummary.roomId,
393
- entityId: newSummary.entityId || null,
394
- summary: newSummary.summary,
395
- messageCount: newSummary.messageCount,
396
- lastMessageOffset: newSummary.lastMessageOffset,
397
- startTime: newSummary.startTime,
398
- endTime: newSummary.endTime,
399
- topics: newSummary.topics || [],
400
- metadata: newSummary.metadata || {},
401
- embedding: newSummary.embedding,
402
- createdAt: now,
403
- updatedAt: now
404
- });
405
- logger.info(`Stored session summary for room ${newSummary.roomId}`);
406
- return newSummary;
407
- }
408
- async updateSessionSummary(id, roomId, updates) {
409
- const db = this.getDb();
410
- const updateData = {
411
- updatedAt: new Date
412
- };
413
- if (updates.summary !== undefined) {
414
- updateData.summary = updates.summary;
415
- }
416
- if (updates.messageCount !== undefined) {
417
- updateData.messageCount = updates.messageCount;
418
- }
419
- if (updates.lastMessageOffset !== undefined) {
420
- updateData.lastMessageOffset = updates.lastMessageOffset;
421
- }
422
- if (updates.endTime !== undefined) {
423
- updateData.endTime = updates.endTime;
424
- }
425
- if (updates.topics !== undefined) {
426
- updateData.topics = updates.topics;
427
- }
428
- if (updates.metadata !== undefined) {
429
- updateData.metadata = updates.metadata;
430
- }
431
- if (updates.embedding !== undefined) {
432
- updateData.embedding = updates.embedding;
433
- }
434
- await db.update(sessionSummaries).set(updateData).where(and(eq(sessionSummaries.id, id), eq(sessionSummaries.agentId, this.runtime.agentId), eq(sessionSummaries.roomId, roomId)));
435
- logger.info(`Updated session summary: ${id} for room ${roomId}`);
436
- }
437
- async getSessionSummaries(roomId, limit = 5) {
438
- const db = this.getDb();
439
- const results = await db.select().from(sessionSummaries).where(and(eq(sessionSummaries.agentId, this.runtime.agentId), eq(sessionSummaries.roomId, roomId))).orderBy(desc(sessionSummaries.updatedAt)).limit(limit);
440
- return results.map((row) => ({
441
- id: row.id,
442
- agentId: row.agentId,
443
- roomId: row.roomId,
444
- entityId: row.entityId,
445
- summary: row.summary,
446
- messageCount: row.messageCount,
447
- lastMessageOffset: row.lastMessageOffset,
448
- startTime: row.startTime,
449
- endTime: row.endTime,
450
- topics: row.topics || [],
451
- metadata: row.metadata,
452
- embedding: row.embedding,
453
- createdAt: row.createdAt,
454
- updatedAt: row.updatedAt
455
- }));
456
- }
457
- async searchLongTermMemories(entityId, queryEmbedding, limit = 5, matchThreshold = 0.7) {
458
- if (!this.memoryConfig.longTermVectorSearchEnabled) {
459
- logger.warn("Vector search is not enabled, falling back to recent memories");
460
- return this.getLongTermMemories(entityId, undefined, limit);
461
- }
462
- const db = this.getDb();
463
- try {
464
- const cleanVector = queryEmbedding.map((n) => Number.isFinite(n) ? Number(n.toFixed(6)) : 0);
465
- const similarity = sql4`1 - (${cosineDistance(longTermMemories.embedding, cleanVector)})`;
466
- const conditions = [
467
- eq(longTermMemories.agentId, this.runtime.agentId),
468
- eq(longTermMemories.entityId, entityId),
469
- sql4`${longTermMemories.embedding} IS NOT NULL`
470
- ];
471
- if (matchThreshold > 0) {
472
- conditions.push(gte(similarity, matchThreshold));
473
- }
474
- const results = await db.select({
475
- memory: longTermMemories,
476
- similarity
477
- }).from(longTermMemories).where(and(...conditions)).orderBy(desc(similarity)).limit(limit);
478
- return results.map((row) => ({
479
- id: row.memory.id,
480
- agentId: row.memory.agentId,
481
- entityId: row.memory.entityId,
482
- category: row.memory.category,
483
- content: row.memory.content,
484
- metadata: row.memory.metadata,
485
- embedding: row.memory.embedding,
486
- confidence: row.memory.confidence,
487
- source: row.memory.source,
488
- createdAt: row.memory.createdAt,
489
- updatedAt: row.memory.updatedAt,
490
- lastAccessedAt: row.memory.lastAccessedAt,
491
- accessCount: row.memory.accessCount,
492
- similarity: row.similarity
493
- }));
494
- } catch (error) {
495
- logger.warn({ error }, "Vector search failed, falling back to recent memories");
496
- return this.getLongTermMemories(entityId, undefined, limit);
497
- }
498
- }
499
- async getFormattedLongTermMemories(entityId) {
500
- const memories = await this.getLongTermMemories(entityId, undefined, 20);
501
- if (memories.length === 0) {
502
- return "";
503
- }
504
- const grouped = new Map;
505
- for (const memory of memories) {
506
- if (!grouped.has(memory.category)) {
507
- grouped.set(memory.category, []);
508
- }
509
- grouped.get(memory.category)?.push(memory);
510
- }
511
- const sections = [];
512
- for (const [category, categoryMemories] of grouped.entries()) {
513
- const categoryName = category.split("_").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
514
- const items = categoryMemories.map((m) => `- ${m.content}`).join(`
515
- `);
516
- sections.push(`**${categoryName}**:
517
- ${items}`);
518
- }
519
- return sections.join(`
520
-
521
- `);
522
- }
523
- }
524
-
525
- // src/evaluators/summarization.ts
526
- import {
527
- logger as logger2,
528
- ModelType,
529
- composePromptFromState
530
- } from "@elizaos/core";
531
- async function getDialogueMessageCount(runtime, roomId) {
532
- const messages = await runtime.getMemories({
533
- tableName: "messages",
534
- roomId,
535
- count: 100,
536
- unique: false
537
- });
538
- 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"));
539
- return dialogueMessages.length;
540
- }
541
- var initialSummarizationTemplate = `# Task: Summarize Conversation
19
+ // src/generated/prompts/typescript/prompts.ts
20
+ var initialSummarizationTemplate = `# Task: Summarize Conversation
542
21
 
543
22
  You are analyzing a conversation to create a concise summary that captures the key points, topics, and important details.
544
23
 
@@ -568,232 +47,29 @@ Respond in this XML format:
568
47
  <point>Second key point</point>
569
48
  </keyPoints>
570
49
  </summary>`;
571
- var updateSummarizationTemplate = `# Task: Update and Condense Conversation Summary
50
+ var longTermExtractionTemplate = `# Task: Extract Long-Term Memory (Strict Criteria)
572
51
 
573
- You are updating an existing conversation summary with new messages, while keeping the total summary concise.
52
+ You are analyzing a conversation to extract ONLY the most critical, persistent information about the user using cognitive science memory categories.
574
53
 
575
- # Existing Summary
576
- {{existingSummary}}
54
+ # Recent Messages
55
+ {{recentMessages}}
577
56
 
578
- # Existing Topics
579
- {{existingTopics}}
57
+ # Current Long-Term Memories
58
+ {{existingMemories}}
580
59
 
581
- # New Messages Since Last Summary
582
- {{newMessages}}
60
+ # Memory Categories (Based on Cognitive Science)
583
61
 
584
- # Instructions
585
- Update the summary by:
586
- 1. Merging the existing summary with insights from the new messages
587
- 2. Removing redundant or less important details to stay under the token limit
588
- 3. Keeping the most important context and decisions
589
- 4. Adding new topics if they emerge
590
- 5. **CRITICAL**: Keep the ENTIRE updated summary under 2500 tokens
62
+ ## 1. EPISODIC Memory
63
+ Personal experiences and specific events with temporal/spatial context.
64
+ **Examples:**
65
+ - "User completed migration project from MongoDB to PostgreSQL in Q2 2024"
66
+ - "User encountered authentication bug in production on March 15th"
67
+ - "User had a negative experience with Docker networking in previous job"
591
68
 
592
- The goal is a rolling summary that captures the essence of the conversation without growing indefinitely.
593
-
594
- Respond in this XML format:
595
- <summary>
596
- <text>Your updated and condensed summary here</text>
597
- <topics>topic1, topic2, topic3</topics>
598
- <keyPoints>
599
- <point>First key point</point>
600
- <point>Second key point</point>
601
- </keyPoints>
602
- </summary>`;
603
- function parseSummaryXML(xml) {
604
- const summaryMatch = xml.match(/<text>([\s\S]*?)<\/text>/);
605
- const topicsMatch = xml.match(/<topics>([\s\S]*?)<\/topics>/);
606
- const keyPointsMatches = xml.matchAll(/<point>([\s\S]*?)<\/point>/g);
607
- const summary = summaryMatch ? summaryMatch[1].trim() : "Summary not available";
608
- const topics = topicsMatch ? topicsMatch[1].split(",").map((t) => t.trim()).filter(Boolean) : [];
609
- const keyPoints = Array.from(keyPointsMatches).map((match) => match[1].trim());
610
- return { summary, topics, keyPoints };
611
- }
612
- var summarizationEvaluator = {
613
- name: "MEMORY_SUMMARIZATION",
614
- description: "Automatically summarizes conversations to optimize context usage",
615
- similes: [
616
- "CONVERSATION_SUMMARY",
617
- "CONTEXT_COMPRESSION",
618
- "MEMORY_OPTIMIZATION"
619
- ],
620
- alwaysRun: true,
621
- validate: async (runtime, message) => {
622
- if (!message.content?.text) {
623
- return false;
624
- }
625
- const memoryService = runtime.getService("memory");
626
- if (!memoryService) {
627
- return false;
628
- }
629
- const config = memoryService.getConfig();
630
- const currentDialogueCount = await getDialogueMessageCount(runtime, message.roomId);
631
- const existingSummary = await memoryService.getCurrentSessionSummary(message.roomId);
632
- if (!existingSummary) {
633
- const shouldSummarize = currentDialogueCount >= config.shortTermSummarizationThreshold;
634
- return shouldSummarize;
635
- } else {
636
- const newDialogueCount = currentDialogueCount - existingSummary.lastMessageOffset;
637
- const shouldUpdate = newDialogueCount >= config.shortTermSummarizationInterval;
638
- return shouldUpdate;
639
- }
640
- },
641
- handler: async (runtime, message) => {
642
- const memoryService = runtime.getService("memory");
643
- if (!memoryService) {
644
- logger2.error("MemoryService not found");
645
- return;
646
- }
647
- const config = memoryService.getConfig();
648
- const { roomId } = message;
649
- try {
650
- logger2.info(`Starting summarization for room ${roomId}`);
651
- const existingSummary = await memoryService.getCurrentSessionSummary(roomId);
652
- const lastOffset = existingSummary?.lastMessageOffset || 0;
653
- const allMessages = await runtime.getMemories({
654
- tableName: "messages",
655
- roomId,
656
- count: 1000,
657
- unique: false
658
- });
659
- 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"));
660
- const totalDialogueCount = allDialogueMessages.length;
661
- const newDialogueCount = totalDialogueCount - lastOffset;
662
- if (newDialogueCount === 0) {
663
- logger2.debug("No new dialogue messages to summarize");
664
- return;
665
- }
666
- const maxNewMessages = config.summaryMaxNewMessages || 50;
667
- const messagesToProcess = Math.min(newDialogueCount, maxNewMessages);
668
- if (newDialogueCount > maxNewMessages) {
669
- logger2.warn(`Capping new dialogue messages at ${maxNewMessages} (${newDialogueCount} available). Oldest messages will be skipped.`);
670
- }
671
- const sortedDialogueMessages = allDialogueMessages.sort((a, b) => (a.createdAt || 0) - (b.createdAt || 0));
672
- const newDialogueMessages = sortedDialogueMessages.slice(lastOffset, lastOffset + messagesToProcess);
673
- if (newDialogueMessages.length === 0) {
674
- logger2.debug("No new dialogue messages retrieved after filtering");
675
- return;
676
- }
677
- const formattedMessages = newDialogueMessages.map((msg) => {
678
- const sender = msg.entityId === runtime.agentId ? runtime.character.name : "User";
679
- return `${sender}: ${msg.content.text || "[non-text message]"}`;
680
- }).join(`
681
- `);
682
- const state = await runtime.composeState(message);
683
- let prompt;
684
- let template;
685
- if (existingSummary) {
686
- template = updateSummarizationTemplate;
687
- prompt = composePromptFromState({
688
- state: {
689
- ...state,
690
- existingSummary: existingSummary.summary,
691
- existingTopics: existingSummary.topics?.join(", ") || "None",
692
- newMessages: formattedMessages
693
- },
694
- template
695
- });
696
- } else {
697
- const initialMessages = sortedDialogueMessages.map((msg) => {
698
- const sender = msg.entityId === runtime.agentId ? runtime.character.name : "User";
699
- return `${sender}: ${msg.content.text || "[non-text message]"}`;
700
- }).join(`
701
- `);
702
- template = initialSummarizationTemplate;
703
- prompt = composePromptFromState({
704
- state: {
705
- ...state,
706
- recentMessages: initialMessages
707
- },
708
- template
709
- });
710
- }
711
- const response = await runtime.useModel(ModelType.TEXT_LARGE, {
712
- prompt,
713
- maxTokens: config.summaryMaxTokens || 2500
714
- });
715
- const summaryResult = parseSummaryXML(response);
716
- logger2.info(`${existingSummary ? "Updated" : "Generated"} summary: ${summaryResult.summary.substring(0, 100)}...`);
717
- const newOffset = lastOffset + newDialogueMessages.length;
718
- const firstMessage = newDialogueMessages[0];
719
- const lastMessage = newDialogueMessages[newDialogueMessages.length - 1];
720
- const startTime = existingSummary ? existingSummary.startTime : firstMessage?.createdAt && firstMessage.createdAt > 0 ? new Date(firstMessage.createdAt) : new Date;
721
- const endTime = lastMessage?.createdAt && lastMessage.createdAt > 0 ? new Date(lastMessage.createdAt) : new Date;
722
- if (existingSummary) {
723
- await memoryService.updateSessionSummary(existingSummary.id, roomId, {
724
- summary: summaryResult.summary,
725
- messageCount: existingSummary.messageCount + newDialogueMessages.length,
726
- lastMessageOffset: newOffset,
727
- endTime,
728
- topics: summaryResult.topics,
729
- metadata: {
730
- keyPoints: summaryResult.keyPoints
731
- }
732
- });
733
- logger2.info(`Updated summary for room ${roomId}: ${newDialogueMessages.length} new dialogue messages processed (offset: ${lastOffset} → ${newOffset})`);
734
- } else {
735
- await memoryService.storeSessionSummary({
736
- agentId: runtime.agentId,
737
- roomId,
738
- entityId: message.entityId !== runtime.agentId ? message.entityId : undefined,
739
- summary: summaryResult.summary,
740
- messageCount: totalDialogueCount,
741
- lastMessageOffset: totalDialogueCount,
742
- startTime,
743
- endTime,
744
- topics: summaryResult.topics,
745
- metadata: {
746
- keyPoints: summaryResult.keyPoints
747
- }
748
- });
749
- logger2.info(`Created new summary for room ${roomId}: ${totalDialogueCount} dialogue messages summarized (offset: 0 → ${totalDialogueCount})`);
750
- }
751
- } catch (error) {
752
- logger2.error({ error }, "Error during summarization:");
753
- }
754
- },
755
- examples: []
756
- };
757
-
758
- // src/evaluators/long-term-extraction.ts
759
- import {
760
- logger as logger3,
761
- ModelType as ModelType2,
762
- composePromptFromState as composePromptFromState2
763
- } from "@elizaos/core";
764
-
765
- // src/types/index.ts
766
- var LongTermMemoryCategory;
767
- ((LongTermMemoryCategory2) => {
768
- LongTermMemoryCategory2["EPISODIC"] = "episodic";
769
- LongTermMemoryCategory2["SEMANTIC"] = "semantic";
770
- LongTermMemoryCategory2["PROCEDURAL"] = "procedural";
771
- })(LongTermMemoryCategory ||= {});
772
-
773
- // src/evaluators/long-term-extraction.ts
774
- var extractionTemplate = `# Task: Extract Long-Term Memory (Strict Criteria)
775
-
776
- You are analyzing a conversation to extract ONLY the most critical, persistent information about the user using cognitive science memory categories.
777
-
778
- # Recent Messages
779
- {{recentMessages}}
780
-
781
- # Current Long-Term Memories
782
- {{existingMemories}}
783
-
784
- # Memory Categories (Based on Cognitive Science)
785
-
786
- ## 1. EPISODIC Memory
787
- Personal experiences and specific events with temporal/spatial context.
788
- **Examples:**
789
- - "User completed migration project from MongoDB to PostgreSQL in Q2 2024"
790
- - "User encountered authentication bug in production on March 15th"
791
- - "User had a negative experience with Docker networking in previous job"
792
-
793
- **Requirements:**
794
- - Must include WHO did WHAT, WHEN/WHERE
795
- - Must be a specific, concrete event (not a pattern)
796
- - Must have significant impact or relevance to future work
69
+ **Requirements:**
70
+ - Must include WHO did WHAT, WHEN/WHERE
71
+ - Must be a specific, concrete event (not a pattern)
72
+ - Must have significant impact or relevance to future work
797
73
 
798
74
  ## 2. SEMANTIC Memory
799
75
  General facts, concepts, knowledge, and established truths about the user.
@@ -904,6 +180,49 @@ Skills, workflows, methodologies, and how-to knowledge.
904
180
  <confidence>0.92</confidence>
905
181
  </memory>
906
182
  </memories>`;
183
+ var updateSummarizationTemplate = `# Task: Update and Condense Conversation Summary
184
+
185
+ You are updating an existing conversation summary with new messages, while keeping the total summary concise.
186
+
187
+ # Existing Summary
188
+ {{existingSummary}}
189
+
190
+ # Existing Topics
191
+ {{existingTopics}}
192
+
193
+ # New Messages Since Last Summary
194
+ {{newMessages}}
195
+
196
+ # Instructions
197
+ Update the summary by:
198
+ 1. Merging the existing summary with insights from the new messages
199
+ 2. Removing redundant or less important details to stay under the token limit
200
+ 3. Keeping the most important context and decisions
201
+ 4. Adding new topics if they emerge
202
+ 5. **CRITICAL**: Keep the ENTIRE updated summary under 2500 tokens
203
+
204
+ The goal is a rolling summary that captures the essence of the conversation without growing indefinitely.
205
+
206
+ Respond in this XML format:
207
+ <summary>
208
+ <text>Your updated and condensed summary here</text>
209
+ <topics>topic1, topic2, topic3</topics>
210
+ <keyPoints>
211
+ <point>First key point</point>
212
+ <point>Second key point</point>
213
+ </keyPoints>
214
+ </summary>`;
215
+
216
+ // src/types/index.ts
217
+ var LongTermMemoryCategory;
218
+ ((LongTermMemoryCategory2) => {
219
+ LongTermMemoryCategory2["EPISODIC"] = "episodic";
220
+ LongTermMemoryCategory2["SEMANTIC"] = "semantic";
221
+ LongTermMemoryCategory2["PROCEDURAL"] = "procedural";
222
+ })(LongTermMemoryCategory ||= {});
223
+
224
+ // src/evaluators/long-term-extraction.ts
225
+ var extractionTemplate = longTermExtractionTemplate;
907
226
  function parseMemoryExtractionXML(xml) {
908
227
  const memoryMatches = xml.matchAll(/<memory>[\s\S]*?<category>(.*?)<\/category>[\s\S]*?<content>(.*?)<\/content>[\s\S]*?<confidence>(.*?)<\/confidence>[\s\S]*?<\/memory>/g);
909
228
  const extractions = [];
@@ -912,271 +231,903 @@ function parseMemoryExtractionXML(xml) {
912
231
  const content = match[2].trim();
913
232
  const confidence = parseFloat(match[3].trim());
914
233
  if (!Object.values(LongTermMemoryCategory).includes(category)) {
915
- logger3.warn(`Invalid memory category: ${category}`);
234
+ logger.warn(`Invalid memory category: ${category}`);
916
235
  continue;
917
236
  }
918
- if (content && !isNaN(confidence)) {
237
+ if (content && !Number.isNaN(confidence)) {
919
238
  extractions.push({ category, content, confidence });
920
239
  }
921
240
  }
922
- return extractions;
923
- }
924
- var longTermExtractionEvaluator = {
925
- name: "LONG_TERM_MEMORY_EXTRACTION",
926
- description: "Extracts long-term facts about users from conversations",
927
- similes: ["MEMORY_EXTRACTION", "FACT_LEARNING", "USER_PROFILING"],
928
- alwaysRun: true,
929
- validate: async (runtime, message) => {
930
- if (message.entityId === runtime.agentId) {
931
- return false;
932
- }
933
- if (!message.content?.text) {
934
- return false;
935
- }
936
- const memoryService = runtime.getService("memory");
937
- if (!memoryService) {
938
- return false;
939
- }
940
- const config = memoryService.getConfig();
941
- if (!config.longTermExtractionEnabled) {
942
- logger3.debug("Long-term memory extraction is disabled");
943
- return false;
944
- }
945
- const currentMessageCount = await runtime.countMemories(message.roomId, false, "messages");
946
- const shouldRun = await memoryService.shouldRunExtraction(message.entityId, message.roomId, currentMessageCount);
947
- return shouldRun;
948
- },
949
- handler: async (runtime, message) => {
950
- const memoryService = runtime.getService("memory");
951
- if (!memoryService) {
952
- logger3.error("MemoryService not found");
953
- return;
954
- }
955
- const config = memoryService.getConfig();
956
- const { entityId, roomId } = message;
957
- try {
958
- logger3.info(`Extracting long-term memories for entity ${entityId}`);
959
- const recentMessages = await runtime.getMemories({
960
- tableName: "messages",
961
- roomId,
962
- count: 20,
963
- unique: false
964
- });
965
- const formattedMessages = recentMessages.sort((a, b) => (a.createdAt || 0) - (b.createdAt || 0)).map((msg) => {
966
- const sender = msg.entityId === runtime.agentId ? runtime.character.name : "User";
967
- return `${sender}: ${msg.content.text || "[non-text message]"}`;
968
- }).join(`
969
- `);
970
- const existingMemories = await memoryService.getLongTermMemories(entityId, undefined, 30);
971
- const formattedExisting = existingMemories.length > 0 ? existingMemories.map((m) => `[${m.category}] ${m.content} (confidence: ${m.confidence})`).join(`
972
- `) : "None yet";
973
- const state = await runtime.composeState(message);
974
- const prompt = composePromptFromState2({
975
- state: {
976
- ...state,
977
- recentMessages: formattedMessages,
978
- existingMemories: formattedExisting
979
- },
980
- template: extractionTemplate
981
- });
982
- const response = await runtime.useModel(ModelType2.TEXT_LARGE, {
983
- prompt
984
- });
985
- const extractions = parseMemoryExtractionXML(response);
986
- logger3.info(`Extracted ${extractions.length} long-term memories`);
987
- for (const extraction of extractions) {
988
- if (extraction.confidence >= Math.max(config.longTermConfidenceThreshold, 0.85)) {
989
- await memoryService.storeLongTermMemory({
990
- agentId: runtime.agentId,
991
- entityId,
992
- category: extraction.category,
993
- content: extraction.content,
994
- confidence: extraction.confidence,
995
- source: "conversation",
996
- metadata: {
997
- roomId,
998
- extractedAt: new Date().toISOString()
999
- }
1000
- });
1001
- logger3.info(`Stored long-term memory: [${extraction.category}] ${extraction.content.substring(0, 50)}...`);
1002
- } else {
1003
- logger3.debug(`Skipped low-confidence memory: ${extraction.content} (confidence: ${extraction.confidence}, threshold: ${Math.max(config.longTermConfidenceThreshold, 0.85)})`);
1004
- }
1005
- }
1006
- const currentMessageCount = await runtime.countMemories(roomId, false, "messages");
1007
- await memoryService.setLastExtractionCheckpoint(entityId, roomId, currentMessageCount);
1008
- logger3.debug(`Updated extraction checkpoint to ${currentMessageCount} for entity ${entityId} in room ${roomId}`);
1009
- } catch (error) {
1010
- logger3.error({ error }, "Error during long-term memory extraction:");
241
+ return extractions;
242
+ }
243
+ var longTermExtractionEvaluator = {
244
+ name: "LONG_TERM_MEMORY_EXTRACTION",
245
+ description: "Extracts long-term facts about users from conversations",
246
+ similes: ["MEMORY_EXTRACTION", "FACT_LEARNING", "USER_PROFILING"],
247
+ alwaysRun: true,
248
+ validate: async (runtime, message) => {
249
+ if (message.entityId === runtime.agentId) {
250
+ return false;
251
+ }
252
+ if (!message.content?.text) {
253
+ return false;
254
+ }
255
+ const memoryService = runtime.getService("memory");
256
+ if (!memoryService) {
257
+ return false;
258
+ }
259
+ const config = memoryService.getConfig();
260
+ if (!config.longTermExtractionEnabled) {
261
+ logger.debug("Long-term memory extraction is disabled");
262
+ return false;
263
+ }
264
+ const currentMessageCount = await runtime.countMemories(message.roomId, false, "messages");
265
+ return memoryService.shouldRunExtraction(message.entityId, message.roomId, currentMessageCount);
266
+ },
267
+ handler: async (runtime, message) => {
268
+ const memoryService = runtime.getService("memory");
269
+ if (!memoryService) {
270
+ logger.error("MemoryService not found");
271
+ return;
272
+ }
273
+ const config = memoryService.getConfig();
274
+ const { entityId, roomId } = message;
275
+ try {
276
+ logger.info(`Extracting long-term memories for entity ${entityId}`);
277
+ const recentMessages = await runtime.getMemories({
278
+ tableName: "messages",
279
+ roomId,
280
+ count: 20,
281
+ unique: false
282
+ });
283
+ const formattedMessages = recentMessages.sort((a, b) => (a.createdAt || 0) - (b.createdAt || 0)).map((msg) => {
284
+ const sender = msg.entityId === runtime.agentId ? runtime.character.name : "User";
285
+ return `${sender}: ${msg.content.text || "[non-text message]"}`;
286
+ }).join(`
287
+ `);
288
+ const existingMemories = await memoryService.getLongTermMemories(entityId, undefined, 30);
289
+ const formattedExisting = existingMemories.length > 0 ? existingMemories.map((m) => `[${m.category}] ${m.content} (confidence: ${m.confidence})`).join(`
290
+ `) : "None yet";
291
+ const state = await runtime.composeState(message);
292
+ const prompt = composePromptFromState({
293
+ state: {
294
+ ...state,
295
+ recentMessages: formattedMessages,
296
+ existingMemories: formattedExisting
297
+ },
298
+ template: extractionTemplate
299
+ });
300
+ const response = await runtime.useModel(ModelType.TEXT_LARGE, { prompt });
301
+ const extractions = parseMemoryExtractionXML(response);
302
+ logger.info(`Extracted ${extractions.length} long-term memories`);
303
+ for (const extraction of extractions) {
304
+ if (extraction.confidence >= Math.max(config.longTermConfidenceThreshold, 0.85)) {
305
+ await memoryService.storeLongTermMemory({
306
+ agentId: runtime.agentId,
307
+ entityId,
308
+ category: extraction.category,
309
+ content: extraction.content,
310
+ confidence: extraction.confidence,
311
+ source: "conversation",
312
+ metadata: {
313
+ roomId,
314
+ extractedAt: new Date().toISOString()
315
+ }
316
+ });
317
+ logger.info(`Stored long-term memory: [${extraction.category}] ${extraction.content.substring(0, 50)}...`);
318
+ } else {
319
+ logger.debug(`Skipped low-confidence memory: ${extraction.content} (confidence: ${extraction.confidence})`);
320
+ }
321
+ }
322
+ const currentMessageCount = await runtime.countMemories(roomId, false, "messages");
323
+ await memoryService.setLastExtractionCheckpoint(entityId, roomId, currentMessageCount);
324
+ logger.debug(`Updated checkpoint to ${currentMessageCount} for entity ${entityId}`);
325
+ } catch (error) {
326
+ logger.error({ error }, "Error during long-term memory extraction:");
327
+ }
328
+ return;
329
+ },
330
+ examples: []
331
+ };
332
+ // src/evaluators/summarization.ts
333
+ import {
334
+ composePromptFromState as composePromptFromState2,
335
+ logger as logger2,
336
+ ModelType as ModelType2
337
+ } from "@elizaos/core";
338
+ async function getDialogueMessageCount(runtime, roomId) {
339
+ const messages = await runtime.getMemories({
340
+ tableName: "messages",
341
+ roomId,
342
+ count: 100,
343
+ unique: false
344
+ });
345
+ 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"));
346
+ return dialogueMessages.length;
347
+ }
348
+ function parseSummaryXML(xml) {
349
+ const summaryMatch = xml.match(/<text>([\s\S]*?)<\/text>/);
350
+ const topicsMatch = xml.match(/<topics>([\s\S]*?)<\/topics>/);
351
+ const keyPointsMatches = xml.matchAll(/<point>([\s\S]*?)<\/point>/g);
352
+ const summary = summaryMatch ? summaryMatch[1].trim() : "Summary not available";
353
+ const topics = topicsMatch ? topicsMatch[1].split(",").map((t) => t.trim()).filter(Boolean) : [];
354
+ const keyPoints = Array.from(keyPointsMatches).map((match) => match[1].trim());
355
+ return { summary, topics, keyPoints };
356
+ }
357
+ var summarizationEvaluator = {
358
+ name: "MEMORY_SUMMARIZATION",
359
+ description: "Automatically summarizes conversations to optimize context usage",
360
+ similes: ["CONVERSATION_SUMMARY", "CONTEXT_COMPRESSION", "MEMORY_OPTIMIZATION"],
361
+ alwaysRun: true,
362
+ validate: async (runtime, message) => {
363
+ if (!message.content?.text) {
364
+ return false;
365
+ }
366
+ const memoryService = runtime.getService("memory");
367
+ if (!memoryService) {
368
+ return false;
369
+ }
370
+ const config = memoryService.getConfig();
371
+ const currentDialogueCount = await getDialogueMessageCount(runtime, message.roomId);
372
+ const existingSummary = await memoryService.getCurrentSessionSummary(message.roomId);
373
+ if (!existingSummary) {
374
+ return currentDialogueCount >= config.shortTermSummarizationThreshold;
375
+ } else {
376
+ const newDialogueCount = currentDialogueCount - existingSummary.lastMessageOffset;
377
+ return newDialogueCount >= config.shortTermSummarizationInterval;
378
+ }
379
+ },
380
+ handler: async (runtime, message) => {
381
+ const memoryService = runtime.getService("memory");
382
+ if (!memoryService) {
383
+ logger2.error("MemoryService not found");
384
+ return;
385
+ }
386
+ const config = memoryService.getConfig();
387
+ const { roomId } = message;
388
+ try {
389
+ logger2.info(`Starting summarization for room ${roomId}`);
390
+ const existingSummary = await memoryService.getCurrentSessionSummary(roomId);
391
+ const lastOffset = existingSummary?.lastMessageOffset || 0;
392
+ const allMessages = await runtime.getMemories({
393
+ tableName: "messages",
394
+ roomId,
395
+ count: 1000,
396
+ unique: false
397
+ });
398
+ 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"));
399
+ const totalDialogueCount = allDialogueMessages.length;
400
+ const newDialogueCount = totalDialogueCount - lastOffset;
401
+ if (newDialogueCount === 0) {
402
+ logger2.debug("No new dialogue messages to summarize");
403
+ return;
404
+ }
405
+ const maxNewMessages = config.summaryMaxNewMessages || 50;
406
+ const messagesToProcess = Math.min(newDialogueCount, maxNewMessages);
407
+ if (newDialogueCount > maxNewMessages) {
408
+ logger2.warn(`Capping new dialogue messages at ${maxNewMessages} (${newDialogueCount} available)`);
409
+ }
410
+ const sortedDialogueMessages = allDialogueMessages.sort((a, b) => (a.createdAt || 0) - (b.createdAt || 0));
411
+ const newDialogueMessages = sortedDialogueMessages.slice(lastOffset, lastOffset + messagesToProcess);
412
+ if (newDialogueMessages.length === 0) {
413
+ logger2.debug("No new dialogue messages retrieved after filtering");
414
+ return;
415
+ }
416
+ const formattedMessages = newDialogueMessages.map((msg) => {
417
+ const sender = msg.entityId === runtime.agentId ? runtime.character.name : "User";
418
+ return `${sender}: ${msg.content.text || "[non-text message]"}`;
419
+ }).join(`
420
+ `);
421
+ const state = await runtime.composeState(message);
422
+ let prompt;
423
+ let template;
424
+ if (existingSummary) {
425
+ template = updateSummarizationTemplate;
426
+ prompt = composePromptFromState2({
427
+ state: {
428
+ ...state,
429
+ existingSummary: existingSummary.summary,
430
+ existingTopics: existingSummary.topics?.join(", ") || "None",
431
+ newMessages: formattedMessages
432
+ },
433
+ template
434
+ });
435
+ } else {
436
+ const initialMessages = sortedDialogueMessages.map((msg) => {
437
+ const sender = msg.entityId === runtime.agentId ? runtime.character.name : "User";
438
+ return `${sender}: ${msg.content.text || "[non-text message]"}`;
439
+ }).join(`
440
+ `);
441
+ template = initialSummarizationTemplate;
442
+ prompt = composePromptFromState2({
443
+ state: { ...state, recentMessages: initialMessages },
444
+ template
445
+ });
446
+ }
447
+ const response = await runtime.useModel(ModelType2.TEXT_LARGE, {
448
+ prompt,
449
+ maxTokens: config.summaryMaxTokens || 2500
450
+ });
451
+ const summaryResult = parseSummaryXML(response);
452
+ logger2.info(`${existingSummary ? "Updated" : "Generated"} summary: ${summaryResult.summary.substring(0, 100)}...`);
453
+ const newOffset = lastOffset + newDialogueMessages.length;
454
+ const firstMessage = newDialogueMessages[0];
455
+ const lastMessage = newDialogueMessages[newDialogueMessages.length - 1];
456
+ const startTime = existingSummary ? existingSummary.startTime : firstMessage?.createdAt && firstMessage.createdAt > 0 ? new Date(firstMessage.createdAt) : new Date;
457
+ const endTime = lastMessage?.createdAt && lastMessage.createdAt > 0 ? new Date(lastMessage.createdAt) : new Date;
458
+ if (existingSummary) {
459
+ await memoryService.updateSessionSummary(existingSummary.id, roomId, {
460
+ summary: summaryResult.summary,
461
+ messageCount: existingSummary.messageCount + newDialogueMessages.length,
462
+ lastMessageOffset: newOffset,
463
+ endTime,
464
+ topics: summaryResult.topics,
465
+ metadata: { keyPoints: summaryResult.keyPoints }
466
+ });
467
+ logger2.info(`Updated summary for room ${roomId}: ${newDialogueMessages.length} messages processed`);
468
+ } else {
469
+ await memoryService.storeSessionSummary({
470
+ agentId: runtime.agentId,
471
+ roomId,
472
+ entityId: message.entityId !== runtime.agentId ? message.entityId : undefined,
473
+ summary: summaryResult.summary,
474
+ messageCount: totalDialogueCount,
475
+ lastMessageOffset: totalDialogueCount,
476
+ startTime,
477
+ endTime,
478
+ topics: summaryResult.topics,
479
+ metadata: { keyPoints: summaryResult.keyPoints }
480
+ });
481
+ logger2.info(`Created summary for room ${roomId}: ${totalDialogueCount} messages summarized`);
482
+ }
483
+ } catch (error) {
484
+ logger2.error({ error }, "Error during summarization:");
485
+ }
486
+ return;
487
+ },
488
+ examples: []
489
+ };
490
+ // src/providers/context-summary.ts
491
+ import {
492
+ addHeader,
493
+ logger as logger3
494
+ } from "@elizaos/core";
495
+ var contextSummaryProvider = {
496
+ name: "SUMMARIZED_CONTEXT",
497
+ description: "Provides summarized context from previous conversations",
498
+ position: 96,
499
+ get: async (runtime, message, _state) => {
500
+ try {
501
+ const memoryService = runtime.getService("memory");
502
+ const { roomId } = message;
503
+ if (!memoryService) {
504
+ return {
505
+ data: {},
506
+ values: { sessionSummaries: "", sessionSummariesWithTopics: "" },
507
+ text: ""
508
+ };
509
+ }
510
+ const currentSummary = await memoryService.getCurrentSessionSummary(roomId);
511
+ if (!currentSummary) {
512
+ return {
513
+ data: {},
514
+ values: { sessionSummaries: "", sessionSummariesWithTopics: "" },
515
+ text: ""
516
+ };
517
+ }
518
+ const messageRange = `${currentSummary.messageCount} messages`;
519
+ const timeRange = new Date(currentSummary.startTime).toLocaleDateString();
520
+ let summaryOnly = `**Previous Conversation** (${messageRange}, ${timeRange})
521
+ `;
522
+ summaryOnly += currentSummary.summary;
523
+ let summaryWithTopics = summaryOnly;
524
+ if (currentSummary.topics && currentSummary.topics.length > 0) {
525
+ summaryWithTopics += `
526
+ *Topics: ${currentSummary.topics.join(", ")}*`;
527
+ }
528
+ const sessionSummaries = addHeader("# Conversation Summary", summaryOnly);
529
+ const sessionSummariesWithTopics = addHeader("# Conversation Summary", summaryWithTopics);
530
+ return {
531
+ data: {
532
+ summaryText: currentSummary.summary,
533
+ messageCount: currentSummary.messageCount,
534
+ topics: currentSummary.topics?.join(", ") || ""
535
+ },
536
+ values: { sessionSummaries, sessionSummariesWithTopics },
537
+ text: sessionSummariesWithTopics
538
+ };
539
+ } catch (error) {
540
+ logger3.error({ error }, "Error in contextSummaryProvider:");
541
+ return {
542
+ data: {},
543
+ values: { sessionSummaries: "", sessionSummariesWithTopics: "" },
544
+ text: ""
545
+ };
546
+ }
547
+ }
548
+ };
549
+ // src/providers/long-term-memory.ts
550
+ import {
551
+ addHeader as addHeader2,
552
+ logger as logger4
553
+ } from "@elizaos/core";
554
+ var longTermMemoryProvider = {
555
+ name: "LONG_TERM_MEMORY",
556
+ description: "Persistent facts and preferences about the user",
557
+ position: 50,
558
+ get: async (runtime, message, _state) => {
559
+ try {
560
+ const memoryService = runtime.getService("memory");
561
+ if (!memoryService) {
562
+ return {
563
+ data: { memoryCount: 0 },
564
+ values: { longTermMemories: "" },
565
+ text: ""
566
+ };
567
+ }
568
+ const { entityId } = message;
569
+ if (entityId === runtime.agentId) {
570
+ return {
571
+ data: { memoryCount: 0 },
572
+ values: { longTermMemories: "" },
573
+ text: ""
574
+ };
575
+ }
576
+ const memories = await memoryService.getLongTermMemories(entityId, undefined, 25);
577
+ if (memories.length === 0) {
578
+ return {
579
+ data: { memoryCount: 0 },
580
+ values: { longTermMemories: "" },
581
+ text: ""
582
+ };
583
+ }
584
+ const formattedMemories = await memoryService.getFormattedLongTermMemories(entityId);
585
+ const text = addHeader2("# What I Know About You", formattedMemories);
586
+ const categoryCounts = new Map;
587
+ for (const memory of memories) {
588
+ const count = categoryCounts.get(memory.category) || 0;
589
+ categoryCounts.set(memory.category, count + 1);
590
+ }
591
+ const categoryList = Array.from(categoryCounts.entries()).map(([cat, count]) => `${cat}: ${count}`).join(", ");
592
+ return {
593
+ data: {
594
+ memoryCount: memories.length,
595
+ categories: categoryList
596
+ },
597
+ values: {
598
+ longTermMemories: text,
599
+ memoryCategories: categoryList
600
+ },
601
+ text
602
+ };
603
+ } catch (error) {
604
+ logger4.error({ error }, "Error in longTermMemoryProvider:");
605
+ return {
606
+ data: { memoryCount: 0 },
607
+ values: { longTermMemories: "" },
608
+ text: ""
609
+ };
610
+ }
611
+ }
612
+ };
613
+ // src/schemas/index.ts
614
+ var exports_schemas = {};
615
+ __export(exports_schemas, {
616
+ sessionSummaries: () => sessionSummaries,
617
+ memoryAccessLogs: () => memoryAccessLogs,
618
+ longTermMemories: () => longTermMemories
619
+ });
620
+
621
+ // src/schemas/long-term-memories.ts
622
+ import { sql } from "drizzle-orm";
623
+ import {
624
+ index,
625
+ integer,
626
+ jsonb,
627
+ pgTable,
628
+ real,
629
+ text,
630
+ timestamp,
631
+ varchar
632
+ } from "drizzle-orm/pg-core";
633
+ var longTermMemories = pgTable("long_term_memories", {
634
+ id: varchar("id", { length: 36 }).primaryKey(),
635
+ agentId: varchar("agent_id", { length: 36 }).notNull(),
636
+ entityId: varchar("entity_id", { length: 36 }).notNull(),
637
+ category: text("category").notNull(),
638
+ content: text("content").notNull(),
639
+ metadata: jsonb("metadata"),
640
+ embedding: real("embedding").array(),
641
+ confidence: real("confidence").default(1),
642
+ source: text("source"),
643
+ createdAt: timestamp("created_at").default(sql`now()`).notNull(),
644
+ updatedAt: timestamp("updated_at").default(sql`now()`).notNull(),
645
+ lastAccessedAt: timestamp("last_accessed_at"),
646
+ accessCount: integer("access_count").default(0)
647
+ }, (table) => ({
648
+ agentEntityIdx: index("long_term_memories_agent_entity_idx").on(table.agentId, table.entityId),
649
+ categoryIdx: index("long_term_memories_category_idx").on(table.category),
650
+ confidenceIdx: index("long_term_memories_confidence_idx").on(table.confidence),
651
+ createdAtIdx: index("long_term_memories_created_at_idx").on(table.createdAt)
652
+ }));
653
+ // src/schemas/memory-access-logs.ts
654
+ import { sql as sql2 } from "drizzle-orm";
655
+ import { index as index2, pgTable as pgTable2, text as text2, timestamp as timestamp2, varchar as varchar2 } from "drizzle-orm/pg-core";
656
+ var memoryAccessLogs = pgTable2("memory_access_logs", {
657
+ id: varchar2("id", { length: 36 }).primaryKey(),
658
+ memoryId: varchar2("memory_id", { length: 36 }).notNull(),
659
+ memoryType: text2("memory_type").notNull(),
660
+ agentId: varchar2("agent_id", { length: 36 }).notNull(),
661
+ accessType: text2("access_type").notNull(),
662
+ accessedAt: timestamp2("accessed_at").default(sql2`now()`).notNull()
663
+ }, (table) => ({
664
+ memoryIdIdx: index2("memory_access_logs_memory_id_idx").on(table.memoryId),
665
+ agentIdIdx: index2("memory_access_logs_agent_id_idx").on(table.agentId),
666
+ accessedAtIdx: index2("memory_access_logs_accessed_at_idx").on(table.accessedAt)
667
+ }));
668
+ // src/schemas/session-summaries.ts
669
+ import { sql as sql3 } from "drizzle-orm";
670
+ import {
671
+ index as index3,
672
+ integer as integer2,
673
+ jsonb as jsonb2,
674
+ pgTable as pgTable3,
675
+ real as real2,
676
+ text as text3,
677
+ timestamp as timestamp3,
678
+ varchar as varchar3
679
+ } from "drizzle-orm/pg-core";
680
+ var sessionSummaries = pgTable3("session_summaries", {
681
+ id: varchar3("id", { length: 36 }).primaryKey(),
682
+ agentId: varchar3("agent_id", { length: 36 }).notNull(),
683
+ roomId: varchar3("room_id", { length: 36 }).notNull(),
684
+ entityId: varchar3("entity_id", { length: 36 }),
685
+ summary: text3("summary").notNull(),
686
+ messageCount: integer2("message_count").notNull(),
687
+ lastMessageOffset: integer2("last_message_offset").notNull().default(0),
688
+ startTime: timestamp3("start_time").notNull(),
689
+ endTime: timestamp3("end_time").notNull(),
690
+ topics: jsonb2("topics"),
691
+ metadata: jsonb2("metadata"),
692
+ embedding: real2("embedding").array(),
693
+ createdAt: timestamp3("created_at").default(sql3`now()`).notNull(),
694
+ updatedAt: timestamp3("updated_at").default(sql3`now()`).notNull()
695
+ }, (table) => ({
696
+ agentRoomIdx: index3("session_summaries_agent_room_idx").on(table.agentId, table.roomId),
697
+ entityIdx: index3("session_summaries_entity_idx").on(table.entityId),
698
+ startTimeIdx: index3("session_summaries_start_time_idx").on(table.startTime)
699
+ }));
700
+ // src/services/memory-service.ts
701
+ import {
702
+ logger as logger5,
703
+ Service
704
+ } from "@elizaos/core";
705
+ import { and, cosineDistance, desc, eq, gte, sql as sql4 } from "drizzle-orm";
706
+ class MemoryService extends Service {
707
+ static serviceType = "memory";
708
+ sessionMessageCounts;
709
+ memoryConfig;
710
+ lastExtractionCheckpoints;
711
+ capabilityDescription = "Memory management with short-term summarization and long-term persistent facts";
712
+ constructor(runtime) {
713
+ super(runtime);
714
+ this.sessionMessageCounts = new Map;
715
+ this.lastExtractionCheckpoints = new Map;
716
+ this.memoryConfig = {
717
+ shortTermSummarizationThreshold: 16,
718
+ shortTermRetainRecent: 6,
719
+ shortTermSummarizationInterval: 10,
720
+ longTermExtractionEnabled: true,
721
+ longTermVectorSearchEnabled: false,
722
+ longTermConfidenceThreshold: 0.85,
723
+ longTermExtractionThreshold: 30,
724
+ longTermExtractionInterval: 10,
725
+ summaryModelType: "TEXT_LARGE",
726
+ summaryMaxTokens: 2500,
727
+ summaryMaxNewMessages: 20
728
+ };
729
+ }
730
+ static async start(runtime) {
731
+ const service = new MemoryService(runtime);
732
+ await service.initialize(runtime);
733
+ return service;
734
+ }
735
+ async stop() {
736
+ logger5.info("MemoryService stopped");
737
+ }
738
+ async initialize(runtime) {
739
+ this.runtime = runtime;
740
+ const threshold = runtime.getSetting("MEMORY_SUMMARIZATION_THRESHOLD");
741
+ if (threshold) {
742
+ this.memoryConfig.shortTermSummarizationThreshold = parseInt(String(threshold), 10);
743
+ }
744
+ const retainRecent = runtime.getSetting("MEMORY_RETAIN_RECENT");
745
+ if (retainRecent) {
746
+ this.memoryConfig.shortTermRetainRecent = parseInt(String(retainRecent), 10);
747
+ }
748
+ const summarizationInterval = runtime.getSetting("MEMORY_SUMMARIZATION_INTERVAL");
749
+ if (summarizationInterval) {
750
+ this.memoryConfig.shortTermSummarizationInterval = parseInt(String(summarizationInterval), 10);
751
+ }
752
+ const maxNewMessages = runtime.getSetting("MEMORY_MAX_NEW_MESSAGES");
753
+ if (maxNewMessages) {
754
+ this.memoryConfig.summaryMaxNewMessages = parseInt(String(maxNewMessages), 10);
755
+ }
756
+ const longTermEnabled = runtime.getSetting("MEMORY_LONG_TERM_ENABLED");
757
+ if (longTermEnabled === "false" || longTermEnabled === false) {
758
+ this.memoryConfig.longTermExtractionEnabled = false;
759
+ } else if (longTermEnabled === "true" || longTermEnabled === true) {
760
+ this.memoryConfig.longTermExtractionEnabled = true;
761
+ }
762
+ const confidenceThreshold = runtime.getSetting("MEMORY_CONFIDENCE_THRESHOLD");
763
+ if (confidenceThreshold) {
764
+ this.memoryConfig.longTermConfidenceThreshold = parseFloat(String(confidenceThreshold));
765
+ }
766
+ const extractionThreshold = runtime.getSetting("MEMORY_EXTRACTION_THRESHOLD");
767
+ if (extractionThreshold) {
768
+ this.memoryConfig.longTermExtractionThreshold = parseInt(String(extractionThreshold), 10);
769
+ }
770
+ const extractionInterval = runtime.getSetting("MEMORY_EXTRACTION_INTERVAL");
771
+ if (extractionInterval) {
772
+ this.memoryConfig.longTermExtractionInterval = parseInt(String(extractionInterval), 10);
773
+ }
774
+ logger5.debug({
775
+ summarizationThreshold: this.memoryConfig.shortTermSummarizationThreshold,
776
+ summarizationInterval: this.memoryConfig.shortTermSummarizationInterval,
777
+ maxNewMessages: this.memoryConfig.summaryMaxNewMessages,
778
+ retainRecent: this.memoryConfig.shortTermRetainRecent,
779
+ longTermEnabled: this.memoryConfig.longTermExtractionEnabled,
780
+ extractionThreshold: this.memoryConfig.longTermExtractionThreshold,
781
+ extractionInterval: this.memoryConfig.longTermExtractionInterval,
782
+ confidenceThreshold: this.memoryConfig.longTermConfidenceThreshold
783
+ }, "MemoryService initialized");
784
+ }
785
+ getDb() {
786
+ const db = this.runtime.db;
787
+ if (!db) {
788
+ throw new Error("Database not available");
789
+ }
790
+ return db;
791
+ }
792
+ getConfig() {
793
+ return { ...this.memoryConfig };
794
+ }
795
+ updateConfig(updates) {
796
+ this.memoryConfig = { ...this.memoryConfig, ...updates };
797
+ }
798
+ incrementMessageCount(roomId) {
799
+ const current = this.sessionMessageCounts.get(roomId) || 0;
800
+ const newCount = current + 1;
801
+ this.sessionMessageCounts.set(roomId, newCount);
802
+ return newCount;
803
+ }
804
+ resetMessageCount(roomId) {
805
+ this.sessionMessageCounts.set(roomId, 0);
806
+ }
807
+ async shouldSummarize(roomId) {
808
+ const count = await this.runtime.countMemories(roomId, false, "messages");
809
+ return count >= this.memoryConfig.shortTermSummarizationThreshold;
810
+ }
811
+ getExtractionKey(entityId, roomId) {
812
+ return `memory:extraction:${entityId}:${roomId}`;
813
+ }
814
+ async getLastExtractionCheckpoint(entityId, roomId) {
815
+ const key = this.getExtractionKey(entityId, roomId);
816
+ const cached = this.lastExtractionCheckpoints.get(key);
817
+ if (cached !== undefined) {
818
+ return cached;
819
+ }
820
+ try {
821
+ const checkpoint = await this.runtime.getCache(key);
822
+ const messageCount = checkpoint ?? 0;
823
+ this.lastExtractionCheckpoints.set(key, messageCount);
824
+ return messageCount;
825
+ } catch (error) {
826
+ logger5.warn({ error }, "Failed to get extraction checkpoint from cache");
827
+ return 0;
828
+ }
829
+ }
830
+ async setLastExtractionCheckpoint(entityId, roomId, messageCount) {
831
+ const key = this.getExtractionKey(entityId, roomId);
832
+ this.lastExtractionCheckpoints.set(key, messageCount);
833
+ try {
834
+ await this.runtime.setCache(key, messageCount);
835
+ logger5.debug(`Set extraction checkpoint for ${entityId} in room ${roomId} at count ${messageCount}`);
836
+ } catch (error) {
837
+ logger5.error({ error }, "Failed to persist extraction checkpoint to cache");
838
+ }
839
+ }
840
+ async shouldRunExtraction(entityId, roomId, currentMessageCount) {
841
+ const threshold = this.memoryConfig.longTermExtractionThreshold;
842
+ const interval = this.memoryConfig.longTermExtractionInterval;
843
+ if (currentMessageCount < threshold) {
844
+ return false;
845
+ }
846
+ const lastCheckpoint = await this.getLastExtractionCheckpoint(entityId, roomId);
847
+ const currentCheckpoint = Math.floor(currentMessageCount / interval) * interval;
848
+ const shouldRun = currentMessageCount >= threshold && currentCheckpoint > lastCheckpoint;
849
+ logger5.debug({
850
+ entityId,
851
+ roomId,
852
+ currentMessageCount,
853
+ threshold,
854
+ interval,
855
+ lastCheckpoint,
856
+ currentCheckpoint,
857
+ shouldRun
858
+ }, "Extraction check");
859
+ return shouldRun;
860
+ }
861
+ async storeLongTermMemory(memory) {
862
+ const db = this.getDb();
863
+ const id = crypto.randomUUID();
864
+ const now = new Date;
865
+ const newMemory = {
866
+ id,
867
+ createdAt: now,
868
+ updatedAt: now,
869
+ accessCount: 0,
870
+ ...memory
871
+ };
872
+ try {
873
+ await db.insert(longTermMemories).values({
874
+ id: newMemory.id,
875
+ agentId: newMemory.agentId,
876
+ entityId: newMemory.entityId,
877
+ category: newMemory.category,
878
+ content: newMemory.content,
879
+ metadata: newMemory.metadata || {},
880
+ embedding: newMemory.embedding,
881
+ confidence: newMemory.confidence,
882
+ source: newMemory.source,
883
+ accessCount: newMemory.accessCount,
884
+ createdAt: now,
885
+ updatedAt: now,
886
+ lastAccessedAt: newMemory.lastAccessedAt
887
+ });
888
+ } catch (error) {
889
+ logger5.error({ error }, "Failed to store long-term memory");
890
+ throw error;
891
+ }
892
+ logger5.info(`Stored long-term memory: ${newMemory.category} for entity ${newMemory.entityId}`);
893
+ return newMemory;
894
+ }
895
+ async getLongTermMemories(entityId, category, limit = 10) {
896
+ const db = this.getDb();
897
+ const conditions = [
898
+ eq(longTermMemories.agentId, this.runtime.agentId),
899
+ eq(longTermMemories.entityId, entityId)
900
+ ];
901
+ if (category) {
902
+ conditions.push(eq(longTermMemories.category, category));
903
+ }
904
+ const results = await db.select().from(longTermMemories).where(and(...conditions)).orderBy(desc(longTermMemories.confidence), desc(longTermMemories.updatedAt)).limit(limit);
905
+ return results.map((row) => ({
906
+ id: row.id,
907
+ agentId: row.agentId,
908
+ entityId: row.entityId,
909
+ category: row.category,
910
+ content: row.content,
911
+ metadata: row.metadata,
912
+ embedding: row.embedding,
913
+ confidence: row.confidence,
914
+ source: row.source,
915
+ createdAt: row.createdAt,
916
+ updatedAt: row.updatedAt,
917
+ lastAccessedAt: row.lastAccessedAt,
918
+ accessCount: row.accessCount
919
+ }));
920
+ }
921
+ async updateLongTermMemory(id, entityId, updates) {
922
+ const db = this.getDb();
923
+ const updateData = {
924
+ updatedAt: new Date
925
+ };
926
+ if (updates.content !== undefined)
927
+ updateData.content = updates.content;
928
+ if (updates.metadata !== undefined)
929
+ updateData.metadata = updates.metadata;
930
+ if (updates.confidence !== undefined)
931
+ updateData.confidence = updates.confidence;
932
+ if (updates.embedding !== undefined)
933
+ updateData.embedding = updates.embedding;
934
+ if (updates.lastAccessedAt !== undefined)
935
+ updateData.lastAccessedAt = updates.lastAccessedAt;
936
+ if (updates.accessCount !== undefined)
937
+ updateData.accessCount = updates.accessCount;
938
+ await db.update(longTermMemories).set(updateData).where(and(eq(longTermMemories.id, id), eq(longTermMemories.agentId, this.runtime.agentId), eq(longTermMemories.entityId, entityId)));
939
+ logger5.info(`Updated long-term memory: ${id} for entity ${entityId}`);
940
+ }
941
+ async deleteLongTermMemory(id, entityId) {
942
+ const db = this.getDb();
943
+ await db.delete(longTermMemories).where(and(eq(longTermMemories.id, id), eq(longTermMemories.agentId, this.runtime.agentId), eq(longTermMemories.entityId, entityId)));
944
+ logger5.info(`Deleted long-term memory: ${id} for entity ${entityId}`);
945
+ }
946
+ async getCurrentSessionSummary(roomId) {
947
+ const db = this.getDb();
948
+ const results = await db.select().from(sessionSummaries).where(and(eq(sessionSummaries.agentId, this.runtime.agentId), eq(sessionSummaries.roomId, roomId))).orderBy(desc(sessionSummaries.updatedAt)).limit(1);
949
+ if (results.length === 0) {
950
+ return null;
951
+ }
952
+ const row = results[0];
953
+ return {
954
+ id: row.id,
955
+ agentId: row.agentId,
956
+ roomId: row.roomId,
957
+ entityId: row.entityId,
958
+ summary: row.summary,
959
+ messageCount: row.messageCount,
960
+ lastMessageOffset: row.lastMessageOffset,
961
+ startTime: row.startTime,
962
+ endTime: row.endTime,
963
+ topics: row.topics || [],
964
+ metadata: row.metadata,
965
+ embedding: row.embedding,
966
+ createdAt: row.createdAt,
967
+ updatedAt: row.updatedAt
968
+ };
969
+ }
970
+ async storeSessionSummary(summary) {
971
+ const db = this.getDb();
972
+ const id = crypto.randomUUID();
973
+ const now = new Date;
974
+ const newSummary = {
975
+ id,
976
+ createdAt: now,
977
+ updatedAt: now,
978
+ ...summary
979
+ };
980
+ await db.insert(sessionSummaries).values({
981
+ id: newSummary.id,
982
+ agentId: newSummary.agentId,
983
+ roomId: newSummary.roomId,
984
+ entityId: newSummary.entityId || null,
985
+ summary: newSummary.summary,
986
+ messageCount: newSummary.messageCount,
987
+ lastMessageOffset: newSummary.lastMessageOffset,
988
+ startTime: newSummary.startTime,
989
+ endTime: newSummary.endTime,
990
+ topics: newSummary.topics || [],
991
+ metadata: newSummary.metadata || {},
992
+ embedding: newSummary.embedding,
993
+ createdAt: now,
994
+ updatedAt: now
995
+ });
996
+ logger5.info(`Stored session summary for room ${newSummary.roomId}`);
997
+ return newSummary;
998
+ }
999
+ async updateSessionSummary(id, roomId, updates) {
1000
+ const db = this.getDb();
1001
+ const updateData = {
1002
+ updatedAt: new Date
1003
+ };
1004
+ if (updates.summary !== undefined)
1005
+ updateData.summary = updates.summary;
1006
+ if (updates.messageCount !== undefined)
1007
+ updateData.messageCount = updates.messageCount;
1008
+ if (updates.lastMessageOffset !== undefined)
1009
+ updateData.lastMessageOffset = updates.lastMessageOffset;
1010
+ if (updates.endTime !== undefined)
1011
+ updateData.endTime = updates.endTime;
1012
+ if (updates.topics !== undefined)
1013
+ updateData.topics = updates.topics;
1014
+ if (updates.metadata !== undefined)
1015
+ updateData.metadata = updates.metadata;
1016
+ if (updates.embedding !== undefined)
1017
+ updateData.embedding = updates.embedding;
1018
+ await db.update(sessionSummaries).set(updateData).where(and(eq(sessionSummaries.id, id), eq(sessionSummaries.agentId, this.runtime.agentId), eq(sessionSummaries.roomId, roomId)));
1019
+ logger5.info(`Updated session summary: ${id} for room ${roomId}`);
1020
+ }
1021
+ async getSessionSummaries(roomId, limit = 5) {
1022
+ const db = this.getDb();
1023
+ const results = await db.select().from(sessionSummaries).where(and(eq(sessionSummaries.agentId, this.runtime.agentId), eq(sessionSummaries.roomId, roomId))).orderBy(desc(sessionSummaries.updatedAt)).limit(limit);
1024
+ return results.map((row) => ({
1025
+ id: row.id,
1026
+ agentId: row.agentId,
1027
+ roomId: row.roomId,
1028
+ entityId: row.entityId,
1029
+ summary: row.summary,
1030
+ messageCount: row.messageCount,
1031
+ lastMessageOffset: row.lastMessageOffset,
1032
+ startTime: row.startTime,
1033
+ endTime: row.endTime,
1034
+ topics: row.topics || [],
1035
+ metadata: row.metadata,
1036
+ embedding: row.embedding,
1037
+ createdAt: row.createdAt,
1038
+ updatedAt: row.updatedAt
1039
+ }));
1040
+ }
1041
+ async searchLongTermMemories(entityId, queryEmbedding, limit = 5, matchThreshold = 0.7) {
1042
+ if (!this.memoryConfig.longTermVectorSearchEnabled) {
1043
+ logger5.warn("Vector search is not enabled, falling back to recent memories");
1044
+ return this.getLongTermMemories(entityId, undefined, limit);
1011
1045
  }
1012
- },
1013
- examples: []
1014
- };
1015
-
1016
- // src/providers/long-term-memory.ts
1017
- import {
1018
- logger as logger4,
1019
- addHeader
1020
- } from "@elizaos/core";
1021
- var longTermMemoryProvider = {
1022
- name: "LONG_TERM_MEMORY",
1023
- description: "Persistent facts and preferences about the user",
1024
- position: 50,
1025
- get: async (runtime, message, _state) => {
1046
+ const db = this.getDb();
1026
1047
  try {
1027
- const memoryService = runtime.getService("memory");
1028
- if (!memoryService) {
1029
- return {
1030
- data: { memories: [] },
1031
- values: { longTermMemories: "" },
1032
- text: ""
1033
- };
1034
- }
1035
- const { entityId } = message;
1036
- if (entityId === runtime.agentId) {
1037
- return {
1038
- data: { memories: [] },
1039
- values: { longTermMemories: "" },
1040
- text: ""
1041
- };
1042
- }
1043
- const memories = await memoryService.getLongTermMemories(entityId, undefined, 25);
1044
- if (memories.length === 0) {
1045
- return {
1046
- data: { memories: [] },
1047
- values: { longTermMemories: "" },
1048
- text: ""
1049
- };
1050
- }
1051
- const formattedMemories = await memoryService.getFormattedLongTermMemories(entityId);
1052
- const text4 = addHeader("# What I Know About You", formattedMemories);
1053
- const categoryCounts = new Map;
1054
- for (const memory of memories) {
1055
- const count = categoryCounts.get(memory.category) || 0;
1056
- categoryCounts.set(memory.category, count + 1);
1048
+ const cleanVector = queryEmbedding.map((n) => Number.isFinite(n) ? Number(n.toFixed(6)) : 0);
1049
+ const similarity = sql4`1 - (${cosineDistance(longTermMemories.embedding, cleanVector)})`;
1050
+ const conditions = [
1051
+ eq(longTermMemories.agentId, this.runtime.agentId),
1052
+ eq(longTermMemories.entityId, entityId),
1053
+ sql4`${longTermMemories.embedding} IS NOT NULL`
1054
+ ];
1055
+ if (matchThreshold > 0) {
1056
+ conditions.push(gte(similarity, matchThreshold));
1057
1057
  }
1058
- const categoryList = Array.from(categoryCounts.entries()).map(([cat, count]) => `${cat}: ${count}`).join(", ");
1059
- return {
1060
- data: {
1061
- memories,
1062
- categoryCounts: Object.fromEntries(categoryCounts)
1063
- },
1064
- values: {
1065
- longTermMemories: text4,
1066
- memoryCategories: categoryList
1067
- },
1068
- text: text4
1069
- };
1058
+ const results = await db.select({
1059
+ memory: longTermMemories,
1060
+ similarity
1061
+ }).from(longTermMemories).where(and(...conditions)).orderBy(desc(similarity)).limit(limit);
1062
+ return results.map((row) => ({
1063
+ id: row.memory.id,
1064
+ agentId: row.memory.agentId,
1065
+ entityId: row.memory.entityId,
1066
+ category: row.memory.category,
1067
+ content: row.memory.content,
1068
+ metadata: row.memory.metadata ?? {},
1069
+ embedding: row.memory.embedding ?? [],
1070
+ confidence: row.memory.confidence ?? 1,
1071
+ source: row.memory.source ?? "",
1072
+ createdAt: row.memory.createdAt,
1073
+ updatedAt: row.memory.updatedAt,
1074
+ lastAccessedAt: row.memory.lastAccessedAt ?? row.memory.updatedAt,
1075
+ accessCount: row.memory.accessCount ?? 0,
1076
+ similarity: row.similarity
1077
+ }));
1070
1078
  } catch (error) {
1071
- logger4.error({ error }, "Error in longTermMemoryProvider:");
1072
- return {
1073
- data: { memories: [] },
1074
- values: { longTermMemories: "" },
1075
- text: ""
1076
- };
1079
+ logger5.warn({ error }, "Vector search failed, falling back to recent memories");
1080
+ return this.getLongTermMemories(entityId, undefined, limit);
1077
1081
  }
1078
1082
  }
1079
- };
1080
-
1081
- // src/providers/context-summary.ts
1082
- import {
1083
- addHeader as addHeader2,
1084
- logger as logger5
1085
- } from "@elizaos/core";
1086
- var contextSummaryProvider = {
1087
- name: "SUMMARIZED_CONTEXT",
1088
- description: "Provides summarized context from previous conversations",
1089
- position: 96,
1090
- get: async (runtime, message, _state) => {
1091
- try {
1092
- const memoryService = runtime.getService("memory");
1093
- const { roomId } = message;
1094
- if (!memoryService) {
1095
- return {
1096
- data: {
1097
- summary: null
1098
- },
1099
- values: {
1100
- sessionSummaries: "",
1101
- sessionSummariesWithTopics: ""
1102
- },
1103
- text: ""
1104
- };
1105
- }
1106
- const currentSummary = await memoryService.getCurrentSessionSummary(roomId);
1107
- if (!currentSummary) {
1108
- return {
1109
- data: {
1110
- summary: null
1111
- },
1112
- values: {
1113
- sessionSummaries: "",
1114
- sessionSummariesWithTopics: ""
1115
- },
1116
- text: ""
1117
- };
1118
- }
1119
- const messageRange = `${currentSummary.messageCount} messages`;
1120
- const timeRange = new Date(currentSummary.startTime).toLocaleDateString();
1121
- let summaryOnly = `**Previous Conversation** (${messageRange}, ${timeRange})
1122
- `;
1123
- summaryOnly += currentSummary.summary;
1124
- let summaryWithTopics = summaryOnly;
1125
- if (currentSummary.topics && currentSummary.topics.length > 0) {
1126
- summaryWithTopics += `
1127
- *Topics: ${currentSummary.topics.join(", ")}*`;
1083
+ async getFormattedLongTermMemories(entityId) {
1084
+ const memories = await this.getLongTermMemories(entityId, undefined, 20);
1085
+ if (memories.length === 0) {
1086
+ return "";
1087
+ }
1088
+ const grouped = new Map;
1089
+ for (const memory of memories) {
1090
+ if (!grouped.has(memory.category)) {
1091
+ grouped.set(memory.category, []);
1128
1092
  }
1129
- const sessionSummaries2 = addHeader2("# Conversation Summary", summaryOnly);
1130
- const sessionSummariesWithTopics = addHeader2("# Conversation Summary", summaryWithTopics);
1131
- return {
1132
- data: {
1133
- summary: currentSummary
1134
- },
1135
- values: {
1136
- sessionSummaries: sessionSummaries2,
1137
- sessionSummariesWithTopics
1138
- },
1139
- text: sessionSummariesWithTopics
1140
- };
1141
- } catch (error) {
1142
- logger5.error({ error }, "Error in contextSummaryProvider:");
1143
- return {
1144
- data: {
1145
- summary: null
1146
- },
1147
- values: {
1148
- sessionSummaries: "",
1149
- sessionSummariesWithTopics: ""
1150
- },
1151
- text: ""
1152
- };
1093
+ grouped.get(memory.category)?.push(memory);
1094
+ }
1095
+ const sections = [];
1096
+ for (const [category, categoryMemories] of grouped.entries()) {
1097
+ const categoryName = category.split("_").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
1098
+ const items = categoryMemories.map((m) => `- ${m.content}`).join(`
1099
+ `);
1100
+ sections.push(`**${categoryName}**:
1101
+ ${items}`);
1153
1102
  }
1103
+ return sections.join(`
1104
+
1105
+ `);
1154
1106
  }
1155
- };
1107
+ }
1156
1108
 
1157
1109
  // src/index.ts
1158
1110
  var memoryPlugin = {
1159
1111
  name: "memory",
1160
- description: "Advanced memory management with conversation summarization and long-term persistent memory",
1112
+ description: "Memory management with conversation summarization and long-term persistent memory",
1161
1113
  services: [MemoryService],
1162
1114
  evaluators: [summarizationEvaluator, longTermExtractionEvaluator],
1163
- providers: [
1164
- longTermMemoryProvider,
1165
- contextSummaryProvider
1166
- ],
1115
+ providers: [longTermMemoryProvider, contextSummaryProvider],
1167
1116
  schema: exports_schemas
1168
1117
  };
1169
1118
  var src_default = memoryPlugin;
1170
1119
  export {
1120
+ summarizationEvaluator,
1171
1121
  sessionSummaries,
1172
1122
  memoryPlugin,
1173
1123
  memoryAccessLogs,
1174
1124
  longTermMemoryProvider,
1175
1125
  longTermMemories,
1126
+ longTermExtractionEvaluator,
1176
1127
  src_default as default,
1177
1128
  contextSummaryProvider,
1178
1129
  MemoryService,
1179
1130
  LongTermMemoryCategory
1180
1131
  };
1181
1132
 
1182
- //# debugId=6798CB2FB52CC5AF64756E2164756E21
1133
+ //# debugId=FC048A8C8739D95E64756E2164756E21