fix(memory): centralize entity cleanup and skip malformed LLM relation dicts (#4515)

This commit is contained in:
Himanshu
2026-03-28 21:23:05 +05:30
committed by GitHub
parent 4b7f51d194
commit ae49edec44
6 changed files with 93 additions and 26 deletions
+2 -6
View File
@@ -1,7 +1,7 @@
import logging
from abc import ABC, abstractmethod
from mem0.memory.utils import format_entities
from mem0.memory.utils import format_entities, remove_spaces_from_entities
try:
from rank_bm25 import BM25Okapi
@@ -151,11 +151,7 @@ class NeptuneBase(ABC):
return entities
def _remove_spaces_from_entities(self, entity_list):
for item in entity_list:
item["source"] = item["source"].lower().replace(" ", "_")
item["relationship"] = item["relationship"].lower().replace(" ", "_")
item["destination"] = item["destination"].lower().replace(" ", "_")
return entity_list
return remove_spaces_from_entities(entity_list, sanitize_relationship=False)
def _get_delete_entities_from_search_output(self, search_output, data, filters):
"""
+2 -7
View File
@@ -1,6 +1,6 @@
import logging
from mem0.memory.utils import format_entities, sanitize_relationship_for_cypher
from mem0.memory.utils import format_entities, remove_spaces_from_entities
try:
from langchain_neo4j import Neo4jGraph
@@ -657,12 +657,7 @@ class MemoryGraph:
return results
def _remove_spaces_from_entities(self, entity_list):
for item in entity_list:
item["source"] = item["source"].lower().replace(" ", "_")
# Use the sanitization function for relationships to handle special characters
item["relationship"] = sanitize_relationship_for_cypher(item["relationship"].lower().replace(" ", "_"))
item["destination"] = item["destination"].lower().replace(" ", "_")
return entity_list
return remove_spaces_from_entities(entity_list, sanitize_relationship=True)
def _search_source_node(self, source_embedding, filters, threshold=0.9):
# Build WHERE conditions
+2 -6
View File
@@ -1,6 +1,6 @@
import logging
from mem0.memory.utils import format_entities
from mem0.memory.utils import format_entities, remove_spaces_from_entities
try:
import kuzu
@@ -654,11 +654,7 @@ class MemoryGraph:
return results
def _remove_spaces_from_entities(self, entity_list):
for item in entity_list:
item["source"] = item["source"].lower().replace(" ", "_")
item["relationship"] = item["relationship"].lower().replace(" ", "_")
item["destination"] = item["destination"].lower().replace(" ", "_")
return entity_list
return remove_spaces_from_entities(entity_list, sanitize_relationship=False)
def _search_source_node(self, source_embedding, filters, threshold=0.9):
params = {
+2 -7
View File
@@ -1,6 +1,6 @@
import logging
from mem0.memory.utils import format_entities, sanitize_relationship_for_cypher
from mem0.memory.utils import format_entities, remove_spaces_from_entities
try:
from langchain_memgraph.graphs.memgraph import Memgraph
@@ -550,12 +550,7 @@ class MemoryGraph:
return results
def _remove_spaces_from_entities(self, entity_list):
for item in entity_list:
item["source"] = item["source"].lower().replace(" ", "_")
# Use the sanitization function for relationships to handle special characters
item["relationship"] = sanitize_relationship_for_cypher(item["relationship"].lower().replace(" ", "_"))
item["destination"] = item["destination"].lower().replace(" ", "_")
return entity_list
return remove_spaces_from_entities(entity_list, sanitize_relationship=True)
def _search_source_node(self, source_embedding, filters, threshold=0.9):
"""Search for source nodes with similar embeddings."""
+28
View File
@@ -1,6 +1,7 @@
import hashlib
import logging
import re
from typing import Any, Dict, List
from mem0.configs.prompts import (
AGENT_MEMORY_EXTRACTION_PROMPT,
@@ -265,3 +266,30 @@ def sanitize_relationship_for_cypher(relationship) -> str:
return re.sub(r"_+", "_", sanitized).strip("_")
def remove_spaces_from_entities(
entity_list: List[Any],
*,
sanitize_relationship: bool = True,
) -> List[Dict[str, Any]]:
"""
Normalize entity relation dicts from LLM/tool output: lowercase, spaces to underscores.
Skips entries that are not non-empty dicts or that lack any of
``source``, ``relationship``, or ``destination`` (avoids KeyError on ``[{}]``
or partial dicts).
"""
required = ("source", "relationship", "destination")
cleaned: List[Dict[str, Any]] = []
for item in entity_list:
if not isinstance(item, dict) or not item:
continue
if not all(key in item for key in required):
continue
item["source"] = item["source"].lower().replace(" ", "_")
rel = item["relationship"].lower().replace(" ", "_")
item["relationship"] = sanitize_relationship_for_cypher(rel) if sanitize_relationship else rel
item["destination"] = item["destination"].lower().replace(" ", "_")
cleaned.append(item)
return cleaned