unique_toolkit 1.58__tar.gz → 1.59.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 (288) hide show
  1. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/PKG-INFO +1 -1
  2. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/pyproject.toml +1 -1
  3. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/tools/openai_builtin/code_interpreter/postprocessors/generated_files.py +72 -1
  4. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/app/unique_settings.py +177 -54
  5. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/README.md +0 -0
  6. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/__init__.py +0 -0
  7. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/_common/__init__.py +0 -0
  8. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/_common/_base_service.py +0 -0
  9. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/_common/_time_utils.py +0 -0
  10. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/_common/api_calling/human_verification_manager.py +0 -0
  11. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/_common/base_model_type_attribute.py +0 -0
  12. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/_common/chunk_relevancy_sorter/config.py +0 -0
  13. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/_common/chunk_relevancy_sorter/exception.py +0 -0
  14. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/_common/chunk_relevancy_sorter/schemas.py +0 -0
  15. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/_common/chunk_relevancy_sorter/service.py +0 -0
  16. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/_common/chunk_relevancy_sorter/tests/test_service.py +0 -0
  17. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/_common/config_checker/README.md +0 -0
  18. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/_common/config_checker/__init__.py +0 -0
  19. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/_common/config_checker/__main__.py +0 -0
  20. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/_common/config_checker/cli.py +0 -0
  21. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/_common/config_checker/differ.py +0 -0
  22. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/_common/config_checker/exporter.py +0 -0
  23. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/_common/config_checker/models.py +0 -0
  24. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/_common/config_checker/registry.py +0 -0
  25. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/_common/config_checker/validator.py +0 -0
  26. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/_common/default_language_model.py +0 -0
  27. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/_common/docx_generator/__init__.py +0 -0
  28. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/_common/docx_generator/config.py +0 -0
  29. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/_common/docx_generator/pandoc_converter.py +0 -0
  30. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/_common/docx_generator/schemas.py +0 -0
  31. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/_common/docx_generator/service.py +0 -0
  32. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/_common/docx_generator/template/Doc Template.docx +0 -0
  33. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/_common/endpoint_builder.py +0 -0
  34. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/_common/endpoint_requestor.py +0 -0
  35. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/_common/event_bus.py +0 -0
  36. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/_common/exception.py +0 -0
  37. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/_common/execution.py +0 -0
  38. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/_common/experimental/endpoint_builder.py +0 -0
  39. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/_common/experimental/endpoint_requestor.py +0 -0
  40. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/_common/experimental/write_up_agent/README.md +0 -0
  41. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/_common/experimental/write_up_agent/__init__.py +0 -0
  42. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/_common/experimental/write_up_agent/agent.py +0 -0
  43. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/_common/experimental/write_up_agent/config.py +0 -0
  44. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/_common/experimental/write_up_agent/examples/data.csv +0 -0
  45. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/_common/experimental/write_up_agent/examples/example_usage.py +0 -0
  46. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/_common/experimental/write_up_agent/schemas.py +0 -0
  47. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/_common/experimental/write_up_agent/services/__init__.py +0 -0
  48. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/_common/experimental/write_up_agent/services/dataframe_handler/__init__.py +0 -0
  49. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/_common/experimental/write_up_agent/services/dataframe_handler/exceptions.py +0 -0
  50. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/_common/experimental/write_up_agent/services/dataframe_handler/service.py +0 -0
  51. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/_common/experimental/write_up_agent/services/dataframe_handler/utils.py +0 -0
  52. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/_common/experimental/write_up_agent/services/generation_handler/__init__.py +0 -0
  53. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/_common/experimental/write_up_agent/services/generation_handler/config.py +0 -0
  54. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/_common/experimental/write_up_agent/services/generation_handler/exceptions.py +0 -0
  55. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/_common/experimental/write_up_agent/services/generation_handler/prompts/config.py +0 -0
  56. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/_common/experimental/write_up_agent/services/generation_handler/prompts/system_prompt.j2 +0 -0
  57. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/_common/experimental/write_up_agent/services/generation_handler/prompts/user_prompt.j2 +0 -0
  58. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/_common/experimental/write_up_agent/services/generation_handler/service.py +0 -0
  59. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/_common/experimental/write_up_agent/services/template_handler/__init__.py +0 -0
  60. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/_common/experimental/write_up_agent/services/template_handler/default_template.j2 +0 -0
  61. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/_common/experimental/write_up_agent/services/template_handler/exceptions.py +0 -0
  62. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/_common/experimental/write_up_agent/services/template_handler/service.py +0 -0
  63. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/_common/experimental/write_up_agent/services/template_handler/utils.py +0 -0
  64. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/_common/experimental/write_up_agent/utils.py +0 -0
  65. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/_common/feature_flags/schema.py +0 -0
  66. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/_common/pydantic/rjsf_tags.py +0 -0
  67. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/_common/pydantic_helpers.py +0 -0
  68. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/_common/referencing.py +0 -0
  69. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/_common/string_utilities.py +0 -0
  70. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/_common/tests/test_referencing.py +0 -0
  71. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/_common/tests/test_string_utilities.py +0 -0
  72. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/_common/token/__init__.py +0 -0
  73. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/_common/token/image_token_counting.py +0 -0
  74. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/_common/token/token_counting.py +0 -0
  75. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/_common/token/tokenizers/deepseek/tokenizer.json +0 -0
  76. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/_common/token/tokenizers/qwen/tokenizer.json +0 -0
  77. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/_common/utils/__init__.py +0 -0
  78. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/_common/utils/files.py +0 -0
  79. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/_common/utils/image/encode.py +0 -0
  80. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/_common/utils/jinja/helpers.py +0 -0
  81. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/_common/utils/jinja/render.py +0 -0
  82. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/_common/utils/jinja/schema.py +0 -0
  83. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/_common/utils/jinja/utils.py +0 -0
  84. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/_common/utils/structured_output/__init__.py +0 -0
  85. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/_common/utils/structured_output/schema.py +0 -0
  86. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/_common/utils/write_configuration.py +0 -0
  87. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/_common/validate_required_values.py +0 -0
  88. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/_common/validators.py +0 -0
  89. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/__init__.py +0 -0
  90. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/debug_info_manager/debug_info_manager.py +0 -0
  91. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/debug_info_manager/test/test_debug_info_manager.py +0 -0
  92. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/evaluation/config.py +0 -0
  93. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/evaluation/context_relevancy/prompts/__init__.py +0 -0
  94. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/evaluation/context_relevancy/prompts/system_prompt.j2 +0 -0
  95. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/evaluation/context_relevancy/prompts/user_prompt.j2 +0 -0
  96. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/evaluation/context_relevancy/schema.py +0 -0
  97. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/evaluation/context_relevancy/service.py +0 -0
  98. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/evaluation/evaluation_manager.py +0 -0
  99. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/evaluation/exception.py +0 -0
  100. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/evaluation/hallucination/constants.py +0 -0
  101. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/evaluation/hallucination/hallucination_evaluation.py +0 -0
  102. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/evaluation/hallucination/prompts/__init__.py +0 -0
  103. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/evaluation/hallucination/prompts/system_prompt.j2 +0 -0
  104. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/evaluation/hallucination/prompts/user_prompt.j2 +0 -0
  105. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/evaluation/hallucination/service.py +0 -0
  106. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/evaluation/hallucination/utils.py +0 -0
  107. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/evaluation/output_parser.py +0 -0
  108. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/evaluation/schemas.py +0 -0
  109. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/evaluation/tests/fixtures.py +0 -0
  110. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/evaluation/tests/test_config.py +0 -0
  111. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/evaluation/tests/test_context_relevancy_service.py +0 -0
  112. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/evaluation/tests/test_hallucination_constants.py +0 -0
  113. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/evaluation/tests/test_hallucination_utils.py +0 -0
  114. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/evaluation/tests/test_output_parser.py +0 -0
  115. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/evaluation/tests/test_prompt_loaders.py +0 -0
  116. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/evaluation/utils.py +0 -0
  117. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/feature_flags/__init__.py +0 -0
  118. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/feature_flags/feature_flags.py +0 -0
  119. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/history_manager/history_construction_with_contents.py +0 -0
  120. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/history_manager/history_manager.py +0 -0
  121. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/history_manager/loop_token_reducer.py +0 -0
  122. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/history_manager/utils.py +0 -0
  123. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/loop_runner/__init__.py +0 -0
  124. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/loop_runner/_iteration_handler_utils.py +0 -0
  125. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/loop_runner/_responses_iteration_handler_utils.py +0 -0
  126. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/loop_runner/_responses_stream_handler_utils.py +0 -0
  127. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/loop_runner/_stream_handler_utils.py +0 -0
  128. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/loop_runner/base.py +0 -0
  129. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/loop_runner/middleware/__init__.py +0 -0
  130. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/loop_runner/middleware/planning/__init__.py +0 -0
  131. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/loop_runner/middleware/planning/planning.py +0 -0
  132. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/loop_runner/middleware/planning/schema.py +0 -0
  133. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/loop_runner/runners/__init__.py +0 -0
  134. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/loop_runner/runners/basic.py +0 -0
  135. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/loop_runner/runners/mistral/__init__.py +0 -0
  136. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/loop_runner/runners/mistral/mistral_runner.py +0 -0
  137. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/loop_runner/runners/qwen/__init__.py +0 -0
  138. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/loop_runner/runners/qwen/helpers.py +0 -0
  139. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/loop_runner/runners/qwen/qwen_runner.py +0 -0
  140. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/message_log_manager/__init__.py +0 -0
  141. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/message_log_manager/service.py +0 -0
  142. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/postprocessor/postprocessor_manager.py +0 -0
  143. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/reference_manager/reference_manager.py +0 -0
  144. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/responses_api/__init__.py +0 -0
  145. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/responses_api/postprocessors/code_display.py +0 -0
  146. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/responses_api/postprocessors/generated_files.py +0 -0
  147. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/responses_api/stream_handler.py +0 -0
  148. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/short_term_memory_manager/persistent_short_term_memory_manager.py +0 -0
  149. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/thinking_manager/thinking_manager.py +0 -0
  150. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/tools/__init__.py +0 -0
  151. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/tools/a2a/__init__.py +0 -0
  152. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/tools/a2a/config.py +0 -0
  153. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/tools/a2a/evaluation/__init__.py +0 -0
  154. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/tools/a2a/evaluation/_utils.py +0 -0
  155. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/tools/a2a/evaluation/config.py +0 -0
  156. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/tools/a2a/evaluation/evaluator.py +0 -0
  157. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/tools/a2a/evaluation/summarization_user_message.j2 +0 -0
  158. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/tools/a2a/manager.py +0 -0
  159. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/tools/a2a/postprocessing/__init__.py +0 -0
  160. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/tools/a2a/postprocessing/_display_utils.py +0 -0
  161. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/tools/a2a/postprocessing/_ref_utils.py +0 -0
  162. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/tools/a2a/postprocessing/config.py +0 -0
  163. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/tools/a2a/postprocessing/display.py +0 -0
  164. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/tools/a2a/postprocessing/references.py +0 -0
  165. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/tools/a2a/postprocessing/test/test_display.py +0 -0
  166. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/tools/a2a/postprocessing/test/test_display_utils.py +0 -0
  167. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/tools/a2a/postprocessing/test/test_ref_utils.py +0 -0
  168. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/tools/a2a/prompts.py +0 -0
  169. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/tools/a2a/response_watcher/__init__.py +0 -0
  170. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/tools/a2a/response_watcher/service.py +0 -0
  171. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/tools/a2a/tool/__init__.py +0 -0
  172. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/tools/a2a/tool/_memory.py +0 -0
  173. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/tools/a2a/tool/_schema.py +0 -0
  174. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/tools/a2a/tool/config.py +0 -0
  175. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/tools/a2a/tool/service.py +0 -0
  176. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/tools/a2a/tool/test/test_service_utils.py +0 -0
  177. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/tools/agent_chunks_hanlder.py +0 -0
  178. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/tools/config.py +0 -0
  179. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/tools/factory.py +0 -0
  180. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/tools/mcp/__init__.py +0 -0
  181. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/tools/mcp/manager.py +0 -0
  182. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/tools/mcp/models.py +0 -0
  183. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/tools/mcp/tool_wrapper.py +0 -0
  184. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/tools/openai_builtin/__init__.py +0 -0
  185. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/tools/openai_builtin/base.py +0 -0
  186. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/tools/openai_builtin/code_interpreter/__init__.py +0 -0
  187. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/tools/openai_builtin/code_interpreter/config.py +0 -0
  188. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/tools/openai_builtin/code_interpreter/postprocessors/__init__.py +0 -0
  189. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/tools/openai_builtin/code_interpreter/postprocessors/code_display.py +0 -0
  190. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/tools/openai_builtin/code_interpreter/schemas.py +0 -0
  191. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/tools/openai_builtin/code_interpreter/service.py +0 -0
  192. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/tools/openai_builtin/manager.py +0 -0
  193. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/tools/schemas.py +0 -0
  194. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/tools/test/test_mcp_manager.py +0 -0
  195. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/tools/test/test_tool_progress_reporter.py +0 -0
  196. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/tools/tool.py +0 -0
  197. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/tools/tool_manager.py +0 -0
  198. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/tools/tool_progress_reporter.py +0 -0
  199. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/tools/utils/__init__.py +0 -0
  200. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/tools/utils/source_handling/__init__.py +0 -0
  201. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/tools/utils/source_handling/schema.py +0 -0
  202. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/tools/utils/source_handling/source_formatting.py +0 -0
  203. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic/tools/utils/source_handling/tests/test_source_formatting.py +0 -0
  204. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic_table/__init__.py +0 -0
  205. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic_table/schemas.py +0 -0
  206. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/agentic_table/service.py +0 -0
  207. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/app/__init__.py +0 -0
  208. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/app/dev_util.py +0 -0
  209. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/app/fast_api_factory.py +0 -0
  210. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/app/init_logging.py +0 -0
  211. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/app/init_sdk.py +0 -0
  212. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/app/performance/async_tasks.py +0 -0
  213. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/app/performance/async_wrapper.py +0 -0
  214. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/app/schemas.py +0 -0
  215. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/app/verification.py +0 -0
  216. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/app/webhook.py +0 -0
  217. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/chat/__init__.py +0 -0
  218. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/chat/cancellation.py +0 -0
  219. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/chat/constants.py +0 -0
  220. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/chat/deprecated/service.py +0 -0
  221. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/chat/functions.py +0 -0
  222. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/chat/rendering.py +0 -0
  223. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/chat/responses_api.py +0 -0
  224. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/chat/schemas.py +0 -0
  225. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/chat/service.py +0 -0
  226. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/chat/state.py +0 -0
  227. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/chat/utils.py +0 -0
  228. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/content/__init__.py +0 -0
  229. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/content/constants.py +0 -0
  230. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/content/functions.py +0 -0
  231. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/content/schemas.py +0 -0
  232. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/content/service.py +0 -0
  233. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/content/smart_rules.py +0 -0
  234. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/content/utils.py +0 -0
  235. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/data_extraction/README.md +0 -0
  236. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/data_extraction/__init__.py +0 -0
  237. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/data_extraction/augmented/__init__.py +0 -0
  238. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/data_extraction/augmented/service.py +0 -0
  239. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/data_extraction/base.py +0 -0
  240. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/data_extraction/basic/__init__.py +0 -0
  241. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/data_extraction/basic/config.py +0 -0
  242. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/data_extraction/basic/prompt.py +0 -0
  243. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/data_extraction/basic/service.py +0 -0
  244. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/elicitation/__init__.py +0 -0
  245. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/elicitation/constants.py +0 -0
  246. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/elicitation/exceptions.py +0 -0
  247. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/elicitation/functions.py +0 -0
  248. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/elicitation/schemas.py +0 -0
  249. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/elicitation/service.py +0 -0
  250. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/embedding/__init__.py +0 -0
  251. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/embedding/constants.py +0 -0
  252. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/embedding/functions.py +0 -0
  253. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/embedding/schemas.py +0 -0
  254. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/embedding/service.py +0 -0
  255. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/embedding/utils.py +0 -0
  256. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/framework_utilities/__init__.py +0 -0
  257. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/framework_utilities/langchain/__init__.py +0 -0
  258. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/framework_utilities/langchain/client.py +0 -0
  259. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/framework_utilities/langchain/history.py +0 -0
  260. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/framework_utilities/openai/__init__.py +0 -0
  261. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/framework_utilities/openai/client.py +0 -0
  262. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/framework_utilities/openai/message_builder.py +0 -0
  263. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/framework_utilities/utils.py +0 -0
  264. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/language_model/__init__.py +0 -0
  265. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/language_model/_responses_api_utils.py +0 -0
  266. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/language_model/builder.py +0 -0
  267. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/language_model/constants.py +0 -0
  268. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/language_model/default_language_model.py +0 -0
  269. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/language_model/functions.py +0 -0
  270. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/language_model/infos.py +0 -0
  271. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/language_model/prompt.py +0 -0
  272. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/language_model/reference.py +0 -0
  273. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/language_model/schemas.py +0 -0
  274. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/language_model/service.py +0 -0
  275. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/language_model/stream_transform.py +0 -0
  276. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/language_model/utils.py +0 -0
  277. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/protocols/support.py +0 -0
  278. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/services/__init__.py +0 -0
  279. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/services/chat_service.py +0 -0
  280. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/services/knowledge_base.py +0 -0
  281. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/short_term_memory/__init__.py +0 -0
  282. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/short_term_memory/constants.py +0 -0
  283. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/short_term_memory/functions.py +0 -0
  284. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/short_term_memory/schemas.py +0 -0
  285. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/short_term_memory/service.py +0 -0
  286. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/smart_rules/__init__.py +0 -0
  287. {unique_toolkit-1.58 → unique_toolkit-1.59.0}/unique_toolkit/smart_rules/compile.py +0 -0
  288. {unique_toolkit-1.58 → unique_toolkit-1.59.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.58
3
+ Version: 1.59.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>
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "unique_toolkit"
3
- version = "1.58"
3
+ version = "1.59.0"
4
4
  description = ""
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.12"
@@ -495,10 +495,25 @@ def _build_code_blocks(
495
495
  For each file, the LAST code block that references its path is treated as the
496
496
  producer — this handles the case where a file is overwritten across blocks, where
497
497
  the final content belongs to the last writer.
498
+
499
+ Three matching tiers are used in priority order:
500
+ 1. Primary: literal path ``/mnt/data/{filename}`` appears in the code.
501
+ 2. Secondary: the filename (with or without extension) appears as a quoted
502
+ string literal — last-writer-wins among blocks (same as primary), but
503
+ never overrides a primary match. Covers helper patterns such as:
504
+ - stem only: ``save_fig(fig, "nvda_price_sma")``
505
+ - full name: ``make_chart(kind, "random_line_chart.png", 42)``
506
+ 3. Last-resort: assign remaining unmatched files to the last code block —
507
+ covers fully dynamic names built via f-strings or variable concatenation,
508
+ e.g. ``f"/mnt/data/chart_{chart_type}_{i}.png"``, where no static token
509
+ in the source matches the actual filename.
510
+ Primary matches always take precedence over secondary ones; secondary always
511
+ takes precedence over the last-resort fallback.
498
512
  """
499
513
  calls = loop_response.code_interpreter_calls
500
514
 
501
- # Step 1: for each file, find the index of the last block that references it.
515
+ # Step 1a: primary matching — full literal path /mnt/data/{filename} in code.
516
+ # Last-writer-wins: later blocks overwrite earlier ones for the same file.
502
517
  file_to_block_idx: dict[str, int] = {}
503
518
  for idx, call in enumerate(calls):
504
519
  if not call.code:
@@ -510,6 +525,62 @@ def _build_code_blocks(
510
525
  ):
511
526
  file_to_block_idx[annotation.filename] = idx
512
527
 
528
+ # Snapshot primary matches only — secondary must not override these, but within
529
+ # secondary we use last-writer-wins (later blocks overwrite earlier), same as 1a.
530
+ primary_matched_filenames = set(file_to_block_idx.keys())
531
+
532
+ # Step 1b: secondary matching for files not matched by primary.
533
+ # Handles two common helper-function patterns where the full /mnt/data/ path
534
+ # is never a literal string in the code:
535
+ #
536
+ # Pattern A — stem only (no extension at the call site):
537
+ # save_fig(fig, "nvda_price_sma") → f"/mnt/data/{name}.png" at runtime
538
+ # → matches quoted stem "nvda_price_sma"
539
+ #
540
+ # Pattern B — full filename at the call site:
541
+ # make_chart(kind, "random_line_chart.png", 42)
542
+ # fig.savefig(os.path.join(output_dir, filename), ...)
543
+ # → matches quoted full filename "random_line_chart.png"
544
+ #
545
+ # Last-writer-wins within secondary: do not skip when a prior block already matched
546
+ # via secondary — only skip filenames that matched in Step 1a (primary).
547
+ for idx, call in enumerate(calls):
548
+ if not call.code:
549
+ continue
550
+ for annotation in loop_response.container_files:
551
+ if annotation.filename in primary_matched_filenames:
552
+ continue
553
+ if content_map.get(annotation.filename) is None:
554
+ continue
555
+ fname = annotation.filename
556
+ stem = fname.rsplit(".", 1)[0]
557
+ quoted_fname = f'"{fname}"' in call.code or f"'{fname}'" in call.code
558
+ quoted_stem = bool(stem) and (
559
+ f'"{stem}"' in call.code or f"'{stem}'" in call.code
560
+ )
561
+ if quoted_fname or quoted_stem:
562
+ file_to_block_idx[annotation.filename] = idx
563
+
564
+ # Step 1c: last-resort fallback for files still unmatched after primary and secondary.
565
+ # Covers Pattern C: filenames assembled entirely at runtime via f-strings or
566
+ # variable concatenation, e.g. f"/mnt/data/chart_{chart_type}_{i}.png", where
567
+ # no static string token in the code corresponds to the actual filename.
568
+ # The last code block is used as the owner; when there is only one block this is
569
+ # always correct. For multi-block responses it is a best-effort heuristic: the
570
+ # worst outcome is the fence shows code from the wrong block, which is still
571
+ # better than leaving the file as a bare inline image with no fence at all.
572
+ last_block_idx: int | None = None
573
+ for idx, call in enumerate(calls):
574
+ if call.code:
575
+ last_block_idx = idx
576
+ if last_block_idx is not None:
577
+ for annotation in loop_response.container_files:
578
+ if annotation.filename in file_to_block_idx:
579
+ continue
580
+ if content_map.get(annotation.filename) is None:
581
+ continue
582
+ file_to_block_idx[annotation.filename] = last_block_idx
583
+
513
584
  # Step 2: group files by their owning block index, deduplicating by filename.
514
585
  # OpenAI may emit multiple annotations for the same filename when a file is
515
586
  # overwritten across executions. Using a dict keyed by filename ensures each
@@ -1,3 +1,5 @@
1
+ from __future__ import annotations
2
+
1
3
  import os
2
4
  from logging import getLogger
3
5
  from pathlib import Path
@@ -6,8 +8,9 @@ from urllib.parse import ParseResult, urlparse, urlunparse
6
8
 
7
9
  import unique_sdk
8
10
  from platformdirs import user_config_dir
9
- from pydantic import AliasChoices, Field, SecretStr, model_validator
11
+ from pydantic import AliasChoices, BaseModel, Field, SecretStr, model_validator
10
12
  from pydantic_settings import BaseSettings, SettingsConfigDict
13
+ from typing_extensions import Protocol, deprecated
11
14
 
12
15
  from unique_toolkit._common.config_checker import register_config
13
16
 
@@ -37,6 +40,97 @@ def warn_about_defaults(instance: T) -> T:
37
40
  return instance
38
41
 
39
42
 
43
+ # Auth
44
+ # We have a BaseModel and a BaseSetting class here because the context can be
45
+ # obtained from the environment and or a request. In the case of a request we
46
+ # should be using the AuthContext.
47
+ # Both classes implement the protocol that can be used for typing.
48
+ class AuthContextProtocol(Protocol):
49
+ company_id: SecretStr
50
+ user_id: SecretStr
51
+
52
+ def get_confidential_company_id(self) -> str: ...
53
+ def get_confidential_user_id(self) -> str: ...
54
+
55
+
56
+ class AuthContext(BaseModel):
57
+ company_id: SecretStr = Field(..., description="The company ID.")
58
+ user_id: SecretStr = Field(..., description="The user ID.")
59
+
60
+ def get_confidential_company_id(self) -> str:
61
+ return self.company_id.get_secret_value()
62
+
63
+ def get_confidential_user_id(self) -> str:
64
+ return self.user_id.get_secret_value()
65
+
66
+
67
+ @register_config()
68
+ class UniqueAuth(BaseSettings):
69
+ company_id: SecretStr = Field(
70
+ default=SecretStr("dummy_company_id"),
71
+ validation_alias=AliasChoices(
72
+ "unique_auth_company_id",
73
+ "company_id",
74
+ "UNIQUE_AUTH_COMPANY_ID",
75
+ "COMPANY_ID",
76
+ ),
77
+ )
78
+ user_id: SecretStr = Field(
79
+ default=SecretStr("dummy_user_id"),
80
+ validation_alias=AliasChoices(
81
+ "unique_auth_user_id", "user_id", "UNIQUE_AUTH_USER_ID", "USER_ID"
82
+ ),
83
+ )
84
+
85
+ model_config = SettingsConfigDict(
86
+ env_prefix="unique_auth_",
87
+ env_file_encoding="utf-8",
88
+ case_sensitive=False,
89
+ extra="ignore",
90
+ )
91
+
92
+ def get_confidential_company_id(self) -> str:
93
+ return self.company_id.get_secret_value()
94
+
95
+ def get_confidential_user_id(self) -> str:
96
+ return self.user_id.get_secret_value()
97
+
98
+ @model_validator(mode="after")
99
+ def _warn_about_defaults(self) -> Self:
100
+ return warn_about_defaults(self)
101
+
102
+ @classmethod
103
+ def from_event(cls, event: "BaseEvent") -> Self:
104
+ return cls(
105
+ company_id=SecretStr(event.company_id),
106
+ user_id=SecretStr(event.user_id),
107
+ )
108
+
109
+ def to_auth_context(self) -> AuthContext:
110
+ return AuthContext(
111
+ company_id=self.company_id,
112
+ user_id=self.user_id,
113
+ )
114
+
115
+
116
+ # Chat
117
+ # BaseModel only as only obtained from a request.
118
+ class ChatContextProtocol(Protocol):
119
+ chat_id: str
120
+ assistant_id: str
121
+ last_assistant_message_id: str
122
+
123
+
124
+ class ChatContext(BaseModel):
125
+ chat_id: str = Field(..., description="The chat ID.")
126
+ assistant_id: str = Field(..., description="The assistant ID.")
127
+ last_assistant_message_id: str = Field(
128
+ ..., description="The last assistant message ID."
129
+ )
130
+
131
+
132
+ # App
133
+ # Settings only as only obtained from the environment.
40
134
  @register_config()
41
135
  class UniqueApp(BaseSettings):
42
136
  id: SecretStr = Field(
@@ -79,6 +173,10 @@ class UniqueApp(BaseSettings):
79
173
  )
80
174
 
81
175
 
176
+ # Api
177
+ # Settings only as only obtained from the environment.
178
+
179
+
82
180
  @register_config()
83
181
  class UniqueApi(BaseSettings):
84
182
  base_url: str = Field(
@@ -147,43 +245,8 @@ class UniqueApi(BaseSettings):
147
245
  return urlunparse(parsed._replace(path=path, query=None, fragment=None))
148
246
 
149
247
 
150
- @register_config()
151
- class UniqueAuth(BaseSettings):
152
- company_id: SecretStr = Field(
153
- default=SecretStr("dummy_company_id"),
154
- validation_alias=AliasChoices(
155
- "unique_auth_company_id",
156
- "company_id",
157
- "UNIQUE_AUTH_COMPANY_ID",
158
- "COMPANY_ID",
159
- ),
160
- )
161
- user_id: SecretStr = Field(
162
- default=SecretStr("dummy_user_id"),
163
- validation_alias=AliasChoices(
164
- "unique_auth_user_id", "user_id", "UNIQUE_AUTH_USER_ID", "USER_ID"
165
- ),
166
- )
167
-
168
- model_config = SettingsConfigDict(
169
- env_prefix="unique_auth_",
170
- env_file_encoding="utf-8",
171
- case_sensitive=False,
172
- extra="ignore",
173
- )
174
-
175
- @model_validator(mode="after")
176
- def _warn_about_defaults(self) -> Self:
177
- return warn_about_defaults(self)
178
-
179
- @classmethod
180
- def from_event(cls, event: "BaseEvent") -> Self:
181
- return cls(
182
- company_id=SecretStr(event.company_id),
183
- user_id=SecretStr(event.user_id),
184
- )
185
-
186
-
248
+ # EventFilterOptions
249
+ # Settings only as only obtained from the environment.
187
250
  class UniqueChatEventFilterOptions(BaseSettings):
188
251
  # Empty string evals to False
189
252
  assistant_ids: list[str] = Field(
@@ -211,19 +274,71 @@ class EnvFileNotFoundError(FileNotFoundError):
211
274
  """Raised when no environment file can be found in any of the expected locations."""
212
275
 
213
276
 
277
+ class UniqueEnvironment:
278
+ """
279
+ Contains all settings that come exclusively from the environment.
280
+ This means if a setting can be intialized from either request or the environment, this class will not contain it.
281
+ """
282
+
283
+ def __init__(self, app: UniqueApp, api: UniqueApi) -> None:
284
+ self._app = app
285
+ self._api = api
286
+
287
+ @property
288
+ def app(self) -> UniqueApp:
289
+ return self._app
290
+
291
+ @property
292
+ def api(self) -> UniqueApi:
293
+ return self._api
294
+
295
+
296
+ class UniqueRequestContext:
297
+ """
298
+ Contains all settings/configuration that come from a request or an environment.
299
+ """
300
+
301
+ def __init__(
302
+ self,
303
+ auth: AuthContextProtocol | None = None,
304
+ chat: ChatContextProtocol | None = None,
305
+ ) -> None:
306
+ self._auth = auth
307
+ self._chat = chat
308
+
309
+ @property
310
+ def auth(self) -> AuthContextProtocol:
311
+ if self._auth is None:
312
+ raise ValueError("Auth context not set")
313
+ return self._auth
314
+
315
+ @auth.setter
316
+ @deprecated(
317
+ "Avoid this, rather create a new request context with the new auth context. Kept for backwards compatibility."
318
+ )
319
+ def auth(self, value: AuthContextProtocol) -> None:
320
+ self._auth = value
321
+
322
+ @property
323
+ def chat(self) -> ChatContextProtocol:
324
+ if self._chat is None:
325
+ raise ValueError("Chat context not set")
326
+ return self._chat
327
+
328
+
329
+ # Bundling: Build this object for every request.
214
330
  class UniqueSettings:
215
331
  def __init__(
216
332
  self,
217
- auth: UniqueAuth,
333
+ auth: AuthContextProtocol,
218
334
  app: UniqueApp,
219
335
  api: UniqueApi,
220
336
  *,
221
337
  chat_event_filter_options: UniqueChatEventFilterOptions | None = None,
222
338
  env_file: Path | None = None,
223
339
  ):
224
- self._app = app
225
- self._auth = auth
226
- self._api = api
340
+ self._env = UniqueEnvironment(app=app, api=api)
341
+ self._request_context = UniqueRequestContext(auth=auth, chat=None)
227
342
  self._chat_event_filter_options = chat_event_filter_options
228
343
  self._env_file: Path | None = (
229
344
  env_file if (env_file and env_file.exists()) else None
@@ -274,7 +389,7 @@ class UniqueSettings:
274
389
  def from_env(
275
390
  cls,
276
391
  env_file: Path | None = None,
277
- ) -> "UniqueSettings":
392
+ ) -> UniqueSettings:
278
393
  """Initialize settings from environment variables and/or env file.
279
394
 
280
395
  Args:
@@ -305,7 +420,7 @@ class UniqueSettings:
305
420
  )
306
421
 
307
422
  @classmethod
308
- def from_env_auto(cls, filename: str = "unique.env") -> "UniqueSettings":
423
+ def from_env_auto(cls, filename: str = "unique.env") -> UniqueSettings:
309
424
  """Initialize settings by automatically finding environment file.
310
425
 
311
426
  This method will automatically search for an environment file in standard locations
@@ -334,14 +449,14 @@ class UniqueSettings:
334
449
  This method configures the global unique_sdk module with the API key,
335
450
  app ID, and base URL from these settings.
336
451
  """
337
- unique_sdk.api_key = self._app.key.get_secret_value()
338
- unique_sdk.app_id = self._app.id.get_secret_value()
339
- unique_sdk.api_base = self._api.sdk_url()
452
+ unique_sdk.api_key = self.app.key.get_secret_value()
453
+ unique_sdk.app_id = self.app.id.get_secret_value()
454
+ unique_sdk.api_base = self.api.sdk_url()
340
455
 
341
456
  @classmethod
342
457
  def from_env_auto_with_sdk_init(
343
458
  cls, filename: str = "unique.env"
344
- ) -> "UniqueSettings":
459
+ ) -> UniqueSettings:
345
460
  """Initialize settings and SDK in one convenient call.
346
461
 
347
462
  This method combines from_env_auto() and init_sdk() for the most common use case.
@@ -356,24 +471,32 @@ class UniqueSettings:
356
471
  settings.init_sdk()
357
472
  return settings
358
473
 
359
- def update_from_event(self, event: "BaseEvent") -> None:
360
- self._auth = UniqueAuth.from_event(event)
474
+ def update_from_event(self, event: BaseEvent) -> None:
475
+ self._request_context.auth = UniqueAuth.from_event(event)
361
476
 
362
477
  @property
363
478
  def api(self) -> UniqueApi:
364
- return self._api
479
+ return self._env.api
365
480
 
366
481
  @property
367
482
  def app(self) -> UniqueApp:
368
- return self._app
483
+ return self._env.app
369
484
 
370
485
  @property
486
+ @deprecated("Use authcontext instead")
371
487
  def auth(self) -> UniqueAuth:
372
- return self._auth
488
+ if not isinstance(self._request_context.auth, UniqueAuth):
489
+ raise ValueError("Auth context is not a UniqueAuth instance")
490
+ return self._request_context.auth
373
491
 
374
492
  @auth.setter
493
+ @deprecated("Use authcontext instead")
375
494
  def auth(self, value: UniqueAuth) -> None:
376
- self._auth = value
495
+ self._request_context.auth = value
496
+
497
+ @property
498
+ def authcontext(self) -> AuthContextProtocol:
499
+ return self._request_context.auth
377
500
 
378
501
  @property
379
502
  def chat_event_filter_options(self) -> UniqueChatEventFilterOptions | None:
File without changes