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
|
@@ -61,6 +61,9 @@ export declare class EventStore {
|
|
|
61
61
|
getLatestEvent(): MemoryEvent | null;
|
|
62
62
|
listRawEventsAfterGlobalSeq(options?: {
|
|
63
63
|
projectId?: string;
|
|
64
|
+
workspaceId?: string;
|
|
65
|
+
threadId?: string;
|
|
66
|
+
sessionId?: string;
|
|
64
67
|
afterGlobalSeq?: number;
|
|
65
68
|
limit?: number;
|
|
66
69
|
}): MemoryEvent[];
|
|
@@ -78,6 +81,9 @@ export declare class EventStore {
|
|
|
78
81
|
sessionId?: string[];
|
|
79
82
|
startTime?: number;
|
|
80
83
|
endTime?: number;
|
|
84
|
+
sinceGlobalSeq?: number;
|
|
85
|
+
untilGlobalSeq?: number;
|
|
86
|
+
order?: 'asc' | 'desc';
|
|
81
87
|
}): EventAuditPage;
|
|
82
88
|
getEvent(eventId: string): MemoryEvent | null;
|
|
83
89
|
getThreadEvents(threadId: string, options?: {
|
package/dist/store/EventStore.js
CHANGED
|
@@ -270,6 +270,18 @@ export class EventStore {
|
|
|
270
270
|
conditions.push('project_id = ?');
|
|
271
271
|
params.push(options.projectId);
|
|
272
272
|
}
|
|
273
|
+
if (options.workspaceId) {
|
|
274
|
+
conditions.push('workspace_id = ?');
|
|
275
|
+
params.push(options.workspaceId);
|
|
276
|
+
}
|
|
277
|
+
if (options.threadId) {
|
|
278
|
+
conditions.push('thread_id = ?');
|
|
279
|
+
params.push(options.threadId);
|
|
280
|
+
}
|
|
281
|
+
if (options.sessionId) {
|
|
282
|
+
conditions.push('session_id = ?');
|
|
283
|
+
params.push(options.sessionId);
|
|
284
|
+
}
|
|
273
285
|
if (options.afterGlobalSeq !== undefined) {
|
|
274
286
|
conditions.push('COALESCE(global_seq, 0) > ?');
|
|
275
287
|
params.push(options.afterGlobalSeq);
|
|
@@ -347,7 +359,18 @@ export class EventStore {
|
|
|
347
359
|
conditions.push('occurred_at <= ?');
|
|
348
360
|
params.push(filters.endTime);
|
|
349
361
|
}
|
|
362
|
+
if (filters?.sinceGlobalSeq !== undefined) {
|
|
363
|
+
conditions.push('COALESCE(global_seq, 0) >= ?');
|
|
364
|
+
params.push(filters.sinceGlobalSeq);
|
|
365
|
+
}
|
|
366
|
+
if (filters?.untilGlobalSeq !== undefined) {
|
|
367
|
+
conditions.push('COALESCE(global_seq, 0) <= ?');
|
|
368
|
+
params.push(filters.untilGlobalSeq);
|
|
369
|
+
}
|
|
350
370
|
const where = conditions.length ? `WHERE ${conditions.join(' AND ')}` : '';
|
|
371
|
+
const orderSql = filters?.order === 'asc'
|
|
372
|
+
? 'COALESCE(global_seq, 0) ASC, occurred_at ASC, event_id ASC'
|
|
373
|
+
: 'COALESCE(global_seq, 0) DESC, occurred_at DESC, event_id DESC';
|
|
351
374
|
const totalRow = this.db.prepare(`
|
|
352
375
|
SELECT COUNT(*) AS count FROM memory_events ${where}
|
|
353
376
|
`).get(...params);
|
|
@@ -355,7 +378,7 @@ export class EventStore {
|
|
|
355
378
|
SELECT ${MEMORY_EVENT_COLUMNS}
|
|
356
379
|
FROM memory_events
|
|
357
380
|
${where}
|
|
358
|
-
ORDER BY
|
|
381
|
+
ORDER BY ${orderSql}
|
|
359
382
|
LIMIT ? OFFSET ?
|
|
360
383
|
`).all(...params, safePageSize, offset);
|
|
361
384
|
return {
|
|
@@ -375,7 +398,10 @@ export class EventStore {
|
|
|
375
398
|
threadId: filters?.threadId,
|
|
376
399
|
sessionId: filters?.sessionId,
|
|
377
400
|
startTime: filters?.startTime,
|
|
378
|
-
endTime: filters?.endTime
|
|
401
|
+
endTime: filters?.endTime,
|
|
402
|
+
sinceGlobalSeq: filters?.sinceGlobalSeq,
|
|
403
|
+
untilGlobalSeq: filters?.untilGlobalSeq,
|
|
404
|
+
order: filters?.order,
|
|
379
405
|
}
|
|
380
406
|
};
|
|
381
407
|
}
|
|
@@ -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
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { createHash, randomUUID } from 'node:crypto';
|
|
2
|
+
export const MEMORY_ATLAS_PROJECTION_NAME = 'memory_atlas.v2';
|
|
3
|
+
export const MEMORY_ATLAS_PROJECTION_SCHEMA_VERSION = '3.7.0';
|
|
2
4
|
export class MemoryAtlasStore {
|
|
3
5
|
db;
|
|
4
6
|
constructor(db) {
|
|
@@ -82,12 +84,81 @@ export class MemoryAtlasStore {
|
|
|
82
84
|
return mapNode(row, matches + Number(row.activation || 0));
|
|
83
85
|
}).sort((a, b) => b.score - a.score);
|
|
84
86
|
}
|
|
87
|
+
searchCanonicalEpisodeCards(projectId, plan, limit) {
|
|
88
|
+
const plannedFacets = plan.facets;
|
|
89
|
+
if (!plannedFacets.length)
|
|
90
|
+
return [];
|
|
91
|
+
const facetMatches = plannedFacets.map((facet) => ({ facet, rows: this.episodeEdgesForFacet(projectId, facet) }));
|
|
92
|
+
if (plan.operator === 'intersection' && facetMatches.some((match) => match.rows.length === 0))
|
|
93
|
+
return [];
|
|
94
|
+
const candidateIds = plan.operator === 'intersection'
|
|
95
|
+
? intersectSets(facetMatches.map((match) => new Set(match.rows.map((row) => row.source_id))))
|
|
96
|
+
: new Set(facetMatches.flatMap((match) => match.rows.map((row) => row.source_id)));
|
|
97
|
+
if (!candidateIds.size)
|
|
98
|
+
return [];
|
|
99
|
+
const rows = this.episodeRows(projectId, Array.from(candidateIds));
|
|
100
|
+
const cards = rows.map((row) => {
|
|
101
|
+
const candidateEdges = facetMatches.flatMap((match) => match.rows.filter((edge) => edge.source_id === row.source_id));
|
|
102
|
+
return this.cardFromEpisodeRow(row, candidateEdges, projectId);
|
|
103
|
+
});
|
|
104
|
+
const selectedIds = new Set(cards.map((card) => card.canonicalId));
|
|
105
|
+
for (const card of cards) {
|
|
106
|
+
card.relatedButNotSelected = mergeRelatedCards(this.relatedEpisodeCards(projectId, card.canonicalId, selectedIds, 4), this.topicRelatedCardsForPlan(projectId, plan, selectedIds, 4)).slice(0, 4);
|
|
107
|
+
}
|
|
108
|
+
return cards.sort((left, right) => scoreCard(right) - scoreCard(left)).slice(0, Math.max(1, Math.min(limit, 100)));
|
|
109
|
+
}
|
|
110
|
+
relatedEpisodeCards(projectId, canonicalId, selectedIds, limit) {
|
|
111
|
+
const parsed = parseNodeId(canonicalId, projectId);
|
|
112
|
+
if (!parsed || parsed.type !== 'episode')
|
|
113
|
+
return [];
|
|
114
|
+
const rows = this.db.prepare(`
|
|
115
|
+
SELECT e.relation_type, e.confidence, d.node_id, d.label, d.metadata_json
|
|
116
|
+
FROM memory_edges e
|
|
117
|
+
JOIN memory_atlas_documents d ON d.project_id=e.project_id AND d.node_id=CASE
|
|
118
|
+
WHEN e.source_type='episode' AND e.source_id=? THEN 'episode:' || e.target_id
|
|
119
|
+
ELSE 'episode:' || e.source_id
|
|
120
|
+
END
|
|
121
|
+
WHERE e.project_id=? AND e.status IN ('active','weak') AND e.relation_type IN ('SAME_ISSUE','FOLLOWS_UP','REFINES','CORRECTS','CONTRADICTS','SUPERSEDES','RELATED_TO')
|
|
122
|
+
AND ((e.source_type='episode' AND e.source_id=?) OR (e.target_type='episode' AND e.target_id=?))
|
|
123
|
+
ORDER BY CASE e.relation_type WHEN 'SAME_ISSUE' THEN 1 WHEN 'FOLLOWS_UP' THEN 2 WHEN 'REFINES' THEN 3 ELSE 4 END, e.confidence DESC
|
|
124
|
+
LIMIT ?
|
|
125
|
+
`).all(parsed.id, projectId, parsed.id, parsed.id, Math.max(1, Math.min(limit * 3, 30)));
|
|
126
|
+
const result = [];
|
|
127
|
+
for (const row of rows) {
|
|
128
|
+
if (selectedIds.has(row.node_id))
|
|
129
|
+
continue;
|
|
130
|
+
result.push({
|
|
131
|
+
canonicalId: row.node_id,
|
|
132
|
+
displayTitle: row.label,
|
|
133
|
+
reason: row.relation_type === 'RELATED_TO' ? 'related topic but different issue/date' : row.relation_type.toLowerCase(),
|
|
134
|
+
});
|
|
135
|
+
if (result.length >= limit)
|
|
136
|
+
break;
|
|
137
|
+
}
|
|
138
|
+
return result;
|
|
139
|
+
}
|
|
140
|
+
topicRelatedCardsForPlan(projectId, plan, selectedIds, limit) {
|
|
141
|
+
const topicFacets = plan.facets.filter((facet) => facet.type === 'topic');
|
|
142
|
+
if (!topicFacets.length)
|
|
143
|
+
return [];
|
|
144
|
+
const rows = topicFacets.flatMap((facet) => this.episodeEdgesForFacet(projectId, facet));
|
|
145
|
+
const candidateIds = Array.from(new Set(rows.map((row) => row.source_id))).filter((id) => !selectedIds.has(`episode:${id}`));
|
|
146
|
+
if (!candidateIds.length)
|
|
147
|
+
return [];
|
|
148
|
+
return this.episodeRows(projectId, candidateIds)
|
|
149
|
+
.map((row) => ({
|
|
150
|
+
canonicalId: row.node_id,
|
|
151
|
+
displayTitle: row.label,
|
|
152
|
+
reason: 'related topic but different issue/date',
|
|
153
|
+
}))
|
|
154
|
+
.slice(0, Math.max(1, Math.min(limit, 20)));
|
|
155
|
+
}
|
|
85
156
|
resolveTargetNodeIds(projectId, query) {
|
|
86
157
|
const normalizedQuery = normalizeLookup(query);
|
|
87
158
|
const candidates = this.db.prepare(`
|
|
88
159
|
SELECT node_id,node_type,source_id,label,topic_path,metadata_json,evidence_event_ids_json
|
|
89
160
|
FROM memory_atlas_documents
|
|
90
|
-
WHERE project_id=? AND node_type IN ('entity','topic','project') AND status NOT IN ('rejected','archived')
|
|
161
|
+
WHERE project_id=? AND node_type IN ('entity','topic','issue','project') AND status NOT IN ('rejected','archived')
|
|
91
162
|
`).all(projectId);
|
|
92
163
|
const seeds = [];
|
|
93
164
|
const labels = [];
|
|
@@ -375,12 +446,34 @@ export class MemoryAtlasStore {
|
|
|
375
446
|
}
|
|
376
447
|
projectionNeedsRefresh(projectId) {
|
|
377
448
|
const row = this.db.prepare(`
|
|
449
|
+
SELECT status, metadata_json FROM memory_atlas_projection_state
|
|
450
|
+
WHERE project_id=? AND projection_name=?
|
|
451
|
+
`).get(projectId, MEMORY_ATLAS_PROJECTION_NAME);
|
|
452
|
+
if (!row || row.status !== 'clean')
|
|
453
|
+
return true;
|
|
454
|
+
const metadata = parseMetadata(row.metadata_json);
|
|
455
|
+
if (metadata.projectionSchemaVersion !== MEMORY_ATLAS_PROJECTION_SCHEMA_VERSION)
|
|
456
|
+
return true;
|
|
457
|
+
const legacyDirty = this.db.prepare(`
|
|
378
458
|
SELECT status FROM memory_atlas_projection_state
|
|
379
|
-
WHERE project_id=? AND projection_name='memory_atlas.v1'
|
|
459
|
+
WHERE project_id=? AND projection_name='memory_atlas.v1' AND status<>'clean'
|
|
380
460
|
`).get(projectId);
|
|
381
|
-
return
|
|
461
|
+
return Boolean(legacyDirty);
|
|
382
462
|
}
|
|
383
463
|
markProjectionClean(projectId, metadata = {}, now = Date.now()) {
|
|
464
|
+
const enrichedMetadata = {
|
|
465
|
+
...metadata,
|
|
466
|
+
projectionName: MEMORY_ATLAS_PROJECTION_NAME,
|
|
467
|
+
projectionSchemaVersion: MEMORY_ATLAS_PROJECTION_SCHEMA_VERSION,
|
|
468
|
+
};
|
|
469
|
+
this.db.prepare(`
|
|
470
|
+
INSERT INTO memory_atlas_projection_state(
|
|
471
|
+
project_id, projection_name, cursor_value, status, last_rebuild_at, last_error, metadata_json
|
|
472
|
+
) VALUES(?, ?, ?, 'clean', ?, NULL, ?)
|
|
473
|
+
ON CONFLICT(project_id, projection_name) DO UPDATE SET
|
|
474
|
+
cursor_value=excluded.cursor_value, status='clean', last_rebuild_at=excluded.last_rebuild_at,
|
|
475
|
+
last_error=NULL, metadata_json=excluded.metadata_json
|
|
476
|
+
`).run(projectId, MEMORY_ATLAS_PROJECTION_NAME, String(now), now, JSON.stringify(enrichedMetadata));
|
|
384
477
|
this.db.prepare(`
|
|
385
478
|
INSERT INTO memory_atlas_projection_state(
|
|
386
479
|
project_id, projection_name, cursor_value, status, last_rebuild_at, last_error, metadata_json
|
|
@@ -388,17 +481,20 @@ export class MemoryAtlasStore {
|
|
|
388
481
|
ON CONFLICT(project_id, projection_name) DO UPDATE SET
|
|
389
482
|
cursor_value=excluded.cursor_value, status='clean', last_rebuild_at=excluded.last_rebuild_at,
|
|
390
483
|
last_error=NULL, metadata_json=excluded.metadata_json
|
|
391
|
-
`).run(projectId, String(now), now, JSON.stringify(
|
|
484
|
+
`).run(projectId, String(now), now, JSON.stringify({ compatibilityAliasFor: MEMORY_ATLAS_PROJECTION_NAME }));
|
|
392
485
|
}
|
|
393
486
|
markProjectionFailed(projectId, error, now = Date.now()) {
|
|
394
487
|
this.db.prepare(`
|
|
395
488
|
INSERT INTO memory_atlas_projection_state(project_id,projection_name,status,last_rebuild_at,last_error,metadata_json)
|
|
396
|
-
VALUES(
|
|
489
|
+
VALUES(?,?,'error',?,?,?)
|
|
397
490
|
ON CONFLICT(project_id,projection_name) DO UPDATE SET status='error',last_rebuild_at=excluded.last_rebuild_at,last_error=excluded.last_error
|
|
398
|
-
`).run(projectId, now, error.slice(0, 2000)
|
|
491
|
+
`).run(projectId, MEMORY_ATLAS_PROJECTION_NAME, now, error.slice(0, 2000), JSON.stringify({
|
|
492
|
+
projectionName: MEMORY_ATLAS_PROJECTION_NAME,
|
|
493
|
+
projectionSchemaVersion: MEMORY_ATLAS_PROJECTION_SCHEMA_VERSION,
|
|
494
|
+
}));
|
|
399
495
|
}
|
|
400
496
|
getProjectionState(projectId) {
|
|
401
|
-
const row = this.db.prepare(`SELECT status,last_rebuild_at,last_error FROM memory_atlas_projection_state WHERE project_id=? AND projection_name
|
|
497
|
+
const row = this.db.prepare(`SELECT status,last_rebuild_at,last_error FROM memory_atlas_projection_state WHERE project_id=? AND projection_name=?`).get(projectId, MEMORY_ATLAS_PROJECTION_NAME);
|
|
402
498
|
return row ? { status: row.status, lastRebuildAt: row.last_rebuild_at ?? undefined, lastError: row.last_error || undefined } : null;
|
|
403
499
|
}
|
|
404
500
|
listKnownProjectIds() {
|
|
@@ -436,6 +532,60 @@ export class MemoryAtlasStore {
|
|
|
436
532
|
target: nodeId('topic', row.target_path, projectId), confidence: Number(row.confidence),
|
|
437
533
|
evidenceEventIds: parseStringArray(row.evidence_event_ids_json) }));
|
|
438
534
|
}
|
|
535
|
+
episodeEdgesForFacet(projectId, facet) {
|
|
536
|
+
const relationFilter = facet.relation ? 'AND relation_type=?' : '';
|
|
537
|
+
const params = facet.relation
|
|
538
|
+
? [projectId, facet.type, facet.value, facet.relation]
|
|
539
|
+
: [projectId, facet.type, facet.value];
|
|
540
|
+
return this.db.prepare(`
|
|
541
|
+
SELECT source_id, relation_type, target_type, target_id, confidence, evidence_event_ids_json
|
|
542
|
+
FROM memory_edges
|
|
543
|
+
WHERE project_id=? AND source_type='episode' AND target_type=? AND target_id=? ${relationFilter}
|
|
544
|
+
AND status IN ('active','weak')
|
|
545
|
+
ORDER BY confidence DESC
|
|
546
|
+
LIMIT 5000
|
|
547
|
+
`).all(...params);
|
|
548
|
+
}
|
|
549
|
+
episodeRows(projectId, episodeIds) {
|
|
550
|
+
const bounded = Array.from(new Set(episodeIds)).slice(0, 500);
|
|
551
|
+
if (!bounded.length)
|
|
552
|
+
return [];
|
|
553
|
+
return this.db.prepare(`
|
|
554
|
+
SELECT d.*, COALESCE(a.activation, 0) AS activation
|
|
555
|
+
FROM memory_atlas_documents d LEFT JOIN memory_atlas_activation a
|
|
556
|
+
ON a.project_id=d.project_id AND a.node_id=d.node_id
|
|
557
|
+
WHERE d.project_id=? AND d.node_id IN (${bounded.map(() => '?').join(',')})
|
|
558
|
+
AND d.node_type='episode' AND d.status NOT IN ('rejected','archived')
|
|
559
|
+
`).all(projectId, ...bounded.map((id) => `episode:${id}`));
|
|
560
|
+
}
|
|
561
|
+
cardFromEpisodeRow(row, edges, projectId) {
|
|
562
|
+
const metadata = parseMetadata(row.metadata_json);
|
|
563
|
+
const evidenceEventIds = parseStringArray(row.evidence_event_ids_json);
|
|
564
|
+
const matchedFacets = edges.map((edge) => facetFromEdge(edge, projectId));
|
|
565
|
+
const matchedPaths = edges.map((edge) => {
|
|
566
|
+
const facet = facetFromEdge(edge, projectId);
|
|
567
|
+
return { facet, via: [facet.nodeId, row.node_id], relation: edge.relation_type, confidence: Number(edge.confidence || 0) };
|
|
568
|
+
});
|
|
569
|
+
const issueHints = stringArray(metadata.issueHints);
|
|
570
|
+
const topicHints = stringArray(metadata.topicHints);
|
|
571
|
+
return {
|
|
572
|
+
canonicalId: row.node_id,
|
|
573
|
+
nodeType: 'episode',
|
|
574
|
+
displayTitle: row.label,
|
|
575
|
+
oneLineSummary: row.summary || undefined,
|
|
576
|
+
matchedFacets,
|
|
577
|
+
matchedPaths,
|
|
578
|
+
parentTopics: topicHints.length ? topicHints : row.topic_path ? [row.topic_path] : [],
|
|
579
|
+
issueType: issueHints[0],
|
|
580
|
+
eventKind: optionalMetadataString(metadata.eventKind),
|
|
581
|
+
localDate: optionalMetadataString(metadata.localDate) ?? (row.occurred_at ? new Date(row.occurred_at).toISOString().slice(0, 10) : undefined),
|
|
582
|
+
whyMatched: matchedFacets.length ? `matched ${matchedFacets.map((facet) => `${facet.type}:${facet.value}`).join(', ')}` : 'matched canonical episode',
|
|
583
|
+
relatedButNotSelected: [],
|
|
584
|
+
evidenceEventIds,
|
|
585
|
+
evidenceTotal: evidenceEventIds.length,
|
|
586
|
+
evidenceReturned: 0,
|
|
587
|
+
};
|
|
588
|
+
}
|
|
439
589
|
}
|
|
440
590
|
function mapNode(row, score) {
|
|
441
591
|
return { id: row.node_id, projectId: row.project_id, nodeType: row.node_type, sourceId: row.source_id,
|
|
@@ -479,7 +629,7 @@ catch {
|
|
|
479
629
|
} }
|
|
480
630
|
function escapeLike(value) { return value.replace(/[\\%_]/g, '\\$&'); }
|
|
481
631
|
function nodeId(type, id, projectId) {
|
|
482
|
-
if (
|
|
632
|
+
if (['topic', 'time', 'issue', 'session', 'thread', 'memoryKind', 'actionKind'].includes(type))
|
|
483
633
|
return `${type}:${projectId}:${id}`;
|
|
484
634
|
return `${type}:${id}`;
|
|
485
635
|
}
|
|
@@ -487,14 +637,78 @@ function timeNodeId(projectId, occurredAt) {
|
|
|
487
637
|
return `time:${projectId}:${new Date(occurredAt).getUTCFullYear()}`;
|
|
488
638
|
}
|
|
489
639
|
function parseNodeId(value, projectId) {
|
|
490
|
-
const
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
return { type: 'time', id: value.slice(timePrefix.length) };
|
|
640
|
+
for (const type of ['topic', 'time', 'issue', 'session', 'thread', 'memoryKind', 'actionKind']) {
|
|
641
|
+
const prefix = `${type}:${projectId}:`;
|
|
642
|
+
if (value.startsWith(prefix))
|
|
643
|
+
return { type, id: value.slice(prefix.length) };
|
|
644
|
+
}
|
|
496
645
|
const separator = value.indexOf(':');
|
|
497
646
|
if (separator <= 0 || separator === value.length - 1)
|
|
498
647
|
return null;
|
|
499
648
|
return { type: value.slice(0, separator), id: value.slice(separator + 1) };
|
|
500
649
|
}
|
|
650
|
+
function parseMetadata(value) {
|
|
651
|
+
try {
|
|
652
|
+
const parsed = JSON.parse(value || '{}');
|
|
653
|
+
return parsed && typeof parsed === 'object' && !Array.isArray(parsed) ? parsed : {};
|
|
654
|
+
}
|
|
655
|
+
catch {
|
|
656
|
+
return {};
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
function stringArray(value) {
|
|
660
|
+
return Array.isArray(value) ? value.filter((item) => typeof item === 'string' && item.length > 0) : [];
|
|
661
|
+
}
|
|
662
|
+
function optionalMetadataString(value) {
|
|
663
|
+
return typeof value === 'string' && value ? value : undefined;
|
|
664
|
+
}
|
|
665
|
+
function facetFromEdge(edge, projectId) {
|
|
666
|
+
return {
|
|
667
|
+
type: edge.target_type,
|
|
668
|
+
value: edge.target_id,
|
|
669
|
+
label: facetLabel(edge.target_type, edge.target_id),
|
|
670
|
+
nodeId: nodeId(edge.target_type, edge.target_id, projectId),
|
|
671
|
+
relation: edge.relation_type,
|
|
672
|
+
};
|
|
673
|
+
}
|
|
674
|
+
function facetLabel(type, value) {
|
|
675
|
+
if (type === 'topic')
|
|
676
|
+
return value.split('/').pop() || value;
|
|
677
|
+
if (type === 'issue') {
|
|
678
|
+
if (value === 'memory-context-blackbox')
|
|
679
|
+
return 'Memory Context 黑盒';
|
|
680
|
+
if (value === 'graph-runtime-blackbox')
|
|
681
|
+
return 'Graph Runtime 黑盒';
|
|
682
|
+
if (value === 'atlas-readability')
|
|
683
|
+
return 'Atlas 可读性黑盒';
|
|
684
|
+
if (value === 'auto-injection-mismatch')
|
|
685
|
+
return '自动注入不一致';
|
|
686
|
+
}
|
|
687
|
+
return value;
|
|
688
|
+
}
|
|
689
|
+
function intersectSets(sets) {
|
|
690
|
+
if (!sets.length)
|
|
691
|
+
return new Set();
|
|
692
|
+
const [first, ...rest] = sets;
|
|
693
|
+
const result = new Set();
|
|
694
|
+
for (const value of first ?? []) {
|
|
695
|
+
if (rest.every((set) => set.has(value)))
|
|
696
|
+
result.add(value);
|
|
697
|
+
}
|
|
698
|
+
return result;
|
|
699
|
+
}
|
|
700
|
+
function scoreCard(card) {
|
|
701
|
+
const issuePriority = card.issueType === 'memory-context-blackbox' ? 4
|
|
702
|
+
: card.issueType === 'graph-runtime-blackbox' ? 2
|
|
703
|
+
: card.issueType === 'atlas-readability' ? 1
|
|
704
|
+
: 0;
|
|
705
|
+
return card.matchedFacets.length * 10 + issuePriority + card.matchedPaths.reduce((sum, path) => sum + path.confidence, 0) + (card.localDate ? 0.1 : 0);
|
|
706
|
+
}
|
|
707
|
+
function mergeRelatedCards(...groups) {
|
|
708
|
+
const merged = new Map();
|
|
709
|
+
for (const group of groups)
|
|
710
|
+
for (const card of group)
|
|
711
|
+
if (!merged.has(card.canonicalId))
|
|
712
|
+
merged.set(card.canonicalId, card);
|
|
713
|
+
return Array.from(merged.values());
|
|
714
|
+
}
|
package/dist/types/index.d.ts
CHANGED
|
@@ -122,12 +122,14 @@ cogmem normalize-transcript --input ./hermes-sessions.jsonl --output ./hermes.no
|
|
|
122
122
|
cogmem import-hermes --workspace . --project hermes --session ./hermes.normalized.md
|
|
123
123
|
```
|
|
124
124
|
|
|
125
|
-
Cogmem
|
|
125
|
+
Cogmem skips import batch sealing for empty episode boundaries and skips legacy empty Dream jobs so one bad imported episode cannot block the queue.
|
|
126
126
|
|
|
127
127
|
After import, use this order:
|
|
128
128
|
|
|
129
129
|
```bash
|
|
130
|
+
cogmem memory plan --project hermes --json
|
|
130
131
|
cogmem memory status --project hermes --json
|
|
132
|
+
cogmem memory candidates --project hermes --json
|
|
131
133
|
cogmem episode status --project hermes --json
|
|
132
134
|
cogmem dream status --project hermes --json
|
|
133
135
|
cogmem dream tick --project hermes --mode auto --max-episodes 20 --json
|
|
@@ -135,9 +137,10 @@ cogmem memory candidates --project hermes --status candidate --json
|
|
|
135
137
|
cogmem memory govern --project hermes --limit 100 --json
|
|
136
138
|
cogmem memory candidates --project hermes --status needs_confirmation --json
|
|
137
139
|
cogmem memory review --project hermes --id <candidate-id> --action approve --actor <operator> --reason "confirmed by user" --confirmation-event <user-event-id> --json
|
|
140
|
+
cogmem memory recall --query "<verification question>" --project hermes --agent hermes --json
|
|
138
141
|
```
|
|
139
142
|
|
|
140
|
-
`needs_confirmation` is not the Dream backlog. `memory govern` does not approve it; use `memory review` with explicit evidence.
|
|
143
|
+
`memory plan` is the first agent-safe health and next-action command. Only run `dream_tick` when it appears in `nextActions`; if `nonBlocking` contains `raw_dream_ledger_lag` with `resolvableByDreamTick:false`, inspect raw sources or episode/import boundaries instead of retrying `dream tick`. Default `memory candidates --json` groups ordinary, `needs_confirmation`, and deferred review queues; use `--status` only when a human asks for one queue. `needs_confirmation` is not the Dream backlog. `memory govern` does not approve it; use `memory review` with explicit evidence.
|
|
141
144
|
|
|
142
145
|
## Active Memory Search
|
|
143
146
|
|
|
@@ -153,15 +156,18 @@ For inventory or product questions, use recall first and raw search as a forensi
|
|
|
153
156
|
cogmem memory recall --query "我们记录过哪些库存" --project hermes --agent hermes --json
|
|
154
157
|
cogmem memory search --query "エルビ 库存" --project hermes --json
|
|
155
158
|
cogmem memory show --event <event-id> --before 2 --after 2 --json
|
|
159
|
+
cogmem memory recall --query "几个月前我们是不是讨论过 Cogmem 的记忆黑盒" --intent historical_discussion --project hermes --agent hermes --json
|
|
160
|
+
cogmem memory list --project hermes --since <globalSeq> --order asc --json
|
|
156
161
|
```
|
|
157
162
|
|
|
158
163
|
`vectors: 0` does not mean Cogmem has no memory. It means the dense vector index has no hot vectors yet. `memory recall` still falls back to governed raw ledger search and returns `sourceContext` locators. Broad inventory questions are expanded into structured cues such as `库存管理`, `在库`, `产品コード`, and `数量`; if compiled-memory candidates miss those cues, raw ledger evidence is preferred.
|
|
159
164
|
|
|
160
|
-
`sourceContext` and `memory show --json`
|
|
165
|
+
`sourceContext` and `memory show --json` share the same replay contract: each event has a `label`, optional `charRange` / `sourceRange`, and `sourceContext.window` / `window` metadata with requested counts, actual counts, `excludesAnchor`, `ordering`, `roleFilter`, and `overlapHandling`. Use those fields before quoting exact wording or explaining what happened before/after a recalled point. Raw Ledger list rows and Atlas search/explore evidence include `sourceLocator.command` and `sourceLocator.contextCommand`; run those commands before saying the source event is unavailable.
|
|
161
166
|
|
|
162
167
|
Check status with:
|
|
163
168
|
|
|
164
169
|
```bash
|
|
170
|
+
cogmem memory plan --project hermes --json
|
|
165
171
|
cogmem memory status --project hermes --json
|
|
166
172
|
```
|
|
167
173
|
|
|
@@ -221,12 +227,12 @@ Hermes has no automatic observation path in this integration. Use `cogmem_episod
|
|
|
221
227
|
|
|
222
228
|
Use `cogmem_topic_operate` with actor `user_explicit` only for explicit user naming/organization instructions. Model suggestions use `model_candidate` and remain reviewable; alias collisions fail closed. Use `cogmem_episode_repair` for split/merge/move/reclassify/requeue work so receipts, stale candidates, cross-references, Dream jobs, and audit records stay synchronized. Do not hand-edit the database.
|
|
223
229
|
|
|
224
|
-
Use `cogmem memory map --project hermes --json` or MCP `cogmem_memory_map` to inspect Memory Binding and Graph Recall counters. Bindings attach high-value user raw events to stable topic/entity paths, fuse same-claim evidence into claim-key clusters, and create graph anchors for source drill-down only; they are not verified facts, user preferences, or instructions. Correction bindings expose review flags and correction edges. If `cogmem memory tick --project hermes --json` suggests `bind_raw_events`, run `cogmem memory bind --project hermes --json`. Re-run `cogmem connect hermes --workspace . --auto` after upgrades to patch existing MCP allow-lists with new Cogmem tools.
|
|
230
|
+
Use `cogmem memory map --project hermes --json` or MCP `cogmem_memory_map` to inspect Memory Binding and Graph Recall counters. Bindings attach high-value user raw events to stable topic/entity paths, fuse same-claim evidence into claim-key clusters, and create graph anchors for source drill-down only; they are not verified facts, user preferences, or instructions. Correction bindings expose review flags and correction edges. If `cogmem memory tick --project hermes --json` suggests `bind_raw_events`, run `cogmem memory bind --project hermes --json`; it scans the historical ledger by cursor and can resume with `--since <globalSeq>`. For old-discussion questions, use `cogmem memory recall --intent historical_discussion ...` or `cogmem_graph_explore`; in 3.7.0 cards carry `canonicalId`, `matchedFacets`, `matchedPaths`, `relatedButNotSelected`, and `sourceLocator`. Answer from the selected canonical card, not from a side card. Re-run `cogmem connect hermes --workspace . --auto --force --json` after upgrades to patch existing MCP allow-lists with new Cogmem tools. Follow only `nextCommands` for unattended agent work; operator/host actions are in `nextSteps` with `safeForAutomation=false`.
|
|
225
231
|
|
|
226
232
|
Dream correction records require explicit user clarification; assistant self-correction and questions containing `是不是` are not user-owned contradictions. Invalid provider output is a rejected diagnostic. Maintenance ticks supersede `needs_confirmation` entries older than the default 30-day TTL and retain their evidence rows.
|
|
227
233
|
|
|
228
234
|
## Memory Atlas navigation
|
|
229
235
|
|
|
230
|
-
For broad inventory or historical questions call `cogmem_graph_explore`. Use `cogmem_graph_search` and `cogmem_graph_node` for known concepts, `cogmem_graph_neighbors`/`cogmem_graph_path` for relations, and `cogmem_graph_timeline` for ordered reconstruction. Use `cogmem_recall` for a direct fact and follow event IDs to `cogmem memory show` for exact wording.
|
|
236
|
+
For broad inventory or historical questions call `cogmem_graph_explore`. Use `cogmem_graph_search` and `cogmem_graph_node` for known concepts, `cogmem_graph_neighbors`/`cogmem_graph_path` for relations, and `cogmem_graph_timeline` for ordered reconstruction. Use `cogmem_recall` for a direct fact and follow event IDs or returned `sourceLocator` commands to `cogmem memory show` for exact wording.
|
|
231
237
|
|
|
232
238
|
Combine the filters present in the user's message, including project, time, topic, entity/target, memory kind, and ordinary cues. Do not force an entity + time + action tuple. A cold result is newly visible, not newly verified or promoted.
|
|
@@ -75,7 +75,9 @@ cogmem import-hermes --workspace . --project hermes
|
|
|
75
75
|
After import:
|
|
76
76
|
|
|
77
77
|
```bash
|
|
78
|
+
cogmem memory plan --project hermes --json
|
|
78
79
|
cogmem memory status --project hermes --json
|
|
80
|
+
cogmem memory candidates --project hermes --json
|
|
79
81
|
cogmem episode status --project hermes --json
|
|
80
82
|
cogmem dream status --project hermes --json
|
|
81
83
|
cogmem dream tick --project hermes --mode auto --max-episodes 20 --json
|
|
@@ -101,13 +103,13 @@ cogmem import-hermes --workspace . --project hermes --session ./one.md --session
|
|
|
101
103
|
The import command is idempotent. Re-running it against the same database skips records already processed by the cursor store. Imported raw records enter the same Episode Assembler used by live turns and are sealed at the explicit import batch boundary.
|
|
102
104
|
Imported records are embedded through the configured kernel embedder during import.
|
|
103
105
|
|
|
104
|
-
MCP recall JSON includes `decisionTrace`. Check its selected lane, reason, and candidate counts before concluding that a memory is absent, and use `sourceContext.locator.command` for exact wording. Raw text fallback searches the fully scoped ledger and prefers original user anchors over later assistant retellings when cue scores tie.
|
|
106
|
+
MCP recall JSON includes `decisionTrace`. Check its selected lane, reason, and candidate counts before concluding that a memory is absent, and use `sourceContext.locator.command` for exact wording. Raw text fallback searches the fully scoped ledger and prefers original user anchors over later assistant retellings when cue scores tie. For old-discussion questions, run `cogmem memory recall --query "<past discussion>" --intent historical_discussion --project hermes --agent hermes --json`, then follow `sourceLocator` or inspect `cogmem memory list --project hermes --since <globalSeq> --order asc --json`.
|
|
105
107
|
|
|
106
108
|
Dream stores explicit user clarification as organizational correction evidence rather than an automatic contradiction. Assistant self-correction and negative-form questions do not create user-owned corrections. Resolve `needs_confirmation` with `cogmem_candidate_review` or `cogmem memory review`; maintenance only supersedes entries left stale past the default 30-day TTL.
|
|
107
109
|
|
|
108
|
-
After upgrades, reload MCP. Rerun `cogmem connect hermes --workspace . --auto --force` when MCP wiring, allow-listed tools, or the installed skill bundle changed.
|
|
110
|
+
After upgrades, reload MCP. Rerun `cogmem connect hermes --workspace . --auto --force --json` when MCP wiring, allow-listed tools, or the installed skill bundle changed. Follow only JSON `nextCommands` for unattended agent work; operator/host actions are in `nextSteps` with `safeForAutomation=false`.
|
|
109
111
|
|
|
110
|
-
Cogmem 3.
|
|
112
|
+
Cogmem 3.7.0 exposes read-only/idempotent Memory Atlas query tools plus explicit `cogmem_graph_touch`, installs from npm by default, prevents empty imported episodes from blocking Dream, and adds an agent-safe operations protocol. Use `memory plan` for the next safe command, grouped `memory candidates --json` for queue state, `historical_discussion` recall for old-discussion questions, and returned `sourceLocator` commands for exact evidence. Only run `dream_tick` when it appears in `memory plan.nextActions`; `raw_dream_ledger_lag` in `nonBlocking` has `resolvableByDreamTick:false` and is not fixed by looping `dream tick`. Use explore for broad memory inventory/history, search and node for a known concept, path/neighbors for relations, timeline for ordered reconstruction, and normal recall for a direct fact. Query facets combine the user's actual project, day/month/year, topic, issue, entity/target, session/thread, memory-kind, action-kind, and keyword conditions like table filters, so cold memory can be revived without requiring an entity-time-action tuple. Prefer returned `cards[]` for historical discussion: `canonicalId` dedupes the episode, `matchedFacets` explains why it matched, `relatedButNotSelected` is only side context, and `sourceLocator` opens raw evidence. Touch only nodes actually used, and follow returned event IDs or `sourceLocator` commands before quoting exact wording.
|
|
111
113
|
|
|
112
114
|
## Runtime
|
|
113
115
|
|
|
@@ -114,7 +114,7 @@ timeout_ms = 60000
|
|
|
114
114
|
|
|
115
115
|
## Migrate Existing Hermes Memory
|
|
116
116
|
|
|
117
|
-
Upgrade a 3.5.2 database, an existing 3.6.
|
|
117
|
+
Upgrade a 3.5.2 database, an existing 3.6.x database, or a pre-release schema-25 test database to the current 3.7.0 schema/projection set in one backed-up command:
|
|
118
118
|
|
|
119
119
|
```bash
|
|
120
120
|
cogmem migrate --yes --backup --json
|
|
@@ -180,12 +180,14 @@ cogmem import-hermes --workspace . --project hermes --session ./hermes.normalize
|
|
|
180
180
|
|
|
181
181
|
The importer is idempotent. Re-running it skips records already imported into the same memory database.
|
|
182
182
|
|
|
183
|
-
Cogmem
|
|
183
|
+
Cogmem skips import batch sealing for empty episode boundaries and Dream skips legacy empty episode jobs instead of blocking the whole queue. If `episode status` shows `dreamError` beginning with `episode_empty`, inspect the source events and use episode repair instead of editing SQLite rows.
|
|
184
184
|
|
|
185
185
|
Run the maintenance loop under host supervision after import and during normal use. `needs_confirmation` is a human review queue, not the Dream backlog, and `memory govern` promotes only ordinary `candidate` rows:
|
|
186
186
|
|
|
187
187
|
```bash
|
|
188
|
+
cogmem memory plan --project hermes --json
|
|
188
189
|
cogmem memory status --project hermes --json
|
|
190
|
+
cogmem memory candidates --project hermes --json
|
|
189
191
|
cogmem episode status --project hermes --json
|
|
190
192
|
cogmem dream status --project hermes --json
|
|
191
193
|
cogmem dream tick --project hermes --mode auto --max-episodes 20 --json
|
|
@@ -196,6 +198,8 @@ cogmem memory review --project hermes --id <candidate-id> --action approve --act
|
|
|
196
198
|
cogmem memory recall --query "<verification question>" --project hermes --agent hermes --json
|
|
197
199
|
```
|
|
198
200
|
|
|
201
|
+
`memory plan` is the first agent-safe health and next-action command. It explains which queues block release, which work is non-blocking, whether vectors are empty but fallback recall is available, and what command should run next. Only run `dream_tick` when it appears in `nextActions`; if `nonBlocking` contains `raw_dream_ledger_lag` with `resolvableByDreamTick:false`, inspect raw sources or episode/import boundaries instead of retrying `dream tick`. Default `memory candidates --json` groups ordinary candidates, `needs_confirmation`, and deferred review entries; use `--status` only when the operator asks for one queue.
|
|
202
|
+
|
|
199
203
|
A host timer may run this bounded tick periodically. The tick exits after inspecting the backlog and performs no work when no sealed episode is ready.
|
|
200
204
|
|
|
201
205
|
## Active Memory Search
|
|
@@ -210,7 +214,9 @@ Choose the graph tool from the question shape:
|
|
|
210
214
|
- Direct factual question: `cogmem_recall`.
|
|
211
215
|
- Exact wording: follow an event ID with `cogmem memory show`.
|
|
212
216
|
|
|
213
|
-
Atlas combines whatever conditions the user supplies like table filters. Do not require entity + time + action. Project,
|
|
217
|
+
Atlas combines whatever conditions the user supplies like table filters. Do not require entity + time + action. Project, day/month/year, topic, issue, entity/target, session/thread, memory kind, action kind, and ordinary cues may revive cold nodes together. Activation is visibility, not truth. Atlas summaries are hints and never replace raw evidence.
|
|
218
|
+
|
|
219
|
+
In 3.7.0, `cogmem_graph_search`, `cogmem_graph_explore`, and historical recall can return canonical `cards[]`. Prefer cards over raw node labels for past-discussion questions. A card's `canonicalId` is the single episode identity; `matchedFacets` explains time/topic/issue/entity matches; `matchedPaths` explains how the card was reached; `relatedButNotSelected` is context only and must not replace the selected answer; `sourceLocator.command` is the command to inspect exact original text. If `relaxationTrace` exists, say the answer is a relaxed nearby match, not an exact hit.
|
|
214
220
|
|
|
215
221
|
When the prompt does not contain enough injected Cogmem context, do not search legacy memory files first. Ask Cogmem directly:
|
|
216
222
|
|
|
@@ -233,9 +239,25 @@ cogmem memory show --event <event-id> --before 2 --after 2 --json
|
|
|
233
239
|
|
|
234
240
|
`sourceContext` entries include stable `label` values, optional `charRange` / `sourceRange`, and `sourceContext.window` metadata. Use `window.before.requestedCount`, `window.before.count`, `window.after.requestedCount`, `window.after.count`, `excludesAnchor`, `ordering`, `roleFilter`, and `overlapHandling` to understand the before/after replay. `memory show --json` returns the same contract, so the labels in MCP recall can be matched to the local CLI output.
|
|
235
241
|
|
|
242
|
+
For “did we discuss this before?”, “几个月前是不是聊过…”, “记忆黑盒”, MCP memory gaps, or other old-discussion questions, force the historical-discussion lane before saying memory is absent:
|
|
243
|
+
|
|
244
|
+
```bash
|
|
245
|
+
cogmem memory recall --query "<past discussion question>" --intent historical_discussion --project hermes --agent hermes --json
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
If the answer depends on exact wording or nearby context, run the returned `sourceLocator` or use a Raw Ledger cursor:
|
|
249
|
+
|
|
250
|
+
```bash
|
|
251
|
+
cogmem memory show --event <eventId> --project hermes --before 2 --after 2 --json
|
|
252
|
+
cogmem memory list --project hermes --since <globalSeq> --order asc --json
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
Raw list rows and Atlas search/explore evidence include `sourceLocator.command` and a deeper `sourceLocator.contextCommand`. Use those commands before claiming an event ID is missing, before quoting exact words, or before treating an Atlas summary as the source.
|
|
256
|
+
|
|
236
257
|
`vectors: 0` does not mean memory is unavailable. It means dense vector search has no hot index yet; `memory recall` still has governed raw-ledger fallback. Broad inventory questions are expanded into structured cues such as `库存管理`, `在库`, `产品コード`, and `数量`; when compiled candidates miss those cues, prefer the raw ledger result and use its `sourceContext` for details. Check status with:
|
|
237
258
|
|
|
238
259
|
```bash
|
|
260
|
+
cogmem memory plan --project hermes --json
|
|
239
261
|
cogmem memory status --project hermes --json
|
|
240
262
|
```
|
|
241
263
|
|
|
@@ -252,12 +274,13 @@ Default recall includes untagged and `collection:anchor` memory only. Ask for `c
|
|
|
252
274
|
For host upkeep, inspect the self-map and run an explicit tick:
|
|
253
275
|
|
|
254
276
|
```bash
|
|
277
|
+
cogmem memory plan --project hermes --json
|
|
255
278
|
cogmem memory map --project hermes --json
|
|
256
279
|
cogmem memory tick --project hermes --json
|
|
257
280
|
cogmem memory bind --project hermes --json
|
|
258
281
|
```
|
|
259
282
|
|
|
260
|
-
`memory tick` does not start a daemon. Use its `suggestedActions` to decide whether Hermes should run `dream tick`, `memory govern`, `episode repair`, entity review, re-embedding, or `memory bind` for unbound high-value raw events.
|
|
283
|
+
`memory tick` does not start a daemon. Use its `suggestedActions` to decide whether Hermes should run `dream tick`, `memory govern`, `episode repair`, entity review, re-embedding, or `memory bind` for unbound high-value raw events. `undreamedRawCount` by itself is Raw Ledger coverage lag, not a sealed-episode job; do not loop `dream tick` unless `memory plan.nextActions` contains `dream_tick`. `memory bind` scans the historical Raw Ledger by cursor instead of only the latest page; resume large repairs with `--since <globalSeq>`.
|
|
261
284
|
|
|
262
285
|
`memory map` also exposes Memory Binding and Graph Recall counters. Bindings connect high-value user raw events to stable topic/entity paths before promotion, fuse same-claim evidence into claim-key clusters, and create graph anchors for source drill-down. Correction bindings expose review flags and correction edges. Use graph recall hits for source drill-down and topic continuity only; do not treat bindings, clusters, or edges as verified facts, user preferences, or prompt instructions.
|
|
263
286
|
|
|
@@ -267,7 +290,7 @@ Explicit user clarification is organizational correction evidence, not an automa
|
|
|
267
290
|
|
|
268
291
|
When importing OpenClaw-style session Markdown into a Hermes project, Cogmem accepts multiline bodies below empty role headers, collapses only adjacent exact export duplicates, and uses `# Session: ... UTC` as the chronological timestamp base rather than file mtime.
|
|
269
292
|
|
|
270
|
-
After upgrading, rerun `cogmem connect hermes --workspace . --auto --force` and reload MCP so existing allow-lists and skill instructions receive the current tools and contracts.
|
|
293
|
+
After upgrading, rerun `cogmem connect hermes --workspace . --auto --force --json` and reload MCP so existing allow-lists and skill instructions receive the current tools and contracts. In JSON output, follow only `nextCommands` for unattended agent work; unsafe operator or host steps such as interactive init and `/reload-mcp` are listed under `nextSteps` with `safeForAutomation=false`.
|
|
271
294
|
|
|
272
295
|
## Runtime Wiring
|
|
273
296
|
|