unique_orchestrator 1.11.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of unique_orchestrator might be problematic. Click here for more details.

@@ -0,0 +1,729 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import TYPE_CHECKING
4
+ from unittest.mock import MagicMock
5
+
6
+ import pytest
7
+
8
+ if TYPE_CHECKING:
9
+ from unique_orchestrator.unique_ai import UniqueAI
10
+
11
+
12
+ class TestLogToolCalls:
13
+ """Test suite for UniqueAI._log_tool_calls method"""
14
+
15
+ @pytest.fixture
16
+ def mock_unique_ai(self, monkeypatch):
17
+ """Create a minimal UniqueAI instance with mocked dependencies"""
18
+ # Mock MessageStepLogger before importing UniqueAI to avoid import errors
19
+ mock_message_step_logger_class = MagicMock()
20
+ mock_service_module = MagicMock()
21
+ mock_service_module.MessageStepLogger = mock_message_step_logger_class
22
+
23
+ # Use monkeypatch to set the module in sys.modules before import
24
+ import sys
25
+
26
+ monkeypatch.setitem(
27
+ sys.modules,
28
+ "unique_toolkit.agentic.message_log_manager.service",
29
+ mock_service_module,
30
+ )
31
+
32
+ # Lazy import to avoid heavy dependencies at module import time
33
+ from unique_orchestrator.unique_ai import UniqueAI
34
+
35
+ mock_logger = MagicMock()
36
+
37
+ # Create minimal event structure
38
+ dummy_event = MagicMock()
39
+ dummy_event.payload.assistant_message.id = "assist_1"
40
+ dummy_event.payload.user_message.text = "query"
41
+
42
+ # Create minimal config structure
43
+ mock_config = MagicMock()
44
+ mock_config.agent.prompt_config.user_metadata = []
45
+
46
+ # Create minimal required dependencies
47
+ mock_chat_service = MagicMock()
48
+ mock_content_service = MagicMock()
49
+ mock_debug_info_manager = MagicMock()
50
+ mock_reference_manager = MagicMock()
51
+ mock_thinking_manager = MagicMock()
52
+ mock_tool_manager = MagicMock()
53
+ mock_history_manager = MagicMock()
54
+ mock_evaluation_manager = MagicMock()
55
+ mock_postprocessor_manager = MagicMock()
56
+ mock_streaming_handler = MagicMock()
57
+ mock_message_step_logger = MagicMock()
58
+
59
+ # Instantiate UniqueAI
60
+ ua = UniqueAI(
61
+ logger=mock_logger,
62
+ event=dummy_event,
63
+ config=mock_config,
64
+ chat_service=mock_chat_service,
65
+ content_service=mock_content_service,
66
+ debug_info_manager=mock_debug_info_manager,
67
+ streaming_handler=mock_streaming_handler,
68
+ reference_manager=mock_reference_manager,
69
+ thinking_manager=mock_thinking_manager,
70
+ tool_manager=mock_tool_manager,
71
+ history_manager=mock_history_manager,
72
+ evaluation_manager=mock_evaluation_manager,
73
+ postprocessor_manager=mock_postprocessor_manager,
74
+ message_step_logger=mock_message_step_logger,
75
+ mcp_servers=[],
76
+ )
77
+
78
+ return ua
79
+
80
+ @pytest.mark.ai
81
+ def test_log_tool_calls__creates_log_entry__with_single_tool_call(
82
+ self, mock_unique_ai: UniqueAI
83
+ ) -> None:
84
+ """
85
+ Purpose: Verify that _log_tool_calls creates a message log entry with the correct format when a single tool call is provided.
86
+
87
+ Why this matters: The logging of tool calls is critical for user visibility and debugging. The function must correctly format and log tool call information.
88
+
89
+ Setup summary: Create a UniqueAI instance with mocked dependencies, set up a tool manager with one available tool, and provide a single tool call.
90
+ """
91
+ # Arrange
92
+ mock_tool = MagicMock(spec=["name", "display_name"])
93
+ mock_tool.name = "search_tool"
94
+ mock_tool.display_name.return_value = "Search Tool"
95
+
96
+ mock_unique_ai._tool_manager.available_tools = [mock_tool]
97
+
98
+ mock_tool_call = MagicMock(spec=["name"])
99
+ mock_tool_call.name = "search_tool"
100
+
101
+ tool_calls = [mock_tool_call]
102
+
103
+ # Act
104
+ mock_unique_ai._log_tool_calls(tool_calls)
105
+
106
+ # Assert
107
+ assert isinstance(mock_unique_ai._history_manager.add_tool_call.call_count, int)
108
+ assert mock_unique_ai._history_manager.add_tool_call.call_count == 1
109
+ mock_unique_ai._history_manager.add_tool_call.assert_called_once_with(
110
+ mock_tool_call
111
+ )
112
+
113
+ assert isinstance(
114
+ mock_unique_ai._message_step_logger.create_message_log_entry.call_count,
115
+ int,
116
+ )
117
+ assert (
118
+ mock_unique_ai._message_step_logger.create_message_log_entry.call_count == 1
119
+ )
120
+ mock_unique_ai._message_step_logger.create_message_log_entry.assert_called_once_with(
121
+ text="**Triggered Tool Calls:**\n \n• Search Tool", references=[]
122
+ )
123
+
124
+ @pytest.mark.ai
125
+ def test_log_tool_calls__creates_log_entry__with_multiple_tool_calls(
126
+ self, mock_unique_ai: UniqueAI
127
+ ) -> None:
128
+ """
129
+ Purpose: Verify that _log_tool_calls correctly formats and logs multiple tool calls in a single log entry.
130
+
131
+ Why this matters: Users may trigger multiple tools simultaneously, and all should be logged in a readable format.
132
+
133
+ Setup summary: Create a UniqueAI instance with mocked dependencies, set up a tool manager with multiple available tools, and provide multiple tool calls.
134
+ """
135
+ # Arrange
136
+ mock_tool_1 = MagicMock(spec=["name", "display_name"])
137
+ mock_tool_1.name = "search_tool"
138
+ mock_tool_1.display_name.return_value = "Search Tool"
139
+
140
+ mock_tool_2 = MagicMock(spec=["name", "display_name"])
141
+ mock_tool_2.name = "web_search"
142
+ mock_tool_2.display_name.return_value = "Web Search"
143
+
144
+ mock_unique_ai._tool_manager.available_tools = [mock_tool_1, mock_tool_2]
145
+
146
+ mock_tool_call_1 = MagicMock(spec=["name"])
147
+ mock_tool_call_1.name = "search_tool"
148
+
149
+ mock_tool_call_2 = MagicMock(spec=["name"])
150
+ mock_tool_call_2.name = "web_search"
151
+
152
+ tool_calls = [mock_tool_call_1, mock_tool_call_2]
153
+
154
+ # Act
155
+ mock_unique_ai._log_tool_calls(tool_calls)
156
+
157
+ # Assert
158
+ assert isinstance(mock_unique_ai._history_manager.add_tool_call.call_count, int)
159
+ assert mock_unique_ai._history_manager.add_tool_call.call_count == 2
160
+ mock_unique_ai._history_manager.add_tool_call.assert_any_call(mock_tool_call_1)
161
+ mock_unique_ai._history_manager.add_tool_call.assert_any_call(mock_tool_call_2)
162
+
163
+ assert isinstance(
164
+ mock_unique_ai._message_step_logger.create_message_log_entry.call_count,
165
+ int,
166
+ )
167
+ assert (
168
+ mock_unique_ai._message_step_logger.create_message_log_entry.call_count == 1
169
+ )
170
+ mock_unique_ai._message_step_logger.create_message_log_entry.assert_called_once_with(
171
+ text="**Triggered Tool Calls:**\n \n• Search Tool\n• Web Search",
172
+ references=[],
173
+ )
174
+
175
+ @pytest.mark.ai
176
+ def test_log_tool_calls__uses_tool_name__when_tool_not_in_available_tools(
177
+ self, mock_unique_ai: UniqueAI
178
+ ) -> None:
179
+ """
180
+ Purpose: Verify that _log_tool_calls does not create a message log entry when the tool is not found in available_tools.
181
+ Setup summary: Create a UniqueAI instance with mocked dependencies, set up a tool manager with no matching tools, and provide a tool call with a name not in available_tools.
182
+ """
183
+ # Arrange
184
+ mock_tool = MagicMock(spec=["name", "display_name"])
185
+ mock_tool.name = "other_tool"
186
+ mock_tool.display_name.return_value = "Other Tool"
187
+
188
+ mock_unique_ai._tool_manager.available_tools = [mock_tool]
189
+
190
+ mock_tool_call = MagicMock(spec=["name"])
191
+ mock_tool_call.name = "unknown_tool"
192
+
193
+ tool_calls = [mock_tool_call]
194
+
195
+ # Act
196
+ mock_unique_ai._log_tool_calls(tool_calls)
197
+
198
+ # Assert
199
+ assert isinstance(mock_unique_ai._history_manager.add_tool_call.call_count, int)
200
+ assert mock_unique_ai._history_manager.add_tool_call.call_count == 1
201
+ mock_unique_ai._history_manager.add_tool_call.assert_called_once_with(
202
+ mock_tool_call
203
+ )
204
+
205
+ assert isinstance(
206
+ mock_unique_ai._message_step_logger.create_message_log_entry.call_count,
207
+ int,
208
+ )
209
+ # Tool call not in available_tools should not create a log entry
210
+ assert (
211
+ mock_unique_ai._message_step_logger.create_message_log_entry.call_count == 0
212
+ )
213
+
214
+ @pytest.mark.ai
215
+ def test_log_tool_calls__uses_tool_name__when_display_name_is_falsy(
216
+ self, mock_unique_ai: UniqueAI
217
+ ) -> None:
218
+ """
219
+ Purpose: Verify that _log_tool_calls falls back to the tool call's name when display_name returns a falsy value.
220
+
221
+ Why this matters: The function must handle edge cases where display_name might return None or empty string, ensuring the log entry always contains meaningful information.
222
+
223
+ Setup summary: Create a UniqueAI instance with mocked dependencies, set up a tool manager with a tool that returns a falsy display_name, and provide a matching tool call.
224
+ """
225
+ # Arrange
226
+ mock_tool = MagicMock(spec=["name", "display_name"])
227
+ mock_tool.name = "search_tool"
228
+ mock_tool.display_name.return_value = None
229
+
230
+ mock_unique_ai._tool_manager.available_tools = [mock_tool]
231
+
232
+ mock_tool_call = MagicMock(spec=["name"])
233
+ mock_tool_call.name = "search_tool"
234
+
235
+ tool_calls = [mock_tool_call]
236
+
237
+ # Act
238
+ mock_unique_ai._log_tool_calls(tool_calls)
239
+
240
+ # Assert
241
+ assert isinstance(mock_unique_ai._history_manager.add_tool_call.call_count, int)
242
+ assert mock_unique_ai._history_manager.add_tool_call.call_count == 1
243
+ mock_unique_ai._history_manager.add_tool_call.assert_called_once_with(
244
+ mock_tool_call
245
+ )
246
+
247
+ assert isinstance(
248
+ mock_unique_ai._message_step_logger.create_message_log_entry.call_count,
249
+ int,
250
+ )
251
+ assert (
252
+ mock_unique_ai._message_step_logger.create_message_log_entry.call_count == 1
253
+ )
254
+ # When display_name is falsy, should use tool_call.name
255
+ mock_unique_ai._message_step_logger.create_message_log_entry.assert_called_once_with(
256
+ text="**Triggered Tool Calls:**\n \n• search_tool", references=[]
257
+ )
258
+
259
+ @pytest.mark.ai
260
+ def test_log_tool_calls__handles_empty_list__without_error(
261
+ self, mock_unique_ai: UniqueAI
262
+ ) -> None:
263
+ """
264
+ Purpose: Verify that _log_tool_calls handles an empty tool_calls list without raising errors and does not create a log entry.
265
+
266
+ Why this matters: The function should be resilient to edge cases like empty input, ensuring the system continues to function even when no tool calls are present.
267
+
268
+ Setup summary: Create a UniqueAI instance with mocked dependencies, set up a tool manager with available tools, and provide an empty tool_calls list.
269
+ """
270
+ # Arrange
271
+ mock_tool = MagicMock(spec=["name", "display_name"])
272
+ mock_tool.name = "search_tool"
273
+ mock_tool.display_name.return_value = "Search Tool"
274
+
275
+ mock_unique_ai._tool_manager.available_tools = [mock_tool]
276
+
277
+ tool_calls: list = []
278
+
279
+ # Act
280
+ mock_unique_ai._log_tool_calls(tool_calls)
281
+
282
+ # Assert
283
+ assert isinstance(mock_unique_ai._history_manager.add_tool_call.call_count, int)
284
+ assert mock_unique_ai._history_manager.add_tool_call.call_count == 0
285
+
286
+ assert isinstance(
287
+ mock_unique_ai._message_step_logger.create_message_log_entry.call_count,
288
+ int,
289
+ )
290
+ # Empty tool_calls list should not create a log entry
291
+ assert (
292
+ mock_unique_ai._message_step_logger.create_message_log_entry.call_count == 0
293
+ )
294
+
295
+ @pytest.mark.ai
296
+ def test_log_tool_calls__adds_all_tool_calls_to_history__regardless_of_availability(
297
+ self, mock_unique_ai: UniqueAI
298
+ ) -> None:
299
+ """
300
+ Purpose: Verify that _log_tool_calls adds all tool calls to history, even if they are not in the available_tools list.
301
+
302
+ Why this matters: History tracking should be complete and independent of whether tools are available for display name lookup.
303
+
304
+ Setup summary: Create a UniqueAI instance with mocked dependencies, set up a tool manager with some available tools, and provide tool calls including both available and unavailable tools.
305
+ """
306
+ # Arrange
307
+ mock_tool = MagicMock(spec=["name", "display_name"])
308
+ mock_tool.name = "search_tool"
309
+ mock_tool.display_name.return_value = "Search Tool"
310
+
311
+ mock_unique_ai._tool_manager.available_tools = [mock_tool]
312
+
313
+ mock_tool_call_1 = MagicMock(spec=["name"])
314
+ mock_tool_call_1.name = "search_tool"
315
+
316
+ mock_tool_call_2 = MagicMock(spec=["name"])
317
+ mock_tool_call_2.name = "unknown_tool"
318
+
319
+ tool_calls = [mock_tool_call_1, mock_tool_call_2]
320
+
321
+ # Act
322
+ mock_unique_ai._log_tool_calls(tool_calls)
323
+
324
+ # Assert
325
+ assert isinstance(mock_unique_ai._history_manager.add_tool_call.call_count, int)
326
+ assert mock_unique_ai._history_manager.add_tool_call.call_count == 2
327
+ mock_unique_ai._history_manager.add_tool_call.assert_any_call(mock_tool_call_1)
328
+ mock_unique_ai._history_manager.add_tool_call.assert_any_call(mock_tool_call_2)
329
+
330
+ assert isinstance(
331
+ mock_unique_ai._message_step_logger.create_message_log_entry.call_count,
332
+ int,
333
+ )
334
+ assert (
335
+ mock_unique_ai._message_step_logger.create_message_log_entry.call_count == 1
336
+ )
337
+
338
+ @pytest.mark.ai
339
+ def test_log_tool_calls__excludes_deep_research_from_message_log__but_adds_to_history(
340
+ self, mock_unique_ai: UniqueAI
341
+ ) -> None:
342
+ """
343
+ Purpose: Verify that _log_tool_calls excludes "DeepResearch" from the message log entry but still adds it to history.
344
+
345
+ Why this matters: DeepResearch tool calls should be tracked in history for completeness but hidden from the user-facing message steps to avoid clutter or confusion.
346
+
347
+ Setup summary: Create a UniqueAI instance with mocked dependencies, set up a tool manager with "DeepResearch" and other tools, and provide tool calls including "DeepResearch".
348
+ """
349
+ # Arrange
350
+ mock_tool_1 = MagicMock(spec=["name", "display_name"])
351
+ mock_tool_1.name = "DeepResearch"
352
+ mock_tool_1.display_name.return_value = "Deep Research"
353
+
354
+ mock_tool_2 = MagicMock(spec=["name", "display_name"])
355
+ mock_tool_2.name = "search_tool"
356
+ mock_tool_2.display_name.return_value = "Search Tool"
357
+
358
+ mock_unique_ai._tool_manager.available_tools = [mock_tool_1, mock_tool_2]
359
+
360
+ mock_tool_call_1 = MagicMock(spec=["name"])
361
+ mock_tool_call_1.name = "DeepResearch"
362
+
363
+ mock_tool_call_2 = MagicMock(spec=["name"])
364
+ mock_tool_call_2.name = "search_tool"
365
+
366
+ tool_calls = [mock_tool_call_1, mock_tool_call_2]
367
+
368
+ # Act
369
+ mock_unique_ai._log_tool_calls(tool_calls)
370
+
371
+ # Assert
372
+ # Both tool calls should be added to history
373
+ assert isinstance(mock_unique_ai._history_manager.add_tool_call.call_count, int)
374
+ assert mock_unique_ai._history_manager.add_tool_call.call_count == 2
375
+ mock_unique_ai._history_manager.add_tool_call.assert_any_call(mock_tool_call_1)
376
+ mock_unique_ai._history_manager.add_tool_call.assert_any_call(mock_tool_call_2)
377
+
378
+ # But only the non-DeepResearch tool should appear in the message log
379
+ assert isinstance(
380
+ mock_unique_ai._message_step_logger.create_message_log_entry.call_count,
381
+ int,
382
+ )
383
+ assert (
384
+ mock_unique_ai._message_step_logger.create_message_log_entry.call_count == 1
385
+ )
386
+ mock_unique_ai._message_step_logger.create_message_log_entry.assert_called_once_with(
387
+ text="**Triggered Tool Calls:**\n \n• Search Tool", references=[]
388
+ )
389
+
390
+ @pytest.mark.ai
391
+ def test_log_tool_calls__excludes_only_deep_research_when_present__with_multiple_tools(
392
+ self, mock_unique_ai: UniqueAI
393
+ ) -> None:
394
+ """
395
+ Purpose: Verify that _log_tool_calls only excludes "DeepResearch" and logs all other tools when multiple tools are called.
396
+
397
+ Why this matters: The exclusion logic should be precise, affecting only "DeepResearch" while allowing all other tools to be logged normally.
398
+
399
+ Setup summary: Create a UniqueAI instance with mocked dependencies, set up a tool manager with multiple tools including "DeepResearch", and provide multiple tool calls.
400
+ """
401
+ # Arrange
402
+ mock_tool_1 = MagicMock(spec=["name", "display_name"])
403
+ mock_tool_1.name = "DeepResearch"
404
+ mock_tool_1.display_name.return_value = "Deep Research"
405
+
406
+ mock_tool_2 = MagicMock(spec=["name", "display_name"])
407
+ mock_tool_2.name = "search_tool"
408
+ mock_tool_2.display_name.return_value = "Search Tool"
409
+
410
+ mock_tool_3 = MagicMock(spec=["name", "display_name"])
411
+ mock_tool_3.name = "web_search"
412
+ mock_tool_3.display_name.return_value = "Web Search"
413
+
414
+ mock_unique_ai._tool_manager.available_tools = [
415
+ mock_tool_1,
416
+ mock_tool_2,
417
+ mock_tool_3,
418
+ ]
419
+
420
+ mock_tool_call_1 = MagicMock(spec=["name"])
421
+ mock_tool_call_1.name = "search_tool"
422
+
423
+ mock_tool_call_2 = MagicMock(spec=["name"])
424
+ mock_tool_call_2.name = "DeepResearch"
425
+
426
+ mock_tool_call_3 = MagicMock(spec=["name"])
427
+ mock_tool_call_3.name = "web_search"
428
+
429
+ tool_calls = [mock_tool_call_1, mock_tool_call_2, mock_tool_call_3]
430
+
431
+ # Act
432
+ mock_unique_ai._log_tool_calls(tool_calls)
433
+
434
+ # Assert
435
+ # All tool calls should be added to history
436
+ assert isinstance(mock_unique_ai._history_manager.add_tool_call.call_count, int)
437
+ assert mock_unique_ai._history_manager.add_tool_call.call_count == 3
438
+ mock_unique_ai._history_manager.add_tool_call.assert_any_call(mock_tool_call_1)
439
+ mock_unique_ai._history_manager.add_tool_call.assert_any_call(mock_tool_call_2)
440
+ mock_unique_ai._history_manager.add_tool_call.assert_any_call(mock_tool_call_3)
441
+
442
+ # But only the non-DeepResearch tools should appear in the message log
443
+ assert isinstance(
444
+ mock_unique_ai._message_step_logger.create_message_log_entry.call_count,
445
+ int,
446
+ )
447
+ assert (
448
+ mock_unique_ai._message_step_logger.create_message_log_entry.call_count == 1
449
+ )
450
+ mock_unique_ai._message_step_logger.create_message_log_entry.assert_called_once_with(
451
+ text="**Triggered Tool Calls:**\n \n• Search Tool\n• Web Search",
452
+ references=[],
453
+ )
454
+
455
+ @pytest.mark.ai
456
+ def test_log_tool_calls__creates_no_log_entry__when_only_deep_research_called(
457
+ self, mock_unique_ai: UniqueAI
458
+ ) -> None:
459
+ """
460
+ Purpose: Verify that _log_tool_calls does not create a message log entry when only "DeepResearch" is called.
461
+
462
+ Why this matters: When only excluded tools are called, no message log entry should be created since there's nothing to display to the user.
463
+
464
+ Setup summary: Create a UniqueAI instance with mocked dependencies, set up a tool manager with "DeepResearch", and provide only a DeepResearch tool call.
465
+ """
466
+ # Arrange
467
+ mock_tool = MagicMock(spec=["name", "display_name"])
468
+ mock_tool.name = "DeepResearch"
469
+ mock_tool.display_name.return_value = "Deep Research"
470
+
471
+ mock_unique_ai._tool_manager.available_tools = [mock_tool]
472
+
473
+ mock_tool_call = MagicMock(spec=["name"])
474
+ mock_tool_call.name = "DeepResearch"
475
+
476
+ tool_calls = [mock_tool_call]
477
+
478
+ # Act
479
+ mock_unique_ai._log_tool_calls(tool_calls)
480
+
481
+ # Assert
482
+ # DeepResearch should be added to history
483
+ assert isinstance(mock_unique_ai._history_manager.add_tool_call.call_count, int)
484
+ assert mock_unique_ai._history_manager.add_tool_call.call_count == 1
485
+ mock_unique_ai._history_manager.add_tool_call.assert_called_once_with(
486
+ mock_tool_call
487
+ )
488
+
489
+ # But no message log entry should be created since tool_string is empty
490
+ assert isinstance(
491
+ mock_unique_ai._message_step_logger.create_message_log_entry.call_count,
492
+ int,
493
+ )
494
+ assert (
495
+ mock_unique_ai._message_step_logger.create_message_log_entry.call_count == 0
496
+ )
497
+
498
+ @pytest.mark.ai
499
+ def test_log_tool_calls__displays_count__when_same_tool_called_multiple_times(
500
+ self, mock_unique_ai: UniqueAI
501
+ ) -> None:
502
+ """
503
+ Purpose: Verify that _log_tool_calls displays a count indicator when the same tool is called multiple times.
504
+
505
+ Why this matters: Users should see how many times each tool was invoked to understand the execution pattern. Multiple calls to the same tool should be aggregated with a count suffix.
506
+
507
+ Setup summary: Create a UniqueAI instance with mocked dependencies, set up a tool manager with one available tool, and provide multiple calls to the same tool.
508
+ """
509
+ # Arrange
510
+ mock_tool = MagicMock(spec=["name", "display_name"])
511
+ mock_tool.name = "search_tool"
512
+ mock_tool.display_name.return_value = "Search Tool"
513
+
514
+ mock_unique_ai._tool_manager.available_tools = [mock_tool]
515
+
516
+ mock_tool_call_1 = MagicMock(spec=["name"])
517
+ mock_tool_call_1.name = "search_tool"
518
+
519
+ mock_tool_call_2 = MagicMock(spec=["name"])
520
+ mock_tool_call_2.name = "search_tool"
521
+
522
+ tool_calls = [mock_tool_call_1, mock_tool_call_2]
523
+
524
+ # Act
525
+ mock_unique_ai._log_tool_calls(tool_calls)
526
+
527
+ # Assert
528
+ assert isinstance(mock_unique_ai._history_manager.add_tool_call.call_count, int)
529
+ assert mock_unique_ai._history_manager.add_tool_call.call_count == 2
530
+ mock_unique_ai._history_manager.add_tool_call.assert_any_call(mock_tool_call_1)
531
+ mock_unique_ai._history_manager.add_tool_call.assert_any_call(mock_tool_call_2)
532
+
533
+ assert isinstance(
534
+ mock_unique_ai._message_step_logger.create_message_log_entry.call_count,
535
+ int,
536
+ )
537
+ assert (
538
+ mock_unique_ai._message_step_logger.create_message_log_entry.call_count == 1
539
+ )
540
+ # Should display "(2x)" for the tool called twice
541
+ mock_unique_ai._message_step_logger.create_message_log_entry.assert_called_once_with(
542
+ text="**Triggered Tool Calls:**\n \n• Search Tool (2x)", references=[]
543
+ )
544
+
545
+ @pytest.mark.ai
546
+ def test_log_tool_calls__displays_count__when_same_tool_called_three_times(
547
+ self, mock_unique_ai: UniqueAI
548
+ ) -> None:
549
+ """
550
+ Purpose: Verify that _log_tool_calls correctly displays count for tools called three or more times.
551
+
552
+ Why this matters: The counting logic should work for any number of duplicate calls, not just two.
553
+
554
+ Setup summary: Create a UniqueAI instance with mocked dependencies, set up a tool manager with one available tool, and provide three calls to the same tool.
555
+ """
556
+ # Arrange
557
+ mock_tool = MagicMock(spec=["name", "display_name"])
558
+ mock_tool.name = "search_tool"
559
+ mock_tool.display_name.return_value = "Search Tool"
560
+
561
+ mock_unique_ai._tool_manager.available_tools = [mock_tool]
562
+
563
+ mock_tool_call_1 = MagicMock(spec=["name"])
564
+ mock_tool_call_1.name = "search_tool"
565
+
566
+ mock_tool_call_2 = MagicMock(spec=["name"])
567
+ mock_tool_call_2.name = "search_tool"
568
+
569
+ mock_tool_call_3 = MagicMock(spec=["name"])
570
+ mock_tool_call_3.name = "search_tool"
571
+
572
+ tool_calls = [mock_tool_call_1, mock_tool_call_2, mock_tool_call_3]
573
+
574
+ # Act
575
+ mock_unique_ai._log_tool_calls(tool_calls)
576
+
577
+ # Assert
578
+ assert isinstance(mock_unique_ai._history_manager.add_tool_call.call_count, int)
579
+ assert mock_unique_ai._history_manager.add_tool_call.call_count == 3
580
+
581
+ assert isinstance(
582
+ mock_unique_ai._message_step_logger.create_message_log_entry.call_count,
583
+ int,
584
+ )
585
+ assert (
586
+ mock_unique_ai._message_step_logger.create_message_log_entry.call_count == 1
587
+ )
588
+ # Should display "(3x)" for the tool called three times
589
+ mock_unique_ai._message_step_logger.create_message_log_entry.assert_called_once_with(
590
+ text="**Triggered Tool Calls:**\n \n• Search Tool (3x)", references=[]
591
+ )
592
+
593
+ @pytest.mark.ai
594
+ def test_log_tool_calls__displays_mixed_counts__with_some_tools_called_once_and_others_multiple_times(
595
+ self, mock_unique_ai: UniqueAI
596
+ ) -> None:
597
+ """
598
+ Purpose: Verify that _log_tool_calls correctly handles a mix of tools called once and tools called multiple times.
599
+
600
+ Why this matters: Real-world scenarios often involve calling different tools different numbers of times. The log should accurately reflect this with counts only shown for tools called more than once.
601
+
602
+ Setup summary: Create a UniqueAI instance with mocked dependencies, set up a tool manager with multiple available tools, and provide a mix of single and multiple calls.
603
+ """
604
+ # Arrange
605
+ mock_tool_1 = MagicMock(spec=["name", "display_name"])
606
+ mock_tool_1.name = "search_tool"
607
+ mock_tool_1.display_name.return_value = "Search Tool"
608
+
609
+ mock_tool_2 = MagicMock(spec=["name", "display_name"])
610
+ mock_tool_2.name = "web_search"
611
+ mock_tool_2.display_name.return_value = "Web Search"
612
+
613
+ mock_tool_3 = MagicMock(spec=["name", "display_name"])
614
+ mock_tool_3.name = "file_reader"
615
+ mock_tool_3.display_name.return_value = "File Reader"
616
+
617
+ mock_unique_ai._tool_manager.available_tools = [
618
+ mock_tool_1,
619
+ mock_tool_2,
620
+ mock_tool_3,
621
+ ]
622
+
623
+ mock_tool_call_1 = MagicMock(spec=["name"])
624
+ mock_tool_call_1.name = "search_tool"
625
+
626
+ mock_tool_call_2 = MagicMock(spec=["name"])
627
+ mock_tool_call_2.name = "web_search"
628
+
629
+ mock_tool_call_3 = MagicMock(spec=["name"])
630
+ mock_tool_call_3.name = "search_tool"
631
+
632
+ mock_tool_call_4 = MagicMock(spec=["name"])
633
+ mock_tool_call_4.name = "file_reader"
634
+
635
+ mock_tool_call_5 = MagicMock(spec=["name"])
636
+ mock_tool_call_5.name = "search_tool"
637
+
638
+ tool_calls = [
639
+ mock_tool_call_1,
640
+ mock_tool_call_2,
641
+ mock_tool_call_3,
642
+ mock_tool_call_4,
643
+ mock_tool_call_5,
644
+ ]
645
+
646
+ # Act
647
+ mock_unique_ai._log_tool_calls(tool_calls)
648
+
649
+ # Assert
650
+ assert isinstance(mock_unique_ai._history_manager.add_tool_call.call_count, int)
651
+ assert mock_unique_ai._history_manager.add_tool_call.call_count == 5
652
+
653
+ assert isinstance(
654
+ mock_unique_ai._message_step_logger.create_message_log_entry.call_count,
655
+ int,
656
+ )
657
+ assert (
658
+ mock_unique_ai._message_step_logger.create_message_log_entry.call_count == 1
659
+ )
660
+ # Should display:
661
+ # - "Search Tool (3x)" for search_tool (called 3 times)
662
+ # - "Web Search" for web_search (called once, no count)
663
+ # - "File Reader" for file_reader (called once, no count)
664
+ mock_unique_ai._message_step_logger.create_message_log_entry.assert_called_once_with(
665
+ text="**Triggered Tool Calls:**\n \n• Search Tool (3x)\n• Web Search\n• File Reader",
666
+ references=[],
667
+ )
668
+
669
+ @pytest.mark.ai
670
+ def test_log_tool_calls__excludes_deep_research_from_count__when_called_multiple_times(
671
+ self, mock_unique_ai: UniqueAI
672
+ ) -> None:
673
+ """
674
+ Purpose: Verify that _log_tool_calls excludes "DeepResearch" from message log even when it's called multiple times, but still adds all instances to history.
675
+
676
+ Why this matters: The exclusion of DeepResearch should work consistently regardless of how many times it's called.
677
+
678
+ Setup summary: Create a UniqueAI instance with mocked dependencies, set up a tool manager with "DeepResearch" and other tools, and provide multiple DeepResearch calls along with other tool calls.
679
+ """
680
+ # Arrange
681
+ mock_tool_1 = MagicMock(spec=["name", "display_name"])
682
+ mock_tool_1.name = "DeepResearch"
683
+ mock_tool_1.display_name.return_value = "Deep Research"
684
+
685
+ mock_tool_2 = MagicMock(spec=["name", "display_name"])
686
+ mock_tool_2.name = "search_tool"
687
+ mock_tool_2.display_name.return_value = "Search Tool"
688
+
689
+ mock_unique_ai._tool_manager.available_tools = [mock_tool_1, mock_tool_2]
690
+
691
+ mock_tool_call_1 = MagicMock(spec=["name"])
692
+ mock_tool_call_1.name = "DeepResearch"
693
+
694
+ mock_tool_call_2 = MagicMock(spec=["name"])
695
+ mock_tool_call_2.name = "search_tool"
696
+
697
+ mock_tool_call_3 = MagicMock(spec=["name"])
698
+ mock_tool_call_3.name = "DeepResearch"
699
+
700
+ mock_tool_call_4 = MagicMock(spec=["name"])
701
+ mock_tool_call_4.name = "search_tool"
702
+
703
+ tool_calls = [
704
+ mock_tool_call_1,
705
+ mock_tool_call_2,
706
+ mock_tool_call_3,
707
+ mock_tool_call_4,
708
+ ]
709
+
710
+ # Act
711
+ mock_unique_ai._log_tool_calls(tool_calls)
712
+
713
+ # Assert
714
+ # All tool calls should be added to history
715
+ assert isinstance(mock_unique_ai._history_manager.add_tool_call.call_count, int)
716
+ assert mock_unique_ai._history_manager.add_tool_call.call_count == 4
717
+
718
+ # But only the non-DeepResearch tool should appear in the message log, with correct count
719
+ assert isinstance(
720
+ mock_unique_ai._message_step_logger.create_message_log_entry.call_count,
721
+ int,
722
+ )
723
+ assert (
724
+ mock_unique_ai._message_step_logger.create_message_log_entry.call_count == 1
725
+ )
726
+ # DeepResearch should be excluded, only Search Tool (2x) should appear
727
+ mock_unique_ai._message_step_logger.create_message_log_entry.assert_called_once_with(
728
+ text="**Triggered Tool Calls:**\n \n• Search Tool (2x)", references=[]
729
+ )