Update project files

This commit is contained in:
2026-05-22 15:00:14 +09:00
parent 132d130ff1
commit 8016ef18fa
29 changed files with 1353 additions and 804 deletions
+20 -1
View File
@@ -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 [];
}
+10 -1
View File
@@ -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
View File
@@ -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();