diff --git a/src/memory/__tests__/knowledge-graph.test.ts b/src/memory/__tests__/knowledge-graph.test.ts index 236242413a..5cd9c7d138 100644 --- a/src/memory/__tests__/knowledge-graph.test.ts +++ b/src/memory/__tests__/knowledge-graph.test.ts @@ -515,4 +515,20 @@ describe('KnowledgeGraphManager', () => { expect(result.relations[0]).not.toHaveProperty('type'); }); }); + + describe('atomic saveGraph persistence', () => { + it('should cleanly persist data and leave no leftover temp files', async () => { + await manager.createEntities([ + { name: 'Carol', entityType: 'person', observations: ['software engineer'] }, + ]); + + const dir = path.dirname(testFilePath); + const files = await fs.readdir(dir); + const tempFiles = files.filter(f => f.startsWith(path.basename(testFilePath)) && f.endsWith('.tmp')); + expect(tempFiles).toHaveLength(0); + + const content = await fs.readFile(testFilePath, 'utf-8'); + expect(content).toContain('Carol'); + }); + }); }); diff --git a/src/memory/index.ts b/src/memory/index.ts index 9865c5318e..dab0b923d7 100644 --- a/src/memory/index.ts +++ b/src/memory/index.ts @@ -114,7 +114,18 @@ export class KnowledgeGraphManager { relationType: r.relationType })), ]; - await fs.writeFile(this.memoryFilePath, lines.join("\n")); + const tmpPath = `${this.memoryFilePath}.${Date.now()}-${Math.random().toString(36).slice(2)}.tmp`; + try { + await fs.writeFile(tmpPath, lines.join("\n")); + await fs.rename(tmpPath, this.memoryFilePath); + } catch (error) { + try { + await fs.unlink(tmpPath); + } catch { + // Ignore cleanup error if temp file does not exist + } + throw error; + } } async createEntities(entities: Entity[]): Promise {