Add reproduction test for infer=true AttributeError on malformed LLM facts
When smaller LLMs return facts as objects ({"fact": "..."}) instead of
plain strings, embedding_model.embed() crashes with
'dict' object has no attribute 'replace'. This test confirms the bug
by mocking the LLM to return dict-shaped facts and asserting the
failure at mem0/memory/main.py:473.
This commit is contained in:
@@ -1,3 +1,4 @@
|
|||||||
|
import json
|
||||||
from unittest.mock import MagicMock, patch
|
from unittest.mock import MagicMock, patch
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
@@ -245,3 +246,51 @@ def test_get_all_handles_flat_list_from_postgres(mock_sqlite, mock_llm_factory,
|
|||||||
assert len(result) == 2
|
assert len(result) == 2
|
||||||
assert result[0]["memory"] == "Memory 1"
|
assert result[0]["memory"] == "Memory 1"
|
||||||
assert result[1]["memory"] == "Memory 2"
|
assert result[1]["memory"] == "Memory 2"
|
||||||
|
|
||||||
|
|
||||||
|
@patch('mem0.utils.factory.EmbedderFactory.create')
|
||||||
|
@patch('mem0.utils.factory.VectorStoreFactory.create')
|
||||||
|
@patch('mem0.utils.factory.LlmFactory.create')
|
||||||
|
@patch('mem0.memory.storage.SQLiteManager')
|
||||||
|
def test_add_infer_with_malformed_llm_facts(mock_sqlite, mock_llm_factory, mock_vector_factory, mock_embedder_factory):
|
||||||
|
"""
|
||||||
|
Repro for: 'list' object has no attribute 'replace' on infer=true.
|
||||||
|
|
||||||
|
When an LLM (especially smaller models like llama3.1:8b) returns facts as
|
||||||
|
objects ({"fact": "..."} or {"text": "..."}) instead of plain strings,
|
||||||
|
the embedding model's .replace() call crashes with AttributeError.
|
||||||
|
"""
|
||||||
|
mock_embedder = MagicMock()
|
||||||
|
mock_embedder.embed.side_effect = lambda text, action: (_ for _ in ()).throw(
|
||||||
|
AttributeError("'dict' object has no attribute 'replace'")
|
||||||
|
) if not isinstance(text, str) else [0.1, 0.2, 0.3]
|
||||||
|
mock_embedder_factory.return_value = mock_embedder
|
||||||
|
|
||||||
|
mock_vector_store = MagicMock()
|
||||||
|
mock_vector_store.search.return_value = []
|
||||||
|
mock_vector_factory.return_value = mock_vector_store
|
||||||
|
|
||||||
|
# LLM returns malformed facts: dicts instead of strings
|
||||||
|
malformed_response = json.dumps({
|
||||||
|
"facts": [
|
||||||
|
{"fact": "User likes Python"},
|
||||||
|
{"text": "User is a developer"},
|
||||||
|
]
|
||||||
|
})
|
||||||
|
mock_llm = MagicMock()
|
||||||
|
mock_llm.generate_response.return_value = malformed_response
|
||||||
|
mock_llm_factory.return_value = mock_llm
|
||||||
|
|
||||||
|
mock_sqlite.return_value = MagicMock()
|
||||||
|
|
||||||
|
from mem0.memory.main import Memory as MemoryClass
|
||||||
|
config = MemoryConfig()
|
||||||
|
memory = MemoryClass(config)
|
||||||
|
|
||||||
|
# This should NOT raise AttributeError
|
||||||
|
memory._add_to_vector_store(
|
||||||
|
messages=[{"role": "user", "content": "I like Python and I'm a developer"}],
|
||||||
|
metadata={"user_id": "test_user"},
|
||||||
|
filters={"user_id": "test_user"},
|
||||||
|
infer=True,
|
||||||
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user