Update project files
This commit is contained in:
@@ -17,6 +17,14 @@ import { EpisodicEntry, MemoryContextResult } from './types';
|
||||
export class EpisodicMemory {
|
||||
private episodeDir: string;
|
||||
private maxEpisodes: number;
|
||||
/**
|
||||
* mtime-keyed cache of the parsed episode list. The previous implementation
|
||||
* re-read and re-parsed every episode JSON from disk on every message. We now
|
||||
* cache the parsed result and re-read only when the episode directory's mtime
|
||||
* changes (a new/removed/rewritten episode bumps the directory mtime). This
|
||||
* mirrors the mtime-keyed caching style of `retrieval/brainIndex.ts`.
|
||||
*/
|
||||
private _episodeCache: { dirMtimeMs: number; episodes: EpisodicEntry[] } | null = null;
|
||||
|
||||
constructor(brainPath: string, maxEpisodes = 50) {
|
||||
this.episodeDir = path.join(brainPath, 'memory', 'episodes');
|
||||
@@ -85,9 +93,19 @@ export class EpisodicMemory {
|
||||
|
||||
/**
|
||||
* 저장된 모든 에피소드를 최신순으로 로드합니다.
|
||||
*
|
||||
* Result is cached and re-read only when the episode directory's mtime
|
||||
* changes — creating, deleting, or rewriting an episode file all bump the
|
||||
* directory mtime, so the cache stays correct without per-message disk reads.
|
||||
*/
|
||||
public loadAllEpisodes(): EpisodicEntry[] {
|
||||
try {
|
||||
const dirMtimeMs = fs.statSync(this.episodeDir).mtimeMs;
|
||||
const cached = this._episodeCache;
|
||||
if (cached && cached.dirMtimeMs === dirMtimeMs) {
|
||||
return cached.episodes.slice();
|
||||
}
|
||||
|
||||
const files = fs.readdirSync(this.episodeDir)
|
||||
.filter((f) => f.endsWith('.json'))
|
||||
.sort()
|
||||
@@ -101,7 +119,8 @@ export class EpisodicMemory {
|
||||
} catch { /* skip corrupted */ }
|
||||
}
|
||||
|
||||
return episodes;
|
||||
this._episodeCache = { dirMtimeMs, episodes };
|
||||
return episodes.slice();
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
|
||||
@@ -17,13 +17,16 @@ export class LongTermMemory {
|
||||
private store: LongTermStore;
|
||||
private filePath: string;
|
||||
private dirty = false;
|
||||
/** Hard cap on retained entries — oldest are trimmed when exceeded. Default 100 (matches MemoryConfig.longTermMaxEntries). */
|
||||
private maxEntries: number;
|
||||
|
||||
constructor(brainPath: string) {
|
||||
constructor(brainPath: string, maxEntries = 100) {
|
||||
const memoryDir = path.join(brainPath, 'memory');
|
||||
if (!fs.existsSync(memoryDir)) {
|
||||
fs.mkdirSync(memoryDir, { recursive: true });
|
||||
}
|
||||
this.filePath = path.join(memoryDir, 'long_term.json');
|
||||
this.maxEntries = maxEntries > 0 ? maxEntries : 100;
|
||||
this.store = this.load();
|
||||
}
|
||||
|
||||
@@ -62,6 +65,12 @@ export class LongTermMemory {
|
||||
referenceCount: 0
|
||||
};
|
||||
this.store.entries.push(entry);
|
||||
// Enforce the retention cap — drop the oldest entries (by createdAt) once
|
||||
// over the limit. The store array is append-ordered, so the oldest are at
|
||||
// the front; we trim from there.
|
||||
if (this.store.entries.length > this.maxEntries) {
|
||||
this.store.entries.splice(0, this.store.entries.length - this.maxEntries);
|
||||
}
|
||||
this.dirty = true;
|
||||
this.save();
|
||||
return entry;
|
||||
|
||||
+1
-1
@@ -54,7 +54,7 @@ export class MemoryManager {
|
||||
};
|
||||
|
||||
this.shortTerm = new ShortTermMemory();
|
||||
this.longTerm = new LongTermMemory(brainPath);
|
||||
this.longTerm = new LongTermMemory(brainPath, this.config.longTermMaxEntries);
|
||||
this.procedural = new ProceduralMemory(brainPath);
|
||||
this.episodic = new EpisodicMemory(brainPath, this.config.episodicMaxEpisodes);
|
||||
this.extractor = new MemoryExtractor();
|
||||
|
||||
Reference in New Issue
Block a user