@elizaos/plugin-memory 1.1.1 → 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 (44) 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 -39
  10. package/dist/index.d.ts.map +1 -0
  11. package/dist/{node/index.node.js → index.js} +800 -981
  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 -209
  35. package/dist/browser/index.browser.js.map +0 -20
  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 -1293
  39. package/dist/cjs/index.node.js.map +0 -20
  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 -20
  44. package/dist/providers/recent-messages.d.ts +0 -15
@@ -9,535 +9,14 @@ var __export = (target, all) => {
9
9
  });
10
10
  };
11
11
 
12
- // src/services/memory-service.ts
13
- import {
14
- Service,
15
- logger
16
- } from "@elizaos/core";
17
- import { eq, and, desc, sql as sql4, cosineDistance, gte } from "drizzle-orm";
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
12
+ // src/evaluators/long-term-extraction.ts
526
13
  import {
527
- logger as logger2,
528
- ModelType,
529
- composePromptFromState
14
+ composePromptFromState,
15
+ logger,
16
+ ModelType
530
17
  } 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
- }
18
+
19
+ // src/generated/prompts/typescript/prompts.ts
541
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.
@@ -550,228 +29,25 @@ Generate a summary that:
550
29
  1. Captures the main topics discussed
551
30
  2. Highlights key information shared
552
31
  3. Notes any decisions made or questions asked
553
- 4. Maintains context for future reference
554
- 5. Is concise but comprehensive
555
-
556
- **IMPORTANT**: Keep the summary under 2500 tokens. Be comprehensive but concise.
557
-
558
- Also extract:
559
- - **Topics**: List of main topics discussed (comma-separated)
560
- - **Key Points**: Important facts or decisions (bullet points)
561
-
562
- Respond in this XML format:
563
- <summary>
564
- <text>Your comprehensive summary here</text>
565
- <topics>topic1, topic2, topic3</topics>
566
- <keyPoints>
567
- <point>First key point</point>
568
- <point>Second key point</point>
569
- </keyPoints>
570
- </summary>`;
571
- var updateSummarizationTemplate = `# Task: Update and Condense Conversation Summary
572
-
573
- You are updating an existing conversation summary with new messages, while keeping the total summary concise.
574
-
575
- # Existing Summary
576
- {{existingSummary}}
577
-
578
- # Existing Topics
579
- {{existingTopics}}
580
-
581
- # New Messages Since Last Summary
582
- {{newMessages}}
583
-
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
591
-
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
- };
32
+ 4. Maintains context for future reference
33
+ 5. Is concise but comprehensive
757
34
 
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";
35
+ **IMPORTANT**: Keep the summary under 2500 tokens. Be comprehensive but concise.
764
36
 
765
- // src/types/index.ts
766
- var LongTermMemoryCategory;
767
- ((LongTermMemoryCategory2) => {
768
- LongTermMemoryCategory2["EPISODIC"] = "episodic";
769
- LongTermMemoryCategory2["SEMANTIC"] = "semantic";
770
- LongTermMemoryCategory2["PROCEDURAL"] = "procedural";
771
- })(LongTermMemoryCategory ||= {});
37
+ Also extract:
38
+ - **Topics**: List of main topics discussed (comma-separated)
39
+ - **Key Points**: Important facts or decisions (bullet points)
772
40
 
773
- // src/evaluators/long-term-extraction.ts
774
- var extractionTemplate = `# Task: Extract Long-Term Memory (Strict Criteria)
41
+ Respond in this XML format:
42
+ <summary>
43
+ <text>Your comprehensive summary here</text>
44
+ <topics>topic1, topic2, topic3</topics>
45
+ <keyPoints>
46
+ <point>First key point</point>
47
+ <point>Second key point</point>
48
+ </keyPoints>
49
+ </summary>`;
50
+ var longTermExtractionTemplate = `# Task: Extract Long-Term Memory (Strict Criteria)
775
51
 
776
52
  You are analyzing a conversation to extract ONLY the most critical, persistent information about the user using cognitive science memory categories.
777
53
 
@@ -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,10 +231,10 @@ 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
  }
@@ -939,23 +258,22 @@ var longTermExtractionEvaluator = {
939
258
  }
940
259
  const config = memoryService.getConfig();
941
260
  if (!config.longTermExtractionEnabled) {
942
- logger3.debug("Long-term memory extraction is disabled");
261
+ logger.debug("Long-term memory extraction is disabled");
943
262
  return false;
944
263
  }
945
264
  const currentMessageCount = await runtime.countMemories(message.roomId, false, "messages");
946
- const shouldRun = await memoryService.shouldRunExtraction(message.entityId, message.roomId, currentMessageCount);
947
- return shouldRun;
265
+ return memoryService.shouldRunExtraction(message.entityId, message.roomId, currentMessageCount);
948
266
  },
949
267
  handler: async (runtime, message) => {
950
268
  const memoryService = runtime.getService("memory");
951
269
  if (!memoryService) {
952
- logger3.error("MemoryService not found");
270
+ logger.error("MemoryService not found");
953
271
  return;
954
272
  }
955
273
  const config = memoryService.getConfig();
956
274
  const { entityId, roomId } = message;
957
275
  try {
958
- logger3.info(`Extracting long-term memories for entity ${entityId}`);
276
+ logger.info(`Extracting long-term memories for entity ${entityId}`);
959
277
  const recentMessages = await runtime.getMemories({
960
278
  tableName: "messages",
961
279
  roomId,
@@ -971,7 +289,7 @@ var longTermExtractionEvaluator = {
971
289
  const formattedExisting = existingMemories.length > 0 ? existingMemories.map((m) => `[${m.category}] ${m.content} (confidence: ${m.confidence})`).join(`
972
290
  `) : "None yet";
973
291
  const state = await runtime.composeState(message);
974
- const prompt = composePromptFromState2({
292
+ const prompt = composePromptFromState({
975
293
  state: {
976
294
  ...state,
977
295
  recentMessages: formattedMessages,
@@ -979,11 +297,9 @@ var longTermExtractionEvaluator = {
979
297
  },
980
298
  template: extractionTemplate
981
299
  });
982
- const response = await runtime.useModel(ModelType2.TEXT_LARGE, {
983
- prompt
984
- });
300
+ const response = await runtime.useModel(ModelType.TEXT_LARGE, { prompt });
985
301
  const extractions = parseMemoryExtractionXML(response);
986
- logger3.info(`Extracted ${extractions.length} long-term memories`);
302
+ logger.info(`Extracted ${extractions.length} long-term memories`);
987
303
  for (const extraction of extractions) {
988
304
  if (extraction.confidence >= Math.max(config.longTermConfidenceThreshold, 0.85)) {
989
305
  await memoryService.storeLongTermMemory({
@@ -998,25 +314,242 @@ var longTermExtractionEvaluator = {
998
314
  extractedAt: new Date().toISOString()
999
315
  }
1000
316
  });
1001
- logger3.info(`Stored long-term memory: [${extraction.category}] ${extraction.content.substring(0, 50)}...`);
317
+ logger.info(`Stored long-term memory: [${extraction.category}] ${extraction.content.substring(0, 50)}...`);
1002
318
  } else {
1003
- logger3.debug(`Skipped low-confidence memory: ${extraction.content} (confidence: ${extraction.confidence}, threshold: ${Math.max(config.longTermConfidenceThreshold, 0.85)})`);
319
+ logger.debug(`Skipped low-confidence memory: ${extraction.content} (confidence: ${extraction.confidence})`);
1004
320
  }
1005
321
  }
1006
322
  const currentMessageCount = await runtime.countMemories(roomId, false, "messages");
1007
323
  await memoryService.setLastExtractionCheckpoint(entityId, roomId, currentMessageCount);
1008
- logger3.debug(`Updated extraction checkpoint to ${currentMessageCount} for entity ${entityId} in room ${roomId}`);
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
+ };
1009
539
  } catch (error) {
1010
- logger3.error({ error }, "Error during long-term memory extraction:");
540
+ logger3.error({ error }, "Error in contextSummaryProvider:");
541
+ return {
542
+ data: {},
543
+ values: { sessionSummaries: "", sessionSummariesWithTopics: "" },
544
+ text: ""
545
+ };
1011
546
  }
1012
- },
1013
- examples: []
547
+ }
1014
548
  };
1015
-
1016
549
  // src/providers/long-term-memory.ts
1017
550
  import {
1018
- logger as logger4,
1019
- addHeader
551
+ addHeader as addHeader2,
552
+ logger as logger4
1020
553
  } from "@elizaos/core";
1021
554
  var longTermMemoryProvider = {
1022
555
  name: "LONG_TERM_MEMORY",
@@ -1027,7 +560,7 @@ var longTermMemoryProvider = {
1027
560
  const memoryService = runtime.getService("memory");
1028
561
  if (!memoryService) {
1029
562
  return {
1030
- data: { memories: [] },
563
+ data: { memoryCount: 0 },
1031
564
  values: { longTermMemories: "" },
1032
565
  text: ""
1033
566
  };
@@ -1035,7 +568,7 @@ var longTermMemoryProvider = {
1035
568
  const { entityId } = message;
1036
569
  if (entityId === runtime.agentId) {
1037
570
  return {
1038
- data: { memories: [] },
571
+ data: { memoryCount: 0 },
1039
572
  values: { longTermMemories: "" },
1040
573
  text: ""
1041
574
  };
@@ -1043,13 +576,13 @@ var longTermMemoryProvider = {
1043
576
  const memories = await memoryService.getLongTermMemories(entityId, undefined, 25);
1044
577
  if (memories.length === 0) {
1045
578
  return {
1046
- data: { memories: [] },
579
+ data: { memoryCount: 0 },
1047
580
  values: { longTermMemories: "" },
1048
581
  text: ""
1049
582
  };
1050
583
  }
1051
584
  const formattedMemories = await memoryService.getFormattedLongTermMemories(entityId);
1052
- const text4 = addHeader("# What I Know About You", formattedMemories);
585
+ const text = addHeader2("# What I Know About You", formattedMemories);
1053
586
  const categoryCounts = new Map;
1054
587
  for (const memory of memories) {
1055
588
  const count = categoryCounts.get(memory.category) || 0;
@@ -1058,257 +591,543 @@ var longTermMemoryProvider = {
1058
591
  const categoryList = Array.from(categoryCounts.entries()).map(([cat, count]) => `${cat}: ${count}`).join(", ");
1059
592
  return {
1060
593
  data: {
1061
- memories,
1062
- categoryCounts: Object.fromEntries(categoryCounts)
594
+ memoryCount: memories.length,
595
+ categories: categoryList
1063
596
  },
1064
597
  values: {
1065
- longTermMemories: text4,
598
+ longTermMemories: text,
1066
599
  memoryCategories: categoryList
1067
600
  },
1068
- text: text4
601
+ text
1069
602
  };
1070
603
  } catch (error) {
1071
604
  logger4.error({ error }, "Error in longTermMemoryProvider:");
1072
605
  return {
1073
- data: { memories: [] },
606
+ data: { memoryCount: 0 },
1074
607
  values: { longTermMemories: "" },
1075
608
  text: ""
1076
609
  };
1077
610
  }
1078
611
  }
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) => {
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);
1045
+ }
1046
+ const db = this.getDb();
1091
1047
  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(", ")}*`;
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));
1128
1057
  }
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
- };
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
+ }));
1141
1078
  } 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
- };
1079
+ logger5.warn({ error }, "Vector search failed, falling back to recent memories");
1080
+ return this.getLongTermMemories(entityId, undefined, limit);
1153
1081
  }
1154
1082
  }
1155
- };
1156
-
1157
- // src/providers/recent-messages.ts
1158
- import {
1159
- addHeader as addHeader3,
1160
- ChannelType,
1161
- formatMessages,
1162
- formatPosts,
1163
- getEntityDetails,
1164
- logger as logger6
1165
- } from "@elizaos/core";
1166
- var recentMessagesProvider = {
1167
- name: "RECENT_MESSAGES",
1168
- description: "Provides recent conversation messages with detailed context",
1169
- position: 94,
1170
- get: async (runtime, message, _state) => {
1171
- try {
1172
- const memoryService = runtime.getService("memory");
1173
- const { roomId } = message;
1174
- const config = memoryService?.getConfig() || {
1175
- shortTermSummarizationThreshold: 16,
1176
- shortTermRetainRecent: 6
1177
- };
1178
- const conversationLength = runtime.getConversationLength();
1179
- let messagesToFetch = config.shortTermRetainRecent;
1180
- let startOffset = 0;
1181
- let hasSummary = false;
1182
- if (memoryService) {
1183
- const currentSummary = await memoryService.getCurrentSessionSummary(roomId);
1184
- if (currentSummary) {
1185
- hasSummary = true;
1186
- startOffset = currentSummary.lastMessageOffset || 0;
1187
- }
1188
- }
1189
- if (!hasSummary) {
1190
- const allMessages = await runtime.getMemories({
1191
- tableName: "messages",
1192
- roomId,
1193
- count: conversationLength,
1194
- unique: false
1195
- });
1196
- const dialogueMessageCount = allMessages.filter((msg) => !(msg.content?.type === "action_result" && msg.metadata?.type === "action_result") && (msg.metadata?.type === "agent_response_message" || msg.metadata?.type === "user_message")).length;
1197
- if (dialogueMessageCount < config.shortTermSummarizationThreshold) {
1198
- messagesToFetch = conversationLength;
1199
- }
1200
- }
1201
- const [entitiesData, room, recentMessagesData] = await Promise.all([
1202
- getEntityDetails({ runtime, roomId }),
1203
- runtime.getRoom(roomId),
1204
- runtime.getMemories({
1205
- tableName: "messages",
1206
- roomId,
1207
- count: messagesToFetch,
1208
- unique: false,
1209
- start: startOffset
1210
- })
1211
- ]);
1212
- const isPostFormat = room?.type ? room.type === ChannelType.FEED || room.type === ChannelType.THREAD : false;
1213
- const dialogueMessages = recentMessagesData.filter((msg) => !(msg.content?.type === "action_result" && msg.metadata?.type === "action_result") && (msg.metadata?.type === "agent_response_message" || msg.metadata?.type === "user_message"));
1214
- let recentMessagesText = "";
1215
- if (dialogueMessages.length > 0) {
1216
- if (isPostFormat) {
1217
- recentMessagesText = formatPosts({
1218
- messages: dialogueMessages,
1219
- entities: entitiesData,
1220
- conversationHeader: false
1221
- });
1222
- } else {
1223
- recentMessagesText = formatMessages({
1224
- messages: dialogueMessages,
1225
- entities: entitiesData
1226
- });
1227
- }
1228
- if (recentMessagesText) {
1229
- recentMessagesText = addHeader3("# Recent Messages", recentMessagesText);
1230
- }
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, []);
1231
1092
  }
1232
- const formatConversationLog = (messages, includeThoughts) => {
1233
- return messages.sort((a, b) => (a.createdAt || 0) - (b.createdAt || 0)).map((msg) => {
1234
- const entity = entitiesData.find((e) => e.id === msg.entityId);
1235
- const entityName = entity?.names[0] || (msg.entityId === runtime.agentId ? runtime.character.name : "Unknown");
1236
- const timestamp4 = msg.createdAt ? new Date(msg.createdAt).toLocaleString() : "Unknown time";
1237
- const text5 = msg.content.text || "";
1238
- const thought = includeThoughts && msg.content.thought ? `
1239
- [Internal thought: ${msg.content.thought}]` : "";
1240
- return `[${timestamp4}] ${entityName}: ${text5}${thought}`;
1241
- }).join(`
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(`
1242
1099
  `);
1243
- };
1244
- const conversationLog = addHeader3("# Conversation Messages", formatConversationLog(dialogueMessages, false));
1245
- const conversationLogWithAgentThoughts = addHeader3("# Conversation Messages", formatConversationLog(dialogueMessages, true));
1246
- const metaData = message.metadata;
1247
- const senderName = entitiesData.find((entity) => entity.id === message.entityId)?.names[0] || metaData?.entityName || "Unknown User";
1248
- const receivedMessageContent = message.content.text;
1249
- const hasReceivedMessage = !!receivedMessageContent?.trim();
1250
- const receivedMessageHeader = hasReceivedMessage ? addHeader3("# Received Message", `${senderName}: ${receivedMessageContent}`) : "";
1251
- const focusHeader = hasReceivedMessage ? addHeader3("# Focus your response", `You are replying to the above message from **${senderName}**. Keep your answer relevant to that message.`) : "";
1252
- const text4 = [recentMessagesText, receivedMessageHeader, focusHeader].filter(Boolean).join(`
1100
+ sections.push(`**${categoryName}**:
1101
+ ${items}`);
1102
+ }
1103
+ return sections.join(`
1253
1104
 
1254
1105
  `);
1255
- return {
1256
- data: {
1257
- messages: dialogueMessages
1258
- },
1259
- values: {
1260
- recentMessages: recentMessagesText,
1261
- conversationLog,
1262
- conversationLogWithAgentThoughts,
1263
- ...receivedMessageHeader && { receivedMessageHeader },
1264
- ...focusHeader && { focusHeader }
1265
- },
1266
- text: text4
1267
- };
1268
- } catch (error) {
1269
- logger6.error({ error }, "Error in recentMessagesProvider:");
1270
- return {
1271
- data: {
1272
- messages: []
1273
- },
1274
- values: {
1275
- recentMessages: "",
1276
- conversationLog: "",
1277
- conversationLogWithAgentThoughts: "",
1278
- receivedMessageHeader: "",
1279
- focusHeader: ""
1280
- },
1281
- text: ""
1282
- };
1283
- }
1284
1106
  }
1285
- };
1107
+ }
1286
1108
 
1287
1109
  // src/index.ts
1288
1110
  var memoryPlugin = {
1289
1111
  name: "memory",
1290
- description: "Advanced memory management with conversation summarization and long-term persistent memory",
1112
+ description: "Memory management with conversation summarization and long-term persistent memory",
1291
1113
  services: [MemoryService],
1292
1114
  evaluators: [summarizationEvaluator, longTermExtractionEvaluator],
1293
- providers: [
1294
- longTermMemoryProvider,
1295
- contextSummaryProvider,
1296
- recentMessagesProvider
1297
- ],
1115
+ providers: [longTermMemoryProvider, contextSummaryProvider],
1298
1116
  schema: exports_schemas
1299
1117
  };
1300
1118
  var src_default = memoryPlugin;
1301
1119
  export {
1120
+ summarizationEvaluator,
1302
1121
  sessionSummaries,
1303
- recentMessagesProvider,
1304
1122
  memoryPlugin,
1305
1123
  memoryAccessLogs,
1306
1124
  longTermMemoryProvider,
1307
1125
  longTermMemories,
1126
+ longTermExtractionEvaluator,
1308
1127
  src_default as default,
1309
1128
  contextSummaryProvider,
1310
1129
  MemoryService,
1311
1130
  LongTermMemoryCategory
1312
1131
  };
1313
1132
 
1314
- //# debugId=007D7F9163530F2964756E2164756E21
1133
+ //# debugId=FC048A8C8739D95E64756E2164756E21