refactor: drop history subcommand memory_history tool, update platform email mapping, adjust tests
This commit is contained in:
@@ -958,9 +958,8 @@ export function registerCliCommands(
|
||||
auto_capture: "autoCapture",
|
||||
top_k: "topK",
|
||||
mode: "mode",
|
||||
// Dot notation (matches Python CLI: platform.api_key, defaults.user_id)
|
||||
"platform.api_key": "apiKey",
|
||||
"platform.base_url": "baseUrl",
|
||||
"platform.email": "userEmail",
|
||||
"defaults.user_id": "userId",
|
||||
"defaults.org_id": "orgId",
|
||||
"defaults.project_id": "projectId",
|
||||
|
||||
@@ -34,9 +34,6 @@ Identify which memories need action. Use the tools to investigate.
|
||||
**Search for recent additions:**
|
||||
Call `memory_search` with a `created_at` filter to find memories added since the last consolidation. These are the most likely to need merging or cleanup.
|
||||
|
||||
**Check edit history on suspicious entries:**
|
||||
If a memory looks like it was updated multiple times or has contradictory content, call `memory_history` on it to understand how it evolved.
|
||||
|
||||
**Classify each target into one of these actions:**
|
||||
- DELETE: contains credentials, expired by TTL, pure noise, raw tool output, standalone timestamps
|
||||
- MERGE: two or more memories express the same fact in different words, or a series tracks incremental changes to the same entity
|
||||
|
||||
@@ -58,6 +58,8 @@ interface MockCommand {
|
||||
_args: Array<{ name: string; desc: string }>;
|
||||
command(name: string): MockCommand;
|
||||
description(desc: string): MockCommand;
|
||||
configureHelp(opts: any): MockCommand;
|
||||
hook(event: string, fn: (...args: any[]) => any): MockCommand;
|
||||
option(flags: string, desc: string, defaultVal?: string): MockCommand;
|
||||
argument(name: string, desc: string): MockCommand;
|
||||
action(fn: (...args: any[]) => any): MockCommand;
|
||||
@@ -80,6 +82,12 @@ function createMockCommand(name: string): MockCommand {
|
||||
cmd._description = desc;
|
||||
return cmd;
|
||||
},
|
||||
configureHelp(_opts: any) {
|
||||
return cmd;
|
||||
},
|
||||
hook(_event: string, _fn: (...args: any[]) => any) {
|
||||
return cmd;
|
||||
},
|
||||
option(flags: string, desc: string, defaultVal?: string) {
|
||||
cmd._options.push({ flags, desc, defaultVal });
|
||||
return cmd;
|
||||
@@ -284,7 +292,6 @@ describe("registerCliCommands", () => {
|
||||
expect(names).toContain("list");
|
||||
expect(names).toContain("update");
|
||||
expect(names).toContain("delete");
|
||||
expect(names).toContain("history");
|
||||
expect(names).toContain("status");
|
||||
expect(names).toContain("config");
|
||||
expect(names).toContain("dream");
|
||||
@@ -321,7 +328,6 @@ describe("registerCliCommands", () => {
|
||||
expect(writePluginAuth).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
apiKey: "m0-my-key-1234",
|
||||
baseUrl: "https://api.mem0.ai",
|
||||
mode: "platform",
|
||||
}),
|
||||
);
|
||||
@@ -857,48 +863,6 @@ describe("registerCliCommands", () => {
|
||||
});
|
||||
});
|
||||
|
||||
// ========================================================================
|
||||
// history subcommand
|
||||
// ========================================================================
|
||||
|
||||
describe("history subcommand", () => {
|
||||
it("calls provider.history and prints entries as JSON", async () => {
|
||||
const { mem0, provider } = setup();
|
||||
const historyCmd = findCommand(mem0, "history")!;
|
||||
|
||||
await historyCmd._action!("m1");
|
||||
|
||||
expect(provider.history).toHaveBeenCalledWith("m1");
|
||||
expect(consoleSpy.log).toHaveBeenCalledWith(
|
||||
expect.stringContaining("UPDATE"),
|
||||
);
|
||||
});
|
||||
|
||||
it("prints message when no history found", async () => {
|
||||
const { mem0, provider } = setup();
|
||||
provider.history.mockResolvedValueOnce([]);
|
||||
const historyCmd = findCommand(mem0, "history")!;
|
||||
|
||||
await historyCmd._action!("m1");
|
||||
|
||||
expect(consoleSpy.log).toHaveBeenCalledWith(
|
||||
"No history found for this memory.",
|
||||
);
|
||||
});
|
||||
|
||||
it("handles history errors gracefully", async () => {
|
||||
const { mem0, provider } = setup();
|
||||
provider.history.mockRejectedValueOnce(new Error("history boom"));
|
||||
const historyCmd = findCommand(mem0, "history")!;
|
||||
|
||||
await historyCmd._action!("m1");
|
||||
|
||||
expect(consoleSpy.error).toHaveBeenCalledWith(
|
||||
expect.stringContaining("History failed"),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
// ========================================================================
|
||||
// status subcommand
|
||||
// ========================================================================
|
||||
@@ -965,7 +929,7 @@ describe("registerCliCommands", () => {
|
||||
expect(allOutput).toContain("Key");
|
||||
expect(allOutput).toContain("Value");
|
||||
expect(allOutput).toContain("platform.api_key");
|
||||
expect(allOutput).toContain("platform.base_url");
|
||||
expect(allOutput).toContain("platform.email");
|
||||
expect(allOutput).toContain("defaults.user_id");
|
||||
expect(allOutput).toContain("Config file:");
|
||||
});
|
||||
@@ -1031,9 +995,9 @@ describe("registerCliCommands", () => {
|
||||
const configCmd = findCommand(mem0, "config")!;
|
||||
const getCmd = findCommand(configCmd, "get")!;
|
||||
|
||||
getCmd._action!("platform.base_url");
|
||||
getCmd._action!("platform.email");
|
||||
|
||||
expect(consoleSpy.log).toHaveBeenCalledWith("https://api.mem0.ai");
|
||||
expect(consoleSpy.log).toHaveBeenCalledWith("(not set)");
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -15,7 +15,6 @@ import { createMemoryGetTool } from "../tools/memory-get.ts";
|
||||
import { createMemoryDeleteTool } from "../tools/memory-delete.ts";
|
||||
import { createMemoryListTool } from "../tools/memory-list.ts";
|
||||
import { createMemoryUpdateTool } from "../tools/memory-update.ts";
|
||||
import { createMemoryHistoryTool } from "../tools/memory-history.ts";
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Mock helper
|
||||
@@ -80,10 +79,10 @@ function createMockToolDeps(overrides = {}): ToolDeps {
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
describe("registerAllTools", () => {
|
||||
it("calls api.registerTool exactly 7 times", () => {
|
||||
it("calls api.registerTool exactly 6 times", () => {
|
||||
const ctx = createMockToolDeps();
|
||||
registerAllTools(ctx);
|
||||
expect(ctx.api.registerTool).toHaveBeenCalledTimes(7);
|
||||
expect(ctx.api.registerTool).toHaveBeenCalledTimes(6);
|
||||
});
|
||||
|
||||
it("registers tools with the correct names", () => {
|
||||
@@ -103,7 +102,6 @@ describe("registerAllTools", () => {
|
||||
"memory_list",
|
||||
"memory_update",
|
||||
"memory_delete",
|
||||
"memory_history",
|
||||
]);
|
||||
});
|
||||
|
||||
@@ -883,115 +881,3 @@ describe("memory_update execute", () => {
|
||||
});
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// memory_history execute
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
describe("memory_history execute", () => {
|
||||
it("returns formatted history", async () => {
|
||||
const historyEntries = [
|
||||
{
|
||||
event: "ADD",
|
||||
created_at: "2026-01-01T00:00:00Z",
|
||||
old_memory: null,
|
||||
new_memory: "Initial memory text",
|
||||
},
|
||||
{
|
||||
event: "UPDATE",
|
||||
created_at: "2026-01-02T00:00:00Z",
|
||||
old_memory: "Initial memory text",
|
||||
new_memory: "Updated memory text",
|
||||
},
|
||||
];
|
||||
const ctx = createMockToolDeps({
|
||||
provider: {
|
||||
search: vi.fn(),
|
||||
add: vi.fn(),
|
||||
getAll: vi.fn(),
|
||||
update: vi.fn(),
|
||||
delete: vi.fn(),
|
||||
get: vi.fn(),
|
||||
history: vi.fn().mockResolvedValue(historyEntries),
|
||||
},
|
||||
});
|
||||
const tool = createMemoryHistoryTool(ctx);
|
||||
|
||||
const result = await tool.execute("call-1", { memoryId: "mem-abc" });
|
||||
|
||||
expect(ctx.provider!.history).toHaveBeenCalledWith("mem-abc");
|
||||
expect(result.content[0].text).toContain("History for memory mem-abc");
|
||||
expect(result.content[0].text).toContain("2 entries");
|
||||
expect(result.content[0].text).toContain("[ADD]");
|
||||
expect(result.content[0].text).toContain("[UPDATE]");
|
||||
expect(result.content[0].text).toContain("Initial memory text");
|
||||
expect(result.content[0].text).toContain("Updated memory text");
|
||||
expect(result.content[0].text).toContain("Old: (none)");
|
||||
expect(result.details.count).toBe(2);
|
||||
expect(result.details.history).toEqual(historyEntries);
|
||||
});
|
||||
|
||||
it("handles empty history", async () => {
|
||||
const ctx = createMockToolDeps({
|
||||
provider: {
|
||||
search: vi.fn(),
|
||||
add: vi.fn(),
|
||||
getAll: vi.fn(),
|
||||
update: vi.fn(),
|
||||
delete: vi.fn(),
|
||||
get: vi.fn(),
|
||||
history: vi.fn().mockResolvedValue([]),
|
||||
},
|
||||
});
|
||||
const tool = createMemoryHistoryTool(ctx);
|
||||
|
||||
const result = await tool.execute("call-2", { memoryId: "mem-empty" });
|
||||
|
||||
expect(result.content[0].text).toBe(
|
||||
"No history found for memory mem-empty.",
|
||||
);
|
||||
expect(result.details.count).toBe(0);
|
||||
});
|
||||
|
||||
it("handles null history", async () => {
|
||||
const ctx = createMockToolDeps({
|
||||
provider: {
|
||||
search: vi.fn(),
|
||||
add: vi.fn(),
|
||||
getAll: vi.fn(),
|
||||
update: vi.fn(),
|
||||
delete: vi.fn(),
|
||||
get: vi.fn(),
|
||||
history: vi.fn().mockResolvedValue(null),
|
||||
},
|
||||
});
|
||||
const tool = createMemoryHistoryTool(ctx);
|
||||
|
||||
const result = await tool.execute("call-3", { memoryId: "mem-null" });
|
||||
|
||||
expect(result.content[0].text).toBe(
|
||||
"No history found for memory mem-null.",
|
||||
);
|
||||
expect(result.details.count).toBe(0);
|
||||
});
|
||||
|
||||
it("handles errors gracefully", async () => {
|
||||
const ctx = createMockToolDeps({
|
||||
provider: {
|
||||
search: vi.fn(),
|
||||
add: vi.fn(),
|
||||
getAll: vi.fn(),
|
||||
update: vi.fn(),
|
||||
delete: vi.fn(),
|
||||
get: vi.fn(),
|
||||
history: vi.fn().mockRejectedValue(new Error("history unavailable")),
|
||||
},
|
||||
});
|
||||
const tool = createMemoryHistoryTool(ctx);
|
||||
|
||||
const result = await tool.execute("call-4", { memoryId: "mem-err" });
|
||||
|
||||
expect(result.content[0].text).toContain("Memory history failed");
|
||||
expect(result.content[0].text).toContain("history unavailable");
|
||||
expect(result.details.error).toContain("history unavailable");
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user