cogmem 3.6.5 → 3.7.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/CHANGELOG.md +12 -0
- package/MEMORY_ATLAS.md +47 -10
- package/README.md +13 -10
- package/RELEASE_CHECKLIST.md +5 -4
- package/dist/agent/AgentMemoryBackend.d.ts +13 -1
- package/dist/agent/AgentMemoryBackend.js +103 -22
- package/dist/atlas/EpisodeTitleGenerator.d.ts +31 -0
- package/dist/atlas/EpisodeTitleGenerator.js +152 -0
- package/dist/atlas/FacetQueryPlanner.d.ts +31 -0
- package/dist/atlas/FacetQueryPlanner.js +188 -0
- package/dist/atlas/GraphCurator.d.ts +27 -0
- package/dist/atlas/GraphCurator.js +397 -0
- package/dist/atlas/MemoryAtlasIndexer.d.ts +3 -0
- package/dist/atlas/MemoryAtlasIndexer.js +19 -6
- package/dist/atlas/MemoryAtlasService.d.ts +4 -1
- package/dist/atlas/MemoryAtlasService.js +127 -8
- package/dist/atlas/MemoryAtlasTypes.d.ts +75 -11
- package/dist/bin/memory.js +4 -1
- package/dist/factory.js +1 -1
- package/dist/host/openclaw/AutoMemoryPluginInstaller.js +77 -8
- package/dist/mcp/server.js +1 -1
- package/dist/store/MemoryAtlasStore.d.ts +10 -1
- package/dist/store/MemoryAtlasStore.js +228 -14
- package/examples/hermes-backend/AGENTS.md +3 -3
- package/examples/hermes-backend/README.md +1 -1
- package/examples/hermes-backend/SKILL.md +7 -5
- package/examples/hermes-backend/references/operations.md +7 -5
- package/examples/openclaw-backend/AGENTS.md +3 -2
- package/examples/openclaw-backend/README.md +3 -2
- package/examples/openclaw-backend/SKILL.md +12 -7
- package/examples/openclaw-backend/references/operations.md +9 -7
- package/package.json +1 -1
|
@@ -1,8 +1,11 @@
|
|
|
1
|
+
import { MEMORY_ATLAS_PROJECTION_NAME } from '../store/MemoryAtlasStore.js';
|
|
1
2
|
import { eventTextForMemory } from '../episode/CogmemBlockStripper.js';
|
|
3
|
+
import { FacetQueryPlanner } from './FacetQueryPlanner.js';
|
|
2
4
|
import { compileAtlasQuery } from './MemoryAtlasQueryCompiler.js';
|
|
3
5
|
export class MemoryAtlasService {
|
|
4
6
|
store;
|
|
5
7
|
eventStore;
|
|
8
|
+
facetPlanner = new FacetQueryPlanner();
|
|
6
9
|
constructor(store, eventStore) {
|
|
7
10
|
this.store = store;
|
|
8
11
|
this.eventStore = eventStore;
|
|
@@ -14,13 +17,29 @@ export class MemoryAtlasService {
|
|
|
14
17
|
}
|
|
15
18
|
search(query, options) {
|
|
16
19
|
const projectId = requiredProject(options.projectId);
|
|
17
|
-
const
|
|
20
|
+
const limit = boundedLimit(options.limit);
|
|
21
|
+
const facetResult = this.searchFacetCardsWithRelaxation(query, projectId, limit, options);
|
|
22
|
+
const cards = facetResult.cards;
|
|
23
|
+
let nodes = this.store.search(boundedQuery(query), projectId, limit);
|
|
24
|
+
if (cards.length) {
|
|
25
|
+
const cardNodes = cards.map((card) => this.store.getNode(card.canonicalId, projectId)).filter((node) => Boolean(node));
|
|
26
|
+
nodes = uniqueNodes([...cardNodes, ...nodes]).slice(0, limit);
|
|
27
|
+
}
|
|
18
28
|
const withEvidence = this.attachEvidence(nodes, projectId, options);
|
|
19
|
-
|
|
29
|
+
const result = slice(projectId, withEvidence, this.edgesFor(withEvidence, projectId), query);
|
|
30
|
+
result.facets = facetsForPlan(facetResult.plan);
|
|
31
|
+
result.matchedFacets = cards.flatMap((card) => card.matchedFacets);
|
|
32
|
+
if (cards.length)
|
|
33
|
+
result.cards = this.attachCardEvidence(cards, projectId, options);
|
|
34
|
+
if (facetResult.relaxationTrace.length)
|
|
35
|
+
result.relaxationTrace = facetResult.relaxationTrace;
|
|
36
|
+
return result;
|
|
20
37
|
}
|
|
21
38
|
explore(query, options) {
|
|
22
39
|
const projectId = requiredProject(options.projectId);
|
|
23
40
|
const limit = boundedLimit(options.limit);
|
|
41
|
+
const facetResult = this.searchFacetCardsWithRelaxation(query, projectId, limit, options);
|
|
42
|
+
const cards = facetResult.cards;
|
|
24
43
|
const compiled = compileAtlasQuery(boundedQuery(query), options.now);
|
|
25
44
|
const target = this.store.resolveTargetNodeIds(projectId, compiled.text);
|
|
26
45
|
let nodes = this.store.searchFaceted(query, projectId, limit, {
|
|
@@ -28,6 +47,10 @@ export class MemoryAtlasService {
|
|
|
28
47
|
keywords: target.nodeIds.length ? compiled.keywords : compiled.tokens,
|
|
29
48
|
targetNodeIds: target.nodeIds.length ? target.nodeIds : undefined,
|
|
30
49
|
});
|
|
50
|
+
if (cards.length) {
|
|
51
|
+
const cardNodes = cards.map((card) => this.store.getNode(card.canonicalId, projectId)).filter((node) => Boolean(node));
|
|
52
|
+
nodes = uniqueNodes([...cardNodes, ...nodes]).slice(0, limit);
|
|
53
|
+
}
|
|
31
54
|
if (compiled.actionIntent) {
|
|
32
55
|
const actions = this.store.listActions(projectId, { target: compiled.target, targetEntityIds: target.entitySourceIds,
|
|
33
56
|
from: compiled.range?.from, to: compiled.range?.to, limit });
|
|
@@ -36,7 +59,15 @@ export class MemoryAtlasService {
|
|
|
36
59
|
const nodesWithEvidence = this.attachEvidence(nodes, projectId, options);
|
|
37
60
|
const edges = this.edgesFor(nodesWithEvidence, projectId);
|
|
38
61
|
const result = slice(projectId, nodesWithEvidence, edges, query);
|
|
39
|
-
result.facets = {
|
|
62
|
+
result.facets = {
|
|
63
|
+
...facetsForPlan(facetResult.plan),
|
|
64
|
+
legacy: { time: compiled.range, target: target.labels.join(', ') || compiled.target, memoryKinds: compiled.memoryKinds, keywords: compiled.keywords },
|
|
65
|
+
};
|
|
66
|
+
result.matchedFacets = cards.flatMap((card) => card.matchedFacets);
|
|
67
|
+
if (cards.length)
|
|
68
|
+
result.cards = this.attachCardEvidence(cards, projectId, options);
|
|
69
|
+
if (facetResult.relaxationTrace.length)
|
|
70
|
+
result.relaxationTrace = facetResult.relaxationTrace;
|
|
40
71
|
const hasFacet = Boolean(compiled.range || compiled.target || compiled.memoryKinds.length || compiled.tokens.length);
|
|
41
72
|
result.coldMemoryResurrected = hasFacet && nodes.some((node) => node.activation <= 0.1);
|
|
42
73
|
return result;
|
|
@@ -134,19 +165,22 @@ export class MemoryAtlasService {
|
|
|
134
165
|
pathEdges.reverse();
|
|
135
166
|
}
|
|
136
167
|
const path = found ? pathIds.map((id) => this.store.getNode(id, projectId)).filter((node) => Boolean(node)) : [];
|
|
137
|
-
return { version:
|
|
168
|
+
return { version: MEMORY_ATLAS_PROJECTION_NAME, projectId, from: start, to: target, path,
|
|
138
169
|
edges: found ? this.safeEdges(pathEdges, projectId) : [], truncated: expanded.size >= 2000 };
|
|
139
170
|
}
|
|
140
171
|
timeline(query, options) {
|
|
141
172
|
const projectId = requiredProject(options.projectId);
|
|
142
173
|
const compiled = compileAtlasQuery(boundedQuery(query), options.now);
|
|
143
174
|
const limit = boundedLimit(options.limit);
|
|
175
|
+
const facetResult = this.searchFacetCardsWithRelaxation(query, projectId, limit, options);
|
|
176
|
+
const cards = this.attachCardEvidence(facetResult.cards, projectId, options)
|
|
177
|
+
.sort((left, right) => dateKey(left) - dateKey(right) || left.displayTitle.localeCompare(right.displayTitle));
|
|
144
178
|
const target = this.store.resolveTargetNodeIds(projectId, compiled.text);
|
|
145
179
|
const nodes = this.store.searchFaceted(query, projectId, limit, {
|
|
146
180
|
from: compiled.range?.from, to: compiled.range?.to, memoryKinds: compiled.memoryKinds,
|
|
147
181
|
keywords: target.nodeIds.length ? compiled.keywords : compiled.tokens,
|
|
148
182
|
targetNodeIds: target.nodeIds.length ? target.nodeIds : undefined,
|
|
149
|
-
}).sort((left, right) => Number(
|
|
183
|
+
}).sort((left, right) => Number(left.occurredAt || 0) - Number(right.occurredAt || 0)).map((node) => {
|
|
150
184
|
const evidence = this.evidence(node.id, projectId, options.evidenceLimit, options.includeEvidence);
|
|
151
185
|
const evidenceTotal = this.store.evidenceTotal(node.id, projectId);
|
|
152
186
|
return { ...node, evidenceCount: evidenceTotal, evidenceTotal, evidenceReturned: evidence.length, evidence, neighbors: [] };
|
|
@@ -154,8 +188,28 @@ export class MemoryAtlasService {
|
|
|
154
188
|
const actions = this.store.listActions(projectId, { target: compiled.target, targetEntityIds: target.entitySourceIds,
|
|
155
189
|
from: compiled.range?.from, to: compiled.range?.to, limit: boundedLimit(options.limit) })
|
|
156
190
|
.map((action) => ({ ...action, evidence: this.evidence(action.id, projectId, options.evidenceLimit, options.includeEvidence) }));
|
|
157
|
-
return { version:
|
|
158
|
-
temporalResurrection: Boolean(compiled.range && [...nodes, ...actions].length),
|
|
191
|
+
return { version: MEMORY_ATLAS_PROJECTION_NAME, projectId, query, range: compiled.range,
|
|
192
|
+
temporalResurrection: Boolean((compiled.range || facetResult.plan.temporalIntent) && [...nodes, ...actions, ...cards].length),
|
|
193
|
+
nodes, actions, cards,
|
|
194
|
+
groupedByIssue: groupCardsByIssue(cards),
|
|
195
|
+
relaxationTrace: facetResult.relaxationTrace.length ? facetResult.relaxationTrace : undefined,
|
|
196
|
+
facets: facetsForPlan(facetResult.plan),
|
|
197
|
+
matchedFacets: cards.flatMap((card) => card.matchedFacets),
|
|
198
|
+
warnings: [] };
|
|
199
|
+
}
|
|
200
|
+
searchFacetCardsWithRelaxation(query, projectId, limit, options) {
|
|
201
|
+
let plan = this.facetPlanner.plan(boundedQuery(query), { projectId, now: options.now });
|
|
202
|
+
const relaxationTrace = [];
|
|
203
|
+
let cards = plan.facets.length ? this.store.searchCanonicalEpisodeCards(projectId, plan, limit) : [];
|
|
204
|
+
if (!cards.length && plan.facets.length) {
|
|
205
|
+
const relaxed = relaxFacetPlan(plan);
|
|
206
|
+
if (relaxed) {
|
|
207
|
+
plan = relaxed.plan;
|
|
208
|
+
cards = this.store.searchCanonicalEpisodeCards(projectId, relaxed.plan, limit);
|
|
209
|
+
relaxationTrace.push(...relaxed.trace);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
return { plan, cards, relaxationTrace };
|
|
159
213
|
}
|
|
160
214
|
attachEvidence(nodes, projectId, options) {
|
|
161
215
|
return nodes.map((node) => {
|
|
@@ -164,6 +218,17 @@ export class MemoryAtlasService {
|
|
|
164
218
|
return { ...node, evidenceCount: evidenceTotal, evidenceTotal, evidenceReturned: evidence.length, evidence };
|
|
165
219
|
});
|
|
166
220
|
}
|
|
221
|
+
attachCardEvidence(cards, projectId, options) {
|
|
222
|
+
return cards.map((card) => {
|
|
223
|
+
const evidence = this.evidence(card.canonicalId, projectId, options.evidenceLimit, options.includeEvidence);
|
|
224
|
+
return {
|
|
225
|
+
...card,
|
|
226
|
+
sourceLocator: evidence[0]?.sourceLocator ?? card.sourceLocator,
|
|
227
|
+
evidenceTotal: Math.max(card.evidenceTotal, this.store.evidenceTotal(card.canonicalId, projectId)),
|
|
228
|
+
evidenceReturned: evidence.length,
|
|
229
|
+
};
|
|
230
|
+
});
|
|
231
|
+
}
|
|
167
232
|
evidence(nodeId, projectId, requested, includeExcerpt) {
|
|
168
233
|
const limit = Math.max(1, Math.min(requested ?? 2, 10));
|
|
169
234
|
return this.store.evidenceIds(nodeId, projectId, limit).flatMap((eventId) => {
|
|
@@ -229,7 +294,61 @@ function chunked(values, size) {
|
|
|
229
294
|
chunks.push(values.slice(index, index + size));
|
|
230
295
|
return chunks;
|
|
231
296
|
}
|
|
232
|
-
function slice(projectId, nodes, edges, query) { return { version:
|
|
297
|
+
function slice(projectId, nodes, edges, query) { return { version: MEMORY_ATLAS_PROJECTION_NAME, projectId, query, nodes, edges, nextActions: nodes.slice(0, 5).map((node) => ({ label: `Inspect ${node.label}`, tool: 'cogmem_graph_node', args: { id: node.id, projectId } })), warnings: [] }; }
|
|
298
|
+
function facetsForPlan(plan) {
|
|
299
|
+
return {
|
|
300
|
+
planner: {
|
|
301
|
+
intent: plan.intent,
|
|
302
|
+
operator: plan.operator,
|
|
303
|
+
temporalIntent: plan.temporalIntent,
|
|
304
|
+
groupBy: plan.groupBy,
|
|
305
|
+
exactness: plan.exactness,
|
|
306
|
+
keywords: plan.keywords,
|
|
307
|
+
facets: plan.facets.map((facet) => ({
|
|
308
|
+
type: facet.type,
|
|
309
|
+
value: facet.value,
|
|
310
|
+
label: facet.label,
|
|
311
|
+
nodeId: facet.nodeId || `${facet.type}:${facet.value}`,
|
|
312
|
+
relation: facet.relation || 'MATCHES',
|
|
313
|
+
})),
|
|
314
|
+
},
|
|
315
|
+
};
|
|
316
|
+
}
|
|
317
|
+
function dateKey(card) {
|
|
318
|
+
if (card.localDate && /^\d{4}-\d{2}-\d{2}$/u.test(card.localDate)) {
|
|
319
|
+
return Date.parse(`${card.localDate}T00:00:00.000Z`);
|
|
320
|
+
}
|
|
321
|
+
return Number.POSITIVE_INFINITY;
|
|
322
|
+
}
|
|
323
|
+
function groupCardsByIssue(cards) {
|
|
324
|
+
const groups = new Map();
|
|
325
|
+
for (const card of cards) {
|
|
326
|
+
const key = card.issueType || 'unclassified';
|
|
327
|
+
groups.set(key, [...(groups.get(key) || []), card]);
|
|
328
|
+
}
|
|
329
|
+
return Array.from(groups.entries()).map(([issueType, group]) => ({ issueType, cards: group }));
|
|
330
|
+
}
|
|
331
|
+
function relaxFacetPlan(plan) {
|
|
332
|
+
const dayFacet = plan.facets.find((facet) => facet.type === 'time' && facet.granularity === 'day');
|
|
333
|
+
if (!dayFacet)
|
|
334
|
+
return null;
|
|
335
|
+
const monthValue = dayFacet.value.slice(0, 7);
|
|
336
|
+
return {
|
|
337
|
+
plan: {
|
|
338
|
+
...plan,
|
|
339
|
+
exactness: 'relaxed',
|
|
340
|
+
facets: plan.facets.map((facet) => facet === dayFacet ? {
|
|
341
|
+
...facet,
|
|
342
|
+
value: monthValue,
|
|
343
|
+
label: monthValue,
|
|
344
|
+
nodeId: facet.nodeId?.replace(dayFacet.value, monthValue),
|
|
345
|
+
relation: 'OCCURRED_IN',
|
|
346
|
+
granularity: 'month',
|
|
347
|
+
} : facet),
|
|
348
|
+
},
|
|
349
|
+
trace: [{ from: dayFacet.value, to: monthValue, reason: 'exact day facet had no canonical episode match; relaxed to parent month' }],
|
|
350
|
+
};
|
|
351
|
+
}
|
|
233
352
|
function atlasSourceLocator(event, projectId) {
|
|
234
353
|
const project = projectId || event.projectId;
|
|
235
354
|
const projectArg = project ? ` --project ${cliArg(project)}` : '';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type MemoryAtlasNodeType = 'project' | 'topic' | 'entity' | 'cluster' | 'episode' | 'belief' | 'action' | 'time' | 'event';
|
|
1
|
+
export type MemoryAtlasNodeType = 'project' | 'topic' | 'issue' | 'entity' | 'session' | 'thread' | 'memoryKind' | 'actionKind' | 'cluster' | 'episode' | 'raw_event' | 'belief' | 'action' | 'time' | 'event' | 'decision' | 'correction';
|
|
2
2
|
export interface MemoryAtlasEvidence {
|
|
3
3
|
eventId: string;
|
|
4
4
|
globalSeq?: number;
|
|
@@ -39,6 +39,48 @@ export interface MemoryAtlasNode {
|
|
|
39
39
|
/** Bounded first-hop raw evidence locators for agent-facing graph search/explore responses. */
|
|
40
40
|
evidence?: MemoryAtlasEvidence[];
|
|
41
41
|
}
|
|
42
|
+
export interface MemoryAtlasMatchedFacet {
|
|
43
|
+
type: 'time' | 'topic' | 'issue' | 'entity' | 'session' | 'thread' | 'memoryKind' | 'actionKind';
|
|
44
|
+
value: string;
|
|
45
|
+
label: string;
|
|
46
|
+
nodeId: string;
|
|
47
|
+
relation: string;
|
|
48
|
+
}
|
|
49
|
+
export interface MemoryAtlasMatchedPath {
|
|
50
|
+
facet: MemoryAtlasMatchedFacet;
|
|
51
|
+
via: string[];
|
|
52
|
+
relation: string;
|
|
53
|
+
confidence: number;
|
|
54
|
+
}
|
|
55
|
+
export interface MemoryAtlasRelatedCard {
|
|
56
|
+
canonicalId: string;
|
|
57
|
+
displayTitle: string;
|
|
58
|
+
reason: string;
|
|
59
|
+
matchedFacets?: MemoryAtlasMatchedFacet[];
|
|
60
|
+
}
|
|
61
|
+
export interface MemoryAtlasCard {
|
|
62
|
+
canonicalId: string;
|
|
63
|
+
nodeType: MemoryAtlasNodeType;
|
|
64
|
+
displayTitle: string;
|
|
65
|
+
oneLineSummary?: string;
|
|
66
|
+
matchedFacets: MemoryAtlasMatchedFacet[];
|
|
67
|
+
matchedPaths: MemoryAtlasMatchedPath[];
|
|
68
|
+
parentTopics: string[];
|
|
69
|
+
issueType?: string;
|
|
70
|
+
eventKind?: string;
|
|
71
|
+
localDate?: string;
|
|
72
|
+
whyMatched: string;
|
|
73
|
+
relatedButNotSelected: MemoryAtlasRelatedCard[];
|
|
74
|
+
sourceLocator?: MemoryAtlasEvidence['sourceLocator'];
|
|
75
|
+
evidenceEventIds: string[];
|
|
76
|
+
evidenceTotal: number;
|
|
77
|
+
evidenceReturned: number;
|
|
78
|
+
}
|
|
79
|
+
export interface MemoryAtlasRelaxationStep {
|
|
80
|
+
from: string;
|
|
81
|
+
to: string;
|
|
82
|
+
reason: string;
|
|
83
|
+
}
|
|
42
84
|
export interface MemoryAtlasEdge {
|
|
43
85
|
source: string;
|
|
44
86
|
relation: string;
|
|
@@ -52,7 +94,7 @@ export interface MemoryAtlasNextAction {
|
|
|
52
94
|
args: Record<string, unknown>;
|
|
53
95
|
}
|
|
54
96
|
export interface MemoryAtlasSlice {
|
|
55
|
-
version: 'memory_atlas.
|
|
97
|
+
version: 'memory_atlas.v2';
|
|
56
98
|
projectId: string;
|
|
57
99
|
query?: string;
|
|
58
100
|
nodes: MemoryAtlasNode[];
|
|
@@ -60,15 +102,29 @@ export interface MemoryAtlasSlice {
|
|
|
60
102
|
nextActions: MemoryAtlasNextAction[];
|
|
61
103
|
warnings: string[];
|
|
62
104
|
facets?: {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
105
|
+
planner?: {
|
|
106
|
+
intent: string;
|
|
107
|
+
operator: string;
|
|
108
|
+
temporalIntent?: string;
|
|
109
|
+
groupBy?: string;
|
|
110
|
+
exactness: string;
|
|
111
|
+
facets: MemoryAtlasMatchedFacet[];
|
|
112
|
+
keywords: string[];
|
|
113
|
+
};
|
|
114
|
+
legacy?: {
|
|
115
|
+
time?: {
|
|
116
|
+
from: number;
|
|
117
|
+
to: number;
|
|
118
|
+
label: string;
|
|
119
|
+
};
|
|
120
|
+
target?: string;
|
|
121
|
+
memoryKinds: string[];
|
|
122
|
+
keywords: string[];
|
|
67
123
|
};
|
|
68
|
-
target?: string;
|
|
69
|
-
memoryKinds: string[];
|
|
70
|
-
keywords: string[];
|
|
71
124
|
};
|
|
125
|
+
matchedFacets?: MemoryAtlasMatchedFacet[];
|
|
126
|
+
cards?: MemoryAtlasCard[];
|
|
127
|
+
relaxationTrace?: MemoryAtlasRelaxationStep[];
|
|
72
128
|
coldMemoryResurrected?: boolean;
|
|
73
129
|
}
|
|
74
130
|
export interface MemoryAtlasNodeDetail extends MemoryAtlasNode {
|
|
@@ -87,7 +143,7 @@ export interface MemoryAtlasAction {
|
|
|
87
143
|
evidence: MemoryAtlasEvidence[];
|
|
88
144
|
}
|
|
89
145
|
export interface MemoryAtlasTimelineResult {
|
|
90
|
-
version: 'memory_atlas.
|
|
146
|
+
version: 'memory_atlas.v2';
|
|
91
147
|
projectId: string;
|
|
92
148
|
query: string;
|
|
93
149
|
range?: {
|
|
@@ -98,10 +154,18 @@ export interface MemoryAtlasTimelineResult {
|
|
|
98
154
|
temporalResurrection: boolean;
|
|
99
155
|
nodes: MemoryAtlasNodeDetail[];
|
|
100
156
|
actions: MemoryAtlasAction[];
|
|
157
|
+
cards?: MemoryAtlasCard[];
|
|
158
|
+
groupedByIssue?: Array<{
|
|
159
|
+
issueType: string;
|
|
160
|
+
cards: MemoryAtlasCard[];
|
|
161
|
+
}>;
|
|
162
|
+
relaxationTrace?: MemoryAtlasRelaxationStep[];
|
|
163
|
+
facets?: MemoryAtlasSlice['facets'];
|
|
164
|
+
matchedFacets?: MemoryAtlasMatchedFacet[];
|
|
101
165
|
warnings: string[];
|
|
102
166
|
}
|
|
103
167
|
export interface MemoryAtlasPathResult {
|
|
104
|
-
version: 'memory_atlas.
|
|
168
|
+
version: 'memory_atlas.v2';
|
|
105
169
|
projectId: string;
|
|
106
170
|
from: string;
|
|
107
171
|
to: string;
|
package/dist/bin/memory.js
CHANGED
|
@@ -573,6 +573,9 @@ function runRecall(kernel, args) {
|
|
|
573
573
|
decisionTrace: result.decisionTrace,
|
|
574
574
|
strategyCapsule,
|
|
575
575
|
narrative: result.narrative,
|
|
576
|
+
atlasCards: result.atlasCards,
|
|
577
|
+
relatedButNotSelected: result.relatedButNotSelected,
|
|
578
|
+
relaxationTrace: result.relaxationTrace,
|
|
576
579
|
items: result.items,
|
|
577
580
|
};
|
|
578
581
|
}
|
|
@@ -881,7 +884,7 @@ function printHuman(command, payload) {
|
|
|
881
884
|
return;
|
|
882
885
|
}
|
|
883
886
|
if (command === 'graph' || command.startsWith('graph-')) {
|
|
884
|
-
console.log(`memoryAtlas: ${payload.version || 'memory_atlas.
|
|
887
|
+
console.log(`memoryAtlas: ${payload.version || 'memory_atlas.v2'} project=${payload.projectId || 'unknown'}`);
|
|
885
888
|
const rows = Array.isArray(payload.nodes) ? payload.nodes
|
|
886
889
|
: Array.isArray(payload.path) ? payload.path
|
|
887
890
|
: Array.isArray(payload.actions) ? payload.actions
|
package/dist/factory.js
CHANGED
|
@@ -83,7 +83,7 @@ import { SqliteVecStore } from './store/SqliteVecStore.js';
|
|
|
83
83
|
import { VectorStore } from './store/VectorStore.js';
|
|
84
84
|
import { config } from './utils/Config.js';
|
|
85
85
|
import { KernelRunningError, SnapshotExporter, SnapshotImporter, } from './snapshot/index.js';
|
|
86
|
-
const CORE_VERSION = '3.
|
|
86
|
+
const CORE_VERSION = '3.7.0';
|
|
87
87
|
const LATEST_SCHEMA_VERSION = 27;
|
|
88
88
|
export class MemoryKernel {
|
|
89
89
|
options;
|
|
@@ -5,7 +5,7 @@ import { basename, dirname, join, resolve } from 'node:path';
|
|
|
5
5
|
import { fileURLToPath } from 'node:url';
|
|
6
6
|
import { resolveCogmemConfigPath } from '../../config/CogmemConfig.js';
|
|
7
7
|
const PLUGIN_ID = 'cogmem-auto-memory';
|
|
8
|
-
const PLUGIN_VERSION = '0.
|
|
8
|
+
const PLUGIN_VERSION = '0.7.0';
|
|
9
9
|
function defaultPublicEntrypoint() {
|
|
10
10
|
return join(resolve(dirname(fileURLToPath(import.meta.url)), '../..'), 'public.js');
|
|
11
11
|
}
|
|
@@ -992,7 +992,7 @@ function audit(config, record) {
|
|
|
992
992
|
const plugin = {
|
|
993
993
|
id: PLUGIN_ID,
|
|
994
994
|
name: 'CogMem Auto Memory',
|
|
995
|
-
version: '
|
|
995
|
+
version: '${PLUGIN_VERSION}',
|
|
996
996
|
register(api) {
|
|
997
997
|
if (!api || typeof api.on !== 'function') {
|
|
998
998
|
throw new Error('OpenClaw plugin API missing api.on');
|
|
@@ -1338,10 +1338,32 @@ async function recallPayload(input, config, kernel, memory, formatStrategyContex
|
|
|
1338
1338
|
maxMemoryRatio: Number(config.contextMemoryMaxRatio || 0.25), strategy: strategyCapsule,
|
|
1339
1339
|
candidates: result.items.map(contextCandidateFromRecallItem),
|
|
1340
1340
|
});
|
|
1341
|
-
|
|
1341
|
+
let plannedResult = activationPlan
|
|
1342
1342
|
? { ...result, items: activationPlan.selected.map((candidate) => candidate.recallItem) }
|
|
1343
1343
|
: result;
|
|
1344
|
+
let activationReceipt = activationPlan && activationPlan.receipt;
|
|
1345
|
+
if (activationPlan && Array.isArray(result.items)) {
|
|
1346
|
+
const selectedIds = new Set(plannedResult.items.map((item) => item && item.id).filter(Boolean));
|
|
1347
|
+
const strictFacetItem = (result.decisionTrace && result.decisionTrace.selectedLane === 'facet_graph_raw_ledger')
|
|
1348
|
+
? result.items.find((item) => item && item.canonicalId && Array.isArray(item.matchedFacets) && item.matchedFacets.length > 0)
|
|
1349
|
+
: undefined;
|
|
1350
|
+
if (strictFacetItem && !selectedIds.has(strictFacetItem.id)) {
|
|
1351
|
+
plannedResult = { ...plannedResult, items: [strictFacetItem, ...plannedResult.items].slice(0, Number(config.limit || 3)) };
|
|
1352
|
+
activationReceipt = {
|
|
1353
|
+
...(activationReceipt || {}),
|
|
1354
|
+
facetGraphRetained: true,
|
|
1355
|
+
retainedCanonicalId: strictFacetItem.canonicalId,
|
|
1356
|
+
matchedFacets: strictFacetItem.matchedFacets,
|
|
1357
|
+
reason: 'strict_facet_match_must_not_be_silently_dropped',
|
|
1358
|
+
};
|
|
1359
|
+
}
|
|
1360
|
+
}
|
|
1344
1361
|
const anchorItem = plannedResult.items.find((item) => item && item.sourceAnchor && item.sourceAnchor.eventId);
|
|
1362
|
+
const selectedCanonicalIds = new Set(plannedResult.items.map((item) => item && item.canonicalId).filter(Boolean));
|
|
1363
|
+
const selectedEpisodeCards = Array.isArray(result.atlasCards)
|
|
1364
|
+
? result.atlasCards.filter((card) => card && selectedCanonicalIds.has(card.canonicalId))
|
|
1365
|
+
: [];
|
|
1366
|
+
plannedResult = { ...plannedResult, atlasCards: selectedEpisodeCards };
|
|
1345
1367
|
const recallContext = formatRecallContext(plannedResult, config);
|
|
1346
1368
|
return {
|
|
1347
1369
|
context: recallContext ? (strategyCapsule ? formatStrategyContext(strategyCapsule) + '\n\n' : '') + recallContext : '',
|
|
@@ -1349,7 +1371,9 @@ async function recallPayload(input, config, kernel, memory, formatStrategyContex
|
|
|
1349
1371
|
recallMode: result.recallMode, fallbackUsed: result.fallbackUsed, intent: input.intent || 'memory_recall',
|
|
1350
1372
|
anchorEventId: anchorItem && anchorItem.sourceAnchor && anchorItem.sourceAnchor.eventId,
|
|
1351
1373
|
anchorText: anchorItem && anchorItem.text, queryPlan: result.queryPlan, decisionTrace: result.decisionTrace,
|
|
1352
|
-
|
|
1374
|
+
atlasCards: result.atlasCards, selectedEpisodeCards,
|
|
1375
|
+
relatedButNotSelected: result.relatedButNotSelected, relaxationTrace: result.relaxationTrace,
|
|
1376
|
+
activationReceipt, strategyCapsule,
|
|
1353
1377
|
strategyReplanned: replan.replanned, strategyReplanReason: replan.reason,
|
|
1354
1378
|
recallLatencyMs: Date.now() - recallStartedAt,
|
|
1355
1379
|
};
|
|
@@ -1394,16 +1418,27 @@ function stripCogmemRecallBlocks(text) {
|
|
|
1394
1418
|
|
|
1395
1419
|
function formatAtlasContext(result, maxChars) {
|
|
1396
1420
|
const nodes = Array.isArray(result && result.nodes) ? result.nodes : [];
|
|
1397
|
-
|
|
1421
|
+
const cards = Array.isArray(result && result.cards) ? result.cards : [];
|
|
1422
|
+
if (!nodes.length && !cards.length) return '';
|
|
1398
1423
|
const edges = Array.isArray(result && result.edges) ? result.edges : [];
|
|
1399
1424
|
const actions = Array.isArray(result && result.nextActions) ? result.nextActions : [];
|
|
1400
1425
|
const nodeDetails = Array.isArray(result && result.nodeDetails) ? result.nodeDetails : [];
|
|
1401
1426
|
const lines = [
|
|
1402
|
-
'<COGMEM_MEMORY_ATLAS version="memory_atlas.
|
|
1427
|
+
'<COGMEM_MEMORY_ATLAS version="memory_atlas.v2" volatile="true" persistence="forbidden" evidence_authority="raw_event_ids_only">',
|
|
1403
1428
|
'Bounded navigation map; use it to choose nodes and paths, not as durable evidence.',
|
|
1404
|
-
'Matched facets: ' + safeAtlasText(JSON.stringify(result.facets || {}),
|
|
1429
|
+
'Matched facets: ' + safeAtlasText(JSON.stringify(result.facets && result.facets.planner || result.facets || {}), 1400),
|
|
1405
1430
|
'Cold memory resurrected: ' + String(result.coldMemoryResurrected === true),
|
|
1406
1431
|
'',
|
|
1432
|
+
'Selected memory cards:',
|
|
1433
|
+
...cards.slice(0, 8).map((card) => '- ' + formatAtlasCard(card)),
|
|
1434
|
+
...(cards.length ? [
|
|
1435
|
+
'',
|
|
1436
|
+
'Related but not selected:',
|
|
1437
|
+
...cards.flatMap((card) => Array.isArray(card.relatedButNotSelected) ? card.relatedButNotSelected : [])
|
|
1438
|
+
.slice(0, 8)
|
|
1439
|
+
.map((card) => '- ' + safeAtlasText(card.displayTitle, 160) + ' [' + safeAtlasText(card.reason, 160) + ']'),
|
|
1440
|
+
'',
|
|
1441
|
+
] : []),
|
|
1407
1442
|
'Nodes:',
|
|
1408
1443
|
...nodes.slice(0, 30).map((node) => '- ' + JSON.stringify({
|
|
1409
1444
|
id: safeAtlasText(node.id, 500), type: safeAtlasText(node.nodeType, 80),
|
|
@@ -1695,6 +1730,9 @@ function compactRecallItems(items, config) {
|
|
|
1695
1730
|
projectId: item.projectId,
|
|
1696
1731
|
sourceAnchor: item.sourceAnchor,
|
|
1697
1732
|
whyMatched: item.whyMatched,
|
|
1733
|
+
canonicalId: item.canonicalId,
|
|
1734
|
+
displayTitle: item.displayTitle,
|
|
1735
|
+
matchedFacets: item.matchedFacets,
|
|
1698
1736
|
}));
|
|
1699
1737
|
}
|
|
1700
1738
|
|
|
@@ -1731,6 +1769,15 @@ function formatRecallContext(result, config) {
|
|
|
1731
1769
|
if (result.decisionTrace) {
|
|
1732
1770
|
lines.push('recallDecision=' + formatRecallDecision(result.decisionTrace));
|
|
1733
1771
|
}
|
|
1772
|
+
if (Array.isArray(result.atlasCards) && result.atlasCards.length) {
|
|
1773
|
+
lines.push('selectedMemoryCards=' + result.atlasCards.slice(0, Number(config.memoryContextMaxItems || config.limit || 3)).map(formatAtlasCard).join(' | '));
|
|
1774
|
+
}
|
|
1775
|
+
if (Array.isArray(result.relaxationTrace) && result.relaxationTrace.length) {
|
|
1776
|
+
lines.push('relaxationTrace=' + result.relaxationTrace.map((step) => step.from + ' -> ' + step.to + ' (' + step.reason + ')').join(' | '));
|
|
1777
|
+
}
|
|
1778
|
+
if (Array.isArray(result.relatedButNotSelected) && result.relatedButNotSelected.length) {
|
|
1779
|
+
lines.push('relatedButNotSelected=' + result.relatedButNotSelected.slice(0, 4).map((item) => item.displayTitle + ' [' + item.reason + ']').join(' | '));
|
|
1780
|
+
}
|
|
1734
1781
|
lines.push('');
|
|
1735
1782
|
if (result.narrative && result.narrative.summary) {
|
|
1736
1783
|
lines.push(result.narrative.summary);
|
|
@@ -1748,7 +1795,11 @@ function formatRecallContext(result, config) {
|
|
|
1748
1795
|
+ (item.sourceAnchor.sessionId ? '; session=' + item.sourceAnchor.sessionId : '')
|
|
1749
1796
|
+ (item.sourceAnchor.role ? '; role=' + item.sourceAnchor.role : '') : '';
|
|
1750
1797
|
const why = item.whyMatched ? '; whyMatched=' + item.whyMatched : '';
|
|
1751
|
-
|
|
1798
|
+
const canonical = item.canonicalId ? '; canonicalId=' + item.canonicalId : '';
|
|
1799
|
+
const matchedFacets = Array.isArray(item.matchedFacets) && item.matchedFacets.length
|
|
1800
|
+
? '; matchedFacets=' + item.matchedFacets.map((facet) => facet.type + ':' + facet.value).join(',')
|
|
1801
|
+
: '';
|
|
1802
|
+
lines.push(' sourceType=' + sourceType + '; confidence=' + confidence + '; canAnswerExactQuote=' + quote + canonical + matchedFacets + anchor + why);
|
|
1752
1803
|
if (item.sourceContext && item.sourceContext.event) {
|
|
1753
1804
|
const anchorEvent = item.sourceContext.event;
|
|
1754
1805
|
const anchorFormatted = formatContextEvent(anchorEvent, Math.min(220, sourceWindowMaxChars));
|
|
@@ -1801,6 +1852,24 @@ function formatRecallDecision(trace) {
|
|
|
1801
1852
|
+ ',raw:' + Number(counts.rawLedger || 0);
|
|
1802
1853
|
}
|
|
1803
1854
|
|
|
1855
|
+
function formatAtlasCard(card) {
|
|
1856
|
+
const facets = Array.isArray(card && card.matchedFacets)
|
|
1857
|
+
? card.matchedFacets.map((facet) => facet.type + ':' + facet.value).join(',')
|
|
1858
|
+
: '';
|
|
1859
|
+
const paths = Array.isArray(card && card.matchedPaths)
|
|
1860
|
+
? card.matchedPaths.map((path) => path.relation + '@' + (path.facet && path.facet.nodeId || 'facet')).slice(0, 6).join(',')
|
|
1861
|
+
: '';
|
|
1862
|
+
const locator = card && card.sourceLocator && card.sourceLocator.command ? '; sourceLocator=' + card.sourceLocator.command : '';
|
|
1863
|
+
const why = card && card.whyMatched ? '; whyMatched=' + truncateLineWithMeta(card.whyMatched, 180).text : '';
|
|
1864
|
+
return (card && card.canonicalId || 'episode:unknown')
|
|
1865
|
+
+ '; title=' + truncateLineWithMeta(card && card.displayTitle, 120).text
|
|
1866
|
+
+ '; summary=' + truncateLineWithMeta(card && card.oneLineSummary, 180).text
|
|
1867
|
+
+ (facets ? '; matchedFacets=' + facets : '')
|
|
1868
|
+
+ (paths ? '; matchedPaths=' + paths : '')
|
|
1869
|
+
+ why
|
|
1870
|
+
+ locator;
|
|
1871
|
+
}
|
|
1872
|
+
|
|
1804
1873
|
function clampRecallContext(text, maxChars) {
|
|
1805
1874
|
const closingTag = '</COGMEM_RECALL_CONTEXT>';
|
|
1806
1875
|
if (text.length <= maxChars) return text;
|
package/dist/mcp/server.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import type Database from 'bun:sqlite';
|
|
2
|
-
import type {
|
|
2
|
+
import type { FacetQueryPlan } from '../atlas/FacetQueryPlanner.js';
|
|
3
|
+
import type { MemoryAtlasAction, MemoryAtlasCard, MemoryAtlasEdge, MemoryAtlasNode, MemoryAtlasRelatedCard } from '../atlas/MemoryAtlasTypes.js';
|
|
4
|
+
export declare const MEMORY_ATLAS_PROJECTION_NAME = "memory_atlas.v2";
|
|
5
|
+
export declare const MEMORY_ATLAS_PROJECTION_SCHEMA_VERSION = "3.7.0";
|
|
3
6
|
export declare class MemoryAtlasStore {
|
|
4
7
|
readonly db: Database;
|
|
5
8
|
constructor(db: Database);
|
|
@@ -18,6 +21,9 @@ export declare class MemoryAtlasStore {
|
|
|
18
21
|
keywords?: string[];
|
|
19
22
|
targetNodeIds?: string[];
|
|
20
23
|
}): MemoryAtlasNode[];
|
|
24
|
+
searchCanonicalEpisodeCards(projectId: string, plan: FacetQueryPlan, limit: number): MemoryAtlasCard[];
|
|
25
|
+
relatedEpisodeCards(projectId: string, canonicalId: string, selectedIds: Set<string>, limit: number): MemoryAtlasRelatedCard[];
|
|
26
|
+
private topicRelatedCardsForPlan;
|
|
21
27
|
resolveTargetNodeIds(projectId: string, query: string): {
|
|
22
28
|
nodeIds: string[];
|
|
23
29
|
entitySourceIds: string[];
|
|
@@ -56,5 +62,8 @@ export declare class MemoryAtlasStore {
|
|
|
56
62
|
countDocuments(projectId?: string): number;
|
|
57
63
|
private refreshFtsNode;
|
|
58
64
|
private topicRelationEdges;
|
|
65
|
+
private episodeEdgesForFacet;
|
|
66
|
+
private episodeRows;
|
|
67
|
+
private cardFromEpisodeRow;
|
|
59
68
|
}
|
|
60
69
|
//# sourceMappingURL=MemoryAtlasStore.d.ts.map
|