Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 28 additions & 1 deletion src/memory/__tests__/file-path.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,34 @@ describe('ensureMemoryFilePath', () => {
const result = await ensureMemoryFilePath();

expect(path.isAbsolute(result)).toBe(true);
expect(result).toContain('custom-memory.jsonl');
expect(result).toBe(path.resolve(process.cwd(), relativePath));
});

it('should create parent directories for custom absolute paths', async () => {
const absolutePath = path.join(testDir, 'nested', 'dir', 'memory.jsonl');
process.env.MEMORY_FILE_PATH = absolutePath;

const result = await ensureMemoryFilePath();

expect(result).toBe(absolutePath);
const stat = await fs.stat(path.dirname(absolutePath));
expect(stat.isDirectory()).toBe(true);

await fs.rm(path.join(testDir, 'nested'), { recursive: true, force: true });
});

it('should migrate custom memory.json path to memory.jsonl', async () => {
const jsonPath = path.join(testDir, 'custom-memory.json');
const jsonlPath = `${jsonPath}l`;
process.env.MEMORY_FILE_PATH = jsonPath;
await fs.writeFile(jsonPath, '{"type":"entity","name":"a","entityType":"t","observations":[]}');

const result = await ensureMemoryFilePath();

expect(result).toBe(jsonlPath);
await fs.access(jsonlPath);
await fs.rm(jsonPath, { force: true }).catch(() => undefined);
await fs.unlink(jsonlPath).catch(() => undefined);
});

it('should handle Windows absolute paths', async () => {
Expand Down
41 changes: 31 additions & 10 deletions src/memory/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,36 +13,57 @@ export const defaultMemoryPath = path.join(path.dirname(fileURLToPath(import.met
// Handle backward compatibility: migrate memory.json to memory.jsonl if needed
export async function ensureMemoryFilePath(): Promise<string> {
if (process.env.MEMORY_FILE_PATH) {
// Custom path provided, use it as-is (with absolute path resolution)
return path.isAbsolute(process.env.MEMORY_FILE_PATH)
const configuredPath = path.isAbsolute(process.env.MEMORY_FILE_PATH)
? process.env.MEMORY_FILE_PATH
: path.join(path.dirname(fileURLToPath(import.meta.url)), process.env.MEMORY_FILE_PATH);
: path.resolve(process.cwd(), process.env.MEMORY_FILE_PATH);

return normalizeMemoryStoragePath(configuredPath);
}
// No custom path set, check for backward compatibility migration

// No custom path set, check for backward compatibility migration in package dir
const oldMemoryPath = path.join(path.dirname(fileURLToPath(import.meta.url)), 'memory.json');
const newMemoryPath = defaultMemoryPath;

try {
// Check if old file exists and new file doesn't
await fs.access(oldMemoryPath);
try {
await fs.access(newMemoryPath);
// Both files exist, use new one (no migration needed)
return newMemoryPath;
} catch {
// Old file exists, new file doesn't - migrate
console.error('DETECTED: Found legacy memory.json file, migrating to memory.jsonl for JSONL format compatibility');
await fs.rename(oldMemoryPath, newMemoryPath);
console.error('COMPLETED: Successfully migrated memory.json to memory.jsonl');
return newMemoryPath;
}
} catch {
// Old file doesn't exist, use new path
return newMemoryPath;
}
}

async function normalizeMemoryStoragePath(memoryPath: string): Promise<string> {
await fs.mkdir(path.dirname(memoryPath), { recursive: true });

if (memoryPath.endsWith('.json') && !memoryPath.endsWith('.jsonl')) {
const jsonlPath = `${memoryPath}l`;
try {
await fs.access(memoryPath);
try {
await fs.access(jsonlPath);
return jsonlPath;
} catch {
console.error(`DETECTED: Found legacy memory file at ${memoryPath}, migrating to JSONL format`);
await fs.rename(memoryPath, jsonlPath);
console.error(`COMPLETED: Successfully migrated to ${jsonlPath}`);
return jsonlPath;
}
} catch {
return jsonlPath;
}
}

return memoryPath;
}

// Initialize memory file path (will be set during startup)
let MEMORY_FILE_PATH: string;

Expand Down
Loading