unique_toolkit 1.46.9__tar.gz → 1.46.11__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 (283) hide show
  1. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/CHANGELOG.md +11 -0
  2. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/PKG-INFO +12 -1
  3. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/pyproject.toml +1 -1
  4. unique_toolkit-1.46.11/unique_toolkit/_common/event_bus.py +102 -0
  5. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/tools/tool.py +1 -1
  6. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/tools/tool_manager.py +1 -0
  7. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/chat/__init__.py +2 -0
  8. unique_toolkit-1.46.11/unique_toolkit/chat/cancellation.py +176 -0
  9. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/chat/schemas.py +1 -0
  10. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/language_model/__init__.py +15 -0
  11. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/language_model/functions.py +139 -10
  12. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/language_model/reference.py +3 -1
  13. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/language_model/schemas.py +1 -0
  14. unique_toolkit-1.46.11/unique_toolkit/language_model/stream_transform.py +82 -0
  15. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/services/chat_service.py +13 -1
  16. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/LICENSE +0 -0
  17. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/README.md +0 -0
  18. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/__init__.py +0 -0
  19. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/_common/__init__.py +0 -0
  20. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/_common/_base_service.py +0 -0
  21. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/_common/_time_utils.py +0 -0
  22. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/_common/api_calling/human_verification_manager.py +0 -0
  23. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/_common/base_model_type_attribute.py +0 -0
  24. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/_common/chunk_relevancy_sorter/config.py +0 -0
  25. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/_common/chunk_relevancy_sorter/exception.py +0 -0
  26. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/_common/chunk_relevancy_sorter/schemas.py +0 -0
  27. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/_common/chunk_relevancy_sorter/service.py +0 -0
  28. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/_common/chunk_relevancy_sorter/tests/test_service.py +0 -0
  29. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/_common/config_checker/README.md +0 -0
  30. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/_common/config_checker/__init__.py +0 -0
  31. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/_common/config_checker/__main__.py +0 -0
  32. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/_common/config_checker/cli.py +0 -0
  33. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/_common/config_checker/differ.py +0 -0
  34. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/_common/config_checker/exporter.py +0 -0
  35. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/_common/config_checker/models.py +0 -0
  36. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/_common/config_checker/registry.py +0 -0
  37. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/_common/config_checker/validator.py +0 -0
  38. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/_common/default_language_model.py +0 -0
  39. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/_common/docx_generator/__init__.py +0 -0
  40. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/_common/docx_generator/config.py +0 -0
  41. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/_common/docx_generator/schemas.py +0 -0
  42. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/_common/docx_generator/service.py +0 -0
  43. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/_common/docx_generator/template/Doc Template.docx +0 -0
  44. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/_common/endpoint_builder.py +0 -0
  45. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/_common/endpoint_requestor.py +0 -0
  46. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/_common/exception.py +0 -0
  47. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/_common/execution.py +0 -0
  48. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/_common/experimental/endpoint_builder.py +0 -0
  49. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/_common/experimental/endpoint_requestor.py +0 -0
  50. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/_common/experimental/write_up_agent/README.md +0 -0
  51. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/_common/experimental/write_up_agent/__init__.py +0 -0
  52. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/_common/experimental/write_up_agent/agent.py +0 -0
  53. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/_common/experimental/write_up_agent/config.py +0 -0
  54. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/_common/experimental/write_up_agent/examples/data.csv +0 -0
  55. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/_common/experimental/write_up_agent/examples/example_usage.py +0 -0
  56. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/_common/experimental/write_up_agent/schemas.py +0 -0
  57. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/_common/experimental/write_up_agent/services/__init__.py +0 -0
  58. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/_common/experimental/write_up_agent/services/dataframe_handler/__init__.py +0 -0
  59. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/_common/experimental/write_up_agent/services/dataframe_handler/exceptions.py +0 -0
  60. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/_common/experimental/write_up_agent/services/dataframe_handler/service.py +0 -0
  61. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/_common/experimental/write_up_agent/services/dataframe_handler/utils.py +0 -0
  62. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/_common/experimental/write_up_agent/services/generation_handler/__init__.py +0 -0
  63. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/_common/experimental/write_up_agent/services/generation_handler/config.py +0 -0
  64. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/_common/experimental/write_up_agent/services/generation_handler/exceptions.py +0 -0
  65. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/_common/experimental/write_up_agent/services/generation_handler/prompts/config.py +0 -0
  66. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/_common/experimental/write_up_agent/services/generation_handler/prompts/system_prompt.j2 +0 -0
  67. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/_common/experimental/write_up_agent/services/generation_handler/prompts/user_prompt.j2 +0 -0
  68. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/_common/experimental/write_up_agent/services/generation_handler/service.py +0 -0
  69. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/_common/experimental/write_up_agent/services/template_handler/__init__.py +0 -0
  70. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/_common/experimental/write_up_agent/services/template_handler/default_template.j2 +0 -0
  71. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/_common/experimental/write_up_agent/services/template_handler/exceptions.py +0 -0
  72. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/_common/experimental/write_up_agent/services/template_handler/service.py +0 -0
  73. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/_common/experimental/write_up_agent/services/template_handler/utils.py +0 -0
  74. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/_common/experimental/write_up_agent/utils.py +0 -0
  75. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/_common/feature_flags/schema.py +0 -0
  76. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/_common/pydantic/rjsf_tags.py +0 -0
  77. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/_common/pydantic_helpers.py +0 -0
  78. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/_common/referencing.py +0 -0
  79. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/_common/string_utilities.py +0 -0
  80. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/_common/tests/test_referencing.py +0 -0
  81. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/_common/tests/test_string_utilities.py +0 -0
  82. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/_common/token/__init__.py +0 -0
  83. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/_common/token/image_token_counting.py +0 -0
  84. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/_common/token/token_counting.py +0 -0
  85. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/_common/token/tokenizers/deepseek/tokenizer.json +0 -0
  86. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/_common/token/tokenizers/qwen/tokenizer.json +0 -0
  87. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/_common/utils/__init__.py +0 -0
  88. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/_common/utils/files.py +0 -0
  89. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/_common/utils/image/encode.py +0 -0
  90. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/_common/utils/jinja/helpers.py +0 -0
  91. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/_common/utils/jinja/render.py +0 -0
  92. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/_common/utils/jinja/schema.py +0 -0
  93. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/_common/utils/jinja/utils.py +0 -0
  94. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/_common/utils/structured_output/__init__.py +0 -0
  95. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/_common/utils/structured_output/schema.py +0 -0
  96. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/_common/utils/write_configuration.py +0 -0
  97. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/_common/validate_required_values.py +0 -0
  98. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/_common/validators.py +0 -0
  99. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/__init__.py +0 -0
  100. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/debug_info_manager/debug_info_manager.py +0 -0
  101. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/debug_info_manager/test/test_debug_info_manager.py +0 -0
  102. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/evaluation/config.py +0 -0
  103. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/evaluation/context_relevancy/prompts/__init__.py +0 -0
  104. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/evaluation/context_relevancy/prompts/system_prompt.j2 +0 -0
  105. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/evaluation/context_relevancy/prompts/user_prompt.j2 +0 -0
  106. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/evaluation/context_relevancy/schema.py +0 -0
  107. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/evaluation/context_relevancy/service.py +0 -0
  108. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/evaluation/evaluation_manager.py +0 -0
  109. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/evaluation/exception.py +0 -0
  110. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/evaluation/hallucination/constants.py +0 -0
  111. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/evaluation/hallucination/hallucination_evaluation.py +0 -0
  112. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/evaluation/hallucination/prompts/__init__.py +0 -0
  113. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/evaluation/hallucination/prompts/system_prompt.j2 +0 -0
  114. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/evaluation/hallucination/prompts/user_prompt.j2 +0 -0
  115. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/evaluation/hallucination/service.py +0 -0
  116. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/evaluation/hallucination/utils.py +0 -0
  117. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/evaluation/output_parser.py +0 -0
  118. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/evaluation/schemas.py +0 -0
  119. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/evaluation/tests/fixtures.py +0 -0
  120. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/evaluation/tests/test_config.py +0 -0
  121. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/evaluation/tests/test_context_relevancy_service.py +0 -0
  122. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/evaluation/tests/test_hallucination_constants.py +0 -0
  123. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/evaluation/tests/test_hallucination_utils.py +0 -0
  124. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/evaluation/tests/test_output_parser.py +0 -0
  125. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/evaluation/tests/test_prompt_loaders.py +0 -0
  126. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/evaluation/utils.py +0 -0
  127. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/feature_flags/__init__.py +0 -0
  128. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/feature_flags/feature_flags.py +0 -0
  129. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/history_manager/history_construction_with_contents.py +0 -0
  130. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/history_manager/history_manager.py +0 -0
  131. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/history_manager/loop_token_reducer.py +0 -0
  132. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/history_manager/utils.py +0 -0
  133. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/loop_runner/__init__.py +0 -0
  134. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/loop_runner/_iteration_handler_utils.py +0 -0
  135. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/loop_runner/_responses_iteration_handler_utils.py +0 -0
  136. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/loop_runner/_responses_stream_handler_utils.py +0 -0
  137. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/loop_runner/_stream_handler_utils.py +0 -0
  138. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/loop_runner/base.py +0 -0
  139. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/loop_runner/middleware/__init__.py +0 -0
  140. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/loop_runner/middleware/planning/__init__.py +0 -0
  141. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/loop_runner/middleware/planning/planning.py +0 -0
  142. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/loop_runner/middleware/planning/schema.py +0 -0
  143. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/loop_runner/runners/__init__.py +0 -0
  144. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/loop_runner/runners/basic.py +0 -0
  145. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/loop_runner/runners/qwen/__init__.py +0 -0
  146. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/loop_runner/runners/qwen/helpers.py +0 -0
  147. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/loop_runner/runners/qwen/qwen_runner.py +0 -0
  148. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/message_log_manager/__init__.py +0 -0
  149. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/message_log_manager/service.py +0 -0
  150. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/postprocessor/postprocessor_manager.py +0 -0
  151. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/reference_manager/reference_manager.py +0 -0
  152. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/responses_api/__init__.py +0 -0
  153. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/responses_api/postprocessors/code_display.py +0 -0
  154. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/responses_api/postprocessors/generated_files.py +0 -0
  155. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/responses_api/stream_handler.py +0 -0
  156. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/short_term_memory_manager/persistent_short_term_memory_manager.py +0 -0
  157. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/thinking_manager/thinking_manager.py +0 -0
  158. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/tools/__init__.py +0 -0
  159. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/tools/a2a/__init__.py +0 -0
  160. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/tools/a2a/config.py +0 -0
  161. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/tools/a2a/evaluation/__init__.py +0 -0
  162. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/tools/a2a/evaluation/_utils.py +0 -0
  163. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/tools/a2a/evaluation/config.py +0 -0
  164. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/tools/a2a/evaluation/evaluator.py +0 -0
  165. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/tools/a2a/evaluation/summarization_user_message.j2 +0 -0
  166. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/tools/a2a/manager.py +0 -0
  167. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/tools/a2a/postprocessing/__init__.py +0 -0
  168. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/tools/a2a/postprocessing/_display_utils.py +0 -0
  169. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/tools/a2a/postprocessing/_ref_utils.py +0 -0
  170. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/tools/a2a/postprocessing/config.py +0 -0
  171. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/tools/a2a/postprocessing/display.py +0 -0
  172. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/tools/a2a/postprocessing/references.py +0 -0
  173. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/tools/a2a/postprocessing/test/test_display.py +0 -0
  174. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/tools/a2a/postprocessing/test/test_display_utils.py +0 -0
  175. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/tools/a2a/postprocessing/test/test_ref_utils.py +0 -0
  176. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/tools/a2a/prompts.py +0 -0
  177. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/tools/a2a/response_watcher/__init__.py +0 -0
  178. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/tools/a2a/response_watcher/service.py +0 -0
  179. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/tools/a2a/tool/__init__.py +0 -0
  180. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/tools/a2a/tool/_memory.py +0 -0
  181. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/tools/a2a/tool/_schema.py +0 -0
  182. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/tools/a2a/tool/config.py +0 -0
  183. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/tools/a2a/tool/service.py +0 -0
  184. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/tools/a2a/tool/test/test_service_utils.py +0 -0
  185. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/tools/agent_chunks_hanlder.py +0 -0
  186. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/tools/config.py +0 -0
  187. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/tools/factory.py +0 -0
  188. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/tools/mcp/__init__.py +0 -0
  189. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/tools/mcp/manager.py +0 -0
  190. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/tools/mcp/models.py +0 -0
  191. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/tools/mcp/tool_wrapper.py +0 -0
  192. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/tools/openai_builtin/__init__.py +0 -0
  193. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/tools/openai_builtin/base.py +0 -0
  194. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/tools/openai_builtin/code_interpreter/__init__.py +0 -0
  195. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/tools/openai_builtin/code_interpreter/config.py +0 -0
  196. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/tools/openai_builtin/code_interpreter/service.py +0 -0
  197. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/tools/openai_builtin/manager.py +0 -0
  198. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/tools/schemas.py +0 -0
  199. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/tools/test/test_mcp_manager.py +0 -0
  200. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/tools/test/test_tool_progress_reporter.py +0 -0
  201. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/tools/tool_progress_reporter.py +0 -0
  202. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/tools/utils/__init__.py +0 -0
  203. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/tools/utils/source_handling/__init__.py +0 -0
  204. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/tools/utils/source_handling/schema.py +0 -0
  205. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/tools/utils/source_handling/source_formatting.py +0 -0
  206. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic/tools/utils/source_handling/tests/test_source_formatting.py +0 -0
  207. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic_table/__init__.py +0 -0
  208. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic_table/schemas.py +0 -0
  209. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/agentic_table/service.py +0 -0
  210. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/app/__init__.py +0 -0
  211. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/app/dev_util.py +0 -0
  212. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/app/fast_api_factory.py +0 -0
  213. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/app/init_logging.py +0 -0
  214. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/app/init_sdk.py +0 -0
  215. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/app/performance/async_tasks.py +0 -0
  216. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/app/performance/async_wrapper.py +0 -0
  217. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/app/schemas.py +0 -0
  218. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/app/unique_settings.py +0 -0
  219. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/app/verification.py +0 -0
  220. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/app/webhook.py +0 -0
  221. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/chat/constants.py +0 -0
  222. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/chat/deprecated/service.py +0 -0
  223. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/chat/functions.py +0 -0
  224. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/chat/rendering.py +0 -0
  225. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/chat/responses_api.py +0 -0
  226. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/chat/service.py +0 -0
  227. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/chat/state.py +0 -0
  228. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/chat/utils.py +0 -0
  229. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/content/__init__.py +0 -0
  230. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/content/constants.py +0 -0
  231. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/content/functions.py +0 -0
  232. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/content/schemas.py +0 -0
  233. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/content/service.py +0 -0
  234. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/content/smart_rules.py +0 -0
  235. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/content/utils.py +0 -0
  236. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/data_extraction/README.md +0 -0
  237. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/data_extraction/__init__.py +0 -0
  238. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/data_extraction/augmented/__init__.py +0 -0
  239. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/data_extraction/augmented/service.py +0 -0
  240. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/data_extraction/base.py +0 -0
  241. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/data_extraction/basic/__init__.py +0 -0
  242. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/data_extraction/basic/config.py +0 -0
  243. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/data_extraction/basic/prompt.py +0 -0
  244. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/data_extraction/basic/service.py +0 -0
  245. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/elicitation/__init__.py +0 -0
  246. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/elicitation/constants.py +0 -0
  247. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/elicitation/exceptions.py +0 -0
  248. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/elicitation/functions.py +0 -0
  249. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/elicitation/schemas.py +0 -0
  250. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/elicitation/service.py +0 -0
  251. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/embedding/__init__.py +0 -0
  252. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/embedding/constants.py +0 -0
  253. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/embedding/functions.py +0 -0
  254. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/embedding/schemas.py +0 -0
  255. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/embedding/service.py +0 -0
  256. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/embedding/utils.py +0 -0
  257. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/framework_utilities/__init__.py +0 -0
  258. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/framework_utilities/langchain/__init__.py +0 -0
  259. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/framework_utilities/langchain/client.py +0 -0
  260. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/framework_utilities/langchain/history.py +0 -0
  261. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/framework_utilities/openai/__init__.py +0 -0
  262. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/framework_utilities/openai/client.py +0 -0
  263. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/framework_utilities/openai/message_builder.py +0 -0
  264. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/framework_utilities/utils.py +0 -0
  265. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/language_model/_responses_api_utils.py +0 -0
  266. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/language_model/builder.py +0 -0
  267. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/language_model/constants.py +0 -0
  268. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/language_model/default_language_model.py +0 -0
  269. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/language_model/infos.py +0 -0
  270. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/language_model/prompt.py +0 -0
  271. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/language_model/service.py +0 -0
  272. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/language_model/utils.py +0 -0
  273. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/protocols/support.py +0 -0
  274. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/services/__init__.py +0 -0
  275. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/services/knowledge_base.py +0 -0
  276. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/short_term_memory/__init__.py +0 -0
  277. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/short_term_memory/constants.py +0 -0
  278. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/short_term_memory/functions.py +0 -0
  279. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/short_term_memory/schemas.py +0 -0
  280. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/short_term_memory/service.py +0 -0
  281. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/smart_rules/__init__.py +0 -0
  282. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/smart_rules/compile.py +0 -0
  283. {unique_toolkit-1.46.9 → unique_toolkit-1.46.11}/unique_toolkit/test_utilities/events.py +0 -0
@@ -5,6 +5,17 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [1.46.11] - 2026-02-20
9
+ - Add OpenAI-proxy direct streaming with Python-side reference injection (UN-17264)
10
+ - Add `stream_complete_with_references_openai()` using async OpenAI client and `chat.completions.stream()`
11
+ - Add stream transformation pipeline: `StreamTransform` protocol, `TextTransformPipeline`, `ReferenceInjectionTransform` (reuses `add_references_to_message`), `NormalizationTransform` placeholder
12
+ - Export `stream_complete_with_references_openai` and stream transform types from `unique_toolkit.language_model`
13
+
14
+ ## [1.46.10] - 2026-02-19
15
+ - Add flag-based cancellation support via `CancellationWatcher` and `TypedEventBus`
16
+ - Expose `ChatService.cancellation` property for polling, event subscription, and `run_with_cancellation` helper
17
+ - Add `CancellationEvent`, `cancelled_at` on `ChatMessage`, and `stopped_by_user` on `LanguageModelStreamResponse`
18
+
8
19
  ## [1.46.9] - 2026-02-19
9
20
  - Add `litellm:anthropic-claude-sonnet-4-6` to `info.py`
10
21
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: unique_toolkit
3
- Version: 1.46.9
3
+ Version: 1.46.11
4
4
  Summary:
5
5
  License: Proprietary
6
6
  Author: Cedric Klinkert
@@ -127,6 +127,17 @@ All notable changes to this project will be documented in this file.
127
127
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
128
128
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
129
129
 
130
+ ## [1.46.11] - 2026-02-20
131
+ - Add OpenAI-proxy direct streaming with Python-side reference injection (UN-17264)
132
+ - Add `stream_complete_with_references_openai()` using async OpenAI client and `chat.completions.stream()`
133
+ - Add stream transformation pipeline: `StreamTransform` protocol, `TextTransformPipeline`, `ReferenceInjectionTransform` (reuses `add_references_to_message`), `NormalizationTransform` placeholder
134
+ - Export `stream_complete_with_references_openai` and stream transform types from `unique_toolkit.language_model`
135
+
136
+ ## [1.46.10] - 2026-02-19
137
+ - Add flag-based cancellation support via `CancellationWatcher` and `TypedEventBus`
138
+ - Expose `ChatService.cancellation` property for polling, event subscription, and `run_with_cancellation` helper
139
+ - Add `CancellationEvent`, `cancelled_at` on `ChatMessage`, and `stopped_by_user` on `LanguageModelStreamResponse`
140
+
130
141
  ## [1.46.9] - 2026-02-19
131
142
  - Add `litellm:anthropic-claude-sonnet-4-6` to `info.py`
132
143
 
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "unique_toolkit"
3
- version = "1.46.9"
3
+ version = "1.46.11"
4
4
  description = ""
5
5
  authors = [
6
6
  "Cedric Klinkert <cedric.klinkert@unique.ch>",
@@ -0,0 +1,102 @@
1
+ from __future__ import annotations
2
+
3
+ import asyncio
4
+ import logging
5
+ from dataclasses import dataclass
6
+ from typing import Any, Awaitable, Callable, Generic, Protocol, TypeVar, Union
7
+
8
+ logger = logging.getLogger(__name__)
9
+
10
+ T = TypeVar("T")
11
+
12
+ AsyncHandler = Callable[[T], Awaitable[None]]
13
+ SyncHandler = Callable[[T], None]
14
+ Handler = Union[AsyncHandler[T], SyncHandler[T]]
15
+
16
+
17
+ class Subscription(Protocol):
18
+ """Handle returned by ``subscribe`` that allows unsubscribing."""
19
+
20
+ def cancel(self) -> None: ...
21
+
22
+
23
+ @dataclass(slots=True)
24
+ class _ListSubscription:
25
+ _cancel: Callable[[], None]
26
+ _active: bool = True
27
+
28
+ def cancel(self) -> None:
29
+ if not self._active:
30
+ return
31
+ self._active = False
32
+ self._cancel()
33
+
34
+
35
+ class TypedEventBus(Generic[T]):
36
+ """In-process, asyncio-friendly, typed pub/sub.
37
+
38
+ * ``subscribe(handler)`` — returns a :class:`Subscription`
39
+ * ``publish_and_wait(event)`` — synchronous: calls handlers directly,
40
+ schedules async handlers as tasks when a loop is running
41
+ * ``publish_and_forget_async(event)`` — fire-and-forget (schedules tasks)
42
+ * ``publish_and_wait_async(event)`` — awaits all handlers
43
+ """
44
+
45
+ __slots__ = ("_handlers",)
46
+
47
+ def __init__(self) -> None:
48
+ self._handlers: list[Handler[T]] = []
49
+
50
+ def subscribe(self, handler: Handler[T]) -> Subscription:
51
+ self._handlers.append(handler)
52
+
53
+ def _remove() -> None:
54
+ try:
55
+ self._handlers.remove(handler)
56
+ except ValueError:
57
+ pass
58
+
59
+ return _ListSubscription(_cancel=_remove)
60
+
61
+ async def _invoke(self, handler: Handler[T], event: T) -> None:
62
+ result: Any = handler(event)
63
+ if asyncio.iscoroutine(result):
64
+ await result
65
+
66
+ def publish_and_wait(self, event: T) -> None:
67
+ """Synchronous publish: call each handler directly.
68
+
69
+ Sync handlers are invoked inline. Async handlers are scheduled
70
+ as fire-and-forget tasks when a running event loop is detected;
71
+ otherwise they are skipped with a warning.
72
+ """
73
+ loop: asyncio.AbstractEventLoop | None = None
74
+ try:
75
+ loop = asyncio.get_running_loop()
76
+ except RuntimeError:
77
+ pass
78
+
79
+ for handler in list(self._handlers):
80
+ result: Any = handler(event)
81
+ if asyncio.iscoroutine(result):
82
+ if loop is not None:
83
+ loop.create_task(result)
84
+ else:
85
+ result.close()
86
+ logger.warning(
87
+ "Skipping async handler %r — no running event loop",
88
+ handler,
89
+ )
90
+
91
+ def publish_and_forget_async(self, event: T) -> list[asyncio.Task[None]]:
92
+ """Fire-and-forget: schedule each handler as a background task."""
93
+ loop = asyncio.get_running_loop()
94
+ return [loop.create_task(self._invoke(h, event)) for h in list(self._handlers)]
95
+
96
+ async def publish_and_wait_async(
97
+ self, event: T, *, return_exceptions: bool = False
98
+ ) -> None:
99
+ """Invoke every handler and await completion."""
100
+ coros = [self._invoke(h, event) for h in list(self._handlers)]
101
+ if coros:
102
+ await asyncio.gather(*coros, return_exceptions=return_exceptions)
@@ -52,7 +52,7 @@ class Tool(ABC, Generic[ConfigType]):
52
52
  """Whether the tool is enabled or not."""
53
53
  return self.settings.is_enabled
54
54
 
55
- def takes_control(self):
55
+ def takes_control(self) -> bool:
56
56
  """
57
57
  Some tools require to take control of the conversation with the user and do not want the orchestrator to intervene.
58
58
  this function indicates whether the tool takes control or not. It yanks the control away from the orchestrator.
@@ -255,6 +255,7 @@ class _ToolManager(Generic[_ApiMode]):
255
255
 
256
256
  # Wait until all tasks are finished
257
257
  tool_call_results = await asyncio.gather(*tasks)
258
+
258
259
  tool_call_results_unpacked: list[ToolCallResponse] = []
259
260
  for i, result in enumerate(tool_call_results):
260
261
  unpacked_tool_call_result = self._create_tool_call_response(
@@ -1,5 +1,7 @@
1
1
  import warnings
2
2
 
3
+ from .cancellation import CancellationEvent as CancellationEvent
4
+ from .cancellation import CancellationWatcher as CancellationWatcher
3
5
  from .constants import DOMAIN_NAME as DOMAIN_NAME
4
6
  from .schemas import ChatMessage as ChatMessage
5
7
  from .schemas import ChatMessageAssessment as ChatMessageAssessment
@@ -0,0 +1,176 @@
1
+ """Cancellation detection and notification for chat agent executions."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import asyncio
6
+ import logging
7
+ from dataclasses import dataclass
8
+ from typing import Any, Coroutine, TypeVar, overload
9
+
10
+ import unique_sdk
11
+
12
+ from unique_toolkit._common.event_bus import TypedEventBus
13
+
14
+
15
+ @dataclass(frozen=True, slots=True)
16
+ class CancellationEvent:
17
+ """Published on the cancellation event bus when a user abort is detected."""
18
+
19
+ message_id: str
20
+
21
+
22
+ T = TypeVar("T")
23
+
24
+ logger = logging.getLogger(__name__)
25
+
26
+
27
+ class CancellationWatcher:
28
+ """Polls the database for ``cancelledAt`` and publishes to an event bus.
29
+
30
+ The watcher never raises exceptions for cancellation. Instead it:
31
+ - publishes a :class:`CancellationEvent` on the bus
32
+ - sets :attr:`is_cancelled` to ``True``
33
+
34
+ Callers inspect :attr:`is_cancelled` to decide whether to stop.
35
+ """
36
+
37
+ def __init__(
38
+ self,
39
+ *,
40
+ user_id: str,
41
+ company_id: str,
42
+ chat_id: str,
43
+ assistant_message_id: str,
44
+ ) -> None:
45
+ self._bus: TypedEventBus[CancellationEvent] = TypedEventBus()
46
+ self._user_id = user_id
47
+ self._company_id = company_id
48
+ self._chat_id = chat_id
49
+ self._assistant_message_id = assistant_message_id
50
+ self._cancelled = False
51
+
52
+ @property
53
+ def is_cancelled(self) -> bool:
54
+ return self._cancelled
55
+
56
+ @property
57
+ def on_cancellation(self) -> TypedEventBus[CancellationEvent]:
58
+ return self._bus
59
+
60
+ async def check_cancellation_async(self) -> bool:
61
+ """Poll the DB once. Returns ``True`` if the message was cancelled.
62
+
63
+ When cancellation is detected for the first time, all subscribers
64
+ on the bus are notified (awaited) before this method returns.
65
+ """
66
+ if self._cancelled:
67
+ return True
68
+ try:
69
+ raw_msg = await unique_sdk.Message.retrieve_async(
70
+ user_id=self._user_id,
71
+ company_id=self._company_id,
72
+ id=self._assistant_message_id,
73
+ chatId=self._chat_id,
74
+ )
75
+ cancelled_at = getattr(raw_msg, "cancelledAt", None)
76
+ if cancelled_at is not None:
77
+ self._cancelled = True
78
+ event = CancellationEvent(message_id=self._assistant_message_id)
79
+ await self._bus.publish_and_wait_async(event)
80
+ return True
81
+ except Exception as exc:
82
+ logger.warning(
83
+ "Failed to check cancellation: %s: %s", type(exc).__name__, exc
84
+ )
85
+ return False
86
+
87
+ def check_cancellation(self) -> bool:
88
+ """Synchronous single-shot check.
89
+
90
+ Returns ``True`` if the message was cancelled. Subscribers are
91
+ notified via :meth:`TypedEventBus.publish_and_wait` (sync handlers
92
+ are called inline; async handlers are scheduled as tasks when a
93
+ running event loop is detected).
94
+ """
95
+ if self._cancelled:
96
+ return True
97
+ try:
98
+ raw_msg = unique_sdk.Message.retrieve(
99
+ user_id=self._user_id,
100
+ company_id=self._company_id,
101
+ id=self._assistant_message_id,
102
+ chatId=self._chat_id,
103
+ )
104
+ cancelled_at = getattr(raw_msg, "cancelledAt", None)
105
+ if cancelled_at is not None:
106
+ self._cancelled = True
107
+ event = CancellationEvent(message_id=self._assistant_message_id)
108
+ self._bus.publish_and_wait(event)
109
+ return True
110
+ except Exception as exc:
111
+ logger.warning(
112
+ "Failed to check cancellation: %s: %s", type(exc).__name__, exc
113
+ )
114
+ return False
115
+
116
+ @overload
117
+ async def run_with_cancellation(
118
+ self,
119
+ coroutine: Coroutine[Any, Any, T],
120
+ *,
121
+ poll_interval: float = ...,
122
+ cancel_result: T,
123
+ ) -> T: ...
124
+
125
+ @overload
126
+ async def run_with_cancellation(
127
+ self,
128
+ coroutine: Coroutine[Any, Any, T],
129
+ *,
130
+ poll_interval: float = ...,
131
+ ) -> T | None: ...
132
+
133
+ async def run_with_cancellation(
134
+ self,
135
+ coroutine: Coroutine[Any, Any, Any],
136
+ *,
137
+ poll_interval: float = 2.0,
138
+ cancel_result: Any = None,
139
+ ) -> Any:
140
+ """Run *coroutine* while polling for cancellation in the background.
141
+
142
+ When cancelled, subscribers are notified via the bus and
143
+ :attr:`is_cancelled` is set to ``True``.
144
+
145
+ Args:
146
+ coroutine: The async coroutine to execute.
147
+ poll_interval: How often (in seconds) to poll for cancellation.
148
+ cancel_result: Value to return when cancelled. When provided
149
+ the return type matches the coroutine's return type so
150
+ callers don't need a ``None`` check.
151
+
152
+ Returns:
153
+ The coroutine's result on success, or *cancel_result* if
154
+ cancelled (defaults to ``None``).
155
+ """
156
+ task = asyncio.create_task(coroutine)
157
+
158
+ async def _watcher() -> None:
159
+ while not task.done():
160
+ cancelled = await self.check_cancellation_async()
161
+ if cancelled:
162
+ task.cancel()
163
+ return
164
+ await asyncio.sleep(poll_interval)
165
+
166
+ watcher = asyncio.create_task(_watcher())
167
+ try:
168
+ return await task
169
+ except asyncio.CancelledError:
170
+ return cancel_result
171
+ finally:
172
+ watcher.cancel()
173
+ try:
174
+ await watcher
175
+ except asyncio.CancelledError:
176
+ pass
@@ -83,6 +83,7 @@ class ChatMessage(BaseModel):
83
83
  debug_info: dict | None = {}
84
84
  created_at: datetime | None = None
85
85
  completed_at: datetime | None = None
86
+ cancelled_at: datetime | None = None
86
87
  updated_at: datetime | None = None
87
88
  references: list[ContentReference] | None = None
88
89
 
@@ -5,6 +5,9 @@ from .default_language_model import (
5
5
  from .default_language_model import (
6
6
  DEFAULT_GPT_4o as DEFAULT_GPT_4o,
7
7
  )
8
+ from .functions import (
9
+ stream_complete_with_references_openai as stream_complete_with_references_openai,
10
+ )
8
11
  from .infos import LanguageModel as LanguageModel
9
12
  from .infos import LanguageModelName as LanguageModelName
10
13
  from .prompt import (
@@ -67,6 +70,18 @@ from .schemas import (
67
70
  from .service import (
68
71
  LanguageModelService as LanguageModelService,
69
72
  )
73
+ from .stream_transform import (
74
+ NormalizationTransform as NormalizationTransform,
75
+ )
76
+ from .stream_transform import (
77
+ ReferenceInjectionTransform as ReferenceInjectionTransform,
78
+ )
79
+ from .stream_transform import (
80
+ StreamTransform as StreamTransform,
81
+ )
82
+ from .stream_transform import (
83
+ TextTransformPipeline as TextTransformPipeline,
84
+ )
70
85
  from .utils import (
71
86
  convert_string_to_json as convert_string_to_json,
72
87
  )
@@ -2,7 +2,11 @@ import copy
2
2
  import logging
3
3
  import warnings
4
4
  from datetime import UTC, datetime
5
- from typing import Any, Sequence, cast
5
+ from typing import TYPE_CHECKING, Any, Sequence, cast
6
+ from uuid import uuid4
7
+
8
+ if TYPE_CHECKING:
9
+ from unique_toolkit.app.unique_settings import UniqueSettings
6
10
 
7
11
  import humps
8
12
  import unique_sdk
@@ -12,15 +16,6 @@ from pydantic import BaseModel
12
16
 
13
17
  from unique_toolkit.chat.schemas import ChatMessage, ChatMessageRole
14
18
  from unique_toolkit.content.schemas import ContentChunk, ContentReference
15
- from unique_toolkit.language_model import (
16
- LanguageModelMessageRole,
17
- LanguageModelMessages,
18
- LanguageModelResponse,
19
- LanguageModelStreamResponse,
20
- LanguageModelStreamResponseMessage,
21
- LanguageModelTool,
22
- LanguageModelToolDescription,
23
- )
24
19
  from unique_toolkit.language_model.infos import (
25
20
  LanguageModelInfo,
26
21
  LanguageModelName,
@@ -29,6 +24,16 @@ from unique_toolkit.language_model.infos import (
29
24
  from unique_toolkit.language_model.reference import (
30
25
  add_references_to_message,
31
26
  )
27
+ from unique_toolkit.language_model.schemas import (
28
+ LanguageModelFunction,
29
+ LanguageModelMessageRole,
30
+ LanguageModelMessages,
31
+ LanguageModelResponse,
32
+ LanguageModelStreamResponse,
33
+ LanguageModelStreamResponseMessage,
34
+ LanguageModelTool,
35
+ LanguageModelToolDescription,
36
+ )
32
37
 
33
38
  from .constants import (
34
39
  DEFAULT_COMPLETE_TEMPERATURE,
@@ -541,3 +546,127 @@ def _create_language_model_stream_response_with_references(
541
546
  message=stream_response_message,
542
547
  tool_calls=tool_calls,
543
548
  )
549
+
550
+
551
+ async def stream_complete_with_references_openai(
552
+ messages: list[ChatCompletionMessageParam] | LanguageModelMessages,
553
+ model_name: LanguageModelName | str,
554
+ content_chunks: list[ContentChunk] | None = None,
555
+ temperature: float = DEFAULT_COMPLETE_TEMPERATURE,
556
+ start_text: str | None = None,
557
+ tools: Sequence[LanguageModelTool | LanguageModelToolDescription] | None = None,
558
+ tool_choice: ChatCompletionToolChoiceOptionParam | None = None,
559
+ unique_settings: "UniqueSettings | None" = None, # noqa: F821
560
+ message_id: str | None = None,
561
+ ) -> LanguageModelStreamResponse:
562
+ """Stream a chat completion via the OpenAI proxy, apply reference injection, and return a LanguageModelStreamResponse."""
563
+ from unique_toolkit.framework_utilities.openai.client import (
564
+ get_async_openai_client,
565
+ )
566
+ from unique_toolkit.language_model.stream_transform import (
567
+ ReferenceInjectionTransform,
568
+ TextTransformPipeline,
569
+ )
570
+
571
+ # prepare variables
572
+ client = get_async_openai_client(unique_settings=unique_settings)
573
+ model_name_: str = (
574
+ model_name.value if isinstance(model_name, LanguageModelName) else model_name
575
+ )
576
+ messages_: list[ChatCompletionMessageParam] = (
577
+ messages.model_dump(
578
+ exclude_none=True,
579
+ by_alias=False,
580
+ )
581
+ if isinstance(messages, LanguageModelMessages)
582
+ else list(messages)
583
+ )
584
+ tools_ = (
585
+ []
586
+ if tools is None
587
+ else [
588
+ tool.to_openai(mode="completions")
589
+ if isinstance(tool, LanguageModelToolDescription)
590
+ else {"type": "function", "function": tool.model_dump(exclude_none=True)}
591
+ for tool in tools
592
+ ]
593
+ )
594
+
595
+ # pipeline
596
+ pipeline = TextTransformPipeline()
597
+ # pipeline.add(NormalizationTransform()) # no-op for now
598
+ pipeline.add(
599
+ ReferenceInjectionTransform(
600
+ content_chunks=content_chunks or [], model=model_name_
601
+ )
602
+ )
603
+
604
+ stream_kwargs: dict[str, Any] = {
605
+ "messages": messages_,
606
+ "model": model_name_,
607
+ "temperature": temperature,
608
+ "stream": True,
609
+ }
610
+ if tool_choice is not None:
611
+ stream_kwargs["tool_choice"] = tool_choice
612
+ if tools_:
613
+ stream_kwargs["tools"] = tools_
614
+
615
+ full_text: str = start_text or ""
616
+ tool_calls_fragments: dict[int, dict[str, Any]] = {}
617
+ try:
618
+ stream = await client.chat.completions.create(**stream_kwargs)
619
+ async with stream:
620
+ async for chunk in stream:
621
+ if not chunk.choices:
622
+ continue
623
+ choice_ = chunk.choices[0]
624
+ # text
625
+ delta_ = choice_.delta
626
+ if delta_.content is not None:
627
+ full_text += delta_.content
628
+ pipeline.feed_delta(delta_.content) # does nothing right now
629
+ # tools
630
+ for tool_call in delta_.tool_calls or []:
631
+ idx_ = tool_call.index
632
+ if idx_ not in tool_calls_fragments.keys():
633
+ tool_calls_fragments[idx_] = {
634
+ "id": tool_call.id or "",
635
+ "name": "",
636
+ "arguments": "",
637
+ }
638
+ if tool_call.function is not None:
639
+ tool_calls_fragments[idx_]["name"] += (
640
+ tool_call.function.name or ""
641
+ )
642
+ tool_calls_fragments[idx_]["arguments"] += (
643
+ tool_call.function.arguments or ""
644
+ )
645
+ # run on full text
646
+ text_, references_ = pipeline.run(full_text)
647
+ # construct tool calls
648
+ tool_calls_list = None
649
+ if len(tool_calls_fragments) > 0:
650
+ tool_calls_list = [
651
+ LanguageModelFunction(
652
+ id=tool_call["id"],
653
+ name=tool_call["name"],
654
+ arguments=tool_call["arguments"] or None,
655
+ )
656
+ for tool_call in tool_calls_fragments.values()
657
+ ]
658
+
659
+ return LanguageModelStreamResponse(
660
+ message=LanguageModelStreamResponseMessage(
661
+ id=message_id or uuid4().hex,
662
+ previous_message_id=None,
663
+ role=LanguageModelMessageRole.ASSISTANT,
664
+ text=text_,
665
+ original_text=full_text,
666
+ references=references_,
667
+ ),
668
+ tool_calls=tool_calls_list,
669
+ )
670
+ except Exception as e:
671
+ logger.error("Error streaming completion (model=%s): %s", model_name_, e)
672
+ raise
@@ -53,7 +53,9 @@ def _add_references(
53
53
 
54
54
  # Gemini 2.5 models have tendency to add multiple references for the same fact
55
55
  # This is a workaround to limit the number of references to 5
56
- if model and model.startswith("litellm:gemini-2-5"):
56
+ if model and model.startswith(
57
+ "litellm:gemini-2-5"
58
+ ): # TODO - check if this holds also for other models
57
59
  reduced_text = _limit_consecutive_source_references(with_footnotes)
58
60
 
59
61
  # Get the references that remain after reduction
@@ -168,6 +168,7 @@ class LanguageModelStreamResponse(BaseModel):
168
168
 
169
169
  message: LanguageModelStreamResponseMessage
170
170
  tool_calls: list[LanguageModelFunction] | None = None
171
+ stopped_by_user: bool = False
171
172
 
172
173
  def is_empty(self) -> bool:
173
174
  """
@@ -0,0 +1,82 @@
1
+ from datetime import UTC, datetime
2
+ from typing import Protocol, runtime_checkable
3
+
4
+ from unique_toolkit.chat.schemas import ChatMessage, ChatMessageRole
5
+ from unique_toolkit.content.schemas import ContentChunk, ContentReference
6
+ from unique_toolkit.language_model.reference import add_references_to_message
7
+
8
+
9
+ @runtime_checkable
10
+ class StreamTransform(Protocol):
11
+ def process_delta(self, delta: str) -> None: ...
12
+
13
+ def finalize(self, text: str) -> tuple[str, list[ContentReference]]: ...
14
+
15
+
16
+ class ReferenceInjectionTransform:
17
+ """Transform to inject references into the text of a message."""
18
+
19
+ def __init__(self, content_chunks: list[ContentChunk], model: str | None = None):
20
+ self._content_chunks = content_chunks
21
+ self._model = (
22
+ model # needed e.g. for gemini-2.5 models to limit the number of references
23
+ )
24
+
25
+ def process_delta(self, delta: str) -> None:
26
+ pass # cannot manipulate delta right now, as it is a stream
27
+
28
+ def finalize(self, text: str) -> tuple[str, list[ContentReference]]:
29
+ message = ChatMessage(
30
+ id="irrelevant",
31
+ text=text,
32
+ role=ChatMessageRole.ASSISTANT,
33
+ created_at=datetime.now(UTC),
34
+ chat_id="irrelevant",
35
+ )
36
+
37
+ updated_message, __ = add_references_to_message(
38
+ message=message,
39
+ search_context=self._content_chunks,
40
+ model=self._model,
41
+ )
42
+
43
+ references: list[ContentReference] = [
44
+ ContentReference(**u.model_dump()) for u in updated_message.references or []
45
+ ]
46
+ return updated_message.content or "", references
47
+
48
+
49
+ class NormalizationTransform:
50
+ """Transform to normalize the text of a message.
51
+ E.g. remove extra whitespace, convert to lowercase, etc.
52
+ For now, this is a no-op. Only trim trailing whitespace.
53
+ """
54
+
55
+ def process_delta(self, delta: str) -> None:
56
+ pass
57
+
58
+ def finalize(self, text: str) -> tuple[str, list[ContentReference]]:
59
+ return text.strip(), []
60
+
61
+
62
+ class TextTransformPipeline:
63
+ """Pipeline of text transforms to be applied to a stream of text."""
64
+
65
+ def __init__(self):
66
+ self._transforms: list[StreamTransform] = []
67
+
68
+ def add(self, transform: StreamTransform) -> "TextTransformPipeline":
69
+ self._transforms.append(transform)
70
+ return self
71
+
72
+ def feed_delta(self, delta: str) -> None:
73
+ for transform in self._transforms:
74
+ transform.process_delta(delta)
75
+
76
+ def run(self, text: str) -> tuple[str, list[ContentReference]]:
77
+ refs_: list[ContentReference] = []
78
+ text_: str = text
79
+ for transform in self._transforms:
80
+ text_, new_refs = transform.finalize(text_)
81
+ refs_.extend(new_refs)
82
+ return text_, refs_