@@ -35,19 +35,16 @@ def test_initialization_success(self):
3535 assert storage ._entity_limit == 10
3636 assert storage ._mode == "summary" # Should default to summary
3737
38- def test_initialization_without_thread (self ):
39- """Test initialization without thread_id."""
38+ def test_initialization_without_thread_raises_error (self ):
39+ """Test initialization without thread_id raises TypeError ."""
4040 from zep_cloud .client import Zep
4141
4242 mock_client = MagicMock (spec = Zep )
43- storage = ZepUserStorage (
44- client = mock_client ,
45- user_id = "test-user"
46- )
47-
48- assert storage ._client is mock_client
49- assert storage .user_id == "test-user"
50- assert storage .thread_id is None
43+ with pytest .raises (TypeError , match = "missing 1 required positional argument: 'thread_id'" ):
44+ storage = ZepUserStorage (
45+ client = mock_client ,
46+ user_id = "test-user"
47+ )
5148
5249 def test_initialization_requires_user_id (self ):
5350 """Test that user_id is required."""
@@ -56,12 +53,21 @@ def test_initialization_requires_user_id(self):
5653 mock_client = MagicMock (spec = Zep )
5754
5855 with pytest .raises (ValueError , match = "user_id is required" ):
59- ZepUserStorage (client = mock_client , user_id = "" )
56+ ZepUserStorage (client = mock_client , user_id = "" , thread_id = "test-thread" )
57+
58+ def test_initialization_requires_thread_id (self ):
59+ """Test that thread_id is required and non-empty."""
60+ from zep_cloud .client import Zep
61+
62+ mock_client = MagicMock (spec = Zep )
63+
64+ with pytest .raises (ValueError , match = "thread_id is required" ):
65+ ZepUserStorage (client = mock_client , user_id = "test-user" , thread_id = "" )
6066
6167 def test_initialization_requires_zep_client (self ):
6268 """Test that client must be Zep instance."""
6369 with pytest .raises (TypeError , match = "client must be an instance of Zep" ):
64- ZepUserStorage (client = "not_a_client" , user_id = "test-user" )
70+ ZepUserStorage (client = "not_a_client" , user_id = "test-user" , thread_id = "test-thread" )
6571
6672 def test_save_message_with_thread (self ):
6773 """Test saving message when thread_id is set."""
@@ -96,32 +102,6 @@ def test_save_message_with_thread(self):
96102 assert message .role == "assistant"
97103 assert message .name == "Helper"
98104
99- def test_save_message_without_thread (self ):
100- """Test saving message when no thread_id falls back to graph."""
101- from zep_cloud .client import Zep
102-
103- mock_client = MagicMock (spec = Zep )
104- mock_client .graph = MagicMock ()
105- mock_client .graph .add = MagicMock ()
106-
107- storage = ZepUserStorage (
108- client = mock_client ,
109- user_id = "test-user"
110- # No thread_id
111- )
112-
113- # Save message (should go to graph as text)
114- storage .save (
115- "Message without thread" ,
116- metadata = {"type" : "message" , "role" : "user" }
117- )
118-
119- # Should save to graph as text
120- mock_client .graph .add .assert_called_once_with (
121- user_id = "test-user" ,
122- data = "Message without thread" ,
123- type = "text" # Converted from message to text
124- )
125105
126106 def test_save_json_data (self ):
127107 """Test saving JSON data to user graph."""
@@ -131,7 +111,7 @@ def test_save_json_data(self):
131111 mock_client .graph = MagicMock ()
132112 mock_client .graph .add = MagicMock ()
133113
134- storage = ZepUserStorage (client = mock_client , user_id = "test-user" )
114+ storage = ZepUserStorage (client = mock_client , user_id = "test-user" , thread_id = "test-thread" )
135115
136116 # Save JSON data
137117 json_data = '{"preference": "dark_mode", "timezone": "PST"}'
@@ -152,7 +132,7 @@ def test_save_text_data(self):
152132 mock_client .graph = MagicMock ()
153133 mock_client .graph .add = MagicMock ()
154134
155- storage = ZepUserStorage (client = mock_client , user_id = "test-user" )
135+ storage = ZepUserStorage (client = mock_client , user_id = "test-user" , thread_id = "test-thread" )
156136
157137 # Save text data
158138 storage .save ("User prefers morning meetings" , metadata = {"type" : "text" })
@@ -164,8 +144,9 @@ def test_save_text_data(self):
164144 type = "text"
165145 )
166146
167- @patch ('zep_crewai.user_storage.ThreadPoolExecutor' )
168- def test_search_with_thread_context (self , mock_executor ):
147+ @patch ('zep_crewai.utils.compose_context_string' )
148+ @patch ('zep_crewai.utils.ThreadPoolExecutor' )
149+ def test_search_with_thread_context (self , mock_executor , mock_compose ):
169150 """Test search includes thread context when available."""
170151 from zep_cloud .client import Zep
171152 from zep_cloud .types import GraphSearchResults , EntityEdge
@@ -174,36 +155,37 @@ def test_search_with_thread_context(self, mock_executor):
174155 mock_client .thread = MagicMock ()
175156 mock_client .graph = MagicMock ()
176157
177- # Mock thread context
178- mock_context = MagicMock ()
179- mock_context .context = "User's conversation context"
180- mock_client .thread .get_user_context .return_value = mock_context
181-
182158 # Setup mock executor
183159 mock_executor_instance = MagicMock ()
184160 mock_executor .return_value .__enter__ .return_value = mock_executor_instance
185161
186- # Mock futures
187- future_thread = MagicMock ()
188- future_thread .result .return_value = {
189- "memory" : "User's conversation context" ,
190- "type" : "thread_context" ,
191- "source" : "thread"
192- }
162+ # Create proper GraphSearchResults mocks
163+ edge_results = MagicMock (spec = GraphSearchResults )
164+ edge_results .edges = [MagicMock (fact = "User likes Python" )]
165+
166+ node_results = MagicMock (spec = GraphSearchResults )
167+ node_results .nodes = []
193168
169+ episode_results = MagicMock (spec = GraphSearchResults )
170+ episode_results .episodes = []
171+
172+ # Mock futures
194173 future_edges = MagicMock ()
195- future_edges .result .return_value = []
174+ future_edges .result .return_value = edge_results
196175
197176 future_nodes = MagicMock ()
198- future_nodes .result .return_value = []
177+ future_nodes .result .return_value = node_results
199178
200179 future_episodes = MagicMock ()
201- future_episodes .result .return_value = []
180+ future_episodes .result .return_value = episode_results
202181
203182 mock_executor_instance .submit .side_effect = [
204- future_thread , future_edges , future_nodes , future_episodes
183+ future_edges , future_nodes , future_episodes
205184 ]
206185
186+ # Mock compose_context_string to return context
187+ mock_compose .return_value = "Context: User likes Python"
188+
207189 storage = ZepUserStorage (
208190 client = mock_client ,
209191 user_id = "test-user" ,
@@ -213,14 +195,15 @@ def test_search_with_thread_context(self, mock_executor):
213195 # Perform search
214196 results = storage .search ("test query" , limit = 5 )
215197
216- # Verify results include thread context
198+ # Verify results include context
217199 assert isinstance (results , list )
218- assert len (results ) > = 1
219- assert results [0 ]["type" ] == "thread_context "
220- assert results [0 ]["memory " ] == "User's conversation context "
200+ assert len (results ) = = 1
201+ assert results [0 ]["type" ] == "user_graph_context "
202+ assert results [0 ]["context " ] == "Context: User likes Python "
221203
222- @patch ('zep_crewai.user_storage.ThreadPoolExecutor' )
223- def test_search_user_graph (self , mock_executor ):
204+ @patch ('zep_crewai.utils.compose_context_string' )
205+ @patch ('zep_crewai.utils.ThreadPoolExecutor' )
206+ def test_search_user_graph (self , mock_executor , mock_compose ):
224207 """Test search searches user graph correctly."""
225208 from zep_cloud .client import Zep
226209 from zep_cloud .types import EntityEdge , EntityNode , Episode , GraphSearchResults
@@ -249,47 +232,51 @@ def test_search_user_graph(self, mock_executor):
249232 mock_executor_instance = MagicMock ()
250233 mock_executor .return_value .__enter__ .return_value = mock_executor_instance
251234
252- future_thread = MagicMock ()
253- future_thread .result .return_value = None
235+ # Create proper GraphSearchResults mocks
236+ edge_results = MagicMock (spec = GraphSearchResults )
237+ edge_results .edges = [mock_edge ]
254238
239+ node_results = MagicMock (spec = GraphSearchResults )
240+ node_results .nodes = [mock_node ]
241+
242+ episode_results = MagicMock (spec = GraphSearchResults )
243+ episode_results .episodes = []
244+
245+ # Mock futures
255246 future_edges = MagicMock ()
256- future_edges .result .return_value = [{
257- "memory" : mock_edge .fact ,
258- "type" : "edge" ,
259- "name" : mock_edge .name ,
260- "attributes" : mock_edge .attributes ,
261- "created_at" : mock_edge .created_at ,
262- "valid_at" : mock_edge .valid_at ,
263- "invalid_at" : mock_edge .invalid_at ,
264- }]
247+ future_edges .result .return_value = edge_results
265248
266249 future_nodes = MagicMock ()
267- future_nodes .result .return_value = [{
268- "memory" : f"{ mock_node .name } : { mock_node .summary } " ,
269- "type" : "node" ,
270- "name" : mock_node .name ,
271- "attributes" : mock_node .attributes ,
272- "created_at" : mock_node .created_at ,
273- }]
250+ future_nodes .result .return_value = node_results
274251
275252 future_episodes = MagicMock ()
276- future_episodes .result .return_value = []
253+ future_episodes .result .return_value = episode_results
277254
278255 mock_executor_instance .submit .side_effect = [
279- future_thread , future_edges , future_nodes , future_episodes
256+ future_edges , future_nodes , future_episodes
280257 ]
281258
282- storage = ZepUserStorage (client = mock_client , user_id = "test-user" )
259+ # Mock compose_context_string to return formatted context
260+ mock_compose .return_value = "Context: User prefers Python. UserPreference: Programming language preference"
261+
262+ storage = ZepUserStorage (client = mock_client , user_id = "test-user" , thread_id = "test-thread" )
283263
284264 # Perform search
285265 results = storage .search ("preferences" , limit = 5 )
286266
287267 # Verify results
288- assert len (results ) == 2
289- assert results [0 ]["type" ] == "edge"
290- assert "Python" in results [0 ]["memory" ]
291- assert results [1 ]["type" ] == "node"
292- assert "UserPreference" in results [1 ]["memory" ]
268+ # Verify compose_context_string was called with correct arguments
269+ mock_compose .assert_called_once ()
270+ call_args = mock_compose .call_args
271+ assert call_args [1 ]['edges' ] == [mock_edge ]
272+ assert call_args [1 ]['nodes' ] == [mock_node ]
273+ assert call_args [1 ]['episodes' ] == []
274+
275+ # Verify results
276+ assert len (results ) == 1
277+ assert results [0 ]["type" ] == "user_graph_context"
278+ assert "User prefers Python" in results [0 ]["context" ]
279+ assert "UserPreference" in results [0 ]["context" ]
293280
294281 def test_get_context_with_thread (self ):
295282 """Test get_context retrieves context using thread.get_user_context."""
@@ -351,25 +338,6 @@ def test_get_context_with_raw_messages_mode(self):
351338
352339 assert context == "User: Hello\n Assistant: Hi there!\n User: How are you?"
353340
354- def test_get_context_without_thread_id (self ):
355- """Test get_context returns None when no thread_id."""
356- from zep_cloud .client import Zep
357-
358- mock_client = MagicMock (spec = Zep )
359- mock_client .thread = MagicMock ()
360-
361- storage = ZepUserStorage (
362- client = mock_client ,
363- user_id = "test-user"
364- # No thread_id
365- )
366-
367- # Get context should return None
368- context = storage .get_context ()
369-
370- # Verify no client methods were called
371- assert context is None
372- mock_client .thread .get_user_context .assert_not_called ()
373341
374342 def test_get_context_with_empty_response (self ):
375343 """Test get_context handles empty context response."""
@@ -417,6 +385,7 @@ def test_search_with_filters(self):
417385 storage = ZepUserStorage (
418386 client = mock_client ,
419387 user_id = "test-user" ,
388+ thread_id = "test-thread" ,
420389 search_filters = search_filters
421390 )
422391
@@ -434,7 +403,7 @@ def test_reset_does_nothing(self):
434403 from zep_cloud .client import Zep
435404
436405 mock_client = MagicMock (spec = Zep )
437- storage = ZepUserStorage (client = mock_client , user_id = "test-user" )
406+ storage = ZepUserStorage (client = mock_client , user_id = "test-user" , thread_id = "test-thread" )
438407
439408 # Should not raise exception
440409 storage .reset ()
0 commit comments