memo-grafter 0.2.7 → 0.3.0

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 (205) hide show
  1. package/README.md +26 -0
  2. package/USER_GUIDE.md +262 -17
  3. package/dist/MemoGrafter.d.ts +11 -5
  4. package/dist/MemoGrafter.d.ts.map +1 -1
  5. package/dist/MemoGrafter.js +64 -4
  6. package/dist/MemoGrafter.js.map +1 -1
  7. package/dist/MemoGrafterAgent.d.ts +8 -1
  8. package/dist/MemoGrafterAgent.d.ts.map +1 -1
  9. package/dist/MemoGrafterAgent.js +31 -2
  10. package/dist/MemoGrafterAgent.js.map +1 -1
  11. package/dist/adapters/AnthropicAdapter.d.ts +1 -1
  12. package/dist/adapters/AnthropicAdapter.d.ts.map +1 -1
  13. package/dist/adapters/GeminiAdapter.d.ts +1 -1
  14. package/dist/adapters/GeminiAdapter.d.ts.map +1 -1
  15. package/dist/adapters/OpenAIAdapter.d.ts +1 -1
  16. package/dist/adapters/OpenAIAdapter.d.ts.map +1 -1
  17. package/dist/adapters/types.d.ts +1 -1
  18. package/dist/adapters/types.d.ts.map +1 -1
  19. package/dist/agents/MemoGrafterAgent.d.ts +45 -0
  20. package/dist/agents/MemoGrafterAgent.d.ts.map +1 -0
  21. package/dist/agents/MemoGrafterAgent.js +278 -0
  22. package/dist/agents/MemoGrafterAgent.js.map +1 -0
  23. package/dist/agents/fleet/ConductorAgent.d.ts +15 -0
  24. package/dist/agents/fleet/ConductorAgent.d.ts.map +1 -0
  25. package/dist/agents/fleet/ConductorAgent.js +41 -0
  26. package/dist/agents/fleet/ConductorAgent.js.map +1 -0
  27. package/dist/agents/fleet/FleetStore.d.ts +12 -0
  28. package/dist/agents/fleet/FleetStore.d.ts.map +1 -0
  29. package/dist/agents/fleet/FleetStore.js +30 -0
  30. package/dist/agents/fleet/FleetStore.js.map +1 -0
  31. package/dist/agents/fleet/MemoGrafterFleet.d.ts +27 -0
  32. package/dist/agents/fleet/MemoGrafterFleet.d.ts.map +1 -0
  33. package/dist/agents/fleet/MemoGrafterFleet.js +87 -0
  34. package/dist/agents/fleet/MemoGrafterFleet.js.map +1 -0
  35. package/dist/agents/fleet/WorkerAgent.d.ts +36 -0
  36. package/dist/agents/fleet/WorkerAgent.d.ts.map +1 -0
  37. package/dist/agents/fleet/WorkerAgent.js +140 -0
  38. package/dist/agents/fleet/WorkerAgent.js.map +1 -0
  39. package/dist/agents/fleet/types.d.ts +58 -0
  40. package/dist/agents/fleet/types.d.ts.map +1 -0
  41. package/dist/agents/fleet/types.js +2 -0
  42. package/dist/agents/fleet/types.js.map +1 -0
  43. package/dist/cli/commands/init.d.ts +8 -0
  44. package/dist/cli/commands/init.d.ts.map +1 -0
  45. package/dist/cli/commands/init.js +124 -0
  46. package/dist/cli/commands/init.js.map +1 -0
  47. package/dist/cli/commands/migrate.d.ts +6 -0
  48. package/dist/cli/commands/migrate.d.ts.map +1 -0
  49. package/dist/cli/commands/migrate.js +34 -0
  50. package/dist/cli/commands/migrate.js.map +1 -0
  51. package/dist/cli/index.d.ts +3 -0
  52. package/dist/cli/index.d.ts.map +1 -0
  53. package/dist/cli/index.js +39 -0
  54. package/dist/cli/index.js.map +1 -0
  55. package/dist/cli/utils/config.d.ts +11 -0
  56. package/dist/cli/utils/config.d.ts.map +1 -0
  57. package/dist/cli/utils/config.js +92 -0
  58. package/dist/cli/utils/config.js.map +1 -0
  59. package/dist/cli/utils/logger.d.ts +7 -0
  60. package/dist/cli/utils/logger.d.ts.map +1 -0
  61. package/dist/cli/utils/logger.js +15 -0
  62. package/dist/cli/utils/logger.js.map +1 -0
  63. package/dist/core/MemoGrafter.d.ts +46 -0
  64. package/dist/core/MemoGrafter.d.ts.map +1 -0
  65. package/dist/core/MemoGrafter.js +236 -0
  66. package/dist/core/MemoGrafter.js.map +1 -0
  67. package/dist/core/types.d.ts +319 -0
  68. package/dist/core/types.d.ts.map +1 -0
  69. package/dist/core/types.js +2 -0
  70. package/dist/core/types.js.map +1 -0
  71. package/dist/crawler/DecayScoringPass.d.ts.map +1 -1
  72. package/dist/crawler/DecayScoringPass.js +6 -0
  73. package/dist/crawler/DecayScoringPass.js.map +1 -1
  74. package/dist/crawler/memoryMaintenance.d.ts +1 -0
  75. package/dist/crawler/memoryMaintenance.d.ts.map +1 -1
  76. package/dist/crawler/memoryMaintenance.js +2 -1
  77. package/dist/crawler/memoryMaintenance.js.map +1 -1
  78. package/dist/crawler/types.d.ts +1 -0
  79. package/dist/crawler/types.d.ts.map +1 -1
  80. package/dist/fleet/MemoGrafterFleet.d.ts +9 -2
  81. package/dist/fleet/MemoGrafterFleet.d.ts.map +1 -1
  82. package/dist/fleet/MemoGrafterFleet.js +39 -1
  83. package/dist/fleet/MemoGrafterFleet.js.map +1 -1
  84. package/dist/fleet/WorkerAgent.d.ts +9 -4
  85. package/dist/fleet/WorkerAgent.d.ts.map +1 -1
  86. package/dist/fleet/WorkerAgent.js +45 -3
  87. package/dist/fleet/WorkerAgent.js.map +1 -1
  88. package/dist/fleet/types.d.ts +21 -2
  89. package/dist/fleet/types.d.ts.map +1 -1
  90. package/dist/index.d.ts +13 -12
  91. package/dist/index.d.ts.map +1 -1
  92. package/dist/index.js +9 -9
  93. package/dist/index.js.map +1 -1
  94. package/dist/ingestion/IngestQueue.d.ts +17 -0
  95. package/dist/ingestion/IngestQueue.d.ts.map +1 -0
  96. package/dist/ingestion/IngestQueue.js +123 -0
  97. package/dist/ingestion/IngestQueue.js.map +1 -0
  98. package/dist/ingestion/conversation/IngestPipeline.d.ts +41 -0
  99. package/dist/ingestion/conversation/IngestPipeline.d.ts.map +1 -0
  100. package/dist/ingestion/conversation/IngestPipeline.js +189 -0
  101. package/dist/ingestion/conversation/IngestPipeline.js.map +1 -0
  102. package/dist/ingestion/conversation/SegmentProcessor.d.ts +20 -0
  103. package/dist/ingestion/conversation/SegmentProcessor.d.ts.map +1 -0
  104. package/dist/ingestion/conversation/SegmentProcessor.js +110 -0
  105. package/dist/ingestion/conversation/SegmentProcessor.js.map +1 -0
  106. package/dist/ingestion/conversation/TopicDriftDetector.d.ts +40 -0
  107. package/dist/ingestion/conversation/TopicDriftDetector.d.ts.map +1 -0
  108. package/dist/ingestion/conversation/TopicDriftDetector.js +222 -0
  109. package/dist/ingestion/conversation/TopicDriftDetector.js.map +1 -0
  110. package/dist/maintenance/ConflictDetectionPass.d.ts +6 -0
  111. package/dist/maintenance/ConflictDetectionPass.d.ts.map +1 -0
  112. package/dist/maintenance/ConflictDetectionPass.js +46 -0
  113. package/dist/maintenance/ConflictDetectionPass.js.map +1 -0
  114. package/dist/maintenance/DecayScoringPass.d.ts +17 -0
  115. package/dist/maintenance/DecayScoringPass.d.ts.map +1 -0
  116. package/dist/maintenance/DecayScoringPass.js +79 -0
  117. package/dist/maintenance/DecayScoringPass.js.map +1 -0
  118. package/dist/maintenance/MemoGrafterCrawler.d.ts +14 -0
  119. package/dist/maintenance/MemoGrafterCrawler.d.ts.map +1 -0
  120. package/dist/maintenance/MemoGrafterCrawler.js +108 -0
  121. package/dist/maintenance/MemoGrafterCrawler.js.map +1 -0
  122. package/dist/maintenance/VersioningPass.d.ts +6 -0
  123. package/dist/maintenance/VersioningPass.d.ts.map +1 -0
  124. package/dist/maintenance/VersioningPass.js +40 -0
  125. package/dist/maintenance/VersioningPass.js.map +1 -0
  126. package/dist/maintenance/decayScoring.d.ts +7 -0
  127. package/dist/maintenance/decayScoring.d.ts.map +1 -0
  128. package/dist/maintenance/decayScoring.js +9 -0
  129. package/dist/maintenance/decayScoring.js.map +1 -0
  130. package/dist/maintenance/index.d.ts +7 -0
  131. package/dist/maintenance/index.d.ts.map +1 -0
  132. package/dist/maintenance/index.js +5 -0
  133. package/dist/maintenance/index.js.map +1 -0
  134. package/dist/maintenance/memoryMaintenance.d.ts +23 -0
  135. package/dist/maintenance/memoryMaintenance.d.ts.map +1 -0
  136. package/dist/maintenance/memoryMaintenance.js +141 -0
  137. package/dist/maintenance/memoryMaintenance.js.map +1 -0
  138. package/dist/maintenance/types.d.ts +65 -0
  139. package/dist/maintenance/types.d.ts.map +1 -0
  140. package/dist/maintenance/types.js +2 -0
  141. package/dist/maintenance/types.js.map +1 -0
  142. package/dist/pipeline/GrafterPipeline.d.ts +2 -0
  143. package/dist/pipeline/GrafterPipeline.d.ts.map +1 -1
  144. package/dist/pipeline/GrafterPipeline.js +33 -7
  145. package/dist/pipeline/GrafterPipeline.js.map +1 -1
  146. package/dist/pipeline/RetrieverPipeline.d.ts +1 -0
  147. package/dist/pipeline/RetrieverPipeline.d.ts.map +1 -1
  148. package/dist/pipeline/RetrieverPipeline.js +16 -5
  149. package/dist/pipeline/RetrieverPipeline.js.map +1 -1
  150. package/dist/prompts/factRetrievalPrompt.d.ts +1 -1
  151. package/dist/prompts/factRetrievalPrompt.d.ts.map +1 -1
  152. package/dist/prompts/historyCompressionPrompt.d.ts +1 -1
  153. package/dist/prompts/historyCompressionPrompt.d.ts.map +1 -1
  154. package/dist/prompts/intentShiftPrompt.d.ts +1 -1
  155. package/dist/prompts/intentShiftPrompt.d.ts.map +1 -1
  156. package/dist/prompts/memoryInjectionPrompt.d.ts +1 -1
  157. package/dist/prompts/memoryInjectionPrompt.d.ts.map +1 -1
  158. package/dist/prompts/segmentExtractionPrompt.d.ts +1 -1
  159. package/dist/prompts/segmentExtractionPrompt.d.ts.map +1 -1
  160. package/dist/retrieval/GrafterPipeline.d.ts +26 -0
  161. package/dist/retrieval/GrafterPipeline.d.ts.map +1 -0
  162. package/dist/retrieval/GrafterPipeline.js +117 -0
  163. package/dist/retrieval/GrafterPipeline.js.map +1 -0
  164. package/dist/retrieval/RetrieverPipeline.d.ts +28 -0
  165. package/dist/retrieval/RetrieverPipeline.d.ts.map +1 -0
  166. package/dist/retrieval/RetrieverPipeline.js +160 -0
  167. package/dist/retrieval/RetrieverPipeline.js.map +1 -0
  168. package/dist/schema/builders.d.ts +40 -0
  169. package/dist/schema/builders.d.ts.map +1 -0
  170. package/dist/schema/builders.js +10 -0
  171. package/dist/schema/builders.js.map +1 -0
  172. package/dist/schema/index.d.ts +3 -0
  173. package/dist/schema/index.d.ts.map +1 -0
  174. package/dist/schema/index.js +3 -0
  175. package/dist/schema/index.js.map +1 -0
  176. package/dist/schema/mg-tables.d.ts +7 -0
  177. package/dist/schema/mg-tables.d.ts.map +1 -0
  178. package/dist/schema/mg-tables.js +180 -0
  179. package/dist/schema/mg-tables.js.map +1 -0
  180. package/dist/store/GraphStore.d.ts +19 -1
  181. package/dist/store/GraphStore.d.ts.map +1 -1
  182. package/dist/store/postgres-pgvector/GraphStore.d.ts +33 -1
  183. package/dist/store/postgres-pgvector/GraphStore.d.ts.map +1 -1
  184. package/dist/store/postgres-pgvector/GraphStore.js +491 -16
  185. package/dist/store/postgres-pgvector/GraphStore.js.map +1 -1
  186. package/dist/tsconfig.cli.tsbuildinfo +1 -0
  187. package/dist/types.d.ts +53 -0
  188. package/dist/types.d.ts.map +1 -1
  189. package/dist/utils/drift/adaptiveDriftSensitivity.d.ts +1 -1
  190. package/dist/utils/drift/adaptiveDriftSensitivity.d.ts.map +1 -1
  191. package/dist/utils/drift/driftScore.d.ts +1 -1
  192. package/dist/utils/drift/driftScore.d.ts.map +1 -1
  193. package/dist/utils/drift/driftThreshold.d.ts +1 -1
  194. package/dist/utils/drift/driftThreshold.d.ts.map +1 -1
  195. package/dist/utils/drift/reentryMatch.d.ts +1 -1
  196. package/dist/utils/drift/reentryMatch.d.ts.map +1 -1
  197. package/dist/utils/extraction/segmentExtraction.d.ts +1 -1
  198. package/dist/utils/extraction/segmentExtraction.d.ts.map +1 -1
  199. package/dist/utils/reentry/reentryEdges.d.ts +1 -1
  200. package/dist/utils/reentry/reentryEdges.d.ts.map +1 -1
  201. package/dist/utils/reentry/reentrySimilarity.d.ts +1 -1
  202. package/dist/utils/reentry/reentrySimilarity.d.ts.map +1 -1
  203. package/dist/utils/reentry/reentryText.d.ts +1 -1
  204. package/dist/utils/reentry/reentryText.d.ts.map +1 -1
  205. package/package.json +14 -1
@@ -1,5 +1,6 @@
1
1
  import { randomUUID } from "node:crypto";
2
2
  import postgres, {} from "postgres";
3
+ import { memoGrafterExtensionNames, memoGrafterIndexNames, memoGrafterTableNames } from "../../schema/index.js";
3
4
  import { cosineSimilarity } from "../../utils/drift/cosineSimilarity.js";
4
5
  import { normalizeTags } from "../../utils/tags.js";
5
6
  import { parseVector, toVectorLiteral } from "../../utils/vector/vectorLiteral.js";
@@ -10,9 +11,33 @@ export class PostgresGraphStore {
10
11
  max: 10,
11
12
  idle_timeout: 30,
12
13
  connect_timeout: 10,
14
+ onnotice: () => undefined,
13
15
  });
14
16
  }
15
17
  async initialize() {
18
+ await this.verifySchema();
19
+ }
20
+ async verifySchema() {
21
+ const [extensions, tables] = await Promise.all([
22
+ this.getExistingExtensions(memoGrafterExtensionNames),
23
+ this.getExistingTables(memoGrafterTableNames),
24
+ ]);
25
+ const missingExtensions = memoGrafterExtensionNames.filter((name) => !extensions.has(name));
26
+ const missingTables = memoGrafterTableNames.filter((name) => !tables.has(name));
27
+ if (missingExtensions.length === 0 && missingTables.length === 0) {
28
+ return;
29
+ }
30
+ const missing = [
31
+ ...missingExtensions.map((name) => `extension ${name}`),
32
+ ...missingTables.map((name) => `table ${name}`),
33
+ ].join(", ");
34
+ throw new Error(`MemoGrafter database schema is not initialized. Missing ${missing}. `
35
+ + "Run: npx memo-grafter migrate --db <connection-string>");
36
+ }
37
+ async migrate() {
38
+ const existingExtensions = await this.getExistingExtensions(memoGrafterExtensionNames);
39
+ const existingTables = await this.getExistingTables(memoGrafterTableNames);
40
+ const existingIndexes = await this.getExistingIndexes(memoGrafterIndexNames);
16
41
  await this.sql `CREATE EXTENSION IF NOT EXISTS vector`;
17
42
  await this.sql `CREATE EXTENSION IF NOT EXISTS pgcrypto`;
18
43
  await this.sql `
@@ -52,6 +77,8 @@ export class PostgresGraphStore {
52
77
  agent_color TEXT,
53
78
  fleet_id TEXT,
54
79
  agent_id TEXT,
80
+ suppressed BOOLEAN NOT NULL DEFAULT FALSE,
81
+ suppressed_at TIMESTAMPTZ,
55
82
  created_at TIMESTAMPTZ DEFAULT NOW(),
56
83
  UNIQUE (segment_id)
57
84
  )
@@ -85,6 +112,8 @@ export class PostgresGraphStore {
85
112
  source_title TEXT,
86
113
  superseded_by UUID REFERENCES mg_memory_nodes(id),
87
114
  decayed BOOLEAN NOT NULL DEFAULT FALSE,
115
+ forgotten BOOLEAN NOT NULL DEFAULT FALSE,
116
+ forgotten_at TIMESTAMPTZ,
88
117
  has_conflict BOOLEAN NOT NULL DEFAULT FALSE,
89
118
  agent_color TEXT,
90
119
  fleet_id TEXT,
@@ -102,6 +131,22 @@ export class PostgresGraphStore {
102
131
  await this.sql `
103
132
  ALTER TABLE mg_memory_nodes
104
133
  ADD COLUMN IF NOT EXISTS has_conflict BOOLEAN NOT NULL DEFAULT FALSE
134
+ `;
135
+ await this.sql `
136
+ ALTER TABLE mg_memory_nodes
137
+ ADD COLUMN IF NOT EXISTS forgotten BOOLEAN NOT NULL DEFAULT FALSE
138
+ `;
139
+ await this.sql `
140
+ ALTER TABLE mg_memory_nodes
141
+ ADD COLUMN IF NOT EXISTS forgotten_at TIMESTAMPTZ
142
+ `;
143
+ await this.sql `
144
+ ALTER TABLE mg_topic_nodes
145
+ ADD COLUMN IF NOT EXISTS suppressed BOOLEAN NOT NULL DEFAULT FALSE
146
+ `;
147
+ await this.sql `
148
+ ALTER TABLE mg_topic_nodes
149
+ ADD COLUMN IF NOT EXISTS suppressed_at TIMESTAMPTZ
105
150
  `;
106
151
  await this.sql `
107
152
  ALTER TABLE mg_topic_nodes
@@ -157,6 +202,20 @@ export class PostgresGraphStore {
157
202
  `;
158
203
  await this.migrateExistingNodeTable();
159
204
  await this.createIndexes();
205
+ return {
206
+ extensions: memoGrafterExtensionNames.map((name) => ({
207
+ name,
208
+ status: existingExtensions.has(name) ? "exists" : "created",
209
+ })),
210
+ tables: memoGrafterTableNames.map((name) => ({
211
+ name,
212
+ status: existingTables.has(name) ? "exists" : "created",
213
+ })),
214
+ indexes: memoGrafterIndexNames.map((name) => ({
215
+ name,
216
+ status: existingIndexes.has(name) ? "exists" : "created",
217
+ })),
218
+ };
160
219
  }
161
220
  async saveMessages(sessionId, messages) {
162
221
  await this.saveMessagesAt(sessionId, 0, messages);
@@ -308,6 +367,7 @@ export class PostgresGraphStore {
308
367
  JOIN mg_topic_nodes n ON n.id = e.src_id
309
368
  WHERE n.session_id = ${sessionId}
310
369
  AND e.type = ${type}
370
+ AND n.suppressed = FALSE
311
371
  `;
312
372
  return rows.map((row) => ({
313
373
  srcId: row.src_id,
@@ -397,6 +457,7 @@ export class PostgresGraphStore {
397
457
  SELECT COUNT(*)::int AS count
398
458
  FROM mg_topic_nodes
399
459
  WHERE session_id = ${sessionId}
460
+ AND suppressed = FALSE
400
461
  `;
401
462
  return rows[0]?.count ?? 0;
402
463
  }
@@ -406,6 +467,7 @@ export class PostgresGraphStore {
406
467
  const rows = await this.sql `
407
468
  SELECT * FROM mg_topic_nodes
408
469
  WHERE ${searchTaggedSessions ? this.sql `TRUE` : this.sql `session_id = ${sessionId}`}
470
+ ${options.includeSuppressed ? this.sql `` : this.sql `AND suppressed = FALSE`}
409
471
  ${this.topicTagsFilterSql(tags, options.tagMode)}
410
472
  ORDER BY session_id ASC, topic_order ASC, created_at ASC
411
473
  `;
@@ -415,6 +477,7 @@ export class PostgresGraphStore {
415
477
  const rows = await this.sql `
416
478
  SELECT * FROM mg_topic_nodes
417
479
  WHERE session_id = ${sessionId}
480
+ AND suppressed = FALSE
418
481
  ORDER BY topic_order DESC, created_at DESC
419
482
  LIMIT 1
420
483
  `;
@@ -468,11 +531,15 @@ export class PostgresGraphStore {
468
531
  }
469
532
  async getMemoriesByTopic(topicNodeId) {
470
533
  const rows = await this.sql `
471
- SELECT * FROM mg_memory_nodes
472
- WHERE topic_node_id = ${topicNodeId}
473
- AND decayed = false
474
- AND superseded_by IS NULL
475
- ORDER BY created_at ASC
534
+ SELECT memory.*
535
+ FROM mg_memory_nodes memory
536
+ JOIN mg_topic_nodes topic ON topic.id = memory.topic_node_id
537
+ WHERE memory.topic_node_id = ${topicNodeId}
538
+ AND memory.decayed = false
539
+ AND memory.superseded_by IS NULL
540
+ AND memory.forgotten = false
541
+ AND topic.suppressed = false
542
+ ORDER BY memory.created_at ASC
476
543
  `;
477
544
  return rows.map((row) => this.rowToMemoryNode(row));
478
545
  }
@@ -496,13 +563,136 @@ export class PostgresGraphStore {
496
563
  `;
497
564
  return rows.map((row) => this.rowToMemoryEdge(row));
498
565
  }
566
+ async getMemoryHistoryById(memoryNodeId, options = {}) {
567
+ const anchor = await this.getMemoryNodeById(memoryNodeId, options.sessionId);
568
+ if (!anchor) {
569
+ return {
570
+ anchorMemoryId: memoryNodeId,
571
+ ...(options.sessionId ? { sessionId: options.sessionId } : {}),
572
+ entries: [],
573
+ edges: [],
574
+ currentMemory: null,
575
+ };
576
+ }
577
+ const memories = await this.getMemoryNodesByFactKey(anchor.subject, anchor.predicate, {
578
+ sessionId: options.sessionId ?? anchor.sessionId,
579
+ });
580
+ const byId = new Map(memories.map((memory) => [memory.id, memory]));
581
+ byId.set(anchor.id, anchor);
582
+ const firstPassEdges = await this.getMemoryEdgesForMemoryIds([...byId.keys()]);
583
+ for (const id of this.getConnectedMemoryIds(firstPassEdges)) {
584
+ if (!byId.has(id)) {
585
+ byId.set(id, null);
586
+ }
587
+ }
588
+ const missingIds = [...byId.entries()]
589
+ .filter(([, memory]) => memory == null)
590
+ .map(([id]) => id);
591
+ for (const memory of await this.getMemoryNodesByIds(missingIds, options.sessionId ?? anchor.sessionId)) {
592
+ byId.set(memory.id, memory);
593
+ }
594
+ const historyMemories = [...byId.values()].filter((memory) => memory != null);
595
+ const edges = await this.getMemoryEdgesForMemoryIds(historyMemories.map((memory) => memory.id));
596
+ return this.buildMemoryHistoryResult(historyMemories, edges, {
597
+ anchorMemoryId: memoryNodeId,
598
+ subject: anchor.subject,
599
+ predicate: anchor.predicate,
600
+ sessionId: options.sessionId ?? anchor.sessionId,
601
+ });
602
+ }
603
+ async getMemoryHistoryByFact(subject, predicate, options = {}) {
604
+ const memories = await this.getMemoryNodesByFactKey(subject, predicate, options);
605
+ const edges = await this.getMemoryEdgesForMemoryIds(memories.map((memory) => memory.id));
606
+ return this.buildMemoryHistoryResult(memories, edges, {
607
+ subject,
608
+ predicate,
609
+ ...(options.sessionId ? { sessionId: options.sessionId } : {}),
610
+ });
611
+ }
612
+ async getMemoryDiff(fromMemoryId, toMemoryId) {
613
+ const [from, to] = await Promise.all([
614
+ this.getMemoryNodeById(fromMemoryId),
615
+ this.getMemoryNodeById(toMemoryId),
616
+ ]);
617
+ if (!from) {
618
+ throw new Error(`Memory ${fromMemoryId} was not found.`);
619
+ }
620
+ if (!to) {
621
+ throw new Error(`Memory ${toMemoryId} was not found.`);
622
+ }
623
+ const edges = (await this.getMemoryEdgesForMemoryIds([from.id, to.id]))
624
+ .filter((edge) => (edge.sourceId === from.id && edge.targetId === to.id)
625
+ || (edge.sourceId === to.id && edge.targetId === from.id));
626
+ const updateEdges = edges.filter((edge) => edge.edgeType === "updates");
627
+ const conflictEdges = edges.filter((edge) => edge.edgeType === "conflicts");
628
+ const fields = this.diffMemoryFields(from, to);
629
+ return {
630
+ from,
631
+ to,
632
+ fields,
633
+ changedFields: fields.filter((field) => field.changed),
634
+ relationship: {
635
+ supersedes: to.supersededBy === from.id || updateEdges.some((edge) => edge.sourceId === from.id && edge.targetId === to.id),
636
+ supersededBy: from.supersededBy === to.id || updateEdges.some((edge) => edge.sourceId === to.id && edge.targetId === from.id),
637
+ conflicts: conflictEdges.length > 0,
638
+ updateEdges,
639
+ conflictEdges,
640
+ },
641
+ };
642
+ }
499
643
  async listMemoryNodesForMaintenance() {
500
644
  const rows = await this.sql `
501
- SELECT * FROM mg_memory_nodes
502
- ORDER BY session_id ASC, created_at ASC, id ASC
645
+ SELECT memory.*
646
+ FROM mg_memory_nodes memory
647
+ JOIN mg_topic_nodes topic ON topic.id = memory.topic_node_id
648
+ WHERE memory.forgotten = FALSE
649
+ AND topic.suppressed = FALSE
650
+ ORDER BY memory.session_id ASC, memory.created_at ASC, memory.id ASC
503
651
  `;
504
652
  return rows.map((row) => this.rowToMemoryNode(row));
505
653
  }
654
+ async forgetMemory(memoryNodeId) {
655
+ const changed = await this.forgetMemories([memoryNodeId]);
656
+ return changed > 0;
657
+ }
658
+ async forgetMemories(memoryNodeIds) {
659
+ if (memoryNodeIds.length === 0)
660
+ return 0;
661
+ const rows = await this.sql `
662
+ UPDATE mg_memory_nodes
663
+ SET
664
+ forgotten = TRUE,
665
+ forgotten_at = COALESCE(forgotten_at, NOW())
666
+ WHERE id = ANY(${this.sql.array(memoryNodeIds)}::uuid[])
667
+ AND forgotten = FALSE
668
+ RETURNING id
669
+ `;
670
+ return rows.length;
671
+ }
672
+ async suppressTopic(topicNodeId) {
673
+ const rows = await this.sql `
674
+ UPDATE mg_topic_nodes
675
+ SET
676
+ suppressed = TRUE,
677
+ suppressed_at = COALESCE(suppressed_at, NOW())
678
+ WHERE id = ${topicNodeId}
679
+ AND suppressed = FALSE
680
+ RETURNING id
681
+ `;
682
+ return rows.length > 0;
683
+ }
684
+ async restoreTopic(topicNodeId) {
685
+ const rows = await this.sql `
686
+ UPDATE mg_topic_nodes
687
+ SET
688
+ suppressed = FALSE,
689
+ suppressed_at = NULL
690
+ WHERE id = ${topicNodeId}
691
+ AND suppressed = TRUE
692
+ RETURNING id
693
+ `;
694
+ return rows.length > 0;
695
+ }
506
696
  async markMemoryNodesConflicting(memoryNodeIds) {
507
697
  if (memoryNodeIds.length === 0)
508
698
  return 0;
@@ -572,16 +762,45 @@ export class PostgresGraphStore {
572
762
  return true;
573
763
  }
574
764
  async searchMemories(embedding, sessionId, limit, minSimilarity, options = {}) {
765
+ if (options.sessionIds && options.sessionIds.length > 0) {
766
+ return this.searchMemoriesAcrossSessions(embedding, options.sessionIds, limit, minSimilarity, options);
767
+ }
575
768
  const tags = normalizeTags(options.tags);
576
769
  const searchTaggedSessions = options.scope === "tagged" && tags.length > 0;
577
770
  const rows = await this.sql `
578
- SELECT *, 1 - (embedding <=> ${toVectorLiteral(embedding)}::vector) AS similarity
579
- FROM mg_memory_nodes
580
- WHERE ${searchTaggedSessions ? this.sql `TRUE` : this.sql `session_id = ${sessionId}`}
581
- AND decayed = false
582
- AND superseded_by IS NULL
583
- ${this.memoryTagsFilterSql(tags, options.tagMode)}
584
- AND 1 - (embedding <=> ${toVectorLiteral(embedding)}::vector) >= ${minSimilarity}
771
+ SELECT memory.*, 1 - (memory.embedding <=> ${toVectorLiteral(embedding)}::vector) AS similarity
772
+ FROM mg_memory_nodes memory
773
+ JOIN mg_topic_nodes topic ON topic.id = memory.topic_node_id
774
+ WHERE ${searchTaggedSessions ? this.sql `TRUE` : this.sql `memory.session_id = ${sessionId}`}
775
+ AND memory.decayed = false
776
+ AND memory.superseded_by IS NULL
777
+ AND memory.forgotten = false
778
+ AND topic.suppressed = false
779
+ ${this.memoryTagsFilterSql(tags, options.tagMode, "memory")}
780
+ AND 1 - (memory.embedding <=> ${toVectorLiteral(embedding)}::vector) >= ${minSimilarity}
781
+ ORDER BY similarity DESC
782
+ LIMIT ${limit}
783
+ `;
784
+ return rows.map((row) => ({
785
+ ...this.rowToMemoryNode(row),
786
+ similarity: row.similarity,
787
+ }));
788
+ }
789
+ async searchMemoriesAcrossSessions(embedding, sessionIds, limit, minSimilarity, options = {}) {
790
+ if (sessionIds.length === 0)
791
+ return [];
792
+ const tags = normalizeTags(options.tags);
793
+ const rows = await this.sql `
794
+ SELECT memory.*, 1 - (memory.embedding <=> ${toVectorLiteral(embedding)}::vector) AS similarity
795
+ FROM mg_memory_nodes memory
796
+ JOIN mg_topic_nodes topic ON topic.id = memory.topic_node_id
797
+ WHERE memory.session_id = ANY(${this.sql.array(sessionIds)})
798
+ AND memory.decayed = false
799
+ AND memory.superseded_by IS NULL
800
+ AND memory.forgotten = false
801
+ AND topic.suppressed = false
802
+ ${this.memoryTagsFilterSql(tags, options.tagMode, "memory")}
803
+ AND 1 - (memory.embedding <=> ${toVectorLiteral(embedding)}::vector) >= ${minSimilarity}
585
804
  ORDER BY similarity DESC
586
805
  LIMIT ${limit}
587
806
  `;
@@ -634,6 +853,22 @@ export class PostgresGraphStore {
634
853
  SELECT *, 1 - (embedding <=> ${toVectorLiteral(embedding)}::vector) AS similarity
635
854
  FROM mg_topic_nodes
636
855
  WHERE session_id = ${sessionId}
856
+ AND suppressed = FALSE
857
+ ${options.excludeNodeId ? this.sql `AND id != ${options.excludeNodeId}` : this.sql ``}
858
+ ${options.minSimilarity === undefined ? this.sql `` : this.sql `AND 1 - (embedding <=> ${toVectorLiteral(embedding)}::vector) >= ${options.minSimilarity}`}
859
+ ORDER BY embedding <=> ${toVectorLiteral(embedding)}::vector ASC
860
+ LIMIT ${options.k ?? 5}
861
+ `;
862
+ return rows.map((row) => this.rowToNode(row));
863
+ }
864
+ async getSimilarNodesAcrossSessions(embedding, sessionIds, options = {}) {
865
+ if (sessionIds.length === 0)
866
+ return [];
867
+ const rows = await this.sql `
868
+ SELECT *, 1 - (embedding <=> ${toVectorLiteral(embedding)}::vector) AS similarity
869
+ FROM mg_topic_nodes
870
+ WHERE session_id = ANY(${this.sql.array(sessionIds)})
871
+ AND suppressed = FALSE
637
872
  ${options.excludeNodeId ? this.sql `AND id != ${options.excludeNodeId}` : this.sql ``}
638
873
  ${options.minSimilarity === undefined ? this.sql `` : this.sql `AND 1 - (embedding <=> ${toVectorLiteral(embedding)}::vector) >= ${options.minSimilarity}`}
639
874
  ORDER BY embedding <=> ${toVectorLiteral(embedding)}::vector ASC
@@ -646,6 +881,7 @@ export class PostgresGraphStore {
646
881
  SELECT *, 1 - (embedding <=> ${toVectorLiteral(embedding)}::vector) AS similarity
647
882
  FROM mg_topic_nodes
648
883
  WHERE fleet_id = ${fleetId}
884
+ AND suppressed = FALSE
649
885
  ${options.agentColor ? this.sql `AND agent_color = ${options.agentColor}` : this.sql ``}
650
886
  ${options.excludeNodeId ? this.sql `AND id != ${options.excludeNodeId}` : this.sql ``}
651
887
  ${options.minSimilarity === undefined ? this.sql `` : this.sql `AND 1 - (embedding <=> ${toVectorLiteral(embedding)}::vector) >= ${options.minSimilarity}`}
@@ -659,6 +895,7 @@ export class PostgresGraphStore {
659
895
  SELECT * FROM mg_topic_nodes
660
896
  WHERE fleet_id = ${fleetId}
661
897
  AND agent_color = ${agentColor}
898
+ AND suppressed = FALSE
662
899
  ORDER BY topic_order ASC, created_at ASC
663
900
  `;
664
901
  return rows.map((row) => this.rowToNode(row));
@@ -703,6 +940,14 @@ export class PostgresGraphStore {
703
940
  agent_id = ${metadata.agentId},
704
941
  agent_color = ${metadata.agentColor}
705
942
  WHERE session_id = ${sessionId}
943
+ `;
944
+ await this.sql `
945
+ UPDATE mg_memory_nodes
946
+ SET
947
+ fleet_id = ${metadata.fleetId},
948
+ agent_id = ${metadata.agentId},
949
+ agent_color = ${metadata.agentColor}
950
+ WHERE session_id = ${sessionId}
706
951
  `;
707
952
  }
708
953
  async setSessionTags(sessionId, tags) {
@@ -724,6 +969,7 @@ export class PostgresGraphStore {
724
969
  FROM mg_topic_nodes
725
970
  WHERE session_id = ${sessionId}
726
971
  AND topic_order = ${topicOrder - 1}
972
+ AND suppressed = FALSE
727
973
  LIMIT 1
728
974
  `;
729
975
  return rows[0] ? this.rowToNode(rows[0]) : null;
@@ -767,6 +1013,7 @@ export class PostgresGraphStore {
767
1013
  SELECT * FROM mg_topic_nodes
768
1014
  WHERE id = ANY(${this.sql.array(ids)})
769
1015
  ${sessionId ? this.sql `AND session_id = ${sessionId}` : this.sql ``}
1016
+ AND suppressed = FALSE
770
1017
  ORDER BY topic_order ASC, created_at ASC
771
1018
  `;
772
1019
  return rows.map((row) => this.rowToNode(row));
@@ -825,7 +1072,10 @@ export class PostgresGraphStore {
825
1072
  const copiedNodes = [];
826
1073
  const nextMessageIndex = await this.getNextMessageIndex(targetSessionId);
827
1074
  const nextTopicOrder = await this.getNextTopicOrder(targetSessionId);
828
- for (const [index, node] of nodes.entries()) {
1075
+ for (const node of nodes) {
1076
+ if (node.suppressed)
1077
+ continue;
1078
+ const index = copiedNodes.length;
829
1079
  const messageIndex = nextMessageIndex + index;
830
1080
  await this.saveMessagesAt(targetSessionId, messageIndex, [{
831
1081
  role: "assistant",
@@ -919,8 +1169,182 @@ export class PostgresGraphStore {
919
1169
  AND session_id = ${sourceNode.sessionId}
920
1170
  AND decayed = FALSE
921
1171
  AND superseded_by IS NULL
1172
+ AND forgotten = FALSE
922
1173
  `;
923
1174
  }
1175
+ async getMemoryNodeById(memoryNodeId, sessionId) {
1176
+ if (sessionId) {
1177
+ const rows = await this.sql `
1178
+ SELECT *
1179
+ FROM mg_memory_nodes
1180
+ WHERE id = ${memoryNodeId}::uuid
1181
+ AND session_id = ${sessionId}
1182
+ LIMIT 1
1183
+ `;
1184
+ return rows[0] ? this.rowToMemoryNode(rows[0]) : null;
1185
+ }
1186
+ const rows = await this.sql `
1187
+ SELECT *
1188
+ FROM mg_memory_nodes
1189
+ WHERE id = ${memoryNodeId}::uuid
1190
+ LIMIT 1
1191
+ `;
1192
+ return rows[0] ? this.rowToMemoryNode(rows[0]) : null;
1193
+ }
1194
+ async getMemoryNodesByIds(memoryNodeIds, sessionId) {
1195
+ if (memoryNodeIds.length === 0)
1196
+ return [];
1197
+ if (sessionId) {
1198
+ const rows = await this.sql `
1199
+ SELECT *
1200
+ FROM mg_memory_nodes
1201
+ WHERE id = ANY(${this.sql.array(memoryNodeIds)}::uuid[])
1202
+ AND session_id = ${sessionId}
1203
+ ORDER BY created_at ASC, id ASC
1204
+ `;
1205
+ return rows.map((row) => this.rowToMemoryNode(row));
1206
+ }
1207
+ const rows = await this.sql `
1208
+ SELECT *
1209
+ FROM mg_memory_nodes
1210
+ WHERE id = ANY(${this.sql.array(memoryNodeIds)}::uuid[])
1211
+ ORDER BY created_at ASC, id ASC
1212
+ `;
1213
+ return rows.map((row) => this.rowToMemoryNode(row));
1214
+ }
1215
+ async getMemoryNodesByFactKey(subject, predicate, options = {}) {
1216
+ const normalizedSubject = this.normalizeMemoryHistoryPart(subject);
1217
+ const normalizedPredicate = this.normalizeMemoryHistoryPart(predicate);
1218
+ if (options.sessionId) {
1219
+ const rows = await this.sql `
1220
+ SELECT *
1221
+ FROM mg_memory_nodes
1222
+ WHERE lower(regexp_replace(trim(subject), '[[:space:]]+', ' ', 'g')) = ${normalizedSubject}
1223
+ AND lower(regexp_replace(trim(predicate), '[[:space:]]+', ' ', 'g')) = ${normalizedPredicate}
1224
+ AND session_id = ${options.sessionId}
1225
+ ORDER BY created_at ASC, id ASC
1226
+ `;
1227
+ return rows.map((row) => this.rowToMemoryNode(row));
1228
+ }
1229
+ const rows = await this.sql `
1230
+ SELECT *
1231
+ FROM mg_memory_nodes
1232
+ WHERE lower(regexp_replace(trim(subject), '[[:space:]]+', ' ', 'g')) = ${normalizedSubject}
1233
+ AND lower(regexp_replace(trim(predicate), '[[:space:]]+', ' ', 'g')) = ${normalizedPredicate}
1234
+ ORDER BY created_at ASC, id ASC
1235
+ `;
1236
+ return rows.map((row) => this.rowToMemoryNode(row));
1237
+ }
1238
+ async getMemoryEdgesForMemoryIds(memoryNodeIds) {
1239
+ if (memoryNodeIds.length === 0)
1240
+ return [];
1241
+ const rows = await this.sql `
1242
+ SELECT DISTINCT *
1243
+ FROM mg_memory_edges
1244
+ WHERE source_id = ANY(${this.sql.array(memoryNodeIds)}::uuid[])
1245
+ OR target_id = ANY(${this.sql.array(memoryNodeIds)}::uuid[])
1246
+ ORDER BY created_at ASC, id ASC
1247
+ `;
1248
+ return rows.map((row) => this.rowToMemoryEdge(row));
1249
+ }
1250
+ buildMemoryHistoryResult(memories, edges, metadata) {
1251
+ const memoriesById = new Map(memories.map((memory) => [memory.id, memory]));
1252
+ const visibleEdges = edges.filter((edge) => memoriesById.has(edge.sourceId) && memoriesById.has(edge.targetId));
1253
+ const sortedMemories = [...memories].sort((left, right) => left.createdAt.getTime() - right.createdAt.getTime()
1254
+ || left.id.localeCompare(right.id));
1255
+ const entries = sortedMemories.map((memory, index) => {
1256
+ const updateEdges = visibleEdges.filter((edge) => edge.edgeType === "updates"
1257
+ && (edge.sourceId === memory.id || edge.targetId === memory.id));
1258
+ const conflictEdges = visibleEdges.filter((edge) => edge.edgeType === "conflicts"
1259
+ && (edge.sourceId === memory.id || edge.targetId === memory.id));
1260
+ const supersedes = [
1261
+ ...sortedMemories
1262
+ .filter((candidate) => candidate.supersededBy === memory.id)
1263
+ .map((candidate) => candidate.id),
1264
+ ...updateEdges
1265
+ .filter((edge) => edge.sourceId === memory.id)
1266
+ .map((edge) => edge.targetId),
1267
+ ];
1268
+ const conflictsWith = conflictEdges.map((edge) => edge.sourceId === memory.id ? edge.targetId : edge.sourceId);
1269
+ return {
1270
+ memory,
1271
+ versionIndex: index,
1272
+ status: this.resolveMemoryHistoryStatus(memory, conflictEdges),
1273
+ supersedes: [...new Set(supersedes)],
1274
+ supersededBy: memory.supersededBy,
1275
+ conflictsWith: [...new Set(conflictsWith)],
1276
+ updateEdges,
1277
+ conflictEdges,
1278
+ createdAt: memory.createdAt,
1279
+ };
1280
+ });
1281
+ return {
1282
+ ...metadata,
1283
+ entries,
1284
+ edges: visibleEdges,
1285
+ currentMemory: this.resolveCurrentMemory(sortedMemories),
1286
+ };
1287
+ }
1288
+ resolveMemoryHistoryStatus(memory, conflictEdges) {
1289
+ if (memory.forgotten)
1290
+ return "forgotten";
1291
+ if (memory.decayed)
1292
+ return "decayed";
1293
+ if (memory.supersededBy != null)
1294
+ return "superseded";
1295
+ if (memory.hasConflict || conflictEdges.length > 0)
1296
+ return "conflicting";
1297
+ return "active";
1298
+ }
1299
+ resolveCurrentMemory(memories) {
1300
+ return [...memories]
1301
+ .filter((memory) => !memory.forgotten && !memory.decayed && memory.supersededBy == null)
1302
+ .sort((left, right) => right.createdAt.getTime() - left.createdAt.getTime()
1303
+ || right.id.localeCompare(left.id))[0] ?? null;
1304
+ }
1305
+ getConnectedMemoryIds(edges) {
1306
+ return [...new Set(edges.flatMap((edge) => [edge.sourceId, edge.targetId]))];
1307
+ }
1308
+ diffMemoryFields(from, to) {
1309
+ const fields = [
1310
+ "sessionId",
1311
+ "topicNodeId",
1312
+ "agentId",
1313
+ "memoryType",
1314
+ "sourceType",
1315
+ "subject",
1316
+ "predicate",
1317
+ "value",
1318
+ "confidence",
1319
+ "tags",
1320
+ "source",
1321
+ "sourceUrl",
1322
+ "sourceTitle",
1323
+ "supersededBy",
1324
+ "decayed",
1325
+ "forgotten",
1326
+ "forgottenAt",
1327
+ "hasConflict",
1328
+ "agentColor",
1329
+ "fleetId",
1330
+ "createdAt",
1331
+ ];
1332
+ return fields.map((field) => ({
1333
+ field,
1334
+ from: from[field],
1335
+ to: to[field],
1336
+ changed: !this.memoryDiffValuesEqual(from[field], to[field]),
1337
+ }));
1338
+ }
1339
+ memoryDiffValuesEqual(left, right) {
1340
+ if (left instanceof Date && right instanceof Date) {
1341
+ return left.getTime() === right.getTime();
1342
+ }
1343
+ return JSON.stringify(left ?? null) === JSON.stringify(right ?? null);
1344
+ }
1345
+ normalizeMemoryHistoryPart(value) {
1346
+ return value.trim().toLowerCase().replace(/\s+/g, " ");
1347
+ }
924
1348
  async deleteEdgesByNodeIds(nodeIds) {
925
1349
  if (nodeIds.length === 0)
926
1350
  return;
@@ -974,6 +1398,38 @@ export class PostgresGraphStore {
974
1398
  async close() {
975
1399
  await this.sql.end();
976
1400
  }
1401
+ async getExistingExtensions(extensionNames) {
1402
+ if (extensionNames.length === 0)
1403
+ return new Set();
1404
+ const rows = await this.sql `
1405
+ SELECT extname
1406
+ FROM pg_extension
1407
+ `;
1408
+ const expected = new Set(extensionNames);
1409
+ return new Set(rows.map((row) => row.extname).filter((name) => expected.has(name)));
1410
+ }
1411
+ async getExistingTables(tableNames) {
1412
+ if (tableNames.length === 0)
1413
+ return new Set();
1414
+ const rows = await this.sql `
1415
+ SELECT table_name
1416
+ FROM information_schema.tables
1417
+ WHERE table_schema = 'public'
1418
+ `;
1419
+ const expected = new Set(tableNames);
1420
+ return new Set(rows.map((row) => row.table_name).filter((name) => expected.has(name)));
1421
+ }
1422
+ async getExistingIndexes(indexNames) {
1423
+ if (indexNames.length === 0)
1424
+ return new Set();
1425
+ const rows = await this.sql `
1426
+ SELECT indexname
1427
+ FROM pg_indexes
1428
+ WHERE schemaname = 'public'
1429
+ `;
1430
+ const expected = new Set(indexNames);
1431
+ return new Set(rows.map((row) => row.indexname).filter((name) => expected.has(name)));
1432
+ }
977
1433
  async migrateExistingNodeTable() {
978
1434
  await this.sql `ALTER TABLE mg_segments DROP COLUMN IF EXISTS node_id`;
979
1435
  await this.sql `ALTER TABLE mg_topic_nodes ADD COLUMN IF NOT EXISTS segment_id TEXT`;
@@ -1016,6 +1472,11 @@ export class PostgresGraphStore {
1016
1472
  await this.sql `
1017
1473
  CREATE INDEX IF NOT EXISTS mg_nodes_session_idx
1018
1474
  ON mg_topic_nodes(session_id, topic_order)
1475
+ `;
1476
+ await this.sql `
1477
+ CREATE INDEX IF NOT EXISTS idx_topic_nodes_active_lifecycle
1478
+ ON mg_topic_nodes(session_id, suppressed)
1479
+ WHERE suppressed = FALSE
1019
1480
  `;
1020
1481
  await this.sql `
1021
1482
  CREATE INDEX IF NOT EXISTS mg_topic_nodes_tags_idx
@@ -1058,6 +1519,11 @@ export class PostgresGraphStore {
1058
1519
  await this.sql `
1059
1520
  CREATE INDEX IF NOT EXISTS idx_memory_nodes_session
1060
1521
  ON mg_memory_nodes(session_id)
1522
+ `;
1523
+ await this.sql `
1524
+ CREATE INDEX IF NOT EXISTS idx_memory_nodes_active_lifecycle
1525
+ ON mg_memory_nodes(session_id, forgotten, decayed)
1526
+ WHERE forgotten = FALSE
1061
1527
  `;
1062
1528
  await this.sql `
1063
1529
  CREATE INDEX IF NOT EXISTS idx_memory_nodes_tags
@@ -1096,9 +1562,14 @@ export class PostgresGraphStore {
1096
1562
  ? this.sql `AND tags && ${this.sql.array(tags)}::text[]`
1097
1563
  : this.sql `AND tags @> ${this.sql.array(tags)}::text[]`;
1098
1564
  }
1099
- memoryTagsFilterSql(tags, tagMode = "all") {
1565
+ memoryTagsFilterSql(tags, tagMode = "all", tableAlias) {
1100
1566
  if (tags.length === 0)
1101
1567
  return this.sql ``;
1568
+ if (tableAlias === "memory") {
1569
+ return tagMode === "any"
1570
+ ? this.sql `AND memory.tags && ${this.sql.array(tags)}::text[]`
1571
+ : this.sql `AND memory.tags @> ${this.sql.array(tags)}::text[]`;
1572
+ }
1102
1573
  return tagMode === "any"
1103
1574
  ? this.sql `AND tags && ${this.sql.array(tags)}::text[]`
1104
1575
  : this.sql `AND tags @> ${this.sql.array(tags)}::text[]`;
@@ -1142,6 +1613,8 @@ export class PostgresGraphStore {
1142
1613
  agentColor: row.agent_color,
1143
1614
  fleetId: row.fleet_id,
1144
1615
  agentId: row.agent_id,
1616
+ suppressed: row.suppressed ?? false,
1617
+ suppressedAt: row.suppressed_at,
1145
1618
  createdAt: row.created_at,
1146
1619
  };
1147
1620
  }
@@ -1165,6 +1638,8 @@ export class PostgresGraphStore {
1165
1638
  sourceTitle: row.source_title,
1166
1639
  supersededBy: row.superseded_by,
1167
1640
  decayed: row.decayed,
1641
+ forgotten: row.forgotten ?? false,
1642
+ forgottenAt: row.forgotten_at,
1168
1643
  hasConflict: row.has_conflict ?? false,
1169
1644
  agentColor: row.agent_color,
1170
1645
  fleetId: row.fleet_id,