fix(memory): treat a content-less deermem message as empty, not None (#7854)

extract_message_text falls back to str(content), so a message whose content is None becomes the truthy literal 'None'. That string then reaches signal detection and the memory-update prompt as if the user had written it. The canonical helper (utils/messages.py:message_content_to_text) and the mem0 copy both return '' for this shape and the canonical one documents exactly this failure mode.

Co-authored-by: Willem Jiang <willem.jiang@gmail.com>
This commit is contained in:
hdu_zhou 2026-11-05 12:25:51 +08:00 committed by GitHub
parent 713a861e75
commit 9e2cf685b0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 23 additions and 0 deletions

View File

@ -97,6 +97,13 @@ def load_patterns(name: str, *, patterns_dir: str | None = None) -> list[re.Patt
def extract_message_text(message: Any) -> str:
"""Extract plain text from message content for filtering and signal detection."""
content = getattr(message, "content", "")
if content is None:
# ``str(None)`` is the truthy literal ``"None"``, so a content-less
# message would survive every downstream ``text if text else ...``
# fallback and be reported as real user text. Keep this in step with
# ``deerflow/utils/messages.py:message_content_to_text`` and the mem0
# copy of this helper, which both return "" here.
return ""
if isinstance(content, list):
text_parts: list[str] = []
for part in content:

View File

@ -137,3 +137,19 @@ def test_prepare_update_returns_new_signals_after_swap(tmp_path) -> None:
_filtered, signals = r
assert "preference" in signals
assert len(_filtered) == 2 # not trivial -> kept
# ── extract_message_text: content shapes ───────────────────────────────────
def test_extract_message_text_treats_none_as_empty() -> None:
"""A content-less message must not become the literal string ``"None"``.
``str(None)`` is truthy, so the naive fallback would hand ``"None"`` to
signal detection and to the memory-update prompt as if it were real user
text. Mirrors ``utils/messages.py:message_content_to_text`` and
``test_mem0_memory_backend.py::test_extract_message_text_treats_none_as_empty``.
"""
msg = _human("")
msg.content = None
assert extract_message_text(msg) == ""