unique_toolkit 1.59.1__tar.gz → 1.60.0__tar.gz

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.
Files changed (290) hide show
  1. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/PKG-INFO +2 -2
  2. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/pyproject.toml +2 -2
  3. unique_toolkit-1.60.0/unique_toolkit/agentic/history_manager/history_construction_with_contents.py +412 -0
  4. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/history_manager/history_manager.py +121 -6
  5. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/history_manager/loop_token_reducer.py +143 -15
  6. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/chat/functions.py +159 -27
  7. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/chat/schemas.py +51 -9
  8. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/services/chat_service.py +81 -7
  9. unique_toolkit-1.59.1/unique_toolkit/agentic/history_manager/history_construction_with_contents.py +0 -266
  10. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/README.md +0 -0
  11. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/__init__.py +0 -0
  12. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/__init__.py +0 -0
  13. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/_base_service.py +0 -0
  14. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/_time_utils.py +0 -0
  15. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/api_calling/human_verification_manager.py +0 -0
  16. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/base_model_type_attribute.py +0 -0
  17. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/chunk_relevancy_sorter/config.py +0 -0
  18. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/chunk_relevancy_sorter/exception.py +0 -0
  19. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/chunk_relevancy_sorter/schemas.py +0 -0
  20. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/chunk_relevancy_sorter/service.py +0 -0
  21. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/chunk_relevancy_sorter/tests/test_service.py +0 -0
  22. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/config_checker/README.md +0 -0
  23. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/config_checker/__init__.py +0 -0
  24. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/config_checker/__main__.py +0 -0
  25. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/config_checker/cli.py +0 -0
  26. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/config_checker/differ.py +0 -0
  27. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/config_checker/exporter.py +0 -0
  28. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/config_checker/models.py +0 -0
  29. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/config_checker/registry.py +0 -0
  30. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/config_checker/validator.py +0 -0
  31. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/default_language_model.py +0 -0
  32. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/docx_generator/__init__.py +0 -0
  33. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/docx_generator/config.py +0 -0
  34. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/docx_generator/pandoc_converter.py +0 -0
  35. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/docx_generator/schemas.py +0 -0
  36. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/docx_generator/service.py +0 -0
  37. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/docx_generator/template/Doc Template.docx +0 -0
  38. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/endpoint_builder.py +0 -0
  39. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/endpoint_requestor.py +0 -0
  40. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/event_bus.py +0 -0
  41. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/exception.py +0 -0
  42. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/execution.py +0 -0
  43. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/experimental/endpoint_builder.py +0 -0
  44. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/experimental/endpoint_requestor.py +0 -0
  45. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/experimental/write_up_agent/README.md +0 -0
  46. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/experimental/write_up_agent/__init__.py +0 -0
  47. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/experimental/write_up_agent/agent.py +0 -0
  48. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/experimental/write_up_agent/config.py +0 -0
  49. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/experimental/write_up_agent/examples/data.csv +0 -0
  50. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/experimental/write_up_agent/examples/example_usage.py +0 -0
  51. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/experimental/write_up_agent/schemas.py +0 -0
  52. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/experimental/write_up_agent/services/__init__.py +0 -0
  53. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/experimental/write_up_agent/services/dataframe_handler/__init__.py +0 -0
  54. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/experimental/write_up_agent/services/dataframe_handler/exceptions.py +0 -0
  55. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/experimental/write_up_agent/services/dataframe_handler/service.py +0 -0
  56. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/experimental/write_up_agent/services/dataframe_handler/utils.py +0 -0
  57. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/experimental/write_up_agent/services/generation_handler/__init__.py +0 -0
  58. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/experimental/write_up_agent/services/generation_handler/config.py +0 -0
  59. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/experimental/write_up_agent/services/generation_handler/exceptions.py +0 -0
  60. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/experimental/write_up_agent/services/generation_handler/prompts/config.py +0 -0
  61. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/experimental/write_up_agent/services/generation_handler/prompts/system_prompt.j2 +0 -0
  62. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/experimental/write_up_agent/services/generation_handler/prompts/user_prompt.j2 +0 -0
  63. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/experimental/write_up_agent/services/generation_handler/service.py +0 -0
  64. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/experimental/write_up_agent/services/template_handler/__init__.py +0 -0
  65. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/experimental/write_up_agent/services/template_handler/default_template.j2 +0 -0
  66. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/experimental/write_up_agent/services/template_handler/exceptions.py +0 -0
  67. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/experimental/write_up_agent/services/template_handler/service.py +0 -0
  68. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/experimental/write_up_agent/services/template_handler/utils.py +0 -0
  69. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/experimental/write_up_agent/utils.py +0 -0
  70. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/feature_flags/schema.py +0 -0
  71. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/pydantic/rjsf_tags.py +0 -0
  72. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/pydantic_helpers.py +0 -0
  73. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/referencing.py +0 -0
  74. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/string_utilities.py +0 -0
  75. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/tests/test_referencing.py +0 -0
  76. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/tests/test_string_utilities.py +0 -0
  77. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/token/__init__.py +0 -0
  78. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/token/image_token_counting.py +0 -0
  79. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/token/token_counting.py +0 -0
  80. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/token/tokenizers/deepseek/tokenizer.json +0 -0
  81. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/token/tokenizers/qwen/tokenizer.json +0 -0
  82. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/utils/__init__.py +0 -0
  83. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/utils/files.py +0 -0
  84. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/utils/image/encode.py +0 -0
  85. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/utils/jinja/helpers.py +0 -0
  86. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/utils/jinja/render.py +0 -0
  87. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/utils/jinja/schema.py +0 -0
  88. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/utils/jinja/utils.py +0 -0
  89. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/utils/structured_output/__init__.py +0 -0
  90. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/utils/structured_output/schema.py +0 -0
  91. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/utils/write_configuration.py +0 -0
  92. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/validate_required_values.py +0 -0
  93. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/_common/validators.py +0 -0
  94. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/__init__.py +0 -0
  95. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/debug_info_manager/debug_info_manager.py +0 -0
  96. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/debug_info_manager/test/test_debug_info_manager.py +0 -0
  97. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/evaluation/config.py +0 -0
  98. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/evaluation/context_relevancy/prompts/__init__.py +0 -0
  99. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/evaluation/context_relevancy/prompts/system_prompt.j2 +0 -0
  100. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/evaluation/context_relevancy/prompts/user_prompt.j2 +0 -0
  101. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/evaluation/context_relevancy/schema.py +0 -0
  102. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/evaluation/context_relevancy/service.py +0 -0
  103. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/evaluation/evaluation_manager.py +0 -0
  104. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/evaluation/exception.py +0 -0
  105. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/evaluation/hallucination/constants.py +0 -0
  106. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/evaluation/hallucination/hallucination_evaluation.py +0 -0
  107. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/evaluation/hallucination/prompts/__init__.py +0 -0
  108. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/evaluation/hallucination/prompts/system_prompt.j2 +0 -0
  109. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/evaluation/hallucination/prompts/user_prompt.j2 +0 -0
  110. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/evaluation/hallucination/service.py +0 -0
  111. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/evaluation/hallucination/utils.py +0 -0
  112. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/evaluation/output_parser.py +0 -0
  113. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/evaluation/schemas.py +0 -0
  114. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/evaluation/tests/fixtures.py +0 -0
  115. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/evaluation/tests/test_config.py +0 -0
  116. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/evaluation/tests/test_context_relevancy_service.py +0 -0
  117. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/evaluation/tests/test_hallucination_constants.py +0 -0
  118. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/evaluation/tests/test_hallucination_utils.py +0 -0
  119. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/evaluation/tests/test_output_parser.py +0 -0
  120. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/evaluation/tests/test_prompt_loaders.py +0 -0
  121. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/evaluation/utils.py +0 -0
  122. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/feature_flags/__init__.py +0 -0
  123. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/feature_flags/feature_flags.py +0 -0
  124. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/history_manager/utils.py +0 -0
  125. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/loop_runner/__init__.py +0 -0
  126. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/loop_runner/_iteration_handler_utils.py +0 -0
  127. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/loop_runner/_responses_iteration_handler_utils.py +0 -0
  128. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/loop_runner/_responses_stream_handler_utils.py +0 -0
  129. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/loop_runner/_stream_handler_utils.py +0 -0
  130. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/loop_runner/base.py +0 -0
  131. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/loop_runner/middleware/__init__.py +0 -0
  132. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/loop_runner/middleware/planning/__init__.py +0 -0
  133. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/loop_runner/middleware/planning/planning.py +0 -0
  134. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/loop_runner/middleware/planning/schema.py +0 -0
  135. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/loop_runner/runners/__init__.py +0 -0
  136. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/loop_runner/runners/basic.py +0 -0
  137. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/loop_runner/runners/mistral/__init__.py +0 -0
  138. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/loop_runner/runners/mistral/mistral_runner.py +0 -0
  139. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/loop_runner/runners/qwen/__init__.py +0 -0
  140. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/loop_runner/runners/qwen/helpers.py +0 -0
  141. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/loop_runner/runners/qwen/qwen_runner.py +0 -0
  142. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/message_log_manager/__init__.py +0 -0
  143. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/message_log_manager/service.py +0 -0
  144. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/postprocessor/postprocessor_manager.py +0 -0
  145. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/reference_manager/reference_manager.py +0 -0
  146. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/responses_api/__init__.py +0 -0
  147. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/responses_api/postprocessors/code_display.py +0 -0
  148. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/responses_api/postprocessors/generated_files.py +0 -0
  149. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/responses_api/stream_handler.py +0 -0
  150. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/short_term_memory_manager/persistent_short_term_memory_manager.py +0 -0
  151. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/thinking_manager/thinking_manager.py +0 -0
  152. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/__init__.py +0 -0
  153. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/a2a/__init__.py +0 -0
  154. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/a2a/config.py +0 -0
  155. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/a2a/evaluation/__init__.py +0 -0
  156. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/a2a/evaluation/_utils.py +0 -0
  157. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/a2a/evaluation/config.py +0 -0
  158. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/a2a/evaluation/evaluator.py +0 -0
  159. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/a2a/evaluation/summarization_user_message.j2 +0 -0
  160. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/a2a/manager.py +0 -0
  161. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/a2a/postprocessing/__init__.py +0 -0
  162. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/a2a/postprocessing/_display_utils.py +0 -0
  163. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/a2a/postprocessing/_ref_utils.py +0 -0
  164. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/a2a/postprocessing/config.py +0 -0
  165. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/a2a/postprocessing/display.py +0 -0
  166. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/a2a/postprocessing/references.py +0 -0
  167. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/a2a/postprocessing/test/test_display.py +0 -0
  168. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/a2a/postprocessing/test/test_display_utils.py +0 -0
  169. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/a2a/postprocessing/test/test_ref_utils.py +0 -0
  170. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/a2a/prompts.py +0 -0
  171. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/a2a/response_watcher/__init__.py +0 -0
  172. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/a2a/response_watcher/service.py +0 -0
  173. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/a2a/tool/__init__.py +0 -0
  174. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/a2a/tool/_memory.py +0 -0
  175. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/a2a/tool/_schema.py +0 -0
  176. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/a2a/tool/config.py +0 -0
  177. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/a2a/tool/service.py +0 -0
  178. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/a2a/tool/test/test_service_utils.py +0 -0
  179. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/agent_chunks_hanlder.py +0 -0
  180. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/config.py +0 -0
  181. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/factory.py +0 -0
  182. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/mcp/__init__.py +0 -0
  183. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/mcp/manager.py +0 -0
  184. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/mcp/models.py +0 -0
  185. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/mcp/tool_wrapper.py +0 -0
  186. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/openai_builtin/__init__.py +0 -0
  187. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/openai_builtin/base.py +0 -0
  188. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/openai_builtin/code_interpreter/__init__.py +0 -0
  189. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/openai_builtin/code_interpreter/config.py +0 -0
  190. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/openai_builtin/code_interpreter/postprocessors/__init__.py +0 -0
  191. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/openai_builtin/code_interpreter/postprocessors/code_display.py +0 -0
  192. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/openai_builtin/code_interpreter/postprocessors/generated_files.py +0 -0
  193. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/openai_builtin/code_interpreter/schemas.py +0 -0
  194. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/openai_builtin/code_interpreter/service.py +0 -0
  195. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/openai_builtin/manager.py +0 -0
  196. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/schemas.py +0 -0
  197. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/test/test_mcp_manager.py +0 -0
  198. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/test/test_tool_progress_reporter.py +0 -0
  199. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/tool.py +0 -0
  200. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/tool_manager.py +0 -0
  201. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/tool_progress_reporter.py +0 -0
  202. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/utils/__init__.py +0 -0
  203. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/utils/source_handling/__init__.py +0 -0
  204. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/utils/source_handling/schema.py +0 -0
  205. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/utils/source_handling/source_formatting.py +0 -0
  206. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic/tools/utils/source_handling/tests/test_source_formatting.py +0 -0
  207. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic_table/__init__.py +0 -0
  208. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic_table/schemas.py +0 -0
  209. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/agentic_table/service.py +0 -0
  210. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/app/__init__.py +0 -0
  211. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/app/dev_util.py +0 -0
  212. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/app/fast_api_factory.py +0 -0
  213. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/app/init_logging.py +0 -0
  214. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/app/init_sdk.py +0 -0
  215. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/app/performance/async_tasks.py +0 -0
  216. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/app/performance/async_wrapper.py +0 -0
  217. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/app/schemas.py +0 -0
  218. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/app/unique_settings.py +0 -0
  219. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/app/verification.py +0 -0
  220. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/app/webhook.py +0 -0
  221. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/chat/__init__.py +0 -0
  222. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/chat/cancellation.py +0 -0
  223. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/chat/constants.py +0 -0
  224. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/chat/deprecated/service.py +0 -0
  225. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/chat/rendering.py +0 -0
  226. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/chat/responses_api.py +0 -0
  227. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/chat/service.py +0 -0
  228. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/chat/state.py +0 -0
  229. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/chat/utils.py +0 -0
  230. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/content/__init__.py +0 -0
  231. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/content/constants.py +0 -0
  232. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/content/functions.py +0 -0
  233. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/content/schemas.py +0 -0
  234. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/content/service.py +0 -0
  235. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/content/smart_rules.py +0 -0
  236. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/content/utils.py +0 -0
  237. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/data_extraction/README.md +0 -0
  238. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/data_extraction/__init__.py +0 -0
  239. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/data_extraction/augmented/__init__.py +0 -0
  240. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/data_extraction/augmented/service.py +0 -0
  241. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/data_extraction/base.py +0 -0
  242. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/data_extraction/basic/__init__.py +0 -0
  243. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/data_extraction/basic/config.py +0 -0
  244. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/data_extraction/basic/prompt.py +0 -0
  245. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/data_extraction/basic/service.py +0 -0
  246. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/elicitation/__init__.py +0 -0
  247. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/elicitation/constants.py +0 -0
  248. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/elicitation/exceptions.py +0 -0
  249. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/elicitation/functions.py +0 -0
  250. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/elicitation/schemas.py +0 -0
  251. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/elicitation/service.py +0 -0
  252. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/embedding/__init__.py +0 -0
  253. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/embedding/constants.py +0 -0
  254. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/embedding/functions.py +0 -0
  255. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/embedding/schemas.py +0 -0
  256. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/embedding/service.py +0 -0
  257. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/embedding/utils.py +0 -0
  258. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/framework_utilities/__init__.py +0 -0
  259. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/framework_utilities/langchain/__init__.py +0 -0
  260. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/framework_utilities/langchain/client.py +0 -0
  261. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/framework_utilities/langchain/history.py +0 -0
  262. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/framework_utilities/openai/__init__.py +0 -0
  263. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/framework_utilities/openai/client.py +0 -0
  264. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/framework_utilities/openai/message_builder.py +0 -0
  265. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/framework_utilities/utils.py +0 -0
  266. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/language_model/__init__.py +0 -0
  267. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/language_model/_responses_api_utils.py +0 -0
  268. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/language_model/builder.py +0 -0
  269. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/language_model/constants.py +0 -0
  270. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/language_model/default_language_model.py +0 -0
  271. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/language_model/functions.py +0 -0
  272. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/language_model/infos.py +0 -0
  273. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/language_model/prompt.py +0 -0
  274. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/language_model/reference.py +0 -0
  275. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/language_model/schemas.py +0 -0
  276. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/language_model/service.py +0 -0
  277. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/language_model/stream_transform.py +0 -0
  278. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/language_model/utils.py +0 -0
  279. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/protocols/support.py +0 -0
  280. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/services/__init__.py +0 -0
  281. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/services/factory.py +0 -0
  282. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/services/knowledge_base.py +0 -0
  283. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/short_term_memory/__init__.py +0 -0
  284. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/short_term_memory/constants.py +0 -0
  285. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/short_term_memory/functions.py +0 -0
  286. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/short_term_memory/schemas.py +0 -0
  287. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/short_term_memory/service.py +0 -0
  288. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/smart_rules/__init__.py +0 -0
  289. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/smart_rules/compile.py +0 -0
  290. {unique_toolkit-1.59.1 → unique_toolkit-1.60.0}/unique_toolkit/test_utilities/events.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: unique-toolkit
3
- Version: 1.59.1
3
+ Version: 1.60.0
4
4
  Summary:
5
5
  Author: Cedric Klinkert, Martin Fadler, Sadique Sheik, Fabian Schläpfer, Pascal Hauri, Ejiroghene Oki-Peter, Rami Azouz, Ricardo Visini, Sanzio Monti
6
6
  Author-email: Cedric Klinkert <cedric.klinkert@unique.ch>, Martin Fadler <martin.fadler@unique.ch>, Sadique Sheik <sadique@unique.ch>, Fabian Schläpfer <fabian@unique.ch>, Pascal Hauri <pascal@unique.ch>, Ejiroghene Oki-Peter <oki-peter.ejiroghene@unique.ai>, Rami Azouz <rami.ext@unique.ch>, Ricardo Visini <ricardo.visini@unique.ch>, Sanzio Monti <sanzio.monti@unique.ai>
@@ -16,7 +16,7 @@ Requires-Dist: sseclient>=0.0.27,<0.0.28
16
16
  Requires-Dist: openai>=1.105.0,<2
17
17
  Requires-Dist: platformdirs>=4.0.0,<5
18
18
  Requires-Dist: pillow>=12.1.1
19
- Requires-Dist: unique-sdk>=0.10.80,<0.11
19
+ Requires-Dist: unique-sdk>=0.10.85,<0.11
20
20
  Requires-Dist: jambo>=0.1.2,<0.2
21
21
  Requires-Dist: jinja2>=3.1.6,<4
22
22
  Requires-Dist: docxtpl>=0.20.1,<0.21
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "unique_toolkit"
3
- version = "1.59.1"
3
+ version = "1.60.0"
4
4
  description = ""
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.12"
@@ -28,7 +28,7 @@ dependencies = [
28
28
  "openai>=1.105.0,<2",
29
29
  "platformdirs>=4.0.0,<5",
30
30
  "pillow>=12.1.1",
31
- "unique-sdk>=0.10.80,<0.11",
31
+ "unique-sdk>=0.10.85,<0.11",
32
32
  "jambo>=0.1.2,<0.2",
33
33
  "jinja2>=3.1.6,<4",
34
34
  "docxtpl>=0.20.1,<0.21",
@@ -0,0 +1,412 @@
1
+ from __future__ import annotations
2
+
3
+ import base64
4
+ import logging
5
+ import mimetypes
6
+ from datetime import datetime
7
+ from enum import StrEnum
8
+ from itertools import groupby
9
+ from typing import TYPE_CHECKING
10
+
11
+ if TYPE_CHECKING:
12
+ from unique_toolkit.language_model.builder import MessagesBuilder
13
+
14
+ import numpy as np
15
+ from pydantic import RootModel
16
+
17
+ from unique_toolkit._common.token.token_counting import (
18
+ num_tokens_per_language_model_message,
19
+ )
20
+ from unique_toolkit._common.utils import files as FileUtils
21
+ from unique_toolkit.app import ChatEventUserMessage
22
+ from unique_toolkit.chat.schemas import ChatMessage, ChatMessageTool
23
+ from unique_toolkit.chat.schemas import ChatMessageRole as ChatRole
24
+ from unique_toolkit.chat.service import ChatService
25
+ from unique_toolkit.content.schemas import Content
26
+ from unique_toolkit.content.service import ContentService
27
+ from unique_toolkit.language_model import LanguageModelMessageRole as LLMRole
28
+ from unique_toolkit.language_model.infos import EncoderName, LanguageModelInfo
29
+ from unique_toolkit.language_model.schemas import (
30
+ LanguageModelAssistantMessage,
31
+ LanguageModelFunction,
32
+ LanguageModelMessages,
33
+ LanguageModelToolMessage,
34
+ )
35
+
36
+ _LOGGER = logging.getLogger(__name__)
37
+
38
+ map_chat_llm_message_role = {
39
+ ChatRole.USER: LLMRole.USER,
40
+ ChatRole.ASSISTANT: LLMRole.ASSISTANT,
41
+ ChatRole.SYSTEM: LLMRole.SYSTEM,
42
+ }
43
+
44
+
45
+ class ChatMessageWithContents(ChatMessage):
46
+ contents: list[Content] = []
47
+
48
+
49
+ class ChatHistoryWithContent(RootModel):
50
+ root: list[ChatMessageWithContents]
51
+
52
+ @classmethod
53
+ def from_chat_history_and_contents(
54
+ cls,
55
+ chat_history: list[ChatMessage],
56
+ chat_contents: list[Content],
57
+ ):
58
+ combined = chat_contents + chat_history
59
+ combined.sort(key=lambda x: x.created_at or datetime.min)
60
+
61
+ grouped_elements = []
62
+ content_container = []
63
+
64
+ # Content is collected and added to the next chat message
65
+ for c in combined:
66
+ if isinstance(c, ChatMessage):
67
+ grouped_elements.append(
68
+ ChatMessageWithContents(
69
+ contents=content_container.copy(),
70
+ **c.model_dump(),
71
+ ),
72
+ )
73
+ content_container.clear()
74
+ else:
75
+ content_container.append(c)
76
+
77
+ return cls(root=grouped_elements)
78
+
79
+ def __iter__(self):
80
+ return iter(self.root)
81
+
82
+ def __getitem__(self, item):
83
+ return self.root[item]
84
+
85
+
86
+ def get_chat_history_with_contents(
87
+ user_message: ChatEventUserMessage,
88
+ chat_id: str,
89
+ chat_history: list[ChatMessage],
90
+ content_service: ContentService,
91
+ ) -> ChatHistoryWithContent:
92
+ last_user_message = ChatMessage(
93
+ id=user_message.id,
94
+ chat_id=chat_id,
95
+ text=user_message.text,
96
+ originalText=user_message.original_text,
97
+ role=ChatRole.USER,
98
+ gpt_request=None,
99
+ created_at=datetime.fromisoformat(user_message.created_at),
100
+ )
101
+ if len(chat_history) > 0 and last_user_message.id == chat_history[-1].id:
102
+ pass
103
+ else:
104
+ chat_history.append(last_user_message)
105
+
106
+ chat_contents = content_service.search_contents(
107
+ where={
108
+ "ownerId": {
109
+ "equals": chat_id,
110
+ },
111
+ },
112
+ )
113
+
114
+ return ChatHistoryWithContent.from_chat_history_and_contents(
115
+ chat_history,
116
+ chat_contents,
117
+ )
118
+
119
+
120
+ def download_encoded_images(
121
+ contents: list[Content],
122
+ content_service: ContentService,
123
+ chat_id: str,
124
+ ) -> list[str]:
125
+ base64_encoded_images = []
126
+ for im in contents:
127
+ if FileUtils.is_image_content(im.key):
128
+ try:
129
+ file_bytes = content_service.download_content_to_bytes(
130
+ content_id=im.id,
131
+ chat_id=chat_id,
132
+ )
133
+
134
+ mime_type, _ = mimetypes.guess_type(im.key)
135
+ encoded_string = base64.b64encode(file_bytes).decode("utf-8")
136
+ image_string = f"data:{mime_type};base64," + encoded_string
137
+ base64_encoded_images.append(image_string)
138
+ except Exception as e:
139
+ print(e)
140
+ return base64_encoded_images
141
+
142
+
143
+ class FileContentSerialization(StrEnum):
144
+ NONE = "none"
145
+ FILE_NAME = "file_name"
146
+
147
+
148
+ class ImageContentInclusion(StrEnum):
149
+ NONE = "none"
150
+ ALL = "all"
151
+
152
+
153
+ def file_content_serialization(
154
+ file_contents: list[Content],
155
+ file_content_serialization: FileContentSerialization,
156
+ ) -> str:
157
+ match file_content_serialization:
158
+ case FileContentSerialization.NONE:
159
+ return ""
160
+ case FileContentSerialization.FILE_NAME:
161
+ file_names = [
162
+ f"- Uploaded file: {f.key} at {f.created_at}" for f in file_contents
163
+ ]
164
+ return "\n".join(
165
+ [
166
+ "Files Uploaded to Chat can be accessed by internal search tool if available:\n",
167
+ ]
168
+ + file_names,
169
+ )
170
+
171
+
172
+ def _append_element_to_builder(
173
+ builder: MessagesBuilder,
174
+ c: ChatMessageWithContents,
175
+ text: str,
176
+ include_images: ImageContentInclusion,
177
+ file_content_serialization_type: FileContentSerialization,
178
+ content_service: ContentService,
179
+ chat_id: str,
180
+ ) -> None:
181
+ if len(c.contents) > 0:
182
+ file_contents = [co for co in c.contents if FileUtils.is_file_content(co.key)]
183
+ image_contents = [co for co in c.contents if FileUtils.is_image_content(co.key)]
184
+ content = (
185
+ text
186
+ + "\n\n"
187
+ + file_content_serialization(
188
+ file_contents,
189
+ file_content_serialization_type,
190
+ )
191
+ ).strip()
192
+ if include_images and len(image_contents) > 0:
193
+ builder.image_message_append(
194
+ content=content,
195
+ images=download_encoded_images(
196
+ contents=image_contents,
197
+ content_service=content_service,
198
+ chat_id=chat_id,
199
+ ),
200
+ role=map_chat_llm_message_role[c.role],
201
+ )
202
+ else:
203
+ builder.message_append(
204
+ role=map_chat_llm_message_role[c.role],
205
+ content=content,
206
+ )
207
+ else:
208
+ builder.message_append(
209
+ role=map_chat_llm_message_role[c.role],
210
+ content=text,
211
+ )
212
+
213
+
214
+ def get_full_history_with_contents(
215
+ user_message: ChatEventUserMessage,
216
+ chat_id: str,
217
+ chat_service: ChatService,
218
+ content_service: ContentService,
219
+ include_images: ImageContentInclusion = ImageContentInclusion.ALL,
220
+ file_content_serialization_type: FileContentSerialization = FileContentSerialization.FILE_NAME,
221
+ ) -> LanguageModelMessages:
222
+ grouped_elements = get_chat_history_with_contents(
223
+ user_message=user_message,
224
+ chat_id=chat_id,
225
+ chat_history=chat_service.get_full_history(),
226
+ content_service=content_service,
227
+ )
228
+
229
+ builder = LanguageModelMessages([]).builder()
230
+ for c in grouped_elements:
231
+ # LanguageModelUserMessage has no field original_text
232
+ text = c.original_text if c.original_text else c.content
233
+ if text is None:
234
+ if c.role == ChatRole.USER:
235
+ raise ValueError(
236
+ "Content or original_text of LanguageModelMessages should exist.",
237
+ )
238
+ text = ""
239
+ _append_element_to_builder(
240
+ builder=builder,
241
+ c=c,
242
+ text=text,
243
+ include_images=include_images,
244
+ file_content_serialization_type=file_content_serialization_type,
245
+ content_service=content_service,
246
+ chat_id=chat_id,
247
+ )
248
+ return builder.build()
249
+
250
+
251
+ def get_full_history_with_contents_and_tool_calls(
252
+ *,
253
+ user_message: ChatEventUserMessage,
254
+ chat_id: str,
255
+ chat_service: ChatService,
256
+ content_service: ContentService,
257
+ include_images: ImageContentInclusion = ImageContentInclusion.ALL,
258
+ file_content_serialization_type: FileContentSerialization = FileContentSerialization.FILE_NAME,
259
+ ) -> LanguageModelMessages:
260
+ """Build the full LLM message history, including persisted tool call rounds."""
261
+ chat_history = chat_service.get_full_history()
262
+
263
+ assistant_message_ids = [
264
+ msg.id for msg in chat_history if msg.role == ChatRole.ASSISTANT and msg.id
265
+ ]
266
+ tool_calls_by_message: dict[str, list[ChatMessageTool]] = {}
267
+ if assistant_message_ids:
268
+ try:
269
+ all_tool_calls = chat_service.get_message_tools(
270
+ message_ids=assistant_message_ids,
271
+ )
272
+ for tc in all_tool_calls:
273
+ if tc.message_id:
274
+ tool_calls_by_message.setdefault(tc.message_id, []).append(tc)
275
+ except Exception:
276
+ _LOGGER.warning(
277
+ "Failed to batch-load tool calls, falling back to empty", exc_info=True
278
+ )
279
+
280
+ grouped_elements = get_chat_history_with_contents(
281
+ user_message=user_message,
282
+ chat_id=chat_id,
283
+ chat_history=chat_history,
284
+ content_service=content_service,
285
+ )
286
+
287
+ builder = LanguageModelMessages([]).builder()
288
+ for c in grouped_elements:
289
+ text = c.original_text if c.original_text else c.content
290
+ if text is None:
291
+ if c.role == ChatRole.USER:
292
+ raise ValueError(
293
+ "Content or original_text of LanguageModelMessages should exist.",
294
+ )
295
+ text = ""
296
+
297
+ if c.role == ChatRole.ASSISTANT and c.id and c.id in tool_calls_by_message:
298
+ tc_records = sorted(
299
+ tool_calls_by_message[c.id],
300
+ key=lambda tc: (tc.round_index, tc.sequence_index),
301
+ )
302
+ if tc_records:
303
+ for _round, round_group in groupby(
304
+ tc_records, key=lambda tc: tc.round_index
305
+ ):
306
+ round_tcs = list(round_group)
307
+ # Only include tool calls that have a response; without a
308
+ # matching LanguageModelToolMessage the assistant message
309
+ # would reference a tool_call_id that never gets a reply,
310
+ # which LLM APIs (e.g. OpenAI) reject.
311
+ round_tcs_with_response = [
312
+ tc
313
+ for tc in round_tcs
314
+ if tc.response and tc.response.content is not None
315
+ ]
316
+ if not round_tcs_with_response:
317
+ continue
318
+ # Build LanguageModelFunction objects first so we can read
319
+ # back the post-validator id: the randomize_id validator
320
+ # replaces an empty string with a UUID, and we must use
321
+ # the same id in the LanguageModelToolMessage so the
322
+ # tool_call_id references match.
323
+ fns = [
324
+ LanguageModelFunction(
325
+ id=tc.external_tool_call_id,
326
+ name=tc.function_name,
327
+ arguments=tc.arguments,
328
+ )
329
+ for tc in round_tcs_with_response
330
+ ]
331
+ builder.messages.append(
332
+ LanguageModelAssistantMessage.from_functions(tool_calls=fns)
333
+ )
334
+ for fn, tc in zip(fns, round_tcs_with_response):
335
+ builder.messages.append(
336
+ LanguageModelToolMessage(
337
+ tool_call_id=fn.id,
338
+ content=tc.response.content, # type: ignore[union-attr]
339
+ name=tc.function_name,
340
+ )
341
+ )
342
+
343
+ # Drop empty assistant messages that had tool calls.
344
+ # When a turn consists only of tool-call rounds (e.g. the loop was
345
+ # cancelled before producing a final prose response), the DB message
346
+ # ends up with text == "". The full turn is already captured by the
347
+ # interleaved ASSISTANT(tool_calls) + TOOL messages emitted above, so
348
+ # appending an empty ASSISTANT message here would waste tokens and can
349
+ # be misread by LLM APIs as a conversation boundary.
350
+ # Note: get_full_history_with_contents does NOT drop this message — it
351
+ # has no tool-call context and treats the empty message as benign.
352
+ had_tool_calls = (
353
+ c.role == ChatRole.ASSISTANT
354
+ and c.id is not None
355
+ and c.id in tool_calls_by_message
356
+ )
357
+ if had_tool_calls and not text:
358
+ continue
359
+
360
+ _append_element_to_builder(
361
+ builder=builder,
362
+ c=c,
363
+ text=text,
364
+ include_images=include_images,
365
+ file_content_serialization_type=file_content_serialization_type,
366
+ content_service=content_service,
367
+ chat_id=chat_id,
368
+ )
369
+ return builder.build()
370
+
371
+
372
+ def get_full_history_as_llm_messages(
373
+ chat_service: ChatService,
374
+ ) -> LanguageModelMessages:
375
+ chat_history = chat_service.get_full_history()
376
+
377
+ map_chat_llm_message_role = {
378
+ ChatRole.USER: LLMRole.USER,
379
+ ChatRole.ASSISTANT: LLMRole.ASSISTANT,
380
+ }
381
+
382
+ builder = LanguageModelMessages([]).builder()
383
+ for c in chat_history:
384
+ builder.message_append(
385
+ role=map_chat_llm_message_role[c.role],
386
+ content=c.content or "",
387
+ )
388
+ return builder.build()
389
+
390
+
391
+ def limit_to_token_window(
392
+ messages: LanguageModelMessages,
393
+ token_limit: int,
394
+ model_info: LanguageModelInfo | None = None,
395
+ encoding_name: EncoderName = EncoderName.O200K_BASE,
396
+ ) -> LanguageModelMessages:
397
+ if model_info is not None:
398
+ encode = model_info.get_encoder()
399
+ else:
400
+ encode = encoding_name.get_encoder()
401
+
402
+ token_per_message_reversed = num_tokens_per_language_model_message(
403
+ messages,
404
+ encode=encode,
405
+ )
406
+
407
+ to_take: list[bool] = (np.cumsum(token_per_message_reversed) < token_limit).tolist()
408
+ to_take.reverse()
409
+
410
+ return LanguageModelMessages(
411
+ root=[m for m, tt in zip(messages, to_take, strict=False) if tt],
412
+ )
@@ -1,3 +1,5 @@
1
+ import json
2
+ import re
1
3
  from logging import Logger
2
4
  from typing import Annotated, Awaitable, Callable
3
5
 
@@ -13,6 +15,7 @@ from unique_toolkit.agentic.reference_manager.reference_manager import Reference
13
15
  from unique_toolkit.agentic.tools.config import get_configuration_dict
14
16
  from unique_toolkit.agentic.tools.schemas import ToolCallResponse
15
17
  from unique_toolkit.app.schemas import ChatEvent
18
+ from unique_toolkit.chat.schemas import ChatMessageTool, ChatMessageToolResponse
16
19
  from unique_toolkit.language_model.default_language_model import DEFAULT_GPT_4o
17
20
  from unique_toolkit.language_model.infos import LanguageModelInfo
18
21
  from unique_toolkit.language_model.schemas import (
@@ -61,6 +64,13 @@ class HistoryManagerConfig(BaseModel):
61
64
  description="The fraction of the max input tokens that will be reserved for the history.",
62
65
  )
63
66
 
67
+ percent_for_tool_call_history: float = Field(
68
+ default=0.0,
69
+ ge=0.0,
70
+ lt=1.0,
71
+ description="The fraction of the max input tokens reserved for tool call rounds. 0 disables.",
72
+ )
73
+
64
74
  language_model: LMI = LanguageModelInfo.from_name(DEFAULT_GPT_4o)
65
75
 
66
76
  @property
@@ -70,6 +80,13 @@ class HistoryManagerConfig(BaseModel):
70
80
  * self.percent_of_max_tokens_for_history,
71
81
  )
72
82
 
83
+ @property
84
+ def max_tool_call_history_tokens(self) -> int:
85
+ return int(
86
+ self.language_model.token_limits.token_limit_input
87
+ * self.percent_for_tool_call_history,
88
+ )
89
+
73
90
  uploaded_content_config: (
74
91
  Annotated[
75
92
  UploadedContentConfig,
@@ -118,14 +135,13 @@ class HistoryManager:
118
135
  has_uploaded_content_config=bool(self._config.uploaded_content_config),
119
136
  language_model=self._language_model,
120
137
  reference_manager=reference_manager,
138
+ max_tokens_for_tool_call_history=self._config.max_tool_call_history_tokens,
121
139
  )
122
140
  self._tool_call_result_history: list[ToolCallResponse] = []
123
141
  self._tool_calls: list[LanguageModelFunction] = []
124
142
  self._loop_history: list[LanguageModelMessage] = []
125
143
  self._source_enumerator = 0
126
- self._collected_tool_response_image_urls: list[
127
- tuple[str, str]
128
- ] = [] # (url, tool_call_id)
144
+ self._collected_tool_response_image_urls: list[tuple[str, str]] = []
129
145
 
130
146
  def add_tool_call(self, tool_call: LanguageModelFunction) -> None:
131
147
  self._tool_calls.append(tool_call)
@@ -191,9 +207,7 @@ class HistoryManager:
191
207
  if tool_response.system_reminder:
192
208
  content += f"\n\n{tool_response.system_reminder}"
193
209
 
194
- # Tool message content must be string (API rejects array content for tool role).
195
- # Tool result images are attached to the user message so the model sees them. This is the only way to get the images from tool to the model as of 17.2.26.
196
-
210
+ # Append the result to the history
197
211
  return LanguageModelToolMessage(
198
212
  content=content,
199
213
  tool_call_id=tool_response.id, # type: ignore
@@ -252,3 +266,104 @@ class HistoryManager:
252
266
  LanguageModelAssistantMessage(content=assistant_message_text)
253
267
  )
254
268
  return LanguageModelMessages(history)
269
+
270
+ def extract_message_tools(self) -> list[ChatMessageTool]:
271
+ """Convert the in-memory loop history into persistable ChatMessageTool records."""
272
+ records: list[ChatMessageTool] = []
273
+ round_index = 0
274
+ i = 0
275
+ while i < len(self._loop_history):
276
+ msg = self._loop_history[i]
277
+ if isinstance(msg, LanguageModelAssistantMessage) and msg.tool_calls:
278
+ for seq_index, tc in enumerate(msg.tool_calls):
279
+ response_content = None
280
+ for j in range(i + 1, len(self._loop_history)):
281
+ candidate = self._loop_history[j]
282
+ if (
283
+ isinstance(candidate, LanguageModelToolMessage)
284
+ and candidate.tool_call_id == tc.id
285
+ ):
286
+ response_content = (
287
+ candidate.content
288
+ if isinstance(candidate.content, str)
289
+ else None
290
+ )
291
+ break
292
+
293
+ response = (
294
+ ChatMessageToolResponse(content=response_content)
295
+ if response_content is not None
296
+ else None
297
+ )
298
+ records.append(
299
+ ChatMessageTool(
300
+ external_tool_call_id=tc.id or "",
301
+ function_name=tc.function.name,
302
+ arguments=tc.function.arguments,
303
+ round_index=round_index,
304
+ sequence_index=seq_index,
305
+ response=response,
306
+ )
307
+ )
308
+ round_index += 1
309
+ i += 1
310
+ return records
311
+
312
+ @staticmethod
313
+ def compact_message_tools(
314
+ *,
315
+ records: list[ChatMessageTool],
316
+ assistant_text: str | None,
317
+ ) -> list[ChatMessageTool]:
318
+ """Strip uncited source items from tool response content before persistence."""
319
+ if not assistant_text:
320
+ return records
321
+
322
+ cited: set[int] = {
323
+ int(m)
324
+ for m in re.findall(r"\[source(\d+)\]", assistant_text, re.IGNORECASE)
325
+ }
326
+ if not cited:
327
+ return records
328
+
329
+ return [
330
+ record.model_copy(
331
+ update={
332
+ "response": record.response.model_copy(
333
+ update={
334
+ "content": _strip_uncited_sources_from_content(
335
+ record.response.content, cited
336
+ )
337
+ }
338
+ )
339
+ }
340
+ )
341
+ if record.response and record.response.content
342
+ else record
343
+ for record in records
344
+ ]
345
+
346
+
347
+ def _strip_uncited_sources_from_content(content: str, cited: set[int]) -> str:
348
+ """Filter a tool response content string to only keep cited source items.
349
+
350
+ The content is expected to be a JSON array of
351
+ ``{"source_number": N, "content": "..."}`` dicts. Items whose
352
+ ``source_number`` is not in *cited* are removed. If the content is
353
+ not in the expected JSON format it is returned unchanged.
354
+ """
355
+ try:
356
+ data = json.loads(content)
357
+ except (json.JSONDecodeError, TypeError):
358
+ return content
359
+
360
+ if not isinstance(data, list):
361
+ return content
362
+
363
+ if not data or not any(
364
+ isinstance(item, dict) and "source_number" in item for item in data
365
+ ):
366
+ return content
367
+
368
+ filtered = [item for item in data if item.get("source_number") in cited]
369
+ return json.dumps(filtered)