cogmem 3.6.4 → 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 +24 -0
- package/MEMORY_ATLAS.md +47 -10
- package/README.md +36 -13
- package/RELEASE_CHECKLIST.md +7 -4
- package/dist/agent/AgentMemoryBackend.d.ts +19 -2
- package/dist/agent/AgentMemoryBackend.js +134 -3
- package/dist/agent/AgentRecallQueryCompiler.d.ts +1 -1
- package/dist/agent/AgentRecallQueryCompiler.js +12 -0
- 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 +5 -1
- package/dist/atlas/MemoryAtlasService.js +165 -12
- package/dist/atlas/MemoryAtlasTypes.d.ts +89 -11
- package/dist/bin/connect.js +85 -13
- package/dist/bin/memory.js +221 -18
- package/dist/factory.d.ts +2 -0
- package/dist/factory.js +36 -18
- package/dist/host/openclaw/AutoMemoryPluginInstaller.js +83 -10
- package/dist/mcp/server.js +1 -1
- package/dist/store/EventStore.d.ts +6 -0
- package/dist/store/EventStore.js +28 -2
- package/dist/store/MemoryAtlasStore.d.ts +10 -1
- package/dist/store/MemoryAtlasStore.js +228 -14
- package/dist/types/index.d.ts +3 -0
- package/examples/hermes-backend/AGENTS.md +11 -5
- package/examples/hermes-backend/README.md +5 -3
- package/examples/hermes-backend/SKILL.md +28 -5
- package/examples/hermes-backend/references/operations.md +16 -6
- package/examples/openclaw-backend/AGENTS.md +9 -3
- package/examples/openclaw-backend/README.md +9 -3
- package/examples/openclaw-backend/SKILL.md +23 -10
- package/examples/openclaw-backend/references/operations.md +21 -8
- 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,12 +17,29 @@ export class MemoryAtlasService {
|
|
|
14
17
|
}
|
|
15
18
|
search(query, options) {
|
|
16
19
|
const projectId = requiredProject(options.projectId);
|
|
17
|
-
const
|
|
18
|
-
|
|
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
|
+
}
|
|
28
|
+
const withEvidence = this.attachEvidence(nodes, projectId, options);
|
|
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;
|
|
19
37
|
}
|
|
20
38
|
explore(query, options) {
|
|
21
39
|
const projectId = requiredProject(options.projectId);
|
|
22
40
|
const limit = boundedLimit(options.limit);
|
|
41
|
+
const facetResult = this.searchFacetCardsWithRelaxation(query, projectId, limit, options);
|
|
42
|
+
const cards = facetResult.cards;
|
|
23
43
|
const compiled = compileAtlasQuery(boundedQuery(query), options.now);
|
|
24
44
|
const target = this.store.resolveTargetNodeIds(projectId, compiled.text);
|
|
25
45
|
let nodes = this.store.searchFaceted(query, projectId, limit, {
|
|
@@ -27,14 +47,27 @@ export class MemoryAtlasService {
|
|
|
27
47
|
keywords: target.nodeIds.length ? compiled.keywords : compiled.tokens,
|
|
28
48
|
targetNodeIds: target.nodeIds.length ? target.nodeIds : undefined,
|
|
29
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
|
+
}
|
|
30
54
|
if (compiled.actionIntent) {
|
|
31
55
|
const actions = this.store.listActions(projectId, { target: compiled.target, targetEntityIds: target.entitySourceIds,
|
|
32
56
|
from: compiled.range?.from, to: compiled.range?.to, limit });
|
|
33
57
|
nodes = uniqueNodes([...actions.map((action) => this.store.getNode(action.id, projectId)).filter((node) => Boolean(node)), ...nodes]).slice(0, limit);
|
|
34
58
|
}
|
|
35
|
-
const
|
|
36
|
-
const
|
|
37
|
-
result
|
|
59
|
+
const nodesWithEvidence = this.attachEvidence(nodes, projectId, options);
|
|
60
|
+
const edges = this.edgesFor(nodesWithEvidence, projectId);
|
|
61
|
+
const result = slice(projectId, nodesWithEvidence, edges, query);
|
|
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;
|
|
38
71
|
const hasFacet = Boolean(compiled.range || compiled.target || compiled.memoryKinds.length || compiled.tokens.length);
|
|
39
72
|
result.coldMemoryResurrected = hasFacet && nodes.some((node) => node.activation <= 0.1);
|
|
40
73
|
return result;
|
|
@@ -132,19 +165,22 @@ export class MemoryAtlasService {
|
|
|
132
165
|
pathEdges.reverse();
|
|
133
166
|
}
|
|
134
167
|
const path = found ? pathIds.map((id) => this.store.getNode(id, projectId)).filter((node) => Boolean(node)) : [];
|
|
135
|
-
return { version:
|
|
168
|
+
return { version: MEMORY_ATLAS_PROJECTION_NAME, projectId, from: start, to: target, path,
|
|
136
169
|
edges: found ? this.safeEdges(pathEdges, projectId) : [], truncated: expanded.size >= 2000 };
|
|
137
170
|
}
|
|
138
171
|
timeline(query, options) {
|
|
139
172
|
const projectId = requiredProject(options.projectId);
|
|
140
173
|
const compiled = compileAtlasQuery(boundedQuery(query), options.now);
|
|
141
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));
|
|
142
178
|
const target = this.store.resolveTargetNodeIds(projectId, compiled.text);
|
|
143
179
|
const nodes = this.store.searchFaceted(query, projectId, limit, {
|
|
144
180
|
from: compiled.range?.from, to: compiled.range?.to, memoryKinds: compiled.memoryKinds,
|
|
145
181
|
keywords: target.nodeIds.length ? compiled.keywords : compiled.tokens,
|
|
146
182
|
targetNodeIds: target.nodeIds.length ? target.nodeIds : undefined,
|
|
147
|
-
}).sort((left, right) => Number(
|
|
183
|
+
}).sort((left, right) => Number(left.occurredAt || 0) - Number(right.occurredAt || 0)).map((node) => {
|
|
148
184
|
const evidence = this.evidence(node.id, projectId, options.evidenceLimit, options.includeEvidence);
|
|
149
185
|
const evidenceTotal = this.store.evidenceTotal(node.id, projectId);
|
|
150
186
|
return { ...node, evidenceCount: evidenceTotal, evidenceTotal, evidenceReturned: evidence.length, evidence, neighbors: [] };
|
|
@@ -152,8 +188,46 @@ export class MemoryAtlasService {
|
|
|
152
188
|
const actions = this.store.listActions(projectId, { target: compiled.target, targetEntityIds: target.entitySourceIds,
|
|
153
189
|
from: compiled.range?.from, to: compiled.range?.to, limit: boundedLimit(options.limit) })
|
|
154
190
|
.map((action) => ({ ...action, evidence: this.evidence(action.id, projectId, options.evidenceLimit, options.includeEvidence) }));
|
|
155
|
-
return { version:
|
|
156
|
-
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 };
|
|
213
|
+
}
|
|
214
|
+
attachEvidence(nodes, projectId, options) {
|
|
215
|
+
return nodes.map((node) => {
|
|
216
|
+
const evidence = this.evidence(node.id, projectId, options.evidenceLimit, options.includeEvidence);
|
|
217
|
+
const evidenceTotal = this.store.evidenceTotal(node.id, projectId);
|
|
218
|
+
return { ...node, evidenceCount: evidenceTotal, evidenceTotal, evidenceReturned: evidence.length, evidence };
|
|
219
|
+
});
|
|
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
|
+
});
|
|
157
231
|
}
|
|
158
232
|
evidence(nodeId, projectId, requested, includeExcerpt) {
|
|
159
233
|
const limit = Math.max(1, Math.min(requested ?? 2, 10));
|
|
@@ -161,8 +235,15 @@ export class MemoryAtlasService {
|
|
|
161
235
|
const event = this.eventStore.getEvent(eventId);
|
|
162
236
|
if (!event || event.projectId !== projectId)
|
|
163
237
|
return [];
|
|
164
|
-
|
|
165
|
-
|
|
238
|
+
const sourceLocator = atlasSourceLocator(event, projectId);
|
|
239
|
+
return [{
|
|
240
|
+
eventId,
|
|
241
|
+
globalSeq: event.globalSeq,
|
|
242
|
+
projectId,
|
|
243
|
+
drilldown: sourceLocator.command,
|
|
244
|
+
sourceLocator,
|
|
245
|
+
excerpt: includeExcerpt ? eventTextForMemory(event).slice(0, 500) : undefined,
|
|
246
|
+
}];
|
|
166
247
|
});
|
|
167
248
|
}
|
|
168
249
|
edgesFor(nodes, projectId) {
|
|
@@ -213,4 +294,76 @@ function chunked(values, size) {
|
|
|
213
294
|
chunks.push(values.slice(index, index + size));
|
|
214
295
|
return chunks;
|
|
215
296
|
}
|
|
216
|
-
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
|
+
}
|
|
352
|
+
function atlasSourceLocator(event, projectId) {
|
|
353
|
+
const project = projectId || event.projectId;
|
|
354
|
+
const projectArg = project ? ` --project ${cliArg(project)}` : '';
|
|
355
|
+
const base = `cogmem memory show --event ${cliArg(event.eventId)}${projectArg}`;
|
|
356
|
+
return {
|
|
357
|
+
eventId: event.eventId,
|
|
358
|
+
globalSeq: event.globalSeq,
|
|
359
|
+
projectId: project,
|
|
360
|
+
threadId: event.threadId,
|
|
361
|
+
sessionId: event.sessionId,
|
|
362
|
+
localDate: event.localDate,
|
|
363
|
+
command: `${base} --before 2 --after 2 --json`,
|
|
364
|
+
contextCommand: `${base} --before 3 --after 3 --json`,
|
|
365
|
+
};
|
|
366
|
+
}
|
|
367
|
+
function cliArg(value) {
|
|
368
|
+
return /^[A-Za-z0-9._:/=@+-]+$/u.test(value) ? value : `'${value.replace(/'/g, `'\\''`)}'`;
|
|
369
|
+
}
|
|
@@ -1,7 +1,19 @@
|
|
|
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
|
+
globalSeq?: number;
|
|
5
|
+
projectId?: string;
|
|
4
6
|
drilldown: string;
|
|
7
|
+
sourceLocator?: {
|
|
8
|
+
eventId: string;
|
|
9
|
+
globalSeq?: number;
|
|
10
|
+
projectId?: string;
|
|
11
|
+
threadId?: string;
|
|
12
|
+
sessionId?: string;
|
|
13
|
+
localDate?: string;
|
|
14
|
+
command: string;
|
|
15
|
+
contextCommand: string;
|
|
16
|
+
};
|
|
5
17
|
excerpt?: string;
|
|
6
18
|
}
|
|
7
19
|
export interface MemoryAtlasNode {
|
|
@@ -24,6 +36,50 @@ export interface MemoryAtlasNode {
|
|
|
24
36
|
evidenceTotal: number;
|
|
25
37
|
/** Number of evidence records returned in this response. */
|
|
26
38
|
evidenceReturned?: number;
|
|
39
|
+
/** Bounded first-hop raw evidence locators for agent-facing graph search/explore responses. */
|
|
40
|
+
evidence?: MemoryAtlasEvidence[];
|
|
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;
|
|
27
83
|
}
|
|
28
84
|
export interface MemoryAtlasEdge {
|
|
29
85
|
source: string;
|
|
@@ -38,7 +94,7 @@ export interface MemoryAtlasNextAction {
|
|
|
38
94
|
args: Record<string, unknown>;
|
|
39
95
|
}
|
|
40
96
|
export interface MemoryAtlasSlice {
|
|
41
|
-
version: 'memory_atlas.
|
|
97
|
+
version: 'memory_atlas.v2';
|
|
42
98
|
projectId: string;
|
|
43
99
|
query?: string;
|
|
44
100
|
nodes: MemoryAtlasNode[];
|
|
@@ -46,15 +102,29 @@ export interface MemoryAtlasSlice {
|
|
|
46
102
|
nextActions: MemoryAtlasNextAction[];
|
|
47
103
|
warnings: string[];
|
|
48
104
|
facets?: {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
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[];
|
|
53
123
|
};
|
|
54
|
-
target?: string;
|
|
55
|
-
memoryKinds: string[];
|
|
56
|
-
keywords: string[];
|
|
57
124
|
};
|
|
125
|
+
matchedFacets?: MemoryAtlasMatchedFacet[];
|
|
126
|
+
cards?: MemoryAtlasCard[];
|
|
127
|
+
relaxationTrace?: MemoryAtlasRelaxationStep[];
|
|
58
128
|
coldMemoryResurrected?: boolean;
|
|
59
129
|
}
|
|
60
130
|
export interface MemoryAtlasNodeDetail extends MemoryAtlasNode {
|
|
@@ -73,7 +143,7 @@ export interface MemoryAtlasAction {
|
|
|
73
143
|
evidence: MemoryAtlasEvidence[];
|
|
74
144
|
}
|
|
75
145
|
export interface MemoryAtlasTimelineResult {
|
|
76
|
-
version: 'memory_atlas.
|
|
146
|
+
version: 'memory_atlas.v2';
|
|
77
147
|
projectId: string;
|
|
78
148
|
query: string;
|
|
79
149
|
range?: {
|
|
@@ -84,10 +154,18 @@ export interface MemoryAtlasTimelineResult {
|
|
|
84
154
|
temporalResurrection: boolean;
|
|
85
155
|
nodes: MemoryAtlasNodeDetail[];
|
|
86
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[];
|
|
87
165
|
warnings: string[];
|
|
88
166
|
}
|
|
89
167
|
export interface MemoryAtlasPathResult {
|
|
90
|
-
version: 'memory_atlas.
|
|
168
|
+
version: 'memory_atlas.v2';
|
|
91
169
|
projectId: string;
|
|
92
170
|
from: string;
|
|
93
171
|
to: string;
|
package/dist/bin/connect.js
CHANGED
|
@@ -90,21 +90,92 @@ function defaultSkillPath(agent, workspaceRoot) {
|
|
|
90
90
|
return join(process.env.HOME || homedir(), '.hermes', 'skills', 'cogmem-memory', 'SKILL.md');
|
|
91
91
|
}
|
|
92
92
|
function nextCommands(agent) {
|
|
93
|
+
return nextSteps(agent)
|
|
94
|
+
.filter((step) => step.safeForAutomation && step.actor === 'agent')
|
|
95
|
+
.map((step) => step.command);
|
|
96
|
+
}
|
|
97
|
+
function nextSteps(agent) {
|
|
98
|
+
const project = agent === 'openclaw' ? 'openclaw' : 'hermes';
|
|
99
|
+
const importCommand = agent === 'openclaw' ? 'import-openclaw' : 'import-hermes';
|
|
100
|
+
const steps = [
|
|
101
|
+
{
|
|
102
|
+
id: 'doctor',
|
|
103
|
+
actor: 'agent',
|
|
104
|
+
safeForAutomation: true,
|
|
105
|
+
command: './node_modules/.bin/cogmem doctor',
|
|
106
|
+
when: 'after installation or update',
|
|
107
|
+
purpose: 'verify package, config, and database access',
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
id: 'import_dry_run',
|
|
111
|
+
actor: 'agent',
|
|
112
|
+
safeForAutomation: true,
|
|
113
|
+
command: `./node_modules/.bin/cogmem ${importCommand} --workspace . --project ${project} --dry-run --json`,
|
|
114
|
+
when: 'before importing legacy memory',
|
|
115
|
+
purpose: 'preview source discovery and import counts',
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
id: 'import_apply',
|
|
119
|
+
actor: 'agent',
|
|
120
|
+
safeForAutomation: true,
|
|
121
|
+
command: `./node_modules/.bin/cogmem ${importCommand} --workspace . --project ${project} --json`,
|
|
122
|
+
when: 'after dry-run looks correct',
|
|
123
|
+
purpose: 'idempotently import legacy memory into Cogmem',
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
id: 'memory_plan',
|
|
127
|
+
actor: 'agent',
|
|
128
|
+
safeForAutomation: true,
|
|
129
|
+
command: `./node_modules/.bin/cogmem memory plan --project ${project} --json`,
|
|
130
|
+
when: 'after import, update, or user asks for governance progress',
|
|
131
|
+
purpose: 'read agent-safe next actions instead of guessing from raw counters',
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
id: 'memory_status',
|
|
135
|
+
actor: 'agent',
|
|
136
|
+
safeForAutomation: true,
|
|
137
|
+
command: `./node_modules/.bin/cogmem memory status --project ${project} --json`,
|
|
138
|
+
when: 'for read-only health checks',
|
|
139
|
+
purpose: 'inspect raw ledger, vector fallback, dream backlog, and queue summary',
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
id: 'interactive_init',
|
|
143
|
+
actor: 'operator',
|
|
144
|
+
safeForAutomation: false,
|
|
145
|
+
command: `./node_modules/.bin/cogmem init --agent ${agent} --scope project`,
|
|
146
|
+
when: 'only if no Cogmem config exists and a human operator is present',
|
|
147
|
+
purpose: 'interactive first-time config wizard; agents must not run this unattended',
|
|
148
|
+
},
|
|
149
|
+
];
|
|
93
150
|
if (agent === 'openclaw') {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
'./node_modules/.bin/cogmem
|
|
99
|
-
'
|
|
100
|
-
|
|
151
|
+
steps.splice(1, 0, {
|
|
152
|
+
id: 'openclaw_diagnose',
|
|
153
|
+
actor: 'agent',
|
|
154
|
+
safeForAutomation: true,
|
|
155
|
+
command: './node_modules/.bin/cogmem openclaw diagnose --workspace . --json',
|
|
156
|
+
when: 'after connect --auto --force or before investigating injection failures',
|
|
157
|
+
purpose: 'verify generated plugin files, audit log, queue lock, and hook diagnostics',
|
|
158
|
+
});
|
|
159
|
+
steps.push({
|
|
160
|
+
id: 'restart_gateway',
|
|
161
|
+
actor: 'host',
|
|
162
|
+
safeForAutomation: false,
|
|
163
|
+
command: 'openclaw gateway restart',
|
|
164
|
+
when: 'after plugin files or OpenClaw config changed',
|
|
165
|
+
purpose: 'reload OpenClaw hooks so the refreshed Cogmem plugin is active',
|
|
166
|
+
});
|
|
101
167
|
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
168
|
+
else {
|
|
169
|
+
steps.push({
|
|
170
|
+
id: 'reload_hermes',
|
|
171
|
+
actor: 'host',
|
|
172
|
+
safeForAutomation: false,
|
|
173
|
+
command: 'restart or reload Hermes MCP server',
|
|
174
|
+
when: 'after Hermes MCP config changed',
|
|
175
|
+
purpose: 'reload the cogmem MCP server entry',
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
return steps;
|
|
108
179
|
}
|
|
109
180
|
function usage() {
|
|
110
181
|
return [
|
|
@@ -238,6 +309,7 @@ function installSkill(args) {
|
|
|
238
309
|
installed: !args.dryRun && !alreadyCurrent,
|
|
239
310
|
alreadyCurrent,
|
|
240
311
|
nextCommands: nextCommands(args.agent),
|
|
312
|
+
nextSteps: nextSteps(args.agent),
|
|
241
313
|
hostConfigSnippet: hostConfigSnippet(args.agent, args.workspaceRoot, args.auto),
|
|
242
314
|
autoMemory,
|
|
243
315
|
hermesMcp,
|