neo4j-agent-memory 0.4.0 → 0.5.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.
package/dist/index.cjs CHANGED
@@ -86,7 +86,11 @@ var cypher = {
86
86
  feedbackCoUsed: loadCypher("feedback_co_used_with_batch.cypher"),
87
87
  listMemories: loadCypher("list_memories.cypher"),
88
88
  relateConcepts: loadCypher("relate_concepts.cypher"),
89
- autoRelateByTags: loadCypher("auto_relate_memory_by_tags.cypher")
89
+ autoRelateByTags: loadCypher("auto_relate_memory_by_tags.cypher"),
90
+ getMemoriesById: loadCypher("get_memories_by_id.cypher"),
91
+ getMemoryGraph: loadCypher("get_memory_graph.cypher"),
92
+ fallbackRetrieveMemories: loadCypher("fallback_retrieve_memories.cypher"),
93
+ listMemoryEdges: loadCypher("list_memory_edges.cypher")
90
94
  };
91
95
 
92
96
  // src/neo4j/schema.ts
@@ -146,6 +150,20 @@ function envHash(env) {
146
150
  function clamp01(x) {
147
151
  return Math.max(0, Math.min(1, x));
148
152
  }
153
+ function parseJsonField(value) {
154
+ if (value === null || value === void 0) return void 0;
155
+ if (typeof value !== "string") return value;
156
+ try {
157
+ return JSON.parse(value);
158
+ } catch {
159
+ return void 0;
160
+ }
161
+ }
162
+ function toDateString(value) {
163
+ if (value === null || value === void 0) return void 0;
164
+ if (typeof value?.toString === "function") return value.toString();
165
+ return String(value);
166
+ }
149
167
  var DEFAULT_AUTO_RELATE = {
150
168
  enabled: true,
151
169
  minSharedTags: 2,
@@ -172,6 +190,23 @@ function toBetaEdge(raw) {
172
190
  updatedAt: raw?.updatedAt ?? null
173
191
  };
174
192
  }
193
+ function toMemoryRecord(raw) {
194
+ return {
195
+ id: raw.id,
196
+ kind: raw.kind,
197
+ polarity: raw.polarity ?? "positive",
198
+ title: raw.title,
199
+ content: raw.content,
200
+ tags: raw.tags ?? [],
201
+ confidence: raw.confidence ?? 0.7,
202
+ utility: raw.utility ?? 0.2,
203
+ createdAt: toDateString(raw.createdAt),
204
+ updatedAt: toDateString(raw.updatedAt),
205
+ triage: parseJsonField(raw.triage),
206
+ antiPattern: parseJsonField(raw.antiPattern),
207
+ env: raw.env ?? void 0
208
+ };
209
+ }
175
210
  function defaultPolicy(req) {
176
211
  return {
177
212
  minConfidence: req?.minConfidence ?? 0.65,
@@ -243,6 +278,10 @@ var MemoryService = class {
243
278
  cyListMemories = cypher.listMemories;
244
279
  cyRelateConcepts = cypher.relateConcepts;
245
280
  cyAutoRelateByTags = cypher.autoRelateByTags;
281
+ cyGetMemoriesById = cypher.getMemoriesById;
282
+ cyGetMemoryGraph = cypher.getMemoryGraph;
283
+ cyFallbackRetrieve = cypher.fallbackRetrieveMemories;
284
+ cyListMemoryEdges = cypher.listMemoryEdges;
246
285
  cyGetRecallEdges = `
247
286
  UNWIND $ids AS id
248
287
  MATCH (m:Memory {id:id})
@@ -330,7 +369,7 @@ var MemoryService = class {
330
369
  contentHash,
331
370
  tags,
332
371
  confidence: clamp01(l.confidence),
333
- utility: 0.2,
372
+ utility: typeof l.utility === "number" ? clamp01(l.utility) : 0.2,
334
373
  // start modest; reinforce via feedback
335
374
  triage: l.triage ? JSON.stringify(l.triage) : null,
336
375
  antiPattern: l.antiPattern ? JSON.stringify(l.antiPattern) : null
@@ -407,6 +446,13 @@ var MemoryService = class {
407
446
  await session.close();
408
447
  }
409
448
  }
449
+ /**
450
+ * Create a new Case with an auto-generated id if none is provided.
451
+ */
452
+ async createCase(c) {
453
+ const id = c.id ?? newId("case");
454
+ return this.upsertCase({ ...c, id });
455
+ }
410
456
  /**
411
457
  * Retrieve a ContextBundle with separate Fix and Do-not-do sections, using case-based reasoning.
412
458
  * The key idea: match cases by symptoms + env similarity, then pull linked memories.
@@ -432,28 +478,49 @@ var MemoryService = class {
432
478
  halfLifeSeconds: this.halfLifeSeconds
433
479
  });
434
480
  const sections = r.records[0].get("sections");
435
- const fixes = (sections.fixes ?? []).map((m) => ({
436
- id: m.id,
437
- kind: m.kind,
438
- polarity: m.polarity ?? "positive",
439
- title: m.title,
440
- content: m.content,
441
- tags: m.tags ?? [],
442
- confidence: m.confidence ?? 0.7,
443
- utility: m.utility ?? 0.2,
444
- updatedAt: m.updatedAt?.toString?.() ?? null
445
- }));
446
- const doNot = (sections.doNot ?? []).map((m) => ({
481
+ const mapSummary = (m, fallbackPolarity) => ({
447
482
  id: m.id,
448
483
  kind: m.kind,
449
- polarity: m.polarity ?? "negative",
484
+ polarity: m.polarity ?? fallbackPolarity,
450
485
  title: m.title,
451
486
  content: m.content,
452
487
  tags: m.tags ?? [],
453
488
  confidence: m.confidence ?? 0.7,
454
489
  utility: m.utility ?? 0.2,
455
490
  updatedAt: m.updatedAt?.toString?.() ?? null
456
- }));
491
+ });
492
+ let fixes = (sections.fixes ?? []).map((m) => mapSummary(m, "positive"));
493
+ let doNot = (sections.doNot ?? []).map((m) => mapSummary(m, "negative"));
494
+ const fallback = args.fallback ?? {};
495
+ const shouldFallback = fallback.enabled === true && fixes.length === 0 && doNot.length === 0;
496
+ if (shouldFallback) {
497
+ const fallbackFixLimit = fallback.limit ?? fixLimit;
498
+ const fallbackDontLimit = fallback.limit ?? dontLimit;
499
+ try {
500
+ const fallbackRes = await session.run(this.cyFallbackRetrieve, {
501
+ prompt: args.prompt ?? "",
502
+ tags: args.tags ?? [],
503
+ kinds: args.kinds ?? [],
504
+ fulltextIndex: this.fulltextIndex,
505
+ vectorIndex: this.vectorIndex,
506
+ embedding: fallback.embedding ?? null,
507
+ useFulltext: fallback.useFulltext ?? true,
508
+ useVector: fallback.useVector ?? false,
509
+ useTags: fallback.useTags ?? true,
510
+ fixLimit: fallbackFixLimit,
511
+ dontLimit: fallbackDontLimit
512
+ });
513
+ const fbSections = fallbackRes.records[0]?.get("sections");
514
+ fixes = (fbSections?.fixes ?? []).map((m) => mapSummary(m, "positive"));
515
+ doNot = (fbSections?.doNot ?? []).map((m) => mapSummary(m, "negative"));
516
+ } catch (err) {
517
+ this.emit({
518
+ type: "read",
519
+ action: "retrieveContextBundle.fallbackError",
520
+ meta: { message: err instanceof Error ? err.message : String(err) }
521
+ });
522
+ }
523
+ }
457
524
  const allIds = [.../* @__PURE__ */ new Set([...fixes.map((x) => x.id), ...doNot.map((x) => x.id)])];
458
525
  const edgeAfter = /* @__PURE__ */ new Map();
459
526
  if (allIds.length > 0) {
@@ -528,6 +595,66 @@ ${m.content}`).join("");
528
595
  await session.close();
529
596
  }
530
597
  }
598
+ async getMemoriesById(args) {
599
+ const ids = [...new Set((args.ids ?? []).filter(Boolean))];
600
+ if (ids.length === 0) return [];
601
+ const session = this.client.session("READ");
602
+ try {
603
+ const res = await session.run(this.cyGetMemoriesById, { ids });
604
+ const memories = res.records[0]?.get("memories") ?? [];
605
+ return memories.map(toMemoryRecord);
606
+ } finally {
607
+ await session.close();
608
+ }
609
+ }
610
+ async getMemoryGraph(args) {
611
+ const ids = [...new Set((args.memoryIds ?? []).filter(Boolean))];
612
+ if (ids.length === 0) return { nodes: [], edges: [] };
613
+ const session = this.client.session("READ");
614
+ try {
615
+ const res = await session.run(this.cyGetMemoryGraph, {
616
+ agentId: args.agentId ?? null,
617
+ memoryIds: ids,
618
+ includeNodes: args.includeNodes ?? true,
619
+ includeRelatedTo: args.includeRelatedTo ?? false
620
+ });
621
+ const record = res.records[0];
622
+ const nodesRaw = record?.get("nodes") ?? [];
623
+ const edges = record?.get("edges") ?? [];
624
+ return {
625
+ nodes: nodesRaw.map(toMemoryRecord),
626
+ edges
627
+ };
628
+ } finally {
629
+ await session.close();
630
+ }
631
+ }
632
+ async listMemoryEdges(args = {}) {
633
+ const session = this.client.session("READ");
634
+ try {
635
+ const res = await session.run(this.cyListMemoryEdges, {
636
+ limit: args.limit ?? 200,
637
+ minStrength: args.minStrength ?? 0
638
+ });
639
+ return res.records[0]?.get("edges") ?? [];
640
+ } finally {
641
+ await session.close();
642
+ }
643
+ }
644
+ async retrieveContextBundleWithGraph(args) {
645
+ const bundle = await this.retrieveContextBundle(args);
646
+ const ids = [
647
+ ...bundle.sections.fix.map((m) => m.id),
648
+ ...bundle.sections.doNotDo.map((m) => m.id)
649
+ ];
650
+ const graph = await this.getMemoryGraph({
651
+ agentId: args.agentId,
652
+ memoryIds: ids,
653
+ includeNodes: args.includeNodes ?? false,
654
+ includeRelatedTo: args.includeRelatedTo ?? false
655
+ });
656
+ return { bundle, graph };
657
+ }
531
658
  async listEpisodes(args = {}) {
532
659
  return this.listMemories({ ...args, kind: "episodic" });
533
660
  }
@@ -558,6 +685,22 @@ ${m.content}`).join("");
558
685
  this.emit({ type: "write", action: "captureEpisode", meta: { runId: args.runId, title } });
559
686
  return result;
560
687
  }
688
+ async captureUsefulLearning(args) {
689
+ if (args.useful === false) {
690
+ return { saved: [], rejected: [{ title: args.learning.title, reason: "not marked useful" }] };
691
+ }
692
+ const result = await this.saveLearnings({
693
+ agentId: args.agentId,
694
+ sessionId: args.sessionId,
695
+ learnings: [args.learning]
696
+ });
697
+ this.emit({
698
+ type: "write",
699
+ action: "captureUsefulLearning",
700
+ meta: { title: args.learning.title, savedCount: result.saved.length }
701
+ });
702
+ return result;
703
+ }
561
704
  async captureStepEpisode(args) {
562
705
  const title = `Episode ${args.workflowName} - ${args.stepName}`;
563
706
  const base = {
@@ -587,29 +730,45 @@ ${m.content}`).join("");
587
730
  const used = new Set(fb.usedIds ?? []);
588
731
  const useful = new Set(fb.usefulIds ?? []);
589
732
  const notUseful = new Set(fb.notUsefulIds ?? []);
733
+ const neutral = new Set(fb.neutralIds ?? []);
590
734
  const prevented = new Set(fb.preventedErrorIds ?? []);
735
+ const updateUnratedUsed = fb.updateUnratedUsed ?? true;
591
736
  for (const id of prevented) useful.add(id);
592
737
  for (const id of useful) notUseful.delete(id);
738
+ for (const id of neutral) notUseful.delete(id);
593
739
  for (const id of useful) used.add(id);
594
740
  for (const id of notUseful) used.add(id);
741
+ for (const id of neutral) used.add(id);
595
742
  const quality = clamp01(fb.metrics?.quality ?? 0.7);
596
743
  const hallucRisk = clamp01(fb.metrics?.hallucinationRisk ?? 0.2);
597
744
  const baseY = clamp01(quality - 0.7 * hallucRisk);
598
745
  const w = 0.5 + 1.5 * quality;
599
746
  const yById = /* @__PURE__ */ new Map();
600
747
  for (const id of used) {
601
- yById.set(id, useful.has(id) ? baseY : 0);
748
+ if (useful.has(id)) {
749
+ yById.set(id, baseY);
750
+ continue;
751
+ }
752
+ if (notUseful.has(id)) {
753
+ yById.set(id, 0);
754
+ continue;
755
+ }
756
+ if (neutral.has(id) || !updateUnratedUsed) {
757
+ yById.set(id, 0.5);
758
+ continue;
759
+ }
760
+ yById.set(id, 0);
602
761
  }
603
762
  const items = [...used].map((memoryId) => ({
604
763
  memoryId,
605
764
  y: yById.get(memoryId) ?? 0,
606
765
  w
607
766
  }));
608
- if (items.length === 0) return;
767
+ if (items.length === 0) return { updated: [] };
609
768
  const session = this.client.session("WRITE");
610
769
  try {
611
770
  await session.run("MERGE (a:Agent {id:$id}) RETURN a", { id: fb.agentId });
612
- await session.run(this.cyFeedbackBatch, {
771
+ const feedbackRes = await session.run(this.cyFeedbackBatch, {
613
772
  agentId: fb.agentId,
614
773
  nowIso,
615
774
  items,
@@ -617,6 +776,16 @@ ${m.content}`).join("");
617
776
  aMin: 1e-3,
618
777
  bMin: 1e-3
619
778
  });
779
+ const updated = feedbackRes.records.map((rec) => {
780
+ const raw = {
781
+ a: rec.get("a"),
782
+ b: rec.get("b"),
783
+ strength: rec.get("strength"),
784
+ evidence: rec.get("evidence"),
785
+ updatedAt: rec.get("updatedAt")
786
+ };
787
+ return { id: rec.get("id"), edge: toBetaEdge(raw) };
788
+ });
620
789
  const ids = [...used];
621
790
  const pairs = [];
622
791
  for (let i = 0; i < ids.length; i++) {
@@ -638,6 +807,7 @@ ${m.content}`).join("");
638
807
  });
639
808
  }
640
809
  this.emit({ type: "write", action: "feedback", meta: { agentId: fb.agentId, usedCount: used.size } });
810
+ return { updated };
641
811
  } finally {
642
812
  await session.close();
643
813
  }
package/dist/index.d.ts CHANGED
@@ -21,6 +21,13 @@ interface DistilledInvariant {
21
21
  applicability?: string[];
22
22
  risks?: string[];
23
23
  }
24
+ interface MemoryTriage {
25
+ symptoms: string[];
26
+ likelyCauses: string[];
27
+ verificationSteps?: string[];
28
+ fixSteps?: string[];
29
+ gotchas?: string[];
30
+ }
24
31
  interface MemoryRecord {
25
32
  id: string;
26
33
  kind: MemoryKind;
@@ -32,6 +39,7 @@ interface MemoryRecord {
32
39
  utility: number;
33
40
  createdAt?: string;
34
41
  updatedAt?: string;
42
+ triage?: MemoryTriage;
35
43
  signals?: {
36
44
  symptoms?: string[];
37
45
  environment?: string[];
@@ -60,6 +68,18 @@ interface MemorySummary {
60
68
  createdAt?: string | null;
61
69
  updatedAt?: string | null;
62
70
  }
71
+ interface MemoryGraphEdge {
72
+ source: string;
73
+ target: string;
74
+ kind: "recalls" | "co_used_with" | "related_to";
75
+ strength: number;
76
+ evidence: number;
77
+ updatedAt?: string | null;
78
+ }
79
+ interface MemoryGraphResponse {
80
+ nodes: MemoryRecord[];
81
+ edges: MemoryGraphEdge[];
82
+ }
63
83
  interface CaseRecord {
64
84
  id: string;
65
85
  title: string;
@@ -86,12 +106,29 @@ interface RetrieveContextArgs {
86
106
  fixLimit?: number;
87
107
  dontLimit?: number;
88
108
  nowIso?: string;
109
+ fallback?: {
110
+ enabled?: boolean;
111
+ limit?: number;
112
+ useFulltext?: boolean;
113
+ useVector?: boolean;
114
+ useTags?: boolean;
115
+ embedding?: number[];
116
+ };
89
117
  }
90
118
  interface ListMemoriesArgs {
91
119
  kind?: MemoryKind;
92
120
  limit?: number;
93
121
  agentId?: string;
94
122
  }
123
+ interface GetMemoriesByIdArgs {
124
+ ids: string[];
125
+ }
126
+ interface GetMemoryGraphArgs {
127
+ agentId?: string;
128
+ memoryIds: string[];
129
+ includeNodes?: boolean;
130
+ includeRelatedTo?: boolean;
131
+ }
95
132
  interface BetaEdge {
96
133
  a: number;
97
134
  b: number;
@@ -132,10 +169,46 @@ interface MemoryFeedback {
132
169
  usedIds: string[];
133
170
  usefulIds: string[];
134
171
  notUsefulIds: string[];
172
+ neutralIds?: string[];
173
+ updateUnratedUsed?: boolean;
135
174
  preventedErrorIds?: string[];
136
175
  metrics?: FeedbackMetrics;
137
176
  notes?: string;
138
177
  }
178
+ interface MemoryFeedbackResult {
179
+ updated: Array<{
180
+ id: string;
181
+ edge: BetaEdge;
182
+ }>;
183
+ }
184
+ interface ListMemoryEdgesArgs {
185
+ limit?: number;
186
+ minStrength?: number;
187
+ }
188
+ interface MemoryEdgeExport {
189
+ source: string;
190
+ target: string;
191
+ kind: "co_used_with" | "related_to";
192
+ strength: number;
193
+ evidence: number;
194
+ updatedAt?: string | null;
195
+ }
196
+ interface RetrieveContextBundleWithGraphArgs extends RetrieveContextArgs {
197
+ includeNodes?: boolean;
198
+ includeRelatedTo?: boolean;
199
+ }
200
+ interface ContextBundleWithGraph {
201
+ bundle: ContextBundle;
202
+ graph: MemoryGraphResponse;
203
+ }
204
+ interface CaptureUsefulLearningArgs {
205
+ agentId: string;
206
+ sessionId?: string;
207
+ useful?: boolean;
208
+ learning: LearningCandidate & {
209
+ utility?: number;
210
+ };
211
+ }
139
212
  interface CaptureEpisodeArgs {
140
213
  agentId: string;
141
214
  runId: string;
@@ -161,15 +234,10 @@ interface LearningCandidate {
161
234
  content: string;
162
235
  tags: string[];
163
236
  confidence: number;
237
+ utility?: number;
164
238
  signals?: MemoryRecord["signals"];
165
239
  env?: EnvironmentFingerprint;
166
- triage?: {
167
- symptoms: string[];
168
- likelyCauses: string[];
169
- verificationSteps?: string[];
170
- fixSteps?: string[];
171
- gotchas?: string[];
172
- };
240
+ triage?: MemoryTriage;
173
241
  antiPattern?: MemoryRecord["antiPattern"];
174
242
  }
175
243
  interface SaveLearningRequest {
@@ -241,6 +309,10 @@ declare class MemoryService {
241
309
  private cyListMemories;
242
310
  private cyRelateConcepts;
243
311
  private cyAutoRelateByTags;
312
+ private cyGetMemoriesById;
313
+ private cyGetMemoryGraph;
314
+ private cyFallbackRetrieve;
315
+ private cyListMemoryEdges;
244
316
  private cyGetRecallEdges;
245
317
  constructor(cfg: MemoryServiceConfig);
246
318
  init(): Promise<void>;
@@ -261,12 +333,22 @@ declare class MemoryService {
261
333
  * Upsert an episodic Case (case-based reasoning) that links symptoms + env + resolved_by + negative memories.
262
334
  */
263
335
  upsertCase(c: CaseRecord): Promise<string>;
336
+ /**
337
+ * Create a new Case with an auto-generated id if none is provided.
338
+ */
339
+ createCase(c: Omit<CaseRecord, "id"> & {
340
+ id?: string;
341
+ }): Promise<string>;
264
342
  /**
265
343
  * Retrieve a ContextBundle with separate Fix and Do-not-do sections, using case-based reasoning.
266
344
  * The key idea: match cases by symptoms + env similarity, then pull linked memories.
267
345
  */
268
346
  retrieveContextBundle(args: RetrieveContextArgs): Promise<ContextBundle>;
269
347
  listMemories(args?: ListMemoriesArgs): Promise<MemorySummary[]>;
348
+ getMemoriesById(args: GetMemoriesByIdArgs): Promise<MemoryRecord[]>;
349
+ getMemoryGraph(args: GetMemoryGraphArgs): Promise<MemoryGraphResponse>;
350
+ listMemoryEdges(args?: ListMemoryEdgesArgs): Promise<MemoryEdgeExport[]>;
351
+ retrieveContextBundleWithGraph(args: RetrieveContextBundleWithGraphArgs): Promise<ContextBundleWithGraph>;
270
352
  listEpisodes(args?: Omit<ListMemoriesArgs, "kind">): Promise<MemorySummary[]>;
271
353
  listSkills(args?: Omit<ListMemoriesArgs, "kind">): Promise<MemorySummary[]>;
272
354
  listConcepts(args?: Omit<ListMemoriesArgs, "kind">): Promise<MemorySummary[]>;
@@ -276,12 +358,13 @@ declare class MemoryService {
276
358
  weight?: number;
277
359
  }): Promise<void>;
278
360
  captureEpisode(args: CaptureEpisodeArgs): Promise<SaveLearningResult>;
361
+ captureUsefulLearning(args: CaptureUsefulLearningArgs): Promise<SaveLearningResult>;
279
362
  captureStepEpisode(args: CaptureStepEpisodeArgs): Promise<SaveLearningResult>;
280
363
  /**
281
364
  * Reinforce/degrade agent->memory association weights using a single batched Cypher query.
282
365
  * This supports mid-run retrieval by making feedback cheap and frequent.
283
366
  */
284
- feedback(fb: MemoryFeedback): Promise<void>;
367
+ feedback(fb: MemoryFeedback): Promise<MemoryFeedbackResult>;
285
368
  /**
286
369
  * Save distilled learnings discovered during a task.
287
370
  * Enforces quality gates and stores negative memories explicitly.
@@ -320,6 +403,10 @@ declare const cypher: {
320
403
  listMemories: string;
321
404
  relateConcepts: string;
322
405
  autoRelateByTags: string;
406
+ getMemoriesById: string;
407
+ getMemoryGraph: string;
408
+ fallbackRetrieveMemories: string;
409
+ listMemoryEdges: string;
323
410
  };
324
411
 
325
412
  declare function createMemoryTools(service: MemoryService): MemoryToolSet;
@@ -330,4 +417,4 @@ declare function newId(prefix: string): string;
330
417
  declare function normaliseSymptom(s: string): string;
331
418
  declare function envHash(env: EnvironmentFingerprint): string;
332
419
 
333
- export { type AutoRelateConfig, type BetaEdge, type CaptureEpisodeArgs, type CaptureStepEpisodeArgs, type CaseRecord, type ContextBundle, type ContextMemoryBase, type ContextMemorySummary, type DistilledInvariant, type EnvironmentFingerprint, type FeedbackMetrics, type LearningCandidate, type ListMemoriesArgs, type MemoryEvent, type MemoryFeedback, type MemoryKind, type MemoryPolarity, type MemoryRecord, MemoryService, type MemoryServiceConfig, type MemorySummary, type MemoryToolDefinition, type MemoryToolName, type MemoryToolSet, Neo4jClient, type Neo4jClientConfig, type RetrieveContextArgs, type SaveLearningRequest, type SaveLearningResult, canonicaliseForHash, createMemoryService, createMemoryTools, cypher, ensureSchema, envHash, loadCypher, migrate, newId, normaliseSymptom, schemaVersion, sha256Hex };
420
+ export { type AutoRelateConfig, type BetaEdge, type CaptureEpisodeArgs, type CaptureStepEpisodeArgs, type CaptureUsefulLearningArgs, type CaseRecord, type ContextBundle, type ContextBundleWithGraph, type ContextMemoryBase, type ContextMemorySummary, type DistilledInvariant, type EnvironmentFingerprint, type FeedbackMetrics, type GetMemoriesByIdArgs, type GetMemoryGraphArgs, type LearningCandidate, type ListMemoriesArgs, type ListMemoryEdgesArgs, type MemoryEdgeExport, type MemoryEvent, type MemoryFeedback, type MemoryFeedbackResult, type MemoryGraphEdge, type MemoryGraphResponse, type MemoryKind, type MemoryPolarity, type MemoryRecord, MemoryService, type MemoryServiceConfig, type MemorySummary, type MemoryToolDefinition, type MemoryToolName, type MemoryToolSet, type MemoryTriage, Neo4jClient, type Neo4jClientConfig, type RetrieveContextArgs, type RetrieveContextBundleWithGraphArgs, type SaveLearningRequest, type SaveLearningResult, canonicaliseForHash, createMemoryService, createMemoryTools, cypher, ensureSchema, envHash, loadCypher, migrate, newId, normaliseSymptom, schemaVersion, sha256Hex };