feat: sync memory with filesystem tree (#685)

Co-authored-by: Letta <noreply@letta.com>
Co-authored-by: cpacker <packercharles@gmail.com>
This commit is contained in:
Kevin Lin
2026-01-26 21:48:57 -08:00
committed by GitHub
parent 57f99b906b
commit 7ab97e404d
16 changed files with 1815 additions and 249 deletions

View File

@@ -759,3 +759,165 @@ describe("Settings Manager - Edge Cases", () => {
expect(settings.lastAgent).toBe("agent-2"); // Updated
});
});
// ============================================================================
// Agents Array Migration Tests
// ============================================================================
describe("Settings Manager - Agents Array Migration", () => {
test("Migrates from pinnedAgents (oldest legacy format)", async () => {
// Setup: Write old format to disk
const { writeFile, mkdir } = await import("../utils/fs.js");
const settingsDir = join(testHomeDir, ".letta");
await mkdir(settingsDir, { recursive: true });
await writeFile(
join(settingsDir, "settings.json"),
JSON.stringify({
pinnedAgents: ["agent-old-1", "agent-old-2"],
tokenStreaming: true,
}),
);
await settingsManager.initialize();
const settings = settingsManager.getSettings();
// Should have migrated to agents array
expect(settings.agents).toBeDefined();
expect(settings.agents).toHaveLength(2);
expect(settings.agents?.[0]).toEqual({
agentId: "agent-old-1",
pinned: true,
});
expect(settings.agents?.[1]).toEqual({
agentId: "agent-old-2",
pinned: true,
});
// Legacy field should still exist for downgrade compat
expect(settings.pinnedAgents).toEqual(["agent-old-1", "agent-old-2"]);
});
test("Migrates from pinnedAgentsByServer (newer legacy format)", async () => {
const { writeFile, mkdir } = await import("../utils/fs.js");
const settingsDir = join(testHomeDir, ".letta");
await mkdir(settingsDir, { recursive: true });
await writeFile(
join(settingsDir, "settings.json"),
JSON.stringify({
pinnedAgentsByServer: {
"api.letta.com": ["agent-cloud-1"],
"localhost:8283": ["agent-local-1", "agent-local-2"],
},
}),
);
await settingsManager.initialize();
const settings = settingsManager.getSettings();
expect(settings.agents).toHaveLength(3);
// Cloud agents have no baseUrl (or undefined)
expect(settings.agents).toContainEqual({
agentId: "agent-cloud-1",
pinned: true,
});
// Local agents have baseUrl
expect(settings.agents).toContainEqual({
agentId: "agent-local-1",
baseUrl: "localhost:8283",
pinned: true,
});
expect(settings.agents).toContainEqual({
agentId: "agent-local-2",
baseUrl: "localhost:8283",
pinned: true,
});
});
test("Migrates from both legacy formats (deduplicated)", async () => {
const { writeFile, mkdir } = await import("../utils/fs.js");
const settingsDir = join(testHomeDir, ".letta");
await mkdir(settingsDir, { recursive: true });
await writeFile(
join(settingsDir, "settings.json"),
JSON.stringify({
pinnedAgents: ["agent-1", "agent-2"], // Old old format
pinnedAgentsByServer: {
"api.letta.com": ["agent-1", "agent-3"], // agent-1 is duplicate
},
}),
);
await settingsManager.initialize();
const settings = settingsManager.getSettings();
// Should have 3 agents (agent-1 deduped)
expect(settings.agents).toHaveLength(3);
const agentIds = settings.agents?.map((a) => a.agentId);
expect(agentIds).toContain("agent-1");
expect(agentIds).toContain("agent-2");
expect(agentIds).toContain("agent-3");
});
test("Already migrated settings are not re-migrated", async () => {
const { writeFile, mkdir } = await import("../utils/fs.js");
const settingsDir = join(testHomeDir, ".letta");
await mkdir(settingsDir, { recursive: true });
await writeFile(
join(settingsDir, "settings.json"),
JSON.stringify({
agents: [{ agentId: "agent-new", pinned: true, memfs: true }],
pinnedAgentsByServer: {
"api.letta.com": ["agent-old"], // Should be ignored since agents exists
},
}),
);
await settingsManager.initialize();
const settings = settingsManager.getSettings();
// Should only have the new format agent
expect(settings.agents).toHaveLength(1);
expect(settings.agents?.[0]?.agentId).toBe("agent-new");
expect(settings.agents?.[0]?.memfs).toBe(true);
});
test("isMemfsEnabled returns false for agents without memfs flag", async () => {
await settingsManager.initialize();
// Manually set up agents array
settingsManager.updateSettings({
agents: [
{ agentId: "agent-with-memfs", pinned: true, memfs: true },
{ agentId: "agent-without-memfs", pinned: true },
],
});
expect(settingsManager.isMemfsEnabled("agent-with-memfs")).toBe(true);
expect(settingsManager.isMemfsEnabled("agent-without-memfs")).toBe(false);
expect(settingsManager.isMemfsEnabled("agent-unknown")).toBe(false);
});
test("setMemfsEnabled adds/removes memfs flag", async () => {
await settingsManager.initialize();
settingsManager.setMemfsEnabled("agent-test", true);
expect(settingsManager.isMemfsEnabled("agent-test")).toBe(true);
settingsManager.setMemfsEnabled("agent-test", false);
expect(settingsManager.isMemfsEnabled("agent-test")).toBe(false);
});
test("setMemfsEnabled persists to disk", async () => {
await settingsManager.initialize();
settingsManager.setMemfsEnabled("agent-persist-test", true);
// Wait for async persist
await new Promise((resolve) => setTimeout(resolve, 100));
// Reset and reload
await settingsManager.reset();
await settingsManager.initialize();
expect(settingsManager.isMemfsEnabled("agent-persist-test")).toBe(true);
});
});