neo4j-agent-memory 0.4.0 → 0.4.1
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/README.md +20 -1
- package/dist/cypher/feedback_batch.cypher +20 -26
- package/dist/cypher/get_memories_by_id.cypher +41 -0
- package/dist/cypher/get_memory_graph.cypher +85 -0
- package/dist/cypher/index.ts +2 -0
- package/dist/index.cjs +82 -3
- package/dist/index.d.ts +43 -9
- package/dist/index.js +82 -3
- package/package.json +1 -1
- package/dist/index.d.cts +0 -246
package/README.md
CHANGED
|
@@ -55,7 +55,7 @@ const bundle = await mem.retrieveContextBundle({
|
|
|
55
55
|
env: { os: "macos", packageManager: "npm", container: false }
|
|
56
56
|
});
|
|
57
57
|
|
|
58
|
-
await mem.feedback({
|
|
58
|
+
const feedback = await mem.feedback({
|
|
59
59
|
agentId: "auggie",
|
|
60
60
|
sessionId: bundle.sessionId,
|
|
61
61
|
usedIds: bundle.sections.fix.map((m) => m.id),
|
|
@@ -69,6 +69,7 @@ await mem.close();
|
|
|
69
69
|
Notes:
|
|
70
70
|
- `createMemoryService` runs schema setup on init.
|
|
71
71
|
- Cypher assets are bundled at `dist/cypher` in the published package.
|
|
72
|
+
- `feedback()` returns updated RECALLS edge posteriors for the provided memory ids.
|
|
72
73
|
|
|
73
74
|
Auto-relate config (defaults):
|
|
74
75
|
- `enabled: true`
|
|
@@ -127,6 +128,24 @@ const skills = await mem.listSkills({ agentId: "auggie" });
|
|
|
127
128
|
const concepts = await mem.listConcepts({ agentId: "auggie" });
|
|
128
129
|
```
|
|
129
130
|
|
|
131
|
+
## Graph APIs
|
|
132
|
+
|
|
133
|
+
Fetch full memory records by id:
|
|
134
|
+
|
|
135
|
+
```ts
|
|
136
|
+
const records = await mem.getMemoriesById({ ids: ["mem-1", "mem-2"] });
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Retrieve a weighted subgraph for UI maps:
|
|
140
|
+
|
|
141
|
+
```ts
|
|
142
|
+
const graph = await mem.getMemoryGraph({
|
|
143
|
+
agentId: "auggie",
|
|
144
|
+
memoryIds: ["mem-1", "mem-2"],
|
|
145
|
+
includeNodes: true,
|
|
146
|
+
});
|
|
147
|
+
```
|
|
148
|
+
|
|
130
149
|
## Episodic capture helpers
|
|
131
150
|
|
|
132
151
|
```ts
|
|
@@ -4,30 +4,19 @@
|
|
|
4
4
|
// halfLifeSeconds: 86400,
|
|
5
5
|
// aMin: 1.0,
|
|
6
6
|
// bMin: 1.0,
|
|
7
|
-
// w: 1.0,
|
|
8
|
-
// y: 1.0,
|
|
9
7
|
// items: [
|
|
10
|
-
// "mem_8cd773c2-208c-45ad-97ea-1b2337dca751",
|
|
11
|
-
// "mem_64fbcc73-0b5c-4041-8b6b-66514ffaf1d0",
|
|
12
|
-
// "mem_e55b80e2-6156-47bc-a964-9aef596f74a6",
|
|
13
|
-
// "mem_13189119-e3ad-4769-9f2b-2d3e3b8bc07f",
|
|
14
|
-
// "mem_137c3ff7-a81d-453d-8048-5c1b736db6ca",
|
|
15
|
-
// "mem_c0ea5643-3c61-4607-ba9f-67f4c2bb01ee",
|
|
16
|
-
// "mem_aa15e7b6-7f94-445a-9c52-3eb24a315215",
|
|
17
|
-
// "mem_e93e7bb8-b43c-44f5-a5d3-87545d67be59",
|
|
18
|
-
// "mem_b81e3709-35ae-4cab-931d-612dcc2cd43d",
|
|
19
|
-
// "mem_ce8a5b62-7ddb-4618-8a6c-93ed3b425f27",
|
|
20
|
-
// "mem_737df25b-7944-4dee-a7aa-86af93567663"
|
|
8
|
+
// { memoryId: "mem_8cd773c2-208c-45ad-97ea-1b2337dca751", w: 1.0, y: 1.0 },
|
|
9
|
+
// { memoryId: "mem_64fbcc73-0b5c-4041-8b6b-66514ffaf1d0", w: 1.0, y: 0.0 }
|
|
21
10
|
// ]
|
|
22
11
|
// }
|
|
23
12
|
WITH datetime($nowIso) AS now
|
|
24
13
|
|
|
25
|
-
UNWIND $items AS
|
|
26
|
-
WITH now,
|
|
27
|
-
WHERE memoryId IS NOT NULL AND memoryId <> ""
|
|
14
|
+
UNWIND $items AS item
|
|
15
|
+
WITH now, item
|
|
16
|
+
WHERE item.memoryId IS NOT NULL AND item.memoryId <> ""
|
|
28
17
|
|
|
29
18
|
MATCH (a:Agent {id: $agentId})
|
|
30
|
-
MATCH (m:Memory {id: memoryId})
|
|
19
|
+
MATCH (m:Memory {id: item.memoryId})
|
|
31
20
|
|
|
32
21
|
MERGE (a)-[r:RECALLS]->(m)
|
|
33
22
|
ON CREATE SET
|
|
@@ -38,25 +27,25 @@ ON CREATE SET
|
|
|
38
27
|
r.successes = 0,
|
|
39
28
|
r.failures = 0
|
|
40
29
|
|
|
41
|
-
WITH now, r,
|
|
30
|
+
WITH now, r, item,
|
|
42
31
|
CASE
|
|
43
32
|
WHEN duration.inSeconds(coalesce(r.updatedAt, now), now).seconds > 0
|
|
44
33
|
THEN duration.inSeconds(coalesce(r.updatedAt, now), now).seconds
|
|
45
34
|
ELSE 0
|
|
46
35
|
END AS dt
|
|
47
36
|
|
|
48
|
-
WITH now, r,
|
|
37
|
+
WITH now, r, item,
|
|
49
38
|
0.5 ^ (dt / $halfLifeSeconds) AS gamma,
|
|
50
39
|
coalesce(r.a, $aMin) AS aPrev,
|
|
51
40
|
coalesce(r.b, $bMin) AS bPrev
|
|
52
41
|
|
|
53
|
-
WITH now, r, gamma,
|
|
42
|
+
WITH now, r, item, gamma,
|
|
54
43
|
($aMin + gamma * (aPrev - $aMin)) AS a0,
|
|
55
44
|
($bMin + gamma * (bPrev - $bMin)) AS b0
|
|
56
45
|
|
|
57
|
-
WITH now, r,
|
|
58
|
-
(a0 +
|
|
59
|
-
(b0 +
|
|
46
|
+
WITH now, r, item,
|
|
47
|
+
(a0 + item.w * item.y) AS a1,
|
|
48
|
+
(b0 + item.w * (1.0 - item.y)) AS b1
|
|
60
49
|
|
|
61
50
|
SET r.a = a1,
|
|
62
51
|
r.b = b1,
|
|
@@ -64,7 +53,12 @@ SET r.a = a1,
|
|
|
64
53
|
r.evidence = a1 + b1,
|
|
65
54
|
r.updatedAt = now,
|
|
66
55
|
r.uses = coalesce(r.uses, 0) + 1,
|
|
67
|
-
r.successes = coalesce(r.successes, 0) + CASE WHEN
|
|
68
|
-
r.failures = coalesce(r.failures, 0) + CASE WHEN
|
|
56
|
+
r.successes = coalesce(r.successes, 0) + CASE WHEN item.y >= 0.5 THEN 1 ELSE 0 END,
|
|
57
|
+
r.failures = coalesce(r.failures, 0) + CASE WHEN item.y < 0.5 THEN 1 ELSE 0 END
|
|
69
58
|
|
|
70
|
-
RETURN
|
|
59
|
+
RETURN item.memoryId AS id,
|
|
60
|
+
r.a AS a,
|
|
61
|
+
r.b AS b,
|
|
62
|
+
r.strength AS strength,
|
|
63
|
+
r.evidence AS evidence,
|
|
64
|
+
toString(r.updatedAt) AS updatedAt;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
// Parameters:
|
|
2
|
+
// - $ids: Array of memory ids
|
|
3
|
+
WITH [id IN coalesce($ids, []) WHERE id IS NOT NULL AND id <> ""] AS ids
|
|
4
|
+
UNWIND range(0, size(ids) - 1) AS idx
|
|
5
|
+
WITH idx, ids[idx] AS id
|
|
6
|
+
MATCH (m:Memory {id: id})
|
|
7
|
+
OPTIONAL MATCH (m)-[:APPLIES_IN]->(e:EnvironmentFingerprint)
|
|
8
|
+
WITH idx, m, collect(e {
|
|
9
|
+
.hash,
|
|
10
|
+
.os,
|
|
11
|
+
.distro,
|
|
12
|
+
.ci,
|
|
13
|
+
.container,
|
|
14
|
+
.filesystem,
|
|
15
|
+
.workspaceMount,
|
|
16
|
+
.nodeVersion,
|
|
17
|
+
.packageManager,
|
|
18
|
+
.pmVersion
|
|
19
|
+
}) AS envs
|
|
20
|
+
WITH collect({
|
|
21
|
+
idx: idx,
|
|
22
|
+
memory: m {
|
|
23
|
+
.id,
|
|
24
|
+
.kind,
|
|
25
|
+
.polarity,
|
|
26
|
+
.title,
|
|
27
|
+
.content,
|
|
28
|
+
.tags,
|
|
29
|
+
.confidence,
|
|
30
|
+
.utility,
|
|
31
|
+
.triage,
|
|
32
|
+
.antiPattern,
|
|
33
|
+
.createdAt,
|
|
34
|
+
.updatedAt,
|
|
35
|
+
env: envs[0]
|
|
36
|
+
}
|
|
37
|
+
}) AS rows
|
|
38
|
+
UNWIND rows AS row
|
|
39
|
+
WITH row
|
|
40
|
+
ORDER BY row.idx
|
|
41
|
+
RETURN collect(row.memory) AS memories;
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
// Parameters:
|
|
2
|
+
// - $agentId: Agent id for RECALLS edges
|
|
3
|
+
// - $memoryIds: Array of memory ids
|
|
4
|
+
// - $includeNodes: Boolean to include node payloads
|
|
5
|
+
WITH
|
|
6
|
+
coalesce($agentId, "") AS agentId,
|
|
7
|
+
[id IN coalesce($memoryIds, []) WHERE id IS NOT NULL AND id <> ""] AS ids,
|
|
8
|
+
coalesce($includeNodes, true) AS includeNodes
|
|
9
|
+
|
|
10
|
+
CALL (ids, includeNodes) {
|
|
11
|
+
WITH ids, includeNodes
|
|
12
|
+
MATCH (m:Memory)
|
|
13
|
+
WHERE includeNodes = true AND m.id IN ids
|
|
14
|
+
OPTIONAL MATCH (m)-[:APPLIES_IN]->(e:EnvironmentFingerprint)
|
|
15
|
+
WITH m, collect(e {
|
|
16
|
+
.hash,
|
|
17
|
+
.os,
|
|
18
|
+
.distro,
|
|
19
|
+
.ci,
|
|
20
|
+
.container,
|
|
21
|
+
.filesystem,
|
|
22
|
+
.workspaceMount,
|
|
23
|
+
.nodeVersion,
|
|
24
|
+
.packageManager,
|
|
25
|
+
.pmVersion
|
|
26
|
+
}) AS envs
|
|
27
|
+
RETURN collect(m {
|
|
28
|
+
.id,
|
|
29
|
+
.kind,
|
|
30
|
+
.polarity,
|
|
31
|
+
.title,
|
|
32
|
+
.content,
|
|
33
|
+
.tags,
|
|
34
|
+
.confidence,
|
|
35
|
+
.utility,
|
|
36
|
+
.triage,
|
|
37
|
+
.antiPattern,
|
|
38
|
+
.createdAt,
|
|
39
|
+
.updatedAt,
|
|
40
|
+
env: envs[0]
|
|
41
|
+
}) AS nodes
|
|
42
|
+
|
|
43
|
+
UNION
|
|
44
|
+
|
|
45
|
+
WITH ids, includeNodes
|
|
46
|
+
WHERE includeNodes = false
|
|
47
|
+
RETURN [] AS nodes
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
CALL (ids, agentId) {
|
|
51
|
+
WITH ids, agentId
|
|
52
|
+
WHERE agentId IS NOT NULL AND agentId <> ""
|
|
53
|
+
MATCH (a:Agent {id: agentId})-[r:RECALLS]->(m:Memory)
|
|
54
|
+
WHERE m.id IN ids
|
|
55
|
+
RETURN collect({
|
|
56
|
+
source: a.id,
|
|
57
|
+
target: m.id,
|
|
58
|
+
kind: "recalls",
|
|
59
|
+
strength: r.strength,
|
|
60
|
+
evidence: r.evidence,
|
|
61
|
+
updatedAt: toString(r.updatedAt)
|
|
62
|
+
}) AS recallEdges
|
|
63
|
+
|
|
64
|
+
UNION
|
|
65
|
+
|
|
66
|
+
WITH ids, agentId
|
|
67
|
+
WHERE agentId IS NULL OR agentId = ""
|
|
68
|
+
RETURN [] AS recallEdges
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
CALL (ids) {
|
|
72
|
+
WITH ids
|
|
73
|
+
MATCH (m1:Memory)-[c:CO_USED_WITH]->(m2:Memory)
|
|
74
|
+
WHERE m1.id IN ids AND m2.id IN ids
|
|
75
|
+
RETURN collect({
|
|
76
|
+
source: m1.id,
|
|
77
|
+
target: m2.id,
|
|
78
|
+
kind: "co_used_with",
|
|
79
|
+
strength: c.strength,
|
|
80
|
+
evidence: c.evidence,
|
|
81
|
+
updatedAt: toString(c.updatedAt)
|
|
82
|
+
}) AS coUsedEdges
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
RETURN nodes, recallEdges + coUsedEdges AS edges;
|
package/dist/cypher/index.ts
CHANGED
|
@@ -21,4 +21,6 @@ export const cypher = {
|
|
|
21
21
|
listMemories: loadCypher("list_memories.cypher"),
|
|
22
22
|
relateConcepts: loadCypher("relate_concepts.cypher"),
|
|
23
23
|
autoRelateByTags: loadCypher("auto_relate_memory_by_tags.cypher"),
|
|
24
|
+
getMemoriesById: loadCypher("get_memories_by_id.cypher"),
|
|
25
|
+
getMemoryGraph: loadCypher("get_memory_graph.cypher"),
|
|
24
26
|
};
|
package/dist/index.cjs
CHANGED
|
@@ -86,7 +86,9 @@ 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")
|
|
90
92
|
};
|
|
91
93
|
|
|
92
94
|
// src/neo4j/schema.ts
|
|
@@ -146,6 +148,20 @@ function envHash(env) {
|
|
|
146
148
|
function clamp01(x) {
|
|
147
149
|
return Math.max(0, Math.min(1, x));
|
|
148
150
|
}
|
|
151
|
+
function parseJsonField(value) {
|
|
152
|
+
if (value === null || value === void 0) return void 0;
|
|
153
|
+
if (typeof value !== "string") return value;
|
|
154
|
+
try {
|
|
155
|
+
return JSON.parse(value);
|
|
156
|
+
} catch {
|
|
157
|
+
return void 0;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
function toDateString(value) {
|
|
161
|
+
if (value === null || value === void 0) return void 0;
|
|
162
|
+
if (typeof value?.toString === "function") return value.toString();
|
|
163
|
+
return String(value);
|
|
164
|
+
}
|
|
149
165
|
var DEFAULT_AUTO_RELATE = {
|
|
150
166
|
enabled: true,
|
|
151
167
|
minSharedTags: 2,
|
|
@@ -172,6 +188,23 @@ function toBetaEdge(raw) {
|
|
|
172
188
|
updatedAt: raw?.updatedAt ?? null
|
|
173
189
|
};
|
|
174
190
|
}
|
|
191
|
+
function toMemoryRecord(raw) {
|
|
192
|
+
return {
|
|
193
|
+
id: raw.id,
|
|
194
|
+
kind: raw.kind,
|
|
195
|
+
polarity: raw.polarity ?? "positive",
|
|
196
|
+
title: raw.title,
|
|
197
|
+
content: raw.content,
|
|
198
|
+
tags: raw.tags ?? [],
|
|
199
|
+
confidence: raw.confidence ?? 0.7,
|
|
200
|
+
utility: raw.utility ?? 0.2,
|
|
201
|
+
createdAt: toDateString(raw.createdAt),
|
|
202
|
+
updatedAt: toDateString(raw.updatedAt),
|
|
203
|
+
triage: parseJsonField(raw.triage),
|
|
204
|
+
antiPattern: parseJsonField(raw.antiPattern),
|
|
205
|
+
env: raw.env ?? void 0
|
|
206
|
+
};
|
|
207
|
+
}
|
|
175
208
|
function defaultPolicy(req) {
|
|
176
209
|
return {
|
|
177
210
|
minConfidence: req?.minConfidence ?? 0.65,
|
|
@@ -243,6 +276,8 @@ var MemoryService = class {
|
|
|
243
276
|
cyListMemories = cypher.listMemories;
|
|
244
277
|
cyRelateConcepts = cypher.relateConcepts;
|
|
245
278
|
cyAutoRelateByTags = cypher.autoRelateByTags;
|
|
279
|
+
cyGetMemoriesById = cypher.getMemoriesById;
|
|
280
|
+
cyGetMemoryGraph = cypher.getMemoryGraph;
|
|
246
281
|
cyGetRecallEdges = `
|
|
247
282
|
UNWIND $ids AS id
|
|
248
283
|
MATCH (m:Memory {id:id})
|
|
@@ -528,6 +563,39 @@ ${m.content}`).join("");
|
|
|
528
563
|
await session.close();
|
|
529
564
|
}
|
|
530
565
|
}
|
|
566
|
+
async getMemoriesById(args) {
|
|
567
|
+
const ids = [...new Set((args.ids ?? []).filter(Boolean))];
|
|
568
|
+
if (ids.length === 0) return [];
|
|
569
|
+
const session = this.client.session("READ");
|
|
570
|
+
try {
|
|
571
|
+
const res = await session.run(this.cyGetMemoriesById, { ids });
|
|
572
|
+
const memories = res.records[0]?.get("memories") ?? [];
|
|
573
|
+
return memories.map(toMemoryRecord);
|
|
574
|
+
} finally {
|
|
575
|
+
await session.close();
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
async getMemoryGraph(args) {
|
|
579
|
+
const ids = [...new Set((args.memoryIds ?? []).filter(Boolean))];
|
|
580
|
+
if (ids.length === 0) return { nodes: [], edges: [] };
|
|
581
|
+
const session = this.client.session("READ");
|
|
582
|
+
try {
|
|
583
|
+
const res = await session.run(this.cyGetMemoryGraph, {
|
|
584
|
+
agentId: args.agentId ?? null,
|
|
585
|
+
memoryIds: ids,
|
|
586
|
+
includeNodes: args.includeNodes ?? true
|
|
587
|
+
});
|
|
588
|
+
const record = res.records[0];
|
|
589
|
+
const nodesRaw = record?.get("nodes") ?? [];
|
|
590
|
+
const edges = record?.get("edges") ?? [];
|
|
591
|
+
return {
|
|
592
|
+
nodes: nodesRaw.map(toMemoryRecord),
|
|
593
|
+
edges
|
|
594
|
+
};
|
|
595
|
+
} finally {
|
|
596
|
+
await session.close();
|
|
597
|
+
}
|
|
598
|
+
}
|
|
531
599
|
async listEpisodes(args = {}) {
|
|
532
600
|
return this.listMemories({ ...args, kind: "episodic" });
|
|
533
601
|
}
|
|
@@ -605,11 +673,11 @@ ${m.content}`).join("");
|
|
|
605
673
|
y: yById.get(memoryId) ?? 0,
|
|
606
674
|
w
|
|
607
675
|
}));
|
|
608
|
-
if (items.length === 0) return;
|
|
676
|
+
if (items.length === 0) return { updated: [] };
|
|
609
677
|
const session = this.client.session("WRITE");
|
|
610
678
|
try {
|
|
611
679
|
await session.run("MERGE (a:Agent {id:$id}) RETURN a", { id: fb.agentId });
|
|
612
|
-
await session.run(this.cyFeedbackBatch, {
|
|
680
|
+
const feedbackRes = await session.run(this.cyFeedbackBatch, {
|
|
613
681
|
agentId: fb.agentId,
|
|
614
682
|
nowIso,
|
|
615
683
|
items,
|
|
@@ -617,6 +685,16 @@ ${m.content}`).join("");
|
|
|
617
685
|
aMin: 1e-3,
|
|
618
686
|
bMin: 1e-3
|
|
619
687
|
});
|
|
688
|
+
const updated = feedbackRes.records.map((rec) => {
|
|
689
|
+
const raw = {
|
|
690
|
+
a: rec.get("a"),
|
|
691
|
+
b: rec.get("b"),
|
|
692
|
+
strength: rec.get("strength"),
|
|
693
|
+
evidence: rec.get("evidence"),
|
|
694
|
+
updatedAt: rec.get("updatedAt")
|
|
695
|
+
};
|
|
696
|
+
return { id: rec.get("id"), edge: toBetaEdge(raw) };
|
|
697
|
+
});
|
|
620
698
|
const ids = [...used];
|
|
621
699
|
const pairs = [];
|
|
622
700
|
for (let i = 0; i < ids.length; i++) {
|
|
@@ -638,6 +716,7 @@ ${m.content}`).join("");
|
|
|
638
716
|
});
|
|
639
717
|
}
|
|
640
718
|
this.emit({ type: "write", action: "feedback", meta: { agentId: fb.agentId, usedCount: used.size } });
|
|
719
|
+
return { updated };
|
|
641
720
|
} finally {
|
|
642
721
|
await session.close();
|
|
643
722
|
}
|
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";
|
|
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;
|
|
@@ -92,6 +112,14 @@ interface ListMemoriesArgs {
|
|
|
92
112
|
limit?: number;
|
|
93
113
|
agentId?: string;
|
|
94
114
|
}
|
|
115
|
+
interface GetMemoriesByIdArgs {
|
|
116
|
+
ids: string[];
|
|
117
|
+
}
|
|
118
|
+
interface GetMemoryGraphArgs {
|
|
119
|
+
agentId?: string;
|
|
120
|
+
memoryIds: string[];
|
|
121
|
+
includeNodes?: boolean;
|
|
122
|
+
}
|
|
95
123
|
interface BetaEdge {
|
|
96
124
|
a: number;
|
|
97
125
|
b: number;
|
|
@@ -136,6 +164,12 @@ interface MemoryFeedback {
|
|
|
136
164
|
metrics?: FeedbackMetrics;
|
|
137
165
|
notes?: string;
|
|
138
166
|
}
|
|
167
|
+
interface MemoryFeedbackResult {
|
|
168
|
+
updated: Array<{
|
|
169
|
+
id: string;
|
|
170
|
+
edge: BetaEdge;
|
|
171
|
+
}>;
|
|
172
|
+
}
|
|
139
173
|
interface CaptureEpisodeArgs {
|
|
140
174
|
agentId: string;
|
|
141
175
|
runId: string;
|
|
@@ -163,13 +197,7 @@ interface LearningCandidate {
|
|
|
163
197
|
confidence: number;
|
|
164
198
|
signals?: MemoryRecord["signals"];
|
|
165
199
|
env?: EnvironmentFingerprint;
|
|
166
|
-
triage?:
|
|
167
|
-
symptoms: string[];
|
|
168
|
-
likelyCauses: string[];
|
|
169
|
-
verificationSteps?: string[];
|
|
170
|
-
fixSteps?: string[];
|
|
171
|
-
gotchas?: string[];
|
|
172
|
-
};
|
|
200
|
+
triage?: MemoryTriage;
|
|
173
201
|
antiPattern?: MemoryRecord["antiPattern"];
|
|
174
202
|
}
|
|
175
203
|
interface SaveLearningRequest {
|
|
@@ -241,6 +269,8 @@ declare class MemoryService {
|
|
|
241
269
|
private cyListMemories;
|
|
242
270
|
private cyRelateConcepts;
|
|
243
271
|
private cyAutoRelateByTags;
|
|
272
|
+
private cyGetMemoriesById;
|
|
273
|
+
private cyGetMemoryGraph;
|
|
244
274
|
private cyGetRecallEdges;
|
|
245
275
|
constructor(cfg: MemoryServiceConfig);
|
|
246
276
|
init(): Promise<void>;
|
|
@@ -267,6 +297,8 @@ declare class MemoryService {
|
|
|
267
297
|
*/
|
|
268
298
|
retrieveContextBundle(args: RetrieveContextArgs): Promise<ContextBundle>;
|
|
269
299
|
listMemories(args?: ListMemoriesArgs): Promise<MemorySummary[]>;
|
|
300
|
+
getMemoriesById(args: GetMemoriesByIdArgs): Promise<MemoryRecord[]>;
|
|
301
|
+
getMemoryGraph(args: GetMemoryGraphArgs): Promise<MemoryGraphResponse>;
|
|
270
302
|
listEpisodes(args?: Omit<ListMemoriesArgs, "kind">): Promise<MemorySummary[]>;
|
|
271
303
|
listSkills(args?: Omit<ListMemoriesArgs, "kind">): Promise<MemorySummary[]>;
|
|
272
304
|
listConcepts(args?: Omit<ListMemoriesArgs, "kind">): Promise<MemorySummary[]>;
|
|
@@ -281,7 +313,7 @@ declare class MemoryService {
|
|
|
281
313
|
* Reinforce/degrade agent->memory association weights using a single batched Cypher query.
|
|
282
314
|
* This supports mid-run retrieval by making feedback cheap and frequent.
|
|
283
315
|
*/
|
|
284
|
-
feedback(fb: MemoryFeedback): Promise<
|
|
316
|
+
feedback(fb: MemoryFeedback): Promise<MemoryFeedbackResult>;
|
|
285
317
|
/**
|
|
286
318
|
* Save distilled learnings discovered during a task.
|
|
287
319
|
* Enforces quality gates and stores negative memories explicitly.
|
|
@@ -320,6 +352,8 @@ declare const cypher: {
|
|
|
320
352
|
listMemories: string;
|
|
321
353
|
relateConcepts: string;
|
|
322
354
|
autoRelateByTags: string;
|
|
355
|
+
getMemoriesById: string;
|
|
356
|
+
getMemoryGraph: string;
|
|
323
357
|
};
|
|
324
358
|
|
|
325
359
|
declare function createMemoryTools(service: MemoryService): MemoryToolSet;
|
|
@@ -330,4 +364,4 @@ declare function newId(prefix: string): string;
|
|
|
330
364
|
declare function normaliseSymptom(s: string): string;
|
|
331
365
|
declare function envHash(env: EnvironmentFingerprint): string;
|
|
332
366
|
|
|
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 };
|
|
367
|
+
export { type AutoRelateConfig, type BetaEdge, type CaptureEpisodeArgs, type CaptureStepEpisodeArgs, type CaseRecord, type ContextBundle, type ContextMemoryBase, type ContextMemorySummary, type DistilledInvariant, type EnvironmentFingerprint, type FeedbackMetrics, type GetMemoriesByIdArgs, type GetMemoryGraphArgs, type LearningCandidate, type ListMemoriesArgs, 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 SaveLearningRequest, type SaveLearningResult, canonicaliseForHash, createMemoryService, createMemoryTools, cypher, ensureSchema, envHash, loadCypher, migrate, newId, normaliseSymptom, schemaVersion, sha256Hex };
|
package/dist/index.js
CHANGED
|
@@ -36,7 +36,9 @@ var cypher = {
|
|
|
36
36
|
feedbackCoUsed: loadCypher("feedback_co_used_with_batch.cypher"),
|
|
37
37
|
listMemories: loadCypher("list_memories.cypher"),
|
|
38
38
|
relateConcepts: loadCypher("relate_concepts.cypher"),
|
|
39
|
-
autoRelateByTags: loadCypher("auto_relate_memory_by_tags.cypher")
|
|
39
|
+
autoRelateByTags: loadCypher("auto_relate_memory_by_tags.cypher"),
|
|
40
|
+
getMemoriesById: loadCypher("get_memories_by_id.cypher"),
|
|
41
|
+
getMemoryGraph: loadCypher("get_memory_graph.cypher")
|
|
40
42
|
};
|
|
41
43
|
|
|
42
44
|
// src/neo4j/schema.ts
|
|
@@ -96,6 +98,20 @@ function envHash(env) {
|
|
|
96
98
|
function clamp01(x) {
|
|
97
99
|
return Math.max(0, Math.min(1, x));
|
|
98
100
|
}
|
|
101
|
+
function parseJsonField(value) {
|
|
102
|
+
if (value === null || value === void 0) return void 0;
|
|
103
|
+
if (typeof value !== "string") return value;
|
|
104
|
+
try {
|
|
105
|
+
return JSON.parse(value);
|
|
106
|
+
} catch {
|
|
107
|
+
return void 0;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
function toDateString(value) {
|
|
111
|
+
if (value === null || value === void 0) return void 0;
|
|
112
|
+
if (typeof value?.toString === "function") return value.toString();
|
|
113
|
+
return String(value);
|
|
114
|
+
}
|
|
99
115
|
var DEFAULT_AUTO_RELATE = {
|
|
100
116
|
enabled: true,
|
|
101
117
|
minSharedTags: 2,
|
|
@@ -122,6 +138,23 @@ function toBetaEdge(raw) {
|
|
|
122
138
|
updatedAt: raw?.updatedAt ?? null
|
|
123
139
|
};
|
|
124
140
|
}
|
|
141
|
+
function toMemoryRecord(raw) {
|
|
142
|
+
return {
|
|
143
|
+
id: raw.id,
|
|
144
|
+
kind: raw.kind,
|
|
145
|
+
polarity: raw.polarity ?? "positive",
|
|
146
|
+
title: raw.title,
|
|
147
|
+
content: raw.content,
|
|
148
|
+
tags: raw.tags ?? [],
|
|
149
|
+
confidence: raw.confidence ?? 0.7,
|
|
150
|
+
utility: raw.utility ?? 0.2,
|
|
151
|
+
createdAt: toDateString(raw.createdAt),
|
|
152
|
+
updatedAt: toDateString(raw.updatedAt),
|
|
153
|
+
triage: parseJsonField(raw.triage),
|
|
154
|
+
antiPattern: parseJsonField(raw.antiPattern),
|
|
155
|
+
env: raw.env ?? void 0
|
|
156
|
+
};
|
|
157
|
+
}
|
|
125
158
|
function defaultPolicy(req) {
|
|
126
159
|
return {
|
|
127
160
|
minConfidence: req?.minConfidence ?? 0.65,
|
|
@@ -193,6 +226,8 @@ var MemoryService = class {
|
|
|
193
226
|
cyListMemories = cypher.listMemories;
|
|
194
227
|
cyRelateConcepts = cypher.relateConcepts;
|
|
195
228
|
cyAutoRelateByTags = cypher.autoRelateByTags;
|
|
229
|
+
cyGetMemoriesById = cypher.getMemoriesById;
|
|
230
|
+
cyGetMemoryGraph = cypher.getMemoryGraph;
|
|
196
231
|
cyGetRecallEdges = `
|
|
197
232
|
UNWIND $ids AS id
|
|
198
233
|
MATCH (m:Memory {id:id})
|
|
@@ -478,6 +513,39 @@ ${m.content}`).join("");
|
|
|
478
513
|
await session.close();
|
|
479
514
|
}
|
|
480
515
|
}
|
|
516
|
+
async getMemoriesById(args) {
|
|
517
|
+
const ids = [...new Set((args.ids ?? []).filter(Boolean))];
|
|
518
|
+
if (ids.length === 0) return [];
|
|
519
|
+
const session = this.client.session("READ");
|
|
520
|
+
try {
|
|
521
|
+
const res = await session.run(this.cyGetMemoriesById, { ids });
|
|
522
|
+
const memories = res.records[0]?.get("memories") ?? [];
|
|
523
|
+
return memories.map(toMemoryRecord);
|
|
524
|
+
} finally {
|
|
525
|
+
await session.close();
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
async getMemoryGraph(args) {
|
|
529
|
+
const ids = [...new Set((args.memoryIds ?? []).filter(Boolean))];
|
|
530
|
+
if (ids.length === 0) return { nodes: [], edges: [] };
|
|
531
|
+
const session = this.client.session("READ");
|
|
532
|
+
try {
|
|
533
|
+
const res = await session.run(this.cyGetMemoryGraph, {
|
|
534
|
+
agentId: args.agentId ?? null,
|
|
535
|
+
memoryIds: ids,
|
|
536
|
+
includeNodes: args.includeNodes ?? true
|
|
537
|
+
});
|
|
538
|
+
const record = res.records[0];
|
|
539
|
+
const nodesRaw = record?.get("nodes") ?? [];
|
|
540
|
+
const edges = record?.get("edges") ?? [];
|
|
541
|
+
return {
|
|
542
|
+
nodes: nodesRaw.map(toMemoryRecord),
|
|
543
|
+
edges
|
|
544
|
+
};
|
|
545
|
+
} finally {
|
|
546
|
+
await session.close();
|
|
547
|
+
}
|
|
548
|
+
}
|
|
481
549
|
async listEpisodes(args = {}) {
|
|
482
550
|
return this.listMemories({ ...args, kind: "episodic" });
|
|
483
551
|
}
|
|
@@ -555,11 +623,11 @@ ${m.content}`).join("");
|
|
|
555
623
|
y: yById.get(memoryId) ?? 0,
|
|
556
624
|
w
|
|
557
625
|
}));
|
|
558
|
-
if (items.length === 0) return;
|
|
626
|
+
if (items.length === 0) return { updated: [] };
|
|
559
627
|
const session = this.client.session("WRITE");
|
|
560
628
|
try {
|
|
561
629
|
await session.run("MERGE (a:Agent {id:$id}) RETURN a", { id: fb.agentId });
|
|
562
|
-
await session.run(this.cyFeedbackBatch, {
|
|
630
|
+
const feedbackRes = await session.run(this.cyFeedbackBatch, {
|
|
563
631
|
agentId: fb.agentId,
|
|
564
632
|
nowIso,
|
|
565
633
|
items,
|
|
@@ -567,6 +635,16 @@ ${m.content}`).join("");
|
|
|
567
635
|
aMin: 1e-3,
|
|
568
636
|
bMin: 1e-3
|
|
569
637
|
});
|
|
638
|
+
const updated = feedbackRes.records.map((rec) => {
|
|
639
|
+
const raw = {
|
|
640
|
+
a: rec.get("a"),
|
|
641
|
+
b: rec.get("b"),
|
|
642
|
+
strength: rec.get("strength"),
|
|
643
|
+
evidence: rec.get("evidence"),
|
|
644
|
+
updatedAt: rec.get("updatedAt")
|
|
645
|
+
};
|
|
646
|
+
return { id: rec.get("id"), edge: toBetaEdge(raw) };
|
|
647
|
+
});
|
|
570
648
|
const ids = [...used];
|
|
571
649
|
const pairs = [];
|
|
572
650
|
for (let i = 0; i < ids.length; i++) {
|
|
@@ -588,6 +666,7 @@ ${m.content}`).join("");
|
|
|
588
666
|
});
|
|
589
667
|
}
|
|
590
668
|
this.emit({ type: "write", action: "feedback", meta: { agentId: fb.agentId, usedCount: used.size } });
|
|
669
|
+
return { updated };
|
|
591
670
|
} finally {
|
|
592
671
|
await session.close();
|
|
593
672
|
}
|
package/package.json
CHANGED
package/dist/index.d.cts
DELETED
|
@@ -1,246 +0,0 @@
|
|
|
1
|
-
import { Session } from 'neo4j-driver';
|
|
2
|
-
|
|
3
|
-
type MemoryKind = "semantic" | "procedural" | "episodic";
|
|
4
|
-
type MemoryPolarity = "positive" | "negative";
|
|
5
|
-
interface EnvironmentFingerprint {
|
|
6
|
-
hash?: string;
|
|
7
|
-
os?: "macos" | "linux" | "windows";
|
|
8
|
-
distro?: string;
|
|
9
|
-
ci?: string;
|
|
10
|
-
container?: boolean;
|
|
11
|
-
filesystem?: string;
|
|
12
|
-
workspaceMount?: "local" | "network" | "bind" | "readonly";
|
|
13
|
-
nodeVersion?: string;
|
|
14
|
-
packageManager?: "npm" | "pnpm" | "yarn";
|
|
15
|
-
pmVersion?: string;
|
|
16
|
-
}
|
|
17
|
-
interface DistilledInvariant {
|
|
18
|
-
invariant: string;
|
|
19
|
-
justification?: string;
|
|
20
|
-
verification?: string[];
|
|
21
|
-
applicability?: string[];
|
|
22
|
-
risks?: string[];
|
|
23
|
-
}
|
|
24
|
-
interface MemoryRecord {
|
|
25
|
-
id: string;
|
|
26
|
-
kind: MemoryKind;
|
|
27
|
-
polarity: MemoryPolarity;
|
|
28
|
-
title: string;
|
|
29
|
-
content: string;
|
|
30
|
-
tags: string[];
|
|
31
|
-
confidence: number;
|
|
32
|
-
utility: number;
|
|
33
|
-
createdAt?: string;
|
|
34
|
-
updatedAt?: string;
|
|
35
|
-
signals?: {
|
|
36
|
-
symptoms?: string[];
|
|
37
|
-
environment?: string[];
|
|
38
|
-
};
|
|
39
|
-
distilled?: {
|
|
40
|
-
invariants?: DistilledInvariant[];
|
|
41
|
-
steps?: string[];
|
|
42
|
-
verificationSteps?: string[];
|
|
43
|
-
gotchas?: string[];
|
|
44
|
-
};
|
|
45
|
-
antiPattern?: {
|
|
46
|
-
action: string;
|
|
47
|
-
whyBad: string;
|
|
48
|
-
saferAlternative?: string;
|
|
49
|
-
};
|
|
50
|
-
env?: EnvironmentFingerprint;
|
|
51
|
-
}
|
|
52
|
-
interface CaseRecord {
|
|
53
|
-
id: string;
|
|
54
|
-
title: string;
|
|
55
|
-
summary: string;
|
|
56
|
-
outcome: "resolved" | "unresolved" | "workaround";
|
|
57
|
-
symptoms: string[];
|
|
58
|
-
env: EnvironmentFingerprint;
|
|
59
|
-
resolvedByMemoryIds: string[];
|
|
60
|
-
negativeMemoryIds: string[];
|
|
61
|
-
resolvedAtIso?: string | null;
|
|
62
|
-
}
|
|
63
|
-
interface RetrieveContextArgs {
|
|
64
|
-
agentId: string;
|
|
65
|
-
prompt: string;
|
|
66
|
-
symptoms?: string[];
|
|
67
|
-
tags?: string[];
|
|
68
|
-
kinds?: MemoryKind[];
|
|
69
|
-
env?: EnvironmentFingerprint;
|
|
70
|
-
baseline?: Record<string, {
|
|
71
|
-
a: number;
|
|
72
|
-
b: number;
|
|
73
|
-
}>;
|
|
74
|
-
caseLimit?: number;
|
|
75
|
-
fixLimit?: number;
|
|
76
|
-
dontLimit?: number;
|
|
77
|
-
nowIso?: string;
|
|
78
|
-
}
|
|
79
|
-
interface BetaEdge {
|
|
80
|
-
a: number;
|
|
81
|
-
b: number;
|
|
82
|
-
/** Posterior mean a/(a+b), cached for query speed */
|
|
83
|
-
strength: number;
|
|
84
|
-
/** Evidence mass a+b, cached for query speed */
|
|
85
|
-
evidence: number;
|
|
86
|
-
updatedAt: string | null;
|
|
87
|
-
}
|
|
88
|
-
type ContextMemoryBase = Pick<MemoryRecord, "id" | "kind" | "polarity" | "title" | "content" | "tags" | "confidence" | "utility" | "updatedAt">;
|
|
89
|
-
type ContextMemorySummary = ContextMemoryBase & {
|
|
90
|
-
/** Posterior snapshot before the current run (baseline) */
|
|
91
|
-
edgeBefore?: BetaEdge;
|
|
92
|
-
/** Posterior snapshot after the current run (undefined until feedback arrives) */
|
|
93
|
-
edgeAfter?: BetaEdge;
|
|
94
|
-
};
|
|
95
|
-
interface ContextBundle {
|
|
96
|
-
sessionId: string;
|
|
97
|
-
sections: {
|
|
98
|
-
fix: ContextMemorySummary[];
|
|
99
|
-
doNotDo: ContextMemorySummary[];
|
|
100
|
-
};
|
|
101
|
-
injection: {
|
|
102
|
-
fixBlock: string;
|
|
103
|
-
doNotDoBlock: string;
|
|
104
|
-
};
|
|
105
|
-
}
|
|
106
|
-
interface FeedbackMetrics {
|
|
107
|
-
durationMs?: number;
|
|
108
|
-
quality?: number;
|
|
109
|
-
hallucinationRisk?: number;
|
|
110
|
-
toolCalls?: number;
|
|
111
|
-
verificationPassed?: boolean;
|
|
112
|
-
}
|
|
113
|
-
interface MemoryFeedback {
|
|
114
|
-
agentId: string;
|
|
115
|
-
sessionId: string;
|
|
116
|
-
usedIds: string[];
|
|
117
|
-
usefulIds: string[];
|
|
118
|
-
notUsefulIds: string[];
|
|
119
|
-
preventedErrorIds?: string[];
|
|
120
|
-
metrics?: FeedbackMetrics;
|
|
121
|
-
notes?: string;
|
|
122
|
-
}
|
|
123
|
-
interface LearningCandidate {
|
|
124
|
-
kind: MemoryKind;
|
|
125
|
-
polarity?: MemoryPolarity;
|
|
126
|
-
title: string;
|
|
127
|
-
content: string;
|
|
128
|
-
tags: string[];
|
|
129
|
-
confidence: number;
|
|
130
|
-
signals?: MemoryRecord["signals"];
|
|
131
|
-
env?: EnvironmentFingerprint;
|
|
132
|
-
triage?: {
|
|
133
|
-
symptoms: string[];
|
|
134
|
-
likelyCauses: string[];
|
|
135
|
-
verificationSteps?: string[];
|
|
136
|
-
fixSteps?: string[];
|
|
137
|
-
gotchas?: string[];
|
|
138
|
-
};
|
|
139
|
-
antiPattern?: MemoryRecord["antiPattern"];
|
|
140
|
-
}
|
|
141
|
-
interface SaveLearningRequest {
|
|
142
|
-
agentId: string;
|
|
143
|
-
sessionId?: string;
|
|
144
|
-
taskId?: string;
|
|
145
|
-
learnings: LearningCandidate[];
|
|
146
|
-
policy?: {
|
|
147
|
-
minConfidence?: number;
|
|
148
|
-
requireVerificationSteps?: boolean;
|
|
149
|
-
maxItems?: number;
|
|
150
|
-
};
|
|
151
|
-
}
|
|
152
|
-
interface SaveLearningResult {
|
|
153
|
-
saved: Array<{
|
|
154
|
-
id: string;
|
|
155
|
-
kind: MemoryKind;
|
|
156
|
-
title: string;
|
|
157
|
-
deduped: boolean;
|
|
158
|
-
}>;
|
|
159
|
-
rejected: Array<{
|
|
160
|
-
title: string;
|
|
161
|
-
reason: string;
|
|
162
|
-
}>;
|
|
163
|
-
}
|
|
164
|
-
interface MemoryServiceConfig {
|
|
165
|
-
neo4j: {
|
|
166
|
-
uri: string;
|
|
167
|
-
username: string;
|
|
168
|
-
password: string;
|
|
169
|
-
database?: string;
|
|
170
|
-
};
|
|
171
|
-
vectorIndex?: string;
|
|
172
|
-
fulltextIndex?: string;
|
|
173
|
-
halfLifeSeconds?: number;
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
declare class MemoryService {
|
|
177
|
-
private client;
|
|
178
|
-
private vectorIndex;
|
|
179
|
-
private fulltextIndex;
|
|
180
|
-
private halfLifeSeconds;
|
|
181
|
-
private cyUpsertMemory;
|
|
182
|
-
private cyUpsertCase;
|
|
183
|
-
private cyRetrieveBundle;
|
|
184
|
-
private cyFeedbackBatch;
|
|
185
|
-
private cyFeedbackCoUsed;
|
|
186
|
-
private cyGetRecallEdges;
|
|
187
|
-
constructor(cfg: MemoryServiceConfig);
|
|
188
|
-
init(): Promise<void>;
|
|
189
|
-
close(): Promise<void>;
|
|
190
|
-
private ensureEnvHash;
|
|
191
|
-
/**
|
|
192
|
-
* Save a distilled memory (semantic/procedural/episodic) with exact dedupe by contentHash.
|
|
193
|
-
* NOTE: This package intentionally does not store "full answers" as semantic/procedural.
|
|
194
|
-
*/
|
|
195
|
-
upsertMemory(l: LearningCandidate & {
|
|
196
|
-
id?: string;
|
|
197
|
-
}): Promise<{
|
|
198
|
-
id: string;
|
|
199
|
-
deduped: boolean;
|
|
200
|
-
}>;
|
|
201
|
-
/**
|
|
202
|
-
* Upsert an episodic Case (case-based reasoning) that links symptoms + env + resolved_by + negative memories.
|
|
203
|
-
*/
|
|
204
|
-
upsertCase(c: CaseRecord): Promise<string>;
|
|
205
|
-
/**
|
|
206
|
-
* Retrieve a ContextBundle with separate Fix and Do-not-do sections, using case-based reasoning.
|
|
207
|
-
* The key idea: match cases by symptoms + env similarity, then pull linked memories.
|
|
208
|
-
*/
|
|
209
|
-
retrieveContextBundle(args: RetrieveContextArgs): Promise<ContextBundle>;
|
|
210
|
-
/**
|
|
211
|
-
* Reinforce/degrade agent->memory association weights using a single batched Cypher query.
|
|
212
|
-
* This supports mid-run retrieval by making feedback cheap and frequent.
|
|
213
|
-
*/
|
|
214
|
-
feedback(fb: MemoryFeedback): Promise<void>;
|
|
215
|
-
/**
|
|
216
|
-
* Save distilled learnings discovered during a task.
|
|
217
|
-
* Enforces quality gates and stores negative memories explicitly.
|
|
218
|
-
* Automatically creates a Case if learnings have triage.symptoms.
|
|
219
|
-
*/
|
|
220
|
-
saveLearnings(req: SaveLearningRequest): Promise<SaveLearningResult>;
|
|
221
|
-
}
|
|
222
|
-
declare function createMemoryService(cfg: MemoryServiceConfig): Promise<MemoryService>;
|
|
223
|
-
|
|
224
|
-
interface Neo4jClientConfig {
|
|
225
|
-
uri: string;
|
|
226
|
-
username: string;
|
|
227
|
-
password: string;
|
|
228
|
-
database?: string;
|
|
229
|
-
}
|
|
230
|
-
declare class Neo4jClient {
|
|
231
|
-
private driver;
|
|
232
|
-
private database?;
|
|
233
|
-
constructor(cfg: Neo4jClientConfig);
|
|
234
|
-
session(mode?: "READ" | "WRITE"): Session;
|
|
235
|
-
close(): Promise<void>;
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
declare function ensureSchema(client: Neo4jClient): Promise<void>;
|
|
239
|
-
|
|
240
|
-
declare function sha256Hex(s: string): string;
|
|
241
|
-
declare function canonicaliseForHash(title: string, content: string, tags: string[]): string;
|
|
242
|
-
declare function newId(prefix: string): string;
|
|
243
|
-
declare function normaliseSymptom(s: string): string;
|
|
244
|
-
declare function envHash(env: EnvironmentFingerprint): string;
|
|
245
|
-
|
|
246
|
-
export { type BetaEdge, type CaseRecord, type ContextBundle, type ContextMemoryBase, type ContextMemorySummary, type DistilledInvariant, type EnvironmentFingerprint, type FeedbackMetrics, type LearningCandidate, type MemoryFeedback, type MemoryKind, type MemoryPolarity, type MemoryRecord, MemoryService, type MemoryServiceConfig, Neo4jClient, type Neo4jClientConfig, type RetrieveContextArgs, type SaveLearningRequest, type SaveLearningResult, canonicaliseForHash, createMemoryService, ensureSchema, envHash, newId, normaliseSymptom, sha256Hex };
|