fix(core): validate and trim entity IDs in delete_all() (#5735)

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Kartik <kartik.labhshetwar@mem0.ai>
This commit is contained in:
rafid001
2026-06-25 16:14:30 +05:30
committed by GitHub
parent d2ff83cf72
commit 890473f891
4 changed files with 52 additions and 1 deletions
+3 -1
View File
@@ -1601,7 +1601,9 @@ export class Memory {
has_agent_id: !!config.agentId,
has_run_id: !!config.runId,
});
const { userId, agentId, runId } = config;
const userId = validateAndTrimEntityId(config.userId, "userId");
const agentId = validateAndTrimEntityId(config.agentId, "agentId");
const runId = validateAndTrimEntityId(config.runId, "runId");
// Convert camelCase entity params to snake_case for filters (matches storage and search/getAll)
const filters: SearchFilters = {};
@@ -314,4 +314,27 @@ describe("Memory Input Validation", () => {
expect(result.results).toBeDefined();
});
});
describe("deleteAll() entity ID validation", () => {
it("should throw error when userId is whitespace-only", async () => {
await expect(memory.deleteAll({ userId: " " })).rejects.toThrow(
"Invalid userId",
);
});
it("should throw error when userId contains internal whitespace", async () => {
await expect(memory.deleteAll({ userId: "user 123" })).rejects.toThrow(
"Invalid userId: cannot contain whitespace",
);
});
it("should trim userId before listing memories", async () => {
const listSpy = jest.spyOn(memory["vectorStore"], "list");
listSpy.mockResolvedValue([[], null]);
await memory.deleteAll({ userId: " alice " });
expect(listSpy).toHaveBeenCalledWith({ user_id: "alice" });
});
});
});
+8
View File
@@ -1762,6 +1762,10 @@ class Memory(MemoryBase):
agent_id (str, optional): ID of the agent to delete memories for. Defaults to None.
run_id (str, optional): ID of the run to delete memories for. Defaults to None.
"""
user_id = _validate_and_trim_entity_id(user_id, "user_id")
agent_id = _validate_and_trim_entity_id(agent_id, "agent_id")
run_id = _validate_and_trim_entity_id(run_id, "run_id")
filters: Dict[str, Any] = {}
if user_id:
filters["user_id"] = user_id
@@ -3331,6 +3335,10 @@ class AsyncMemory(MemoryBase):
agent_id (str, optional): ID of the agent to delete memories for. Defaults to None.
run_id (str, optional): ID of the run to delete memories for. Defaults to None.
"""
user_id = _validate_and_trim_entity_id(user_id, "user_id")
agent_id = _validate_and_trim_entity_id(agent_id, "agent_id")
run_id = _validate_and_trim_entity_id(run_id, "run_id")
filters = {}
if user_id:
filters["user_id"] = user_id
+18
View File
@@ -286,6 +286,24 @@ class TestEntityIdValidation:
with pytest.raises(ValueError, match="Invalid user_id.*cannot contain whitespace"):
memory_instance.add("test message", user_id="user 123")
def test_delete_all_rejects_whitespace_only_user_id(self, memory_instance):
"""delete_all should reject whitespace-only user_id."""
with pytest.raises(ValueError, match="Invalid user_id.*cannot be empty"):
memory_instance.delete_all(user_id=" ")
def test_delete_all_rejects_internal_whitespace_user_id(self, memory_instance):
"""delete_all should reject user_id with internal whitespace."""
with pytest.raises(ValueError, match="Invalid user_id.*cannot contain whitespace"):
memory_instance.delete_all(user_id="user 123")
def test_delete_all_trims_user_id_before_list(self, memory_instance):
"""delete_all should trim leading/trailing whitespace on entity IDs."""
memory_instance.vector_store.list = Mock(return_value=([], None))
memory_instance.delete_all(user_id=" alice ")
memory_instance.vector_store.list.assert_called_once_with(filters={"user_id": "alice"})
class TestSearchParamValidation:
"""Tests for search parameter validation (threshold and top_k)."""