Skip to content
This repository was archived by the owner on Jul 29, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions haystack_experimental/components/agents/agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ def __init__( # noqa: PLR0913

def _initialize_fresh_execution(
self,
messages: list[ChatMessage],
messages: list[ChatMessage] | None,
streaming_callback: StreamingCallbackT | None,
requires_async: bool,
*,
Expand Down Expand Up @@ -226,7 +226,7 @@ def _initialize_fresh_execution(
)

# NOTE: difference with parent method to add memory retrieval
if self._memory_store:
if self._memory_store and messages:
retrieved_memories = self._memory_store.search_memories(
query=messages[-1].text, **memory_store_kwargs if memory_store_kwargs else {}
)
Expand Down
21 changes: 11 additions & 10 deletions haystack_experimental/memory_stores/mem0/memory_store.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,26 +50,25 @@ def add_memories(
user_id: str | None = None,
run_id: str | None = None,
agent_id: str | None = None,
async_mode: bool = False,
**kwargs: Any,
) -> list[dict[str, Any]]:
"""
Add ChatMessage memories to Mem0.

:param messages: List of ChatMessage objects with memory metadata
:param infer: Whether to infer facts from the messages. If False, the whole message will
be added as a memory.
:param infer: Whether to infer facts from the messages. If False, the whole message will be added as a memory.
With `infer=False`, Mem0 returns the added memory ids synchronously. With `infer=True`, Mem0 may return a
pending status without any memory ids; in that case, the extracted memories become available via
`search_memories` once the server finishes indexing them.
:param user_id: The user ID to to store and retrieve memories from the memory store.
:param run_id: The run ID to to store and retrieve memories from the memory store.
:param agent_id: The agent ID to to store and retrieve memories from the memory store.
If you want Mem0 to store chat messages from the assistant, you need to set the agent_id.
:param async_mode: Whether to add memories asynchronously.
If True, the method will return immediately and the memories will be added in the background.
:param kwargs: Additional keyword arguments to pass to the Mem0 client.add method.
Note: ChatMessage.meta in the list of messages will be ignored because Mem0 doesn't allow
passing metadata for each message in the list. You can pass metadata for the whole memory
by passing the `metadata` keyword argument to the method.
:returns: List of objects with the memory_id and the memory
:returns: List of objects with the memory_id and the memory.
"""
added_ids = []
ids = self._get_ids(user_id, run_id, agent_id)
Expand All @@ -85,11 +84,13 @@ def add_memories(
# we save the role of the message in the metadata
mem0_messages.append({"content": message.text, "role": message.role.value})
try:
status = self.client.add(messages=mem0_messages, infer=infer, **ids, async_mode=async_mode, **kwargs)
if status:
status = self.client.add(messages=mem0_messages, infer=infer, **ids, **kwargs)
if status and "results" in status:
for result in status["results"]:
memory_id = {"memory_id": result.get("id"), "memory": result["memory"]}
added_ids.append(memory_id)
# Mem0 v3 wraps the memory text under a `data` key; older shapes exposed it directly
data = result.get("data")
memory_text = data.get("memory") if isinstance(data, dict) else result.get("memory")
added_ids.append({"memory_id": result.get("id"), "memory": memory_text})
except Exception as e:
raise RuntimeError(f"Failed to add memory message: {e}") from e
return added_ids
Expand Down
23 changes: 14 additions & 9 deletions test/memory_stores/test_mem0_memory_store.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,7 @@ def test_add_memories(self, sample_messages, memory_store):
"""Test adding memories successfully."""
store, user_id = memory_store
result = store.add_memories(messages=sample_messages, user_id=user_id)
# with infer=True (default), two messages are converted to a single memory
assert len(result) == 1
assert result == []

@pytest.mark.skipif(
not os.environ.get("MEM0_API_KEY", None),
Expand All @@ -115,9 +114,7 @@ def test_add_memories_with_metadata(self, memory_store):
"""Test adding memories with metadata."""
store, user_id = memory_store
messages = [ChatMessage.from_user("User likes to work with python on NLP projects")]
result = store.add_memories(
messages=messages, user_id=user_id, metadata={"key": "value"}, async_mode=False
)
result = store.add_memories(messages=messages, infer=False, user_id=user_id, metadata={"key": "value"})
assert len(result) == 1

@pytest.mark.skipif(
Expand Down Expand Up @@ -201,17 +198,25 @@ def test_delete_memory(self, sample_messages, memory_store):
def test_role_based_memories(self, memory_store):
store, user_id = memory_store
unique_agent_id = _get_unique_user_id()
messages = [

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sjrl could you review this change in particular?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hard for me to review since I don't fully understand Mem0. It looks reasonable to me in the sense that if that's what Mem0 requires then that's fine.

I don't think I really know of a use case for this. I.e. I don't know when I'd want to search for these two sets separately.

# in Mem0 v3, to keep user and assistant turns searchable by their own entity id,
# they must be added in separate calls
user_messages = [
ChatMessage.from_user("I'm planning to watch a movie tonight. Any recommendations?"),
ChatMessage.from_assistant("How about thriller movies? They can be quite engaging."),
ChatMessage.from_user("I'm not a big fan of thriller movies but I love sci-fi movies."),
]
assistant_messages = [
ChatMessage.from_assistant("How about thriller movies? They can be quite engaging."),
ChatMessage.from_assistant(
"Got it! Then I would recommend Interstellar or Inception? I would also recommend watching some "
"Japanese anime movies."
),
]
store.add_memories(messages=messages, infer=False, user_id=user_id, agent_id=unique_agent_id)
assistant_mem = store.search_memories(filters={"field": "agent_id", "operator": "==", "value": unique_agent_id})
store.add_memories(messages=user_messages, infer=False, user_id=user_id)
store.add_memories(messages=assistant_messages, infer=False, agent_id=unique_agent_id)

assistant_mem = store.search_memories(
filters={"field": "agent_id", "operator": "==", "value": unique_agent_id}
)
user_mem = store.search_memories(filters={"field": "user_id", "operator": "==", "value": user_id})
assert len(assistant_mem) == 2
assert len(user_mem) == 2
Expand Down