cogmem 3.6.3 → 3.6.5
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 +19 -0
- package/README.md +67 -16
- package/RELEASE_CHECKLIST.md +12 -4
- package/dist/agent/AgentMemoryBackend.d.ts +6 -1
- package/dist/agent/AgentMemoryBackend.js +51 -1
- package/dist/agent/AgentRecallQueryCompiler.d.ts +1 -1
- package/dist/agent/AgentRecallQueryCompiler.js +12 -0
- package/dist/atlas/MemoryAtlasService.d.ts +1 -0
- package/dist/atlas/MemoryAtlasService.js +39 -5
- package/dist/atlas/MemoryAtlasTypes.d.ts +14 -0
- package/dist/bin/connect.js +115 -31
- package/dist/bin/import-support.d.ts +1 -0
- package/dist/bin/import-support.js +15 -2
- package/dist/bin/mcp.js +2 -1
- package/dist/bin/memory.js +217 -17
- package/dist/episode/EpisodeStore.d.ts +7 -0
- package/dist/episode/EpisodeStore.js +75 -6
- package/dist/factory.d.ts +2 -0
- package/dist/factory.js +38 -18
- package/dist/host/openclaw/AutoMemoryPluginInstaller.js +6 -2
- package/dist/mcp/server.js +1 -1
- package/dist/store/EventStore.d.ts +6 -0
- package/dist/store/EventStore.js +28 -2
- package/dist/types/index.d.ts +3 -0
- package/examples/hermes-backend/AGENTS.md +36 -16
- package/examples/hermes-backend/README.md +25 -13
- package/examples/hermes-backend/SKILL.md +72 -22
- package/examples/hermes-backend/references/operations.md +50 -13
- package/examples/openclaw-backend/AGENTS.md +33 -7
- package/examples/openclaw-backend/README.md +27 -12
- package/examples/openclaw-backend/SKILL.md +65 -19
- package/examples/openclaw-backend/references/operations.md +53 -12
- package/package.json +1 -1
|
@@ -54,6 +54,7 @@ export declare class EpisodeStore {
|
|
|
54
54
|
}): EpisodeEventLink;
|
|
55
55
|
getEventLink(eventId: string): EpisodeEventLink | undefined;
|
|
56
56
|
listEventLinks(episodeId: string): EpisodeEventLink[];
|
|
57
|
+
isEpisodeEmpty(episodeId: string): boolean;
|
|
57
58
|
addCrossReference(input: {
|
|
58
59
|
projectId: string;
|
|
59
60
|
episodeId: string;
|
|
@@ -120,6 +121,10 @@ export declare class EpisodeStore {
|
|
|
120
121
|
maxAttempts: number;
|
|
121
122
|
runId?: string;
|
|
122
123
|
}): ClaimedEpisodeDreamJob[];
|
|
124
|
+
skipEmptyDreamJobs(input: {
|
|
125
|
+
projectId?: string;
|
|
126
|
+
now?: number;
|
|
127
|
+
}): number;
|
|
123
128
|
completeDreamJob(episodeId: string, leaseId: string, candidateIds: string[], now: number): void;
|
|
124
129
|
failDreamJob(episodeId: string, leaseId: string, error: string, input: {
|
|
125
130
|
now: number;
|
|
@@ -128,6 +133,8 @@ export declare class EpisodeStore {
|
|
|
128
133
|
retryAfter?: number;
|
|
129
134
|
}): void;
|
|
130
135
|
retryFailed(projectId?: string): number;
|
|
136
|
+
private markEmptyEpisodeDreamSkipped;
|
|
137
|
+
private markEmptyEpisodeDreamSkippedMany;
|
|
131
138
|
getDreamStatus(projectId?: string): EpisodeDreamStatus;
|
|
132
139
|
countUnassignedRawEvents(projectId?: string): number;
|
|
133
140
|
markEventDisposition(input: {
|
|
@@ -142,6 +142,12 @@ export class EpisodeStore {
|
|
|
142
142
|
SELECT * FROM memory_episode_events WHERE episode_id = ? ORDER BY position
|
|
143
143
|
`).all(episodeId).map(mapEventLink);
|
|
144
144
|
}
|
|
145
|
+
isEpisodeEmpty(episodeId) {
|
|
146
|
+
const episode = this.getEpisode(episodeId);
|
|
147
|
+
if (!episode)
|
|
148
|
+
throw new Error(`episode_not_found:${episodeId}`);
|
|
149
|
+
return this.listEventLinks(episodeId).length === 0;
|
|
150
|
+
}
|
|
145
151
|
addCrossReference(input) {
|
|
146
152
|
const episode = this.getEpisode(input.episodeId);
|
|
147
153
|
if (!episode)
|
|
@@ -334,9 +340,18 @@ export class EpisodeStore {
|
|
|
334
340
|
const now = input.now ?? Date.now();
|
|
335
341
|
const episodes = this.listEpisodes({ projectId: input.projectId, statuses: ['soft_sealed'], limit: 1000 })
|
|
336
342
|
.filter((episode) => (episode.sealedAt || episode.updatedAt) <= input.sealedBefore);
|
|
337
|
-
|
|
343
|
+
let sealed = 0;
|
|
344
|
+
for (const episode of episodes) {
|
|
345
|
+
if (this.isEpisodeEmpty(episode.episodeId)) {
|
|
346
|
+
if (episode.dreamError !== 'episode_empty_soft_seal_not_promoted') {
|
|
347
|
+
this.markEmptyEpisodeDreamSkipped(episode.episodeId, now, 'episode_empty_soft_seal_not_promoted');
|
|
348
|
+
}
|
|
349
|
+
continue;
|
|
350
|
+
}
|
|
338
351
|
this.sealEpisode(episode.episodeId, { mode: 'hard', reason: 'soft_seal_stabilized', now });
|
|
339
|
-
|
|
352
|
+
sealed += 1;
|
|
353
|
+
}
|
|
354
|
+
return sealed;
|
|
340
355
|
}
|
|
341
356
|
claimDreamJobs(input) {
|
|
342
357
|
this.db.prepare(`
|
|
@@ -372,15 +387,21 @@ export class EpisodeStore {
|
|
|
372
387
|
UPDATE memory_episodes SET dream_status = 'queued', dream_error = NULL
|
|
373
388
|
WHERE episode_id IN (SELECT episode_id FROM episode_dream_jobs WHERE state = 'retry_scheduled' AND updated_at = ?)
|
|
374
389
|
`).run(input.now);
|
|
375
|
-
|
|
390
|
+
this.skipEmptyDreamJobs({ projectId: input.projectId, now: input.now });
|
|
391
|
+
const where = [`(j.state = 'pending' OR (j.state = 'retry_scheduled' AND j.attempts < ?))`];
|
|
376
392
|
const params = [input.maxAttempts];
|
|
377
393
|
if (input.projectId) {
|
|
378
|
-
where.push('project_id = ?');
|
|
394
|
+
where.push('j.project_id = ?');
|
|
379
395
|
params.push(input.projectId);
|
|
380
396
|
}
|
|
381
397
|
const rows = this.db.prepare(`
|
|
382
|
-
SELECT episode_id, project_id, mode_hint, attempts, created_at
|
|
383
|
-
|
|
398
|
+
SELECT j.episode_id, j.project_id, j.mode_hint, j.attempts, j.created_at
|
|
399
|
+
FROM episode_dream_jobs j
|
|
400
|
+
JOIN memory_episodes e ON e.episode_id = j.episode_id
|
|
401
|
+
WHERE ${where.join(' AND ')}
|
|
402
|
+
AND e.event_count > 0
|
|
403
|
+
AND EXISTS (SELECT 1 FROM memory_episode_events ee WHERE ee.episode_id = j.episode_id)
|
|
404
|
+
ORDER BY j.priority DESC, j.created_at LIMIT ?
|
|
384
405
|
`).all(...params, Math.max(1, Math.min(Math.trunc(input.limit), 100)));
|
|
385
406
|
const claimed = [];
|
|
386
407
|
for (const row of rows) {
|
|
@@ -403,6 +424,32 @@ export class EpisodeStore {
|
|
|
403
424
|
}
|
|
404
425
|
return claimed;
|
|
405
426
|
}
|
|
427
|
+
skipEmptyDreamJobs(input) {
|
|
428
|
+
const now = input.now ?? Date.now();
|
|
429
|
+
const params = [];
|
|
430
|
+
const where = [
|
|
431
|
+
`j.state IN ('pending', 'failed_retryable', 'retry_scheduled')`,
|
|
432
|
+
`(COALESCE(e.event_count, 0) = 0 OR NOT EXISTS (
|
|
433
|
+
SELECT 1 FROM memory_episode_events ee WHERE ee.episode_id = j.episode_id
|
|
434
|
+
))`,
|
|
435
|
+
];
|
|
436
|
+
if (input.projectId) {
|
|
437
|
+
where.push(`j.project_id = ?`);
|
|
438
|
+
params.push(input.projectId);
|
|
439
|
+
}
|
|
440
|
+
const rows = this.db.prepare(`
|
|
441
|
+
SELECT j.episode_id FROM episode_dream_jobs j
|
|
442
|
+
LEFT JOIN memory_episodes e ON e.episode_id = j.episode_id
|
|
443
|
+
WHERE ${where.join(' AND ')}
|
|
444
|
+
ORDER BY j.updated_at DESC
|
|
445
|
+
LIMIT 1000
|
|
446
|
+
`).all(...params);
|
|
447
|
+
const episodeIds = rows.map((row) => row.episode_id);
|
|
448
|
+
if (!episodeIds.length)
|
|
449
|
+
return 0;
|
|
450
|
+
this.markEmptyEpisodeDreamSkippedMany(episodeIds, now, 'episode_empty_skipped_no_raw_evidence');
|
|
451
|
+
return episodeIds.length;
|
|
452
|
+
}
|
|
406
453
|
completeDreamJob(episodeId, leaseId, candidateIds, now) {
|
|
407
454
|
const result = this.db.prepare(`
|
|
408
455
|
UPDATE episode_dream_jobs SET state = 'processed', candidate_ids_json = ?, lease_id = NULL,
|
|
@@ -441,6 +488,28 @@ export class EpisodeStore {
|
|
|
441
488
|
}
|
|
442
489
|
return Number(result.changes || 0);
|
|
443
490
|
}
|
|
491
|
+
markEmptyEpisodeDreamSkipped(episodeId, now, reason) {
|
|
492
|
+
this.markEmptyEpisodeDreamSkippedMany([episodeId], now, reason);
|
|
493
|
+
}
|
|
494
|
+
markEmptyEpisodeDreamSkippedMany(episodeIds, now, reason) {
|
|
495
|
+
if (!episodeIds.length)
|
|
496
|
+
return;
|
|
497
|
+
const placeholders = episodeIds.map(() => '?').join(', ');
|
|
498
|
+
this.db.transaction(() => {
|
|
499
|
+
this.db.prepare(`
|
|
500
|
+
UPDATE episode_dream_jobs SET state = 'skipped', lease_id = NULL, lease_until = NULL,
|
|
501
|
+
retry_after = NULL, failure_category = 'episode_empty', last_error = ?, candidate_ids_json = '[]',
|
|
502
|
+
updated_at = ?
|
|
503
|
+
WHERE episode_id IN (${placeholders})
|
|
504
|
+
AND state IN ('pending', 'processing', 'failed_retryable', 'retry_scheduled')
|
|
505
|
+
`).run(reason, now, ...episodeIds);
|
|
506
|
+
this.db.prepare(`
|
|
507
|
+
UPDATE memory_episodes SET dream_status = 'failed', dream_error = ?, last_dream_run_id = NULL,
|
|
508
|
+
dream_candidate_count = 0, updated_at = ?
|
|
509
|
+
WHERE episode_id IN (${placeholders})
|
|
510
|
+
`).run(reason, now, ...episodeIds);
|
|
511
|
+
})();
|
|
512
|
+
}
|
|
444
513
|
getDreamStatus(projectId) {
|
|
445
514
|
const rows = (projectId
|
|
446
515
|
? this.db.prepare(`SELECT state, COUNT(*) AS count FROM episode_dream_jobs WHERE project_id = ? GROUP BY state`).all(projectId)
|
package/dist/factory.d.ts
CHANGED
|
@@ -138,6 +138,8 @@ export interface MemoryBindingBackfillOptions {
|
|
|
138
138
|
export interface MemoryBindingBackfillResult {
|
|
139
139
|
projectId?: string;
|
|
140
140
|
sinceGlobalSeq?: number;
|
|
141
|
+
nextGlobalSeq?: number;
|
|
142
|
+
hasMore: boolean;
|
|
141
143
|
scannedEvents: number;
|
|
142
144
|
bindableEvents: number;
|
|
143
145
|
boundEvents: number;
|
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.6.
|
|
86
|
+
const CORE_VERSION = '3.6.5';
|
|
87
87
|
const LATEST_SCHEMA_VERSION = 27;
|
|
88
88
|
export class MemoryKernel {
|
|
89
89
|
options;
|
|
@@ -983,6 +983,8 @@ export class MemoryKernel {
|
|
|
983
983
|
}
|
|
984
984
|
sealImportedEpisode(episodeId, input) {
|
|
985
985
|
const links = this.episodeStore.listEventLinks(episodeId);
|
|
986
|
+
if (!links.length)
|
|
987
|
+
throw new Error(`episode_empty:${episodeId}`);
|
|
986
988
|
const averageConfidence = links.length
|
|
987
989
|
? links.reduce((total, link) => total + link.confidence, 0) / links.length
|
|
988
990
|
: 0;
|
|
@@ -1193,18 +1195,22 @@ export class MemoryKernel {
|
|
|
1193
1195
|
}
|
|
1194
1196
|
bindRawEvents(options = {}) {
|
|
1195
1197
|
const limit = Math.max(1, Math.min(options.limit ?? 500, 5000));
|
|
1196
|
-
const
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1198
|
+
const afterGlobalSeq = options.sinceGlobalSeq === undefined
|
|
1199
|
+
? undefined
|
|
1200
|
+
: Math.max(-1, options.sinceGlobalSeq - 1);
|
|
1201
|
+
const records = this.eventStore.listRawEventsAfterGlobalSeq({
|
|
1202
|
+
projectId: options.projectId,
|
|
1203
|
+
workspaceId: options.workspaceId,
|
|
1204
|
+
threadId: options.threadId,
|
|
1205
|
+
sessionId: options.sessionId,
|
|
1206
|
+
afterGlobalSeq,
|
|
1207
|
+
limit,
|
|
1201
1208
|
});
|
|
1202
|
-
const records = page.records
|
|
1203
|
-
.filter((event) => options.sinceGlobalSeq === undefined || (event.globalSeq || 0) >= options.sinceGlobalSeq)
|
|
1204
|
-
.sort((a, b) => (a.globalSeq || 0) - (b.globalSeq || 0));
|
|
1205
1209
|
const result = {
|
|
1206
1210
|
projectId: options.projectId,
|
|
1207
1211
|
sinceGlobalSeq: options.sinceGlobalSeq,
|
|
1212
|
+
nextGlobalSeq: records.at(-1)?.globalSeq,
|
|
1213
|
+
hasMore: records.length >= limit,
|
|
1208
1214
|
scannedEvents: records.length,
|
|
1209
1215
|
bindableEvents: 0,
|
|
1210
1216
|
boundEvents: 0,
|
|
@@ -1323,16 +1329,30 @@ export class MemoryKernel {
|
|
|
1323
1329
|
return { touched: this.memoryAtlasStore.recordAccess(input.projectId, valid, input.reason, input.query, input.now) };
|
|
1324
1330
|
}
|
|
1325
1331
|
countUnboundBindableRawEvents(projectId, limit = 1000) {
|
|
1326
|
-
const
|
|
1327
|
-
|
|
1328
|
-
});
|
|
1332
|
+
const max = Math.max(1, limit);
|
|
1333
|
+
let afterGlobalSeq;
|
|
1329
1334
|
let count = 0;
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1335
|
+
while (count < max) {
|
|
1336
|
+
const batchLimit = Math.min(500, max);
|
|
1337
|
+
const events = this.eventStore.listRawEventsAfterGlobalSeq({
|
|
1338
|
+
projectId,
|
|
1339
|
+
afterGlobalSeq,
|
|
1340
|
+
limit: batchLimit,
|
|
1341
|
+
});
|
|
1342
|
+
if (events.length === 0)
|
|
1343
|
+
break;
|
|
1344
|
+
afterGlobalSeq = events.at(-1)?.globalSeq ?? afterGlobalSeq;
|
|
1345
|
+
for (const event of events) {
|
|
1346
|
+
if (!this.memoryBindingService.isBindableRawEvent(event))
|
|
1347
|
+
continue;
|
|
1348
|
+
if (this.memoryBindingStore.listBindings({ eventId: event.eventId, limit: 1 }).length > 0)
|
|
1349
|
+
continue;
|
|
1350
|
+
count += 1;
|
|
1351
|
+
if (count >= max)
|
|
1352
|
+
break;
|
|
1353
|
+
}
|
|
1354
|
+
if (events.length < batchLimit)
|
|
1355
|
+
break;
|
|
1336
1356
|
}
|
|
1337
1357
|
return count;
|
|
1338
1358
|
}
|
|
@@ -26,7 +26,7 @@ export function installOpenClawAutoMemoryPlugin(options) {
|
|
|
26
26
|
? { kind: 'toml', path: resolve(options.configPath) }
|
|
27
27
|
: resolveCogmemConfigPath({ cwd: workspaceRoot });
|
|
28
28
|
if (configResolution.kind !== 'toml') {
|
|
29
|
-
throw new Error(`Missing cogmem config at ${configResolution.path}.
|
|
29
|
+
throw new Error(`Missing cogmem config at ${configResolution.path}. Ask an operator to run the interactive setup: cogmem init --agent openclaw --scope project.`);
|
|
30
30
|
}
|
|
31
31
|
const configPath = configResolution.path;
|
|
32
32
|
const pluginDir = resolve(options.pluginDir || defaultOpenClawAutoMemoryPluginDir(workspaceRoot));
|
|
@@ -663,6 +663,9 @@ function classifyRecallIntent(query) {
|
|
|
663
663
|
if (/原话|怎么说的|完整对话|上一句|下一句|exact quote|verbatim/.test(text)) {
|
|
664
664
|
return 'forensic_quote';
|
|
665
665
|
}
|
|
666
|
+
if (/记得.{0,12}(聊过|讨论过|说过)|还记得|之前.{0,12}(聊过|讨论过|说过)|以前.{0,12}(聊过|讨论过|说过)|(过去|几个月前|半年前|上个月|前几天|昨天|上次|上个).{0,20}(聊过|讨论过|说过)|当时.{0,12}(聊|说|问)|那次.{0,12}(聊|说|问)|有没有.{0,12}(记录|聊过|讨论过)|have we discussed|did we talk about|previously discussed/.test(text)) {
|
|
667
|
+
return 'historical_discussion';
|
|
668
|
+
}
|
|
666
669
|
return 'memory_recall';
|
|
667
670
|
}
|
|
668
671
|
|
|
@@ -1754,7 +1757,8 @@ function formatRecallContext(result, config) {
|
|
|
1754
1757
|
if (item.sourceContext.locator && item.sourceContext.locator.command) {
|
|
1755
1758
|
lines.push(' sourceLocator=' + item.sourceContext.locator.command);
|
|
1756
1759
|
} else if (item.sourceContext.event.eventId) {
|
|
1757
|
-
|
|
1760
|
+
const project = item.sourceContext.event.projectId ? ' --project ' + item.sourceContext.event.projectId : '';
|
|
1761
|
+
lines.push(' sourceLocator=cogmem memory show --event ' + item.sourceContext.event.eventId + project + ' --before 2 --after 2 --json');
|
|
1758
1762
|
}
|
|
1759
1763
|
const seenEventIds = new Set([anchorEvent.eventId].filter(Boolean));
|
|
1760
1764
|
const before = uniqueWindowEvents(Array.isArray(item.sourceContext.before) ? item.sourceContext.before : [], seenEventIds).slice(-2);
|
package/dist/mcp/server.js
CHANGED
|
@@ -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
|
}
|
package/dist/types/index.d.ts
CHANGED
|
@@ -15,19 +15,24 @@ This writes `~/.hermes/skills/cogmem-memory/SKILL.md`, which Hermes discovers as
|
|
|
15
15
|
Run from the Hermes workspace root:
|
|
16
16
|
|
|
17
17
|
```bash
|
|
18
|
-
|
|
19
|
-
cogmem
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
18
|
+
npm install cogmem@latest --save
|
|
19
|
+
COGMEM="./node_modules/.bin/cogmem"
|
|
20
|
+
"$COGMEM" doctor
|
|
21
|
+
"$COGMEM" connect hermes --workspace . --auto --force --json
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Do not run `cogmem init` as an unattended agent action. It is an interactive wizard. Use it only when an operator is present:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
"$COGMEM" init --agent hermes --scope project
|
|
23
28
|
```
|
|
24
29
|
|
|
25
|
-
The
|
|
30
|
+
The workspace install creates:
|
|
26
31
|
|
|
27
32
|
```text
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
33
|
+
.cogmem/config.toml
|
|
34
|
+
.cogmem/memory.db
|
|
35
|
+
.cogmem/snapshots/
|
|
31
36
|
```
|
|
32
37
|
|
|
33
38
|
Use `~/.cogmem/config.toml` or a project `.cogmem/config.toml` as the stable configuration source. Do not create `.cogmem.env` files or pass `--env-path` for normal installs. Environment variables are only for explicit process-level overrides documented by the CLI, not for hidden workspace configuration.
|
|
@@ -44,7 +49,7 @@ Use MCP `cogmem_strategy_plan` when the agent needs to inspect the selected memo
|
|
|
44
49
|
|
|
45
50
|
Prospective Memory is not executable instruction. Only a user-confirmed candidate may appear as due, and even then the agent must obtain normal host authorization before acting. Use `cogmem prospective` for state transitions and `cogmem brain-eval` for release validation.
|
|
46
51
|
|
|
47
|
-
Use
|
|
52
|
+
Use project-local config when this workspace owns its memory; use global config only when the operator intentionally shares one Cogmem backend across workspaces.
|
|
48
53
|
|
|
49
54
|
To embed imported memories with a local quantized model, run Ollama locally and configure the kernel before importing:
|
|
50
55
|
|
|
@@ -117,14 +122,26 @@ cogmem normalize-transcript --input ./hermes-sessions.jsonl --output ./hermes.no
|
|
|
117
122
|
cogmem import-hermes --workspace . --project hermes --session ./hermes.normalized.md
|
|
118
123
|
```
|
|
119
124
|
|
|
120
|
-
|
|
125
|
+
Cogmem 3.6.4 and later skip import batch sealing for empty episode boundaries and skip legacy empty Dream jobs so one bad imported episode cannot block the queue.
|
|
126
|
+
|
|
127
|
+
After import, use this order:
|
|
121
128
|
|
|
122
129
|
```bash
|
|
130
|
+
cogmem memory plan --project hermes --json
|
|
131
|
+
cogmem memory status --project hermes --json
|
|
132
|
+
cogmem memory candidates --project hermes --json
|
|
123
133
|
cogmem episode status --project hermes --json
|
|
124
|
-
cogmem dream
|
|
125
|
-
cogmem
|
|
134
|
+
cogmem dream status --project hermes --json
|
|
135
|
+
cogmem dream tick --project hermes --mode auto --max-episodes 20 --json
|
|
136
|
+
cogmem memory candidates --project hermes --status candidate --json
|
|
137
|
+
cogmem memory govern --project hermes --limit 100 --json
|
|
138
|
+
cogmem memory candidates --project hermes --status needs_confirmation --json
|
|
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
|
|
126
141
|
```
|
|
127
142
|
|
|
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.
|
|
144
|
+
|
|
128
145
|
## Active Memory Search
|
|
129
146
|
|
|
130
147
|
If the current prompt does not include enough Cogmem memory context, query Cogmem directly before searching legacy files:
|
|
@@ -139,15 +156,18 @@ For inventory or product questions, use recall first and raw search as a forensi
|
|
|
139
156
|
cogmem memory recall --query "我们记录过哪些库存" --project hermes --agent hermes --json
|
|
140
157
|
cogmem memory search --query "エルビ 库存" --project hermes --json
|
|
141
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
|
|
142
161
|
```
|
|
143
162
|
|
|
144
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.
|
|
145
164
|
|
|
146
|
-
`sourceContext` and `memory show --json` now 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.
|
|
165
|
+
`sourceContext` and `memory show --json` now 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. In 3.6.5, 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.
|
|
147
166
|
|
|
148
167
|
Check status with:
|
|
149
168
|
|
|
150
169
|
```bash
|
|
170
|
+
cogmem memory plan --project hermes --json
|
|
151
171
|
cogmem memory status --project hermes --json
|
|
152
172
|
```
|
|
153
173
|
|
|
@@ -207,12 +227,12 @@ Hermes has no automatic observation path in this integration. Use `cogmem_episod
|
|
|
207
227
|
|
|
208
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.
|
|
209
229
|
|
|
210
|
-
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
|
|
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`; in 3.6.5 it scans the historical ledger by cursor and can resume with `--since <globalSeq>`. 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`.
|
|
211
231
|
|
|
212
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.
|
|
213
233
|
|
|
214
234
|
## Memory Atlas navigation
|
|
215
235
|
|
|
216
|
-
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.
|
|
217
237
|
|
|
218
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.
|
|
@@ -14,19 +14,16 @@ Belief Graph writes keep ownership and evidence roles. Hermes may record assista
|
|
|
14
14
|
## Install
|
|
15
15
|
|
|
16
16
|
```bash
|
|
17
|
-
|
|
18
|
-
cogmem
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
cogmem connect hermes --workspace .
|
|
17
|
+
npm install cogmem@latest --save
|
|
18
|
+
COGMEM="./node_modules/.bin/cogmem"
|
|
19
|
+
"$COGMEM" doctor
|
|
20
|
+
"$COGMEM" connect hermes --workspace . --auto --force --json
|
|
22
21
|
```
|
|
23
22
|
|
|
24
|
-
|
|
23
|
+
Use `cogmem init` only as an interactive operator wizard, not as an unattended agent install step:
|
|
25
24
|
|
|
26
25
|
```bash
|
|
27
|
-
|
|
28
|
-
cogmem init --yes --agent hermes
|
|
29
|
-
cogmem connect hermes --workspace . --auto --force
|
|
26
|
+
"$COGMEM" init --agent hermes --scope project
|
|
30
27
|
```
|
|
31
28
|
|
|
32
29
|
Hermes integration is currently a skill plus MCP bridge. It does not replace a native Hermes memory provider and it does not patch Hermes runtime internals.
|
|
@@ -75,6 +72,21 @@ Import:
|
|
|
75
72
|
cogmem import-hermes --workspace . --project hermes
|
|
76
73
|
```
|
|
77
74
|
|
|
75
|
+
After import:
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
cogmem memory plan --project hermes --json
|
|
79
|
+
cogmem memory status --project hermes --json
|
|
80
|
+
cogmem memory candidates --project hermes --json
|
|
81
|
+
cogmem episode status --project hermes --json
|
|
82
|
+
cogmem dream status --project hermes --json
|
|
83
|
+
cogmem dream tick --project hermes --mode auto --max-episodes 20 --json
|
|
84
|
+
cogmem memory candidates --project hermes --status candidate --json
|
|
85
|
+
cogmem memory govern --project hermes --limit 100 --json
|
|
86
|
+
cogmem memory candidates --project hermes --status needs_confirmation --json
|
|
87
|
+
cogmem memory review --project hermes --id <candidate-id> --action approve --actor <operator> --reason "confirmed by user" --confirmation-event <user-event-id> --json
|
|
88
|
+
```
|
|
89
|
+
|
|
78
90
|
If Hermes stores memory somewhere else:
|
|
79
91
|
|
|
80
92
|
```bash
|
|
@@ -91,13 +103,13 @@ cogmem import-hermes --workspace . --project hermes --session ./one.md --session
|
|
|
91
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.
|
|
92
104
|
Imported records are embedded through the configured kernel embedder during import.
|
|
93
105
|
|
|
94
|
-
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`.
|
|
95
107
|
|
|
96
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.
|
|
97
109
|
|
|
98
|
-
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`.
|
|
99
111
|
|
|
100
|
-
Cogmem 3.6.
|
|
112
|
+
Cogmem 3.6.5 exposes seven 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, time, topic, entity/target, memory-kind, action, and keyword conditions like table filters, so cold memory can be revived without requiring an entity-time-action tuple. Touch only nodes actually used, and follow returned event IDs or `sourceLocator` commands to raw evidence before quoting exact wording.
|
|
101
113
|
|
|
102
114
|
## Runtime
|
|
103
115
|
|
|
@@ -155,7 +167,7 @@ cogmem memory map --project hermes --json
|
|
|
155
167
|
cogmem memory tick --project hermes --json
|
|
156
168
|
cogmem memory bind --project hermes --json
|
|
157
169
|
cogmem episode status --project hermes --json
|
|
158
|
-
cogmem dream tick --project hermes --mode auto --json
|
|
170
|
+
cogmem dream tick --project hermes --mode auto --max-episodes 20 --json
|
|
159
171
|
```
|
|
160
172
|
|
|
161
173
|
`memory map` includes Memory Binding and Graph Recall counters. Bindings attach valuable user raw events to stable topic/entity paths, fuse same-claim evidence into claim-key clusters, and create graph anchors for raw-ledger drill-down; they are not verified long-term facts. If `memory tick` suggests `bind_raw_events`, run `memory bind` to backfill imported Hermes raw user events into the binding graph.
|