@@ -38,8 +38,18 @@ def test_mem0_import_error():
3838 if _import_error is None :
3939 pytest .skip ('mem0 is installed, skipping import error test' )
4040
41- with pytest .raises (ImportError , match = 'mem0 is not installed' ):
42- Mem0Toolset (api_key = 'test-key' )
41+ with pytest .raises (ImportError , match = 'mem0 is not installed' ): # pragma: no cover
42+ Mem0Toolset (api_key = 'test-key' ) # pragma: no cover
43+
44+
45+ def test_mem0_import_error_mocked ():
46+ """Test ImportError handling by mocking the import error."""
47+ from unittest .mock import patch
48+
49+ # Mock the import error scenario
50+ with patch ('pydantic_ai.toolsets.mem0._import_error' , new = ImportError ('Mocked import error' )):
51+ with pytest .raises (ImportError , match = 'mem0 is not installed' ):
52+ Mem0Toolset (api_key = 'test-key' )
4353
4454
4555@pytest .mark .skipif (_import_error is not None , reason = 'mem0 is not installed' )
@@ -56,6 +66,36 @@ async def test_mem0_toolset_initialization():
5666 assert toolset ._is_async is True
5767
5868
69+ @pytest .mark .skipif (_import_error is not None , reason = 'mem0 is not installed' )
70+ async def test_mem0_toolset_initialization_without_client ():
71+ """Test Mem0Toolset initialization without providing a client."""
72+ from unittest .mock import patch
73+
74+ # Mock the AsyncMemoryClient to avoid needing real API key
75+ with patch ('pydantic_ai.toolsets.mem0.AsyncMemoryClient' ) as mock_client_class :
76+ mock_client = AsyncMock ()
77+ mock_client_class .return_value = mock_client
78+
79+ # Initialize toolset without client (will create AsyncMemoryClient)
80+ toolset = Mem0Toolset (
81+ api_key = 'test-key' ,
82+ host = 'https://test.mem0.ai' ,
83+ org_id = 'test-org' ,
84+ project_id = 'test-project' ,
85+ )
86+
87+ # Verify AsyncMemoryClient was called with correct params
88+ mock_client_class .assert_called_once_with (
89+ api_key = 'test-key' ,
90+ host = 'https://test.mem0.ai' ,
91+ org_id = 'test-org' ,
92+ project_id = 'test-project' ,
93+ )
94+
95+ assert toolset .client is mock_client
96+ assert toolset ._is_async is True
97+
98+
5999@pytest .mark .skipif (_import_error is not None , reason = 'mem0 is not installed' )
60100async def test_mem0_toolset_tool_registration ():
61101 """Test that Mem0Toolset registers the expected tools."""
@@ -249,6 +289,34 @@ async def test_mem0_toolset_search_memory_unexpected_response():
249289 assert 'Error: Unexpected response format from Mem0' in result
250290
251291
292+ @pytest .mark .skipif (_import_error is not None , reason = 'mem0 is not installed' )
293+ async def test_mem0_toolset_search_memory_with_non_dict_items ():
294+ """Test search_memory with non-dict items in results."""
295+ mock_client = AsyncMock ()
296+ # Mix of dict and non-dict items
297+ mock_client .search = AsyncMock (
298+ return_value = {
299+ 'results' : [
300+ {'memory' : 'Valid memory' , 'score' : 0.9 },
301+ 'invalid_string_item' , # This should be skipped
302+ {'memory' : 'Another valid memory' , 'score' : 0.8 },
303+ None , # This should also be skipped
304+ ]
305+ }
306+ )
307+
308+ toolset = Mem0Toolset (client = mock_client )
309+ context = build_run_context ('user_123' )
310+
311+ result = await toolset ._search_memory_impl (context , 'test' )
312+
313+ # Only dict items should be included in the output
314+ assert 'Found relevant memories:' in result
315+ assert 'Valid memory (relevance: 0.90)' in result
316+ assert 'Another valid memory (relevance: 0.80)' in result
317+ assert 'invalid_string_item' not in result
318+
319+
252320@pytest .mark .skipif (_import_error is not None , reason = 'mem0 is not installed' )
253321async def test_mem0_toolset_save_memory ():
254322 """Test the save_memory tool."""
@@ -336,6 +404,22 @@ async def test_mem0_toolset_sync_client():
336404 assert 'Successfully saved to memory' in result
337405
338406
407+ @pytest .mark .skipif (_import_error is not None , reason = 'mem0 is not installed' )
408+ async def test_mem0_toolset_client_without_search ():
409+ """Test Mem0Toolset with a client that doesn't have search attribute."""
410+
411+ # Create a client without search attribute to test the _is_async=False path
412+ class MinimalClient :
413+ def add (self , messages : Any , user_id : Any ) -> None :
414+ pass
415+
416+ mock_client = MinimalClient ()
417+ toolset = Mem0Toolset (client = mock_client )
418+
419+ # Should detect it's not async because it doesn't have search method
420+ assert toolset ._is_async is False
421+
422+
339423@pytest .mark .skipif (_import_error is not None , reason = 'mem0 is not installed' )
340424async def test_mem0_toolset_with_dataclass_deps ():
341425 """Test Mem0Toolset with dataclass deps containing user_id."""
0 commit comments