88from haystack .dataclasses .chat_message import ChatMessage
99from haystack .lazy_imports import LazyImport
1010
11+ from .utils import Mem0Scope
12+
1113with LazyImport (message = "Run 'pip install mem0ai'" ) as mem0_import :
12- from mem0 import MemoryClient
14+ from mem0 import Memory , MemoryClient
1315
1416
1517class Mem0MemoryStore :
1618 """
1719 A memory store implementation using Mem0 as the backend.
1820
19- :param api_key: The Mem0 API key (if not provided, uses MEM0_API_KEY environment variable)
20- :param user_id: The user ID for the memory store.
21- :param memory_config: Configuration dictionary for Mem0 client
2221 """
2322
24- def __init__ (self , user_id : str , api_key : Optional [str ] = None , memory_config : Optional [dict [str , Any ]] = None ):
23+ def __init__ (
24+ self ,
25+ scope : Mem0Scope ,
26+ api_key : Optional [str ] = None ,
27+ memory_config : Optional [dict [str , Any ]] = None ,
28+ search_criteria : Optional [dict [str , Any ]] = None ,
29+ ):
30+ """
31+ Initialize the Mem0 memory store.
32+
33+ :param scope: The scope for the memory store. This defines the identifiers to retrieve or update memories.
34+ :param api_key: The Mem0 API key (if not provided, uses MEM0_API_KEY environment variable)
35+ :param memory_config: Configuration dictionary for Mem0 client
36+ :param search_criteria: Set the search configuration for the memory store.
37+ This can include query, filters, and top_k.
38+ """
39+
2540 mem0_import .check ()
2641 self .api_key = api_key or os .getenv ("MEM0_API_KEY" )
2742 if not self .api_key :
2843 raise ValueError ("Mem0 API key must be provided either as parameter or MEM0_API_KEY environment variable." )
2944
30- self .user_id = user_id
45+ self .scope = scope
3146 self .memory_config = memory_config
3247
3348 # If a memory config is provided, use it to initialize the Mem0 client
3449 if self .memory_config :
35- self .client = MemoryClient .from_config (self .memory_config )
50+ self .client = Memory .from_config (self .memory_config )
3651 else :
37- self .client = MemoryClient (api_key = self .api_key )
52+ self .client = MemoryClient (
53+ api_key = self .api_key ,
54+ )
3855
3956 # User can set the search criteria using the set_search_criteria method
40- self .search_criteria = {}
57+ self .search_criteria = search_criteria
58+ if not self .search_criteria :
59+ self .search_criteria = {
60+ "query" : None ,
61+ "filters" : None ,
62+ "top_k" : 10 ,
63+ }
4164
4265 def to_dict (self ) -> dict [str , Any ]:
4366 """Serialize the store configuration to a dictionary."""
4467 return default_to_dict (
4568 self ,
46- user_id = self .user_id ,
69+ scope = self .scope ,
4770 api_key = self .api_key ,
4871 memory_config = self .memory_config ,
4972 search_criteria = self .search_criteria ,
@@ -54,7 +77,7 @@ def from_dict(cls, data: dict[str, Any]) -> "Mem0MemoryStore":
5477 """Deserialize the store from a dictionary."""
5578 return default_from_dict (cls , data )
5679
57- def add_memories (self , messages : list [ChatMessage ]) -> list [str ]:
80+ def add_memories (self , messages : list [ChatMessage ], infer : bool = True ) -> list [str ]:
5881 """
5982 Add ChatMessage memories to Mem0.
6083
@@ -69,53 +92,52 @@ def add_memories(self, messages: list[ChatMessage]) -> list[str]:
6992 mem0_message = [{"role" : "user" , "content" : message .text }]
7093
7194 try :
72- # Mem0 primarily uses user_id as the main identifier
73- # org_id and session_id are stored in metadata for filtering
74- result = self . client . add ( messages = mem0_message , user_id = self . user_id , metadata = message . meta )
95+ result = self . client . add (
96+ messages = mem0_message , metadata = message . meta , infer = infer , ** self . scope . get_scope ()
97+ )
7598 # Mem0 returns different response formats, handle both
7699 memory_id = result .get ("id" ) or result .get ("memory_id" ) or str (result )
77100 added_ids .append (memory_id )
78101 except Exception as e :
79102 raise RuntimeError (f"Failed to add memory message: { e } " ) from e
80103
81- return added_ids
82-
83- def set_search_criteria (
84- self , query : Optional [str ] = None , filters : Optional [dict [str , Any ]] = None , top_k : Optional [int ] = None
85- ):
86- """
87- Set the memory configuration for the memory store.
88- """
89- self .search_criteria = {"query" : query , "filters" : filters , "top_k" : top_k }
104+ return list (added_ids )
90105
91106 def search_memories (
92- self , query : Optional [str ] = None , filters : Optional [dict [str , Any ]] = None , top_k : int = 8
107+ self ,
108+ query : Optional [str ] = None ,
109+ filters : Optional [dict [str , Any ]] = None ,
110+ top_k : int = 5 ,
111+ search_criteria : Optional [dict [str , Any ]] = None ,
93112 ) -> list [ChatMessage ]:
94113 """
95114 Search for memories in Mem0.
96115
97116 :param query: Text query to search for. If not provided, all memories will be returned.
98117 :param filters: Additional filters to apply on search. For more details on mem0 filters, see https://mem0.ai/docs/search/
99118 :param top_k: Maximum number of results to return
119+ :param search_criteria: Search criteria to search memories from the store.
120+ This can include query, filters, and top_k.
100121 :returns: List of ChatMessage memories matching the criteria
101122 """
102123 # Prepare filters for Mem0
124+ search_criteria = search_criteria or self .search_criteria
103125
104- search_query = query or self . search_criteria .get ("query" , None )
105- search_filters = filters or self . search_criteria .get ("filters" , {})
106- search_top_k = top_k or self . search_criteria .get ("top_k" , 10 )
126+ search_query = query or search_criteria .get ("query" , None )
127+ search_filters = filters or search_criteria .get ("filters" , {})
128+ search_top_k = top_k or search_criteria .get ("top_k" , 10 )
107129
108130 if search_filters :
109- mem0_filters = { "AND" : [{ "user_id" : self . user_id }, search_filters ]}
131+ mem0_filters = search_filters
110132 else :
111- mem0_filters = { "user_id" : self .user_id }
133+ mem0_filters = self .scope . get_scope ()
112134
113135 try :
114136 if not search_query :
115- memories = self .client .get_all (filters = mem0_filters , top_k = search_top_k )
137+ memories = self .client .get_all (filters = mem0_filters , ** self . scope . get_scope () )
116138 else :
117139 memories = self .client .search (
118- query = search_query , limit = search_top_k , filters = mem0_filters , user_id = self .user_id
140+ query = search_query , limit = search_top_k , filters = mem0_filters , ** self .scope . get_scope ()
119141 )
120142 messages = [
121143 ChatMessage .from_user (text = memory ["memory" ], meta = memory ["metadata" ]) for memory in memories ["results" ]
@@ -135,7 +157,7 @@ def delete_all_memories(self, user_id: Optional[str] = None):
135157 :param user_id: User identifier for scoping the deletion
136158 """
137159 try :
138- self .client .delete_all (user_id = user_id or self .user_id )
160+ self .client .delete_all (** self .scope . get_scope () )
139161 except Exception as e :
140162 raise RuntimeError (f"Failed to delete memories for user { user_id } : { e } " ) from e
141163
@@ -149,15 +171,3 @@ def delete_memory(self, memory_id: str):
149171 self .client .delete (memory_id = memory_id )
150172 except Exception as e :
151173 raise RuntimeError (f"Failed to delete memory { memory_id } : { e } " ) from e
152-
153- def get_memory (self , memory_id : str ) -> ChatMessage :
154- """
155- Get memory from Mem0.
156-
157- :param memory_id: The ID of the memory to get.
158- :returns: The memory.
159- """
160- try :
161- return self .client .get (memory_id = memory_id )
162- except Exception as e :
163- raise RuntimeError (f"Failed to get memory { memory_id } : { e } " ) from e
0 commit comments