unique_toolkit 1.8.1__py3-none-any.whl → 1.23.0__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_toolkit might be problematic. Click here for more details.

Files changed (105) hide show
  1. unique_toolkit/__init__.py +20 -0
  2. unique_toolkit/_common/api_calling/human_verification_manager.py +121 -28
  3. unique_toolkit/_common/chunk_relevancy_sorter/config.py +3 -3
  4. unique_toolkit/_common/chunk_relevancy_sorter/tests/test_service.py +2 -5
  5. unique_toolkit/_common/default_language_model.py +9 -3
  6. unique_toolkit/_common/docx_generator/__init__.py +7 -0
  7. unique_toolkit/_common/docx_generator/config.py +12 -0
  8. unique_toolkit/_common/docx_generator/schemas.py +80 -0
  9. unique_toolkit/_common/docx_generator/service.py +252 -0
  10. unique_toolkit/_common/docx_generator/template/Doc Template.docx +0 -0
  11. unique_toolkit/_common/endpoint_builder.py +138 -117
  12. unique_toolkit/_common/endpoint_requestor.py +240 -14
  13. unique_toolkit/_common/exception.py +20 -0
  14. unique_toolkit/_common/feature_flags/schema.py +1 -5
  15. unique_toolkit/_common/referencing.py +53 -0
  16. unique_toolkit/_common/string_utilities.py +52 -1
  17. unique_toolkit/_common/tests/test_referencing.py +521 -0
  18. unique_toolkit/_common/tests/test_string_utilities.py +506 -0
  19. unique_toolkit/_common/utils/files.py +43 -0
  20. unique_toolkit/agentic/debug_info_manager/debug_info_manager.py +16 -6
  21. unique_toolkit/agentic/debug_info_manager/test/test_debug_info_manager.py +278 -0
  22. unique_toolkit/agentic/evaluation/config.py +3 -2
  23. unique_toolkit/agentic/evaluation/context_relevancy/service.py +2 -2
  24. unique_toolkit/agentic/evaluation/evaluation_manager.py +9 -5
  25. unique_toolkit/agentic/evaluation/hallucination/constants.py +1 -1
  26. unique_toolkit/agentic/evaluation/hallucination/hallucination_evaluation.py +26 -3
  27. unique_toolkit/agentic/history_manager/history_manager.py +14 -11
  28. unique_toolkit/agentic/history_manager/loop_token_reducer.py +3 -4
  29. unique_toolkit/agentic/history_manager/utils.py +10 -87
  30. unique_toolkit/agentic/postprocessor/postprocessor_manager.py +107 -16
  31. unique_toolkit/agentic/reference_manager/reference_manager.py +1 -1
  32. unique_toolkit/agentic/responses_api/__init__.py +19 -0
  33. unique_toolkit/agentic/responses_api/postprocessors/code_display.py +63 -0
  34. unique_toolkit/agentic/responses_api/postprocessors/generated_files.py +145 -0
  35. unique_toolkit/agentic/responses_api/stream_handler.py +15 -0
  36. unique_toolkit/agentic/tools/a2a/__init__.py +18 -2
  37. unique_toolkit/agentic/tools/a2a/evaluation/__init__.py +2 -0
  38. unique_toolkit/agentic/tools/a2a/evaluation/_utils.py +3 -3
  39. unique_toolkit/agentic/tools/a2a/evaluation/config.py +1 -1
  40. unique_toolkit/agentic/tools/a2a/evaluation/evaluator.py +143 -91
  41. unique_toolkit/agentic/tools/a2a/manager.py +7 -1
  42. unique_toolkit/agentic/tools/a2a/postprocessing/__init__.py +11 -3
  43. unique_toolkit/agentic/tools/a2a/postprocessing/_display_utils.py +185 -0
  44. unique_toolkit/agentic/tools/a2a/postprocessing/_ref_utils.py +73 -0
  45. unique_toolkit/agentic/tools/a2a/postprocessing/config.py +21 -0
  46. unique_toolkit/agentic/tools/a2a/postprocessing/display.py +180 -0
  47. unique_toolkit/agentic/tools/a2a/postprocessing/references.py +101 -0
  48. unique_toolkit/agentic/tools/a2a/postprocessing/test/test_display_utils.py +1335 -0
  49. unique_toolkit/agentic/tools/a2a/postprocessing/test/test_ref_utils.py +603 -0
  50. unique_toolkit/agentic/tools/a2a/prompts.py +46 -0
  51. unique_toolkit/agentic/tools/a2a/response_watcher/__init__.py +6 -0
  52. unique_toolkit/agentic/tools/a2a/response_watcher/service.py +91 -0
  53. unique_toolkit/agentic/tools/a2a/tool/config.py +15 -5
  54. unique_toolkit/agentic/tools/a2a/tool/service.py +69 -36
  55. unique_toolkit/agentic/tools/config.py +16 -2
  56. unique_toolkit/agentic/tools/factory.py +4 -0
  57. unique_toolkit/agentic/tools/mcp/tool_wrapper.py +7 -35
  58. unique_toolkit/agentic/tools/openai_builtin/__init__.py +11 -0
  59. unique_toolkit/agentic/tools/openai_builtin/base.py +30 -0
  60. unique_toolkit/agentic/tools/openai_builtin/code_interpreter/__init__.py +8 -0
  61. unique_toolkit/agentic/tools/openai_builtin/code_interpreter/config.py +57 -0
  62. unique_toolkit/agentic/tools/openai_builtin/code_interpreter/service.py +230 -0
  63. unique_toolkit/agentic/tools/openai_builtin/manager.py +62 -0
  64. unique_toolkit/agentic/tools/test/test_mcp_manager.py +95 -7
  65. unique_toolkit/agentic/tools/test/test_tool_progress_reporter.py +240 -0
  66. unique_toolkit/agentic/tools/tool.py +0 -11
  67. unique_toolkit/agentic/tools/tool_manager.py +337 -122
  68. unique_toolkit/agentic/tools/tool_progress_reporter.py +81 -15
  69. unique_toolkit/agentic/tools/utils/__init__.py +18 -0
  70. unique_toolkit/agentic/tools/utils/execution/execution.py +8 -4
  71. unique_toolkit/agentic/tools/utils/source_handling/schema.py +1 -1
  72. unique_toolkit/chat/__init__.py +8 -1
  73. unique_toolkit/chat/deprecated/service.py +232 -0
  74. unique_toolkit/chat/functions.py +54 -40
  75. unique_toolkit/chat/rendering.py +34 -0
  76. unique_toolkit/chat/responses_api.py +461 -0
  77. unique_toolkit/chat/schemas.py +1 -1
  78. unique_toolkit/chat/service.py +96 -1569
  79. unique_toolkit/content/functions.py +116 -1
  80. unique_toolkit/content/schemas.py +59 -0
  81. unique_toolkit/content/service.py +5 -37
  82. unique_toolkit/content/smart_rules.py +301 -0
  83. unique_toolkit/framework_utilities/langchain/client.py +27 -3
  84. unique_toolkit/framework_utilities/openai/client.py +12 -1
  85. unique_toolkit/framework_utilities/openai/message_builder.py +85 -1
  86. unique_toolkit/language_model/default_language_model.py +3 -0
  87. unique_toolkit/language_model/functions.py +25 -9
  88. unique_toolkit/language_model/infos.py +72 -4
  89. unique_toolkit/language_model/schemas.py +246 -40
  90. unique_toolkit/protocols/support.py +91 -9
  91. unique_toolkit/services/__init__.py +7 -0
  92. unique_toolkit/services/chat_service.py +1630 -0
  93. unique_toolkit/services/knowledge_base.py +861 -0
  94. unique_toolkit/smart_rules/compile.py +56 -301
  95. unique_toolkit/test_utilities/events.py +197 -0
  96. {unique_toolkit-1.8.1.dist-info → unique_toolkit-1.23.0.dist-info}/METADATA +173 -3
  97. {unique_toolkit-1.8.1.dist-info → unique_toolkit-1.23.0.dist-info}/RECORD +99 -67
  98. unique_toolkit/agentic/tools/a2a/postprocessing/_display.py +0 -122
  99. unique_toolkit/agentic/tools/a2a/postprocessing/_utils.py +0 -19
  100. unique_toolkit/agentic/tools/a2a/postprocessing/postprocessor.py +0 -230
  101. unique_toolkit/agentic/tools/a2a/postprocessing/test/test_consolidate_references.py +0 -665
  102. unique_toolkit/agentic/tools/a2a/postprocessing/test/test_display.py +0 -391
  103. unique_toolkit/agentic/tools/a2a/postprocessing/test/test_postprocessor_reference_functions.py +0 -256
  104. {unique_toolkit-1.8.1.dist-info → unique_toolkit-1.23.0.dist-info}/LICENSE +0 -0
  105. {unique_toolkit-1.8.1.dist-info → unique_toolkit-1.23.0.dist-info}/WHEEL +0 -0
@@ -7,6 +7,7 @@ from unique_toolkit.agentic.tools.tool_progress_reporter import (
7
7
  ProgressState,
8
8
  ToolExecutionStatus,
9
9
  ToolProgressReporter,
10
+ ToolProgressReporterConfig,
10
11
  ToolWithToolProgressReporter,
11
12
  track_tool_progress,
12
13
  )
@@ -203,3 +204,242 @@ class TestToolProgressDecorator:
203
204
 
204
205
  status = tool_progress_reporter.tool_statuses[tool_call.id]
205
206
  assert status.state == ProgressState.FAILED
207
+
208
+
209
+ class TestToolProgressReporterConfig:
210
+ """Tests for ToolProgressReporterConfig and custom display configuration."""
211
+
212
+ @pytest.mark.ai
213
+ @pytest.mark.asyncio
214
+ async def test_config__uses_default_templates__when_no_config_provided(
215
+ self, chat_service, tool_call
216
+ ) -> None:
217
+ """
218
+ Purpose: Verify that default state-to-display templates are used when no config is provided.
219
+ Why this matters: Ensures backward compatibility and default behavior.
220
+ Setup summary: Create reporter without config, add status, verify default template is used.
221
+ """
222
+ # Arrange
223
+ reporter = ToolProgressReporter(chat_service)
224
+
225
+ # Act
226
+ await reporter.notify_from_tool_call(
227
+ tool_call=tool_call,
228
+ name="Test Tool",
229
+ message="Processing data",
230
+ state=ProgressState.RUNNING,
231
+ )
232
+
233
+ # Assert
234
+ assert tool_call.id in reporter.tool_statuses
235
+ chat_service.modify_assistant_message_async.assert_called()
236
+ call_args = chat_service.modify_assistant_message_async.call_args
237
+ content = call_args.kwargs["content"]
238
+ assert "Test Tool" in content
239
+ assert "🟡" in content # Default emoji for RUNNING state
240
+ assert "Processing data" in content
241
+
242
+ @pytest.mark.ai
243
+ @pytest.mark.asyncio
244
+ async def test_config__uses_custom_templates__when_config_provided(
245
+ self, chat_service, tool_call
246
+ ) -> None:
247
+ """
248
+ Purpose: Verify that custom templates are used when provided via config.
249
+ Why this matters: Enables customization of progress display format.
250
+ Setup summary: Create reporter with custom template, verify custom format is used.
251
+ """
252
+ # Arrange
253
+ custom_config = ToolProgressReporterConfig(
254
+ state_to_display_template={
255
+ "started": "⚪ {tool_name}: {message}",
256
+ "running": "⏳ {tool_name}: {message}",
257
+ "finished": "✅ {tool_name}: {message}",
258
+ "failed": "❌ {tool_name}: {message}",
259
+ }
260
+ )
261
+ reporter = ToolProgressReporter(chat_service, config=custom_config)
262
+
263
+ # Act
264
+ await reporter.notify_from_tool_call(
265
+ tool_call=tool_call,
266
+ name="My Tool",
267
+ message="Working on it",
268
+ state=ProgressState.RUNNING,
269
+ )
270
+
271
+ # Assert
272
+ chat_service.modify_assistant_message_async.assert_called()
273
+ call_args = chat_service.modify_assistant_message_async.call_args
274
+ content = call_args.kwargs["content"]
275
+ assert "⏳ My Tool: Working on it" in content
276
+ assert "🟡" not in content # Default emoji should not appear
277
+
278
+ @pytest.mark.ai
279
+ @pytest.mark.asyncio
280
+ async def test_config__skips_states_with_empty_template__when_state_hidden(
281
+ self, chat_service, tool_call
282
+ ) -> None:
283
+ """
284
+ Purpose: Verify that states with empty string templates are not displayed.
285
+ Why this matters: Allows selective display of only certain states (e.g., hide STARTED).
286
+ Setup summary: Create config with empty string for RUNNING state, verify message is not displayed.
287
+ """
288
+ # Arrange
289
+ custom_config = ToolProgressReporterConfig(
290
+ state_to_display_template={
291
+ "started": "",
292
+ "running": "", # Empty string hides RUNNING state
293
+ "finished": "✅ {tool_name}: {message}",
294
+ "failed": "❌ {tool_name}: {message}",
295
+ }
296
+ )
297
+ reporter = ToolProgressReporter(chat_service, config=custom_config)
298
+
299
+ # Act
300
+ await reporter.notify_from_tool_call(
301
+ tool_call=tool_call,
302
+ name="Test Tool",
303
+ message="Processing",
304
+ state=ProgressState.RUNNING,
305
+ )
306
+
307
+ # Assert
308
+ chat_service.modify_assistant_message_async.assert_called()
309
+ call_args = chat_service.modify_assistant_message_async.call_args
310
+ content = call_args.kwargs["content"]
311
+ # Content should not contain the message since RUNNING template is empty
312
+ assert "Processing" not in content
313
+ assert "Test Tool" not in content
314
+
315
+ @pytest.mark.ai
316
+ @pytest.mark.asyncio
317
+ async def test_config__formats_placeholders_correctly__with_multiple_tools(
318
+ self, chat_service
319
+ ) -> None:
320
+ """
321
+ Purpose: Verify that {tool_name} and {message} placeholders are replaced correctly for multiple tools.
322
+ Why this matters: Ensures template formatting works correctly in multi-tool scenarios.
323
+ Setup summary: Add multiple tool statuses with different names/messages, verify formatting.
324
+ """
325
+ # Arrange
326
+ custom_config = ToolProgressReporterConfig(
327
+ state_to_display_template={
328
+ "started": "○ {tool_name} - {message}",
329
+ "running": "▶️ {tool_name} - {message}",
330
+ "finished": "✓ {tool_name} - {message}",
331
+ "failed": "✗ {tool_name} - {message}",
332
+ }
333
+ )
334
+ reporter = ToolProgressReporter(chat_service, config=custom_config)
335
+ tool_call_1 = LanguageModelFunction(id="tool_1", name="search")
336
+ tool_call_2 = LanguageModelFunction(id="tool_2", name="analyze")
337
+
338
+ # Act
339
+ await reporter.notify_from_tool_call(
340
+ tool_call=tool_call_1,
341
+ name="Search Tool",
342
+ message="Searching database",
343
+ state=ProgressState.RUNNING,
344
+ )
345
+ await reporter.notify_from_tool_call(
346
+ tool_call=tool_call_2,
347
+ name="Analysis Tool",
348
+ message="Analyzing results",
349
+ state=ProgressState.FINISHED,
350
+ )
351
+
352
+ # Assert
353
+ call_args = chat_service.modify_assistant_message_async.call_args
354
+ content = call_args.kwargs["content"]
355
+ assert "▶️ Search Tool - Searching database" in content
356
+ assert "✓ Analysis Tool - Analyzing results" in content
357
+
358
+ @pytest.mark.ai
359
+ @pytest.mark.asyncio
360
+ async def test_config__shows_only_finished_state__when_only_finished_configured(
361
+ self, chat_service, tool_call
362
+ ) -> None:
363
+ """
364
+ Purpose: Verify selective state display shows only FINISHED when other states use empty templates.
365
+ Why this matters: Use case where user only wants final results, not intermediate steps.
366
+ Setup summary: Configure only FINISHED with content, send STARTED and FINISHED, verify only FINISHED appears.
367
+ """
368
+ # Arrange
369
+ custom_config = ToolProgressReporterConfig(
370
+ state_to_display_template={
371
+ "started": "", # Empty template hides STARTED
372
+ "running": "", # Empty template hides RUNNING
373
+ "finished": "Done: {tool_name} - {message}",
374
+ "failed": "Failed: {tool_name} - {message}",
375
+ }
376
+ )
377
+ reporter = ToolProgressReporter(chat_service, config=custom_config)
378
+
379
+ # Act - Send STARTED state (should not appear)
380
+ await reporter.notify_from_tool_call(
381
+ tool_call=tool_call,
382
+ name="Test Tool",
383
+ message="Starting",
384
+ state=ProgressState.STARTED,
385
+ )
386
+
387
+ # Get first call content
388
+ first_call_args = chat_service.modify_assistant_message_async.call_args
389
+ first_content = first_call_args.kwargs["content"]
390
+
391
+ # Act - Update to FINISHED state (should appear)
392
+ await reporter.notify_from_tool_call(
393
+ tool_call=tool_call,
394
+ name="Test Tool",
395
+ message="Completed successfully",
396
+ state=ProgressState.FINISHED,
397
+ )
398
+
399
+ # Assert
400
+ final_call_args = chat_service.modify_assistant_message_async.call_args
401
+ final_content = final_call_args.kwargs["content"]
402
+
403
+ # STARTED state should not appear in first call
404
+ assert "Starting" not in first_content
405
+
406
+ # FINISHED state should appear in final call
407
+ assert "Done: Test Tool - Completed successfully" in final_content
408
+
409
+ @pytest.mark.ai
410
+ @pytest.mark.asyncio
411
+ async def test_config__handles_all_empty_templates__when_all_states_hidden(
412
+ self, chat_service, tool_call
413
+ ) -> None:
414
+ """
415
+ Purpose: Verify that all empty string templates result in no messages being displayed.
416
+ Why this matters: Edge case handling and allows disabling all progress display.
417
+ Setup summary: Create config with all empty templates, verify no tool messages appear.
418
+ """
419
+ # Arrange
420
+ custom_config = ToolProgressReporterConfig(
421
+ state_to_display_template={
422
+ "started": "",
423
+ "running": "",
424
+ "finished": "",
425
+ "failed": "",
426
+ }
427
+ )
428
+ reporter = ToolProgressReporter(chat_service, config=custom_config)
429
+
430
+ # Act
431
+ await reporter.notify_from_tool_call(
432
+ tool_call=tool_call,
433
+ name="Test Tool",
434
+ message="Processing",
435
+ state=ProgressState.RUNNING,
436
+ )
437
+
438
+ # Assert
439
+ chat_service.modify_assistant_message_async.assert_called()
440
+ call_args = chat_service.modify_assistant_message_async.call_args
441
+ content = call_args.kwargs["content"]
442
+
443
+ # Should only have the progress start text and newlines, no actual messages
444
+ assert "Test Tool" not in content
445
+ assert "Processing" not in content
@@ -5,7 +5,6 @@ from typing import Any, Generic, TypeVar, cast
5
5
  from typing_extensions import deprecated
6
6
 
7
7
  from unique_toolkit.agentic.evaluation.schemas import EvaluationMetricName
8
- from unique_toolkit.agentic.tools.agent_chunks_hanlder import AgentChunksHandler
9
8
  from unique_toolkit.agentic.tools.config import ToolBuildConfig, ToolSelectionPolicy
10
9
  from unique_toolkit.agentic.tools.schemas import (
11
10
  BaseToolConfig,
@@ -20,7 +19,6 @@ from unique_toolkit.chat.service import (
20
19
  from unique_toolkit.language_model import LanguageModelToolDescription
21
20
  from unique_toolkit.language_model.schemas import (
22
21
  LanguageModelFunction,
23
- LanguageModelMessage,
24
22
  )
25
23
  from unique_toolkit.language_model.service import LanguageModelService
26
24
 
@@ -100,15 +98,6 @@ class Tool(ABC, Generic[ConfigType]):
100
98
  """
101
99
  return ""
102
100
 
103
- @deprecated("Do not use as is bound to loop agent only")
104
- @abstractmethod
105
- def get_tool_call_result_for_loop_history(
106
- self,
107
- tool_response: ToolCallResponse,
108
- agent_chunks_handler: AgentChunksHandler,
109
- ) -> LanguageModelMessage:
110
- raise NotImplementedError
111
-
112
101
  @deprecated(
113
102
  "Do not use. The tool should not determine how"
114
103
  "it is checked. This should be defined by the user"