unique-toolkit 1.50.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (285) hide show
  1. unique_toolkit/__init__.py +83 -0
  2. unique_toolkit/_common/__init__.py +1 -0
  3. unique_toolkit/_common/_base_service.py +10 -0
  4. unique_toolkit/_common/_time_utils.py +5 -0
  5. unique_toolkit/_common/api_calling/human_verification_manager.py +357 -0
  6. unique_toolkit/_common/base_model_type_attribute.py +303 -0
  7. unique_toolkit/_common/chunk_relevancy_sorter/config.py +51 -0
  8. unique_toolkit/_common/chunk_relevancy_sorter/exception.py +5 -0
  9. unique_toolkit/_common/chunk_relevancy_sorter/schemas.py +46 -0
  10. unique_toolkit/_common/chunk_relevancy_sorter/service.py +387 -0
  11. unique_toolkit/_common/chunk_relevancy_sorter/tests/test_service.py +275 -0
  12. unique_toolkit/_common/config_checker/README.md +418 -0
  13. unique_toolkit/_common/config_checker/__init__.py +42 -0
  14. unique_toolkit/_common/config_checker/__main__.py +6 -0
  15. unique_toolkit/_common/config_checker/cli.py +319 -0
  16. unique_toolkit/_common/config_checker/differ.py +178 -0
  17. unique_toolkit/_common/config_checker/exporter.py +195 -0
  18. unique_toolkit/_common/config_checker/models.py +52 -0
  19. unique_toolkit/_common/config_checker/registry.py +201 -0
  20. unique_toolkit/_common/config_checker/validator.py +303 -0
  21. unique_toolkit/_common/default_language_model.py +15 -0
  22. unique_toolkit/_common/docx_generator/__init__.py +13 -0
  23. unique_toolkit/_common/docx_generator/config.py +12 -0
  24. unique_toolkit/_common/docx_generator/pandoc_converter.py +58 -0
  25. unique_toolkit/_common/docx_generator/schemas.py +73 -0
  26. unique_toolkit/_common/docx_generator/service.py +216 -0
  27. unique_toolkit/_common/docx_generator/template/Doc Template.docx +0 -0
  28. unique_toolkit/_common/endpoint_builder.py +368 -0
  29. unique_toolkit/_common/endpoint_requestor.py +480 -0
  30. unique_toolkit/_common/event_bus.py +102 -0
  31. unique_toolkit/_common/exception.py +57 -0
  32. unique_toolkit/_common/execution.py +286 -0
  33. unique_toolkit/_common/experimental/endpoint_builder.py +368 -0
  34. unique_toolkit/_common/experimental/endpoint_requestor.py +488 -0
  35. unique_toolkit/_common/experimental/write_up_agent/README.md +848 -0
  36. unique_toolkit/_common/experimental/write_up_agent/__init__.py +22 -0
  37. unique_toolkit/_common/experimental/write_up_agent/agent.py +170 -0
  38. unique_toolkit/_common/experimental/write_up_agent/config.py +42 -0
  39. unique_toolkit/_common/experimental/write_up_agent/examples/data.csv +13 -0
  40. unique_toolkit/_common/experimental/write_up_agent/examples/example_usage.py +78 -0
  41. unique_toolkit/_common/experimental/write_up_agent/schemas.py +36 -0
  42. unique_toolkit/_common/experimental/write_up_agent/services/__init__.py +13 -0
  43. unique_toolkit/_common/experimental/write_up_agent/services/dataframe_handler/__init__.py +19 -0
  44. unique_toolkit/_common/experimental/write_up_agent/services/dataframe_handler/exceptions.py +29 -0
  45. unique_toolkit/_common/experimental/write_up_agent/services/dataframe_handler/service.py +150 -0
  46. unique_toolkit/_common/experimental/write_up_agent/services/dataframe_handler/utils.py +130 -0
  47. unique_toolkit/_common/experimental/write_up_agent/services/generation_handler/__init__.py +27 -0
  48. unique_toolkit/_common/experimental/write_up_agent/services/generation_handler/config.py +56 -0
  49. unique_toolkit/_common/experimental/write_up_agent/services/generation_handler/exceptions.py +79 -0
  50. unique_toolkit/_common/experimental/write_up_agent/services/generation_handler/prompts/config.py +34 -0
  51. unique_toolkit/_common/experimental/write_up_agent/services/generation_handler/prompts/system_prompt.j2 +15 -0
  52. unique_toolkit/_common/experimental/write_up_agent/services/generation_handler/prompts/user_prompt.j2 +21 -0
  53. unique_toolkit/_common/experimental/write_up_agent/services/generation_handler/service.py +355 -0
  54. unique_toolkit/_common/experimental/write_up_agent/services/template_handler/__init__.py +29 -0
  55. unique_toolkit/_common/experimental/write_up_agent/services/template_handler/default_template.j2 +37 -0
  56. unique_toolkit/_common/experimental/write_up_agent/services/template_handler/exceptions.py +39 -0
  57. unique_toolkit/_common/experimental/write_up_agent/services/template_handler/service.py +191 -0
  58. unique_toolkit/_common/experimental/write_up_agent/services/template_handler/utils.py +182 -0
  59. unique_toolkit/_common/experimental/write_up_agent/utils.py +24 -0
  60. unique_toolkit/_common/feature_flags/schema.py +9 -0
  61. unique_toolkit/_common/pydantic/rjsf_tags.py +1072 -0
  62. unique_toolkit/_common/pydantic_helpers.py +174 -0
  63. unique_toolkit/_common/referencing.py +53 -0
  64. unique_toolkit/_common/string_utilities.py +140 -0
  65. unique_toolkit/_common/tests/test_referencing.py +521 -0
  66. unique_toolkit/_common/tests/test_string_utilities.py +506 -0
  67. unique_toolkit/_common/token/__init__.py +17 -0
  68. unique_toolkit/_common/token/image_token_counting.py +67 -0
  69. unique_toolkit/_common/token/token_counting.py +225 -0
  70. unique_toolkit/_common/token/tokenizers/deepseek/tokenizer.json +263174 -0
  71. unique_toolkit/_common/token/tokenizers/qwen/tokenizer.json +303282 -0
  72. unique_toolkit/_common/utils/__init__.py +1 -0
  73. unique_toolkit/_common/utils/files.py +126 -0
  74. unique_toolkit/_common/utils/image/encode.py +25 -0
  75. unique_toolkit/_common/utils/jinja/helpers.py +10 -0
  76. unique_toolkit/_common/utils/jinja/render.py +18 -0
  77. unique_toolkit/_common/utils/jinja/schema.py +65 -0
  78. unique_toolkit/_common/utils/jinja/utils.py +80 -0
  79. unique_toolkit/_common/utils/structured_output/__init__.py +1 -0
  80. unique_toolkit/_common/utils/structured_output/schema.py +5 -0
  81. unique_toolkit/_common/utils/write_configuration.py +51 -0
  82. unique_toolkit/_common/validate_required_values.py +21 -0
  83. unique_toolkit/_common/validators.py +96 -0
  84. unique_toolkit/agentic/__init__.py +1 -0
  85. unique_toolkit/agentic/debug_info_manager/debug_info_manager.py +35 -0
  86. unique_toolkit/agentic/debug_info_manager/test/test_debug_info_manager.py +315 -0
  87. unique_toolkit/agentic/evaluation/config.py +47 -0
  88. unique_toolkit/agentic/evaluation/context_relevancy/prompts/__init__.py +13 -0
  89. unique_toolkit/agentic/evaluation/context_relevancy/prompts/system_prompt.j2 +24 -0
  90. unique_toolkit/agentic/evaluation/context_relevancy/prompts/user_prompt.j2 +15 -0
  91. unique_toolkit/agentic/evaluation/context_relevancy/schema.py +80 -0
  92. unique_toolkit/agentic/evaluation/context_relevancy/service.py +241 -0
  93. unique_toolkit/agentic/evaluation/evaluation_manager.py +218 -0
  94. unique_toolkit/agentic/evaluation/exception.py +5 -0
  95. unique_toolkit/agentic/evaluation/hallucination/constants.py +73 -0
  96. unique_toolkit/agentic/evaluation/hallucination/hallucination_evaluation.py +109 -0
  97. unique_toolkit/agentic/evaluation/hallucination/prompts/__init__.py +13 -0
  98. unique_toolkit/agentic/evaluation/hallucination/prompts/system_prompt.j2 +35 -0
  99. unique_toolkit/agentic/evaluation/hallucination/prompts/user_prompt.j2 +27 -0
  100. unique_toolkit/agentic/evaluation/hallucination/service.py +62 -0
  101. unique_toolkit/agentic/evaluation/hallucination/utils.py +311 -0
  102. unique_toolkit/agentic/evaluation/output_parser.py +48 -0
  103. unique_toolkit/agentic/evaluation/schemas.py +102 -0
  104. unique_toolkit/agentic/evaluation/tests/fixtures.py +102 -0
  105. unique_toolkit/agentic/evaluation/tests/test_config.py +247 -0
  106. unique_toolkit/agentic/evaluation/tests/test_context_relevancy_service.py +273 -0
  107. unique_toolkit/agentic/evaluation/tests/test_hallucination_constants.py +634 -0
  108. unique_toolkit/agentic/evaluation/tests/test_hallucination_utils.py +1009 -0
  109. unique_toolkit/agentic/evaluation/tests/test_output_parser.py +146 -0
  110. unique_toolkit/agentic/evaluation/tests/test_prompt_loaders.py +348 -0
  111. unique_toolkit/agentic/evaluation/utils.py +8 -0
  112. unique_toolkit/agentic/feature_flags/__init__.py +6 -0
  113. unique_toolkit/agentic/feature_flags/feature_flags.py +124 -0
  114. unique_toolkit/agentic/history_manager/history_construction_with_contents.py +266 -0
  115. unique_toolkit/agentic/history_manager/history_manager.py +254 -0
  116. unique_toolkit/agentic/history_manager/loop_token_reducer.py +566 -0
  117. unique_toolkit/agentic/history_manager/utils.py +96 -0
  118. unique_toolkit/agentic/loop_runner/__init__.py +43 -0
  119. unique_toolkit/agentic/loop_runner/_iteration_handler_utils.py +95 -0
  120. unique_toolkit/agentic/loop_runner/_responses_iteration_handler_utils.py +63 -0
  121. unique_toolkit/agentic/loop_runner/_responses_stream_handler_utils.py +90 -0
  122. unique_toolkit/agentic/loop_runner/_stream_handler_utils.py +57 -0
  123. unique_toolkit/agentic/loop_runner/base.py +87 -0
  124. unique_toolkit/agentic/loop_runner/middleware/__init__.py +11 -0
  125. unique_toolkit/agentic/loop_runner/middleware/planning/__init__.py +9 -0
  126. unique_toolkit/agentic/loop_runner/middleware/planning/planning.py +94 -0
  127. unique_toolkit/agentic/loop_runner/middleware/planning/schema.py +82 -0
  128. unique_toolkit/agentic/loop_runner/runners/__init__.py +23 -0
  129. unique_toolkit/agentic/loop_runner/runners/basic.py +71 -0
  130. unique_toolkit/agentic/loop_runner/runners/qwen/__init__.py +17 -0
  131. unique_toolkit/agentic/loop_runner/runners/qwen/helpers.py +48 -0
  132. unique_toolkit/agentic/loop_runner/runners/qwen/qwen_runner.py +121 -0
  133. unique_toolkit/agentic/message_log_manager/__init__.py +5 -0
  134. unique_toolkit/agentic/message_log_manager/service.py +279 -0
  135. unique_toolkit/agentic/postprocessor/postprocessor_manager.py +212 -0
  136. unique_toolkit/agentic/reference_manager/reference_manager.py +103 -0
  137. unique_toolkit/agentic/responses_api/__init__.py +19 -0
  138. unique_toolkit/agentic/responses_api/postprocessors/code_display.py +26 -0
  139. unique_toolkit/agentic/responses_api/postprocessors/generated_files.py +30 -0
  140. unique_toolkit/agentic/responses_api/stream_handler.py +15 -0
  141. unique_toolkit/agentic/short_term_memory_manager/persistent_short_term_memory_manager.py +141 -0
  142. unique_toolkit/agentic/thinking_manager/thinking_manager.py +103 -0
  143. unique_toolkit/agentic/tools/__init__.py +1 -0
  144. unique_toolkit/agentic/tools/a2a/__init__.py +36 -0
  145. unique_toolkit/agentic/tools/a2a/config.py +17 -0
  146. unique_toolkit/agentic/tools/a2a/evaluation/__init__.py +15 -0
  147. unique_toolkit/agentic/tools/a2a/evaluation/_utils.py +66 -0
  148. unique_toolkit/agentic/tools/a2a/evaluation/config.py +55 -0
  149. unique_toolkit/agentic/tools/a2a/evaluation/evaluator.py +260 -0
  150. unique_toolkit/agentic/tools/a2a/evaluation/summarization_user_message.j2 +9 -0
  151. unique_toolkit/agentic/tools/a2a/manager.py +55 -0
  152. unique_toolkit/agentic/tools/a2a/postprocessing/__init__.py +21 -0
  153. unique_toolkit/agentic/tools/a2a/postprocessing/_display_utils.py +240 -0
  154. unique_toolkit/agentic/tools/a2a/postprocessing/_ref_utils.py +84 -0
  155. unique_toolkit/agentic/tools/a2a/postprocessing/config.py +80 -0
  156. unique_toolkit/agentic/tools/a2a/postprocessing/display.py +264 -0
  157. unique_toolkit/agentic/tools/a2a/postprocessing/references.py +101 -0
  158. unique_toolkit/agentic/tools/a2a/postprocessing/test/test_display.py +421 -0
  159. unique_toolkit/agentic/tools/a2a/postprocessing/test/test_display_utils.py +2103 -0
  160. unique_toolkit/agentic/tools/a2a/postprocessing/test/test_ref_utils.py +603 -0
  161. unique_toolkit/agentic/tools/a2a/prompts.py +48 -0
  162. unique_toolkit/agentic/tools/a2a/response_watcher/__init__.py +6 -0
  163. unique_toolkit/agentic/tools/a2a/response_watcher/service.py +91 -0
  164. unique_toolkit/agentic/tools/a2a/tool/__init__.py +4 -0
  165. unique_toolkit/agentic/tools/a2a/tool/_memory.py +26 -0
  166. unique_toolkit/agentic/tools/a2a/tool/_schema.py +9 -0
  167. unique_toolkit/agentic/tools/a2a/tool/config.py +189 -0
  168. unique_toolkit/agentic/tools/a2a/tool/service.py +513 -0
  169. unique_toolkit/agentic/tools/a2a/tool/test/test_service_utils.py +829 -0
  170. unique_toolkit/agentic/tools/agent_chunks_hanlder.py +65 -0
  171. unique_toolkit/agentic/tools/config.py +128 -0
  172. unique_toolkit/agentic/tools/factory.py +44 -0
  173. unique_toolkit/agentic/tools/mcp/__init__.py +4 -0
  174. unique_toolkit/agentic/tools/mcp/manager.py +71 -0
  175. unique_toolkit/agentic/tools/mcp/models.py +28 -0
  176. unique_toolkit/agentic/tools/mcp/tool_wrapper.py +391 -0
  177. unique_toolkit/agentic/tools/openai_builtin/__init__.py +19 -0
  178. unique_toolkit/agentic/tools/openai_builtin/base.py +46 -0
  179. unique_toolkit/agentic/tools/openai_builtin/code_interpreter/__init__.py +21 -0
  180. unique_toolkit/agentic/tools/openai_builtin/code_interpreter/config.py +136 -0
  181. unique_toolkit/agentic/tools/openai_builtin/code_interpreter/postprocessors/__init__.py +15 -0
  182. unique_toolkit/agentic/tools/openai_builtin/code_interpreter/postprocessors/code_display.py +71 -0
  183. unique_toolkit/agentic/tools/openai_builtin/code_interpreter/postprocessors/generated_files.py +355 -0
  184. unique_toolkit/agentic/tools/openai_builtin/code_interpreter/service.py +250 -0
  185. unique_toolkit/agentic/tools/openai_builtin/manager.py +81 -0
  186. unique_toolkit/agentic/tools/schemas.py +149 -0
  187. unique_toolkit/agentic/tools/test/test_mcp_manager.py +536 -0
  188. unique_toolkit/agentic/tools/test/test_tool_progress_reporter.py +445 -0
  189. unique_toolkit/agentic/tools/tool.py +187 -0
  190. unique_toolkit/agentic/tools/tool_manager.py +495 -0
  191. unique_toolkit/agentic/tools/tool_progress_reporter.py +285 -0
  192. unique_toolkit/agentic/tools/utils/__init__.py +0 -0
  193. unique_toolkit/agentic/tools/utils/source_handling/__init__.py +0 -0
  194. unique_toolkit/agentic/tools/utils/source_handling/schema.py +21 -0
  195. unique_toolkit/agentic/tools/utils/source_handling/source_formatting.py +207 -0
  196. unique_toolkit/agentic/tools/utils/source_handling/tests/test_source_formatting.py +216 -0
  197. unique_toolkit/agentic_table/__init__.py +62 -0
  198. unique_toolkit/agentic_table/schemas.py +345 -0
  199. unique_toolkit/agentic_table/service.py +452 -0
  200. unique_toolkit/app/__init__.py +54 -0
  201. unique_toolkit/app/dev_util.py +180 -0
  202. unique_toolkit/app/fast_api_factory.py +139 -0
  203. unique_toolkit/app/init_logging.py +31 -0
  204. unique_toolkit/app/init_sdk.py +72 -0
  205. unique_toolkit/app/performance/async_tasks.py +70 -0
  206. unique_toolkit/app/performance/async_wrapper.py +39 -0
  207. unique_toolkit/app/schemas.py +334 -0
  208. unique_toolkit/app/unique_settings.py +380 -0
  209. unique_toolkit/app/verification.py +112 -0
  210. unique_toolkit/app/webhook.py +77 -0
  211. unique_toolkit/chat/__init__.py +20 -0
  212. unique_toolkit/chat/cancellation.py +176 -0
  213. unique_toolkit/chat/constants.py +3 -0
  214. unique_toolkit/chat/deprecated/service.py +304 -0
  215. unique_toolkit/chat/functions.py +1404 -0
  216. unique_toolkit/chat/rendering.py +34 -0
  217. unique_toolkit/chat/responses_api.py +465 -0
  218. unique_toolkit/chat/schemas.py +239 -0
  219. unique_toolkit/chat/service.py +157 -0
  220. unique_toolkit/chat/state.py +50 -0
  221. unique_toolkit/chat/utils.py +34 -0
  222. unique_toolkit/content/__init__.py +38 -0
  223. unique_toolkit/content/constants.py +2 -0
  224. unique_toolkit/content/functions.py +969 -0
  225. unique_toolkit/content/schemas.py +219 -0
  226. unique_toolkit/content/service.py +802 -0
  227. unique_toolkit/content/smart_rules.py +301 -0
  228. unique_toolkit/content/utils.py +244 -0
  229. unique_toolkit/data_extraction/README.md +96 -0
  230. unique_toolkit/data_extraction/__init__.py +11 -0
  231. unique_toolkit/data_extraction/augmented/__init__.py +5 -0
  232. unique_toolkit/data_extraction/augmented/service.py +93 -0
  233. unique_toolkit/data_extraction/base.py +25 -0
  234. unique_toolkit/data_extraction/basic/__init__.py +11 -0
  235. unique_toolkit/data_extraction/basic/config.py +18 -0
  236. unique_toolkit/data_extraction/basic/prompt.py +13 -0
  237. unique_toolkit/data_extraction/basic/service.py +55 -0
  238. unique_toolkit/elicitation/__init__.py +37 -0
  239. unique_toolkit/elicitation/constants.py +1 -0
  240. unique_toolkit/elicitation/exceptions.py +99 -0
  241. unique_toolkit/elicitation/functions.py +367 -0
  242. unique_toolkit/elicitation/schemas.py +179 -0
  243. unique_toolkit/elicitation/service.py +330 -0
  244. unique_toolkit/embedding/__init__.py +8 -0
  245. unique_toolkit/embedding/constants.py +2 -0
  246. unique_toolkit/embedding/functions.py +79 -0
  247. unique_toolkit/embedding/schemas.py +5 -0
  248. unique_toolkit/embedding/service.py +187 -0
  249. unique_toolkit/embedding/utils.py +11 -0
  250. unique_toolkit/framework_utilities/__init__.py +1 -0
  251. unique_toolkit/framework_utilities/langchain/__init__.py +10 -0
  252. unique_toolkit/framework_utilities/langchain/client.py +71 -0
  253. unique_toolkit/framework_utilities/langchain/history.py +19 -0
  254. unique_toolkit/framework_utilities/openai/__init__.py +6 -0
  255. unique_toolkit/framework_utilities/openai/client.py +84 -0
  256. unique_toolkit/framework_utilities/openai/message_builder.py +229 -0
  257. unique_toolkit/framework_utilities/utils.py +23 -0
  258. unique_toolkit/language_model/__init__.py +79 -0
  259. unique_toolkit/language_model/_responses_api_utils.py +93 -0
  260. unique_toolkit/language_model/builder.py +103 -0
  261. unique_toolkit/language_model/constants.py +4 -0
  262. unique_toolkit/language_model/default_language_model.py +37 -0
  263. unique_toolkit/language_model/functions.py +672 -0
  264. unique_toolkit/language_model/infos.py +2176 -0
  265. unique_toolkit/language_model/prompt.py +124 -0
  266. unique_toolkit/language_model/reference.py +244 -0
  267. unique_toolkit/language_model/schemas.py +726 -0
  268. unique_toolkit/language_model/service.py +358 -0
  269. unique_toolkit/language_model/stream_transform.py +82 -0
  270. unique_toolkit/language_model/utils.py +68 -0
  271. unique_toolkit/protocols/support.py +145 -0
  272. unique_toolkit/services/__init__.py +7 -0
  273. unique_toolkit/services/chat_service.py +2182 -0
  274. unique_toolkit/services/knowledge_base.py +1120 -0
  275. unique_toolkit/short_term_memory/__init__.py +5 -0
  276. unique_toolkit/short_term_memory/constants.py +1 -0
  277. unique_toolkit/short_term_memory/functions.py +297 -0
  278. unique_toolkit/short_term_memory/schemas.py +54 -0
  279. unique_toolkit/short_term_memory/service.py +322 -0
  280. unique_toolkit/smart_rules/__init__.py +0 -0
  281. unique_toolkit/smart_rules/compile.py +56 -0
  282. unique_toolkit/test_utilities/events.py +199 -0
  283. unique_toolkit-1.50.2.dist-info/METADATA +129 -0
  284. unique_toolkit-1.50.2.dist-info/RECORD +285 -0
  285. unique_toolkit-1.50.2.dist-info/WHEEL +4 -0
@@ -0,0 +1,83 @@
1
+ # Re-export commonly used classes for easier imports
2
+ from unique_toolkit.chat import ChatService
3
+ from unique_toolkit.content import ContentService
4
+ from unique_toolkit.data_extraction import (
5
+ StructuredOutputDataExtractor,
6
+ StructuredOutputDataExtractorConfig,
7
+ )
8
+ from unique_toolkit.embedding import EmbeddingService
9
+ from unique_toolkit.framework_utilities.openai.client import (
10
+ get_async_openai_client,
11
+ get_openai_client,
12
+ )
13
+ from unique_toolkit.language_model import (
14
+ LanguageModelMessages,
15
+ LanguageModelName,
16
+ LanguageModelService,
17
+ LanguageModelToolDescription,
18
+ )
19
+ from unique_toolkit.services.knowledge_base import KnowledgeBaseService
20
+ from unique_toolkit.short_term_memory import ShortTermMemoryService
21
+
22
+ # Conditionally import config_checker (requires pydantic-settings)
23
+ try:
24
+ from unique_toolkit._common.config_checker import (
25
+ ConfigDiffer, # noqa: F401, I001
26
+ ConfigEntry, # noqa: F401, I001
27
+ ConfigExporter, # noqa: F401, I001
28
+ ConfigRegistry, # noqa: F401, I001
29
+ ConfigValidator, # noqa: F401, I001
30
+ DefaultChangeReport, # noqa: F401, I001
31
+ ExportManifest, # noqa: F401, I001
32
+ ValidationReport, # noqa: F401, I001
33
+ register_config, # noqa: F401, I001
34
+ )
35
+
36
+ _CONFIG_CHECKER_AVAILABLE = True
37
+ except ImportError:
38
+ _CONFIG_CHECKER_AVAILABLE = False
39
+
40
+ # Conditionally import langchain utilities if langchain is installed
41
+ try:
42
+ from unique_toolkit.framework_utilities.langchain.client import get_langchain_client # noqa: F401, I001
43
+
44
+ _LANGCHAIN_AVAILABLE = True
45
+ except ImportError:
46
+ _LANGCHAIN_AVAILABLE = False
47
+
48
+ # You can add other classes you frequently use here as well
49
+
50
+ __all__ = [
51
+ "ChatService",
52
+ "ContentService",
53
+ "EmbeddingService",
54
+ "get_openai_client",
55
+ "get_async_openai_client",
56
+ "KnowledgeBaseService",
57
+ "LanguageModelMessages",
58
+ "LanguageModelName",
59
+ "LanguageModelService",
60
+ "LanguageModelToolDescription",
61
+ "ShortTermMemoryService",
62
+ "StructuredOutputDataExtractor",
63
+ "StructuredOutputDataExtractorConfig",
64
+ ]
65
+
66
+ # Add config_checker exports if available
67
+ if _CONFIG_CHECKER_AVAILABLE:
68
+ __all__.extend(
69
+ [
70
+ "ConfigDiffer",
71
+ "ConfigEntry",
72
+ "ConfigExporter",
73
+ "ConfigRegistry",
74
+ "ConfigValidator",
75
+ "DefaultChangeReport",
76
+ "ExportManifest",
77
+ "ValidationReport",
78
+ "register_config",
79
+ ]
80
+ )
81
+ # Add langchain-specific exports if available
82
+ if _LANGCHAIN_AVAILABLE:
83
+ __all__.append("get_langchain_client")
@@ -0,0 +1 @@
1
+ """Common utilities and shared components."""
@@ -0,0 +1,10 @@
1
+ import logging
2
+ from typing import Optional
3
+
4
+ from unique_toolkit.app.schemas import Event
5
+
6
+
7
+ class BaseService:
8
+ def __init__(self, event: Event, logger: Optional[logging.Logger] = None):
9
+ self.event = event
10
+ self.logger = logger or logging.getLogger(__name__)
@@ -0,0 +1,5 @@
1
+ from datetime import datetime
2
+
3
+
4
+ def get_datetime_now(format: str = "%Y-%m-%d %H:%M:%S.%f"):
5
+ return datetime.now().strftime(format)
@@ -0,0 +1,357 @@
1
+ import hashlib
2
+ from datetime import datetime
3
+ from logging import Logger
4
+ from typing import Any, Generic
5
+
6
+ import jinja2
7
+ from pydantic import BaseModel
8
+
9
+ from unique_toolkit._common.endpoint_builder import (
10
+ ApiOperationProtocol,
11
+ EmptyModel,
12
+ PathParamsSpec,
13
+ PathParamsType,
14
+ PayloadParamSpec,
15
+ PayloadType,
16
+ QueryParamsSpec,
17
+ QueryParamsType,
18
+ ResponseType,
19
+ ResponseValidationException,
20
+ )
21
+ from unique_toolkit._common.endpoint_requestor import (
22
+ RequestContext,
23
+ RequestorType,
24
+ build_requestor,
25
+ )
26
+ from unique_toolkit._common.pydantic_helpers import (
27
+ create_complement_model,
28
+ create_union_model_from_models,
29
+ )
30
+ from unique_toolkit._common.string_utilities import (
31
+ dict_to_markdown_table,
32
+ extract_dicts_from_string,
33
+ )
34
+ from unique_toolkit.chat.schemas import ChatMessage, ChatMessageRole
35
+
36
+
37
+ class HumanConfirmation(BaseModel):
38
+ payload_hash: str
39
+ time_stamp: datetime
40
+
41
+
42
+ NEXT_USER_MESSAGE_JINJA2_TEMPLATE = jinja2.Template("""I confirm the api call with the following data:
43
+ ```json
44
+ {{ api_call_as_json }}
45
+ ```""")
46
+
47
+
48
+ ASSISTANT_CONFIRMATION_MESSAGE_JINJA2_TEMPLATE = jinja2.Template(
49
+ """
50
+ \n
51
+ {{ api_call_as_markdown_table }}
52
+ \n\n
53
+ [{{ button_text }}](https://prompt={{ next_user_message | urlencode }})"""
54
+ )
55
+
56
+
57
+ class HumanVerificationManagerForApiCalling(
58
+ Generic[
59
+ PathParamsSpec,
60
+ PathParamsType,
61
+ PayloadParamSpec,
62
+ PayloadType,
63
+ QueryParamsSpec,
64
+ QueryParamsType,
65
+ ResponseType,
66
+ ]
67
+ ):
68
+ """
69
+ Manages human verification for api calling.
70
+
71
+ The idea is that the manager is able to produce the verification message to the user
72
+ and to detect an api call from the user message.
73
+
74
+ If it detects such a verification message in the user message, it will call the api
75
+ and incorporate the response into the user message.
76
+ """
77
+
78
+ def __init__(
79
+ self,
80
+ *,
81
+ logger: Logger,
82
+ operation: type[
83
+ ApiOperationProtocol[
84
+ PathParamsSpec,
85
+ PathParamsType,
86
+ PayloadParamSpec,
87
+ PayloadType,
88
+ QueryParamsSpec,
89
+ QueryParamsType,
90
+ ResponseType,
91
+ ]
92
+ ],
93
+ requestor_type: RequestorType = RequestorType.REQUESTS,
94
+ environment_payload_params: BaseModel | None = None,
95
+ modifiable_payload_params_model: type[BaseModel] | None = None,
96
+ **kwargs: dict[str, Any],
97
+ ):
98
+ """
99
+ Manages human verification for api calling.
100
+
101
+ Args:
102
+ logger: The logger to use for logging.
103
+ operation: The operation to use for the api calling.
104
+ requestor_type: The requestor type to use for the api calling.
105
+ environment_payload_params: The environment payload params to use for the api calling.
106
+ If None, the modifiable params model will be the operation payload model.
107
+ This can be useful for parameters in the payload that should not be modified by the user.
108
+ modifiable_payload_params_model: The modifiable payload params model to use for the api calling.
109
+ If None, a complement model will be created using the operation payload model
110
+ and the environment payload params.
111
+ If provided, it will be used instead of the complement model.
112
+ This is necessary if the modifiable params model is required
113
+ to use custom validators or serializers.
114
+ **kwargs: Additional keyword arguments to pass to the requestor.
115
+ """
116
+ self._logger = logger
117
+ self._operation = operation
118
+ self._environment_payload_params = environment_payload_params
119
+ # Create internal models for this manager instance
120
+
121
+ if self._environment_payload_params is None:
122
+ self._modifiable_payload_params_model = self._operation.payload_model()
123
+ else:
124
+ if modifiable_payload_params_model is None:
125
+ self._modifiable_payload_params_model = create_complement_model(
126
+ model_type_a=self._operation.payload_model(),
127
+ model_type_b=type(self._environment_payload_params),
128
+ )
129
+ else:
130
+ # This is necessary if the modifiable params model is required
131
+ # to use custom validators or serializers.
132
+ self._modifiable_payload_params_model = modifiable_payload_params_model
133
+
134
+ if self._environment_payload_params is not None:
135
+ combined_keys = set(
136
+ self._modifiable_payload_params_model.model_fields.keys()
137
+ ) | set(type(self._environment_payload_params).model_fields.keys())
138
+ payload_keys = set(self._operation.payload_model().model_fields.keys())
139
+ if not payload_keys.issubset(combined_keys):
140
+ raise ValueError(
141
+ "The modifiable params model + the environment parameters do not have all the keys of the operation payload model."
142
+ )
143
+
144
+ class VerificationModel(BaseModel):
145
+ confirmation: HumanConfirmation
146
+ modifiable_params: self._modifiable_payload_params_model # type: ignore
147
+
148
+ self._verification_model = VerificationModel
149
+
150
+ self._requestor_type = requestor_type
151
+
152
+ self._combined_params_model = create_union_model_from_models(
153
+ model_types=[
154
+ self._operation.path_params_model(),
155
+ self._operation.payload_model(),
156
+ self._operation.query_params_model(),
157
+ ],
158
+ )
159
+ self._requestor = build_requestor(
160
+ requestor_type=requestor_type,
161
+ operation_type=self._operation,
162
+ combined_model=self._combined_params_model,
163
+ **kwargs,
164
+ )
165
+
166
+ def detect_api_calls_from_user_message(
167
+ self,
168
+ *,
169
+ last_assistant_message: ChatMessage,
170
+ user_message: str,
171
+ ) -> PayloadType | None:
172
+ user_message_dicts = extract_dicts_from_string(user_message)
173
+ if len(user_message_dicts) == 0:
174
+ return None
175
+
176
+ user_message_dicts.reverse()
177
+ for user_message_dict in user_message_dicts:
178
+ try:
179
+ # Convert dict to payload model first, then create payload
180
+ verfication_data = self._verification_model.model_validate(
181
+ user_message_dict, by_alias=True, by_name=True
182
+ )
183
+ if self._verify_human_verification(
184
+ verfication_data.confirmation, last_assistant_message
185
+ ):
186
+ payload_dict = verfication_data.modifiable_params.model_dump()
187
+ if self._environment_payload_params is not None:
188
+ payload_dict.update(
189
+ self._environment_payload_params.model_dump()
190
+ )
191
+
192
+ return self._operation.payload_model().model_validate(
193
+ payload_dict, by_alias=True, by_name=True
194
+ )
195
+
196
+ except Exception as e:
197
+ self._logger.error(f"Error detecting api calls from user message: {e}")
198
+
199
+ return None
200
+
201
+ def _verify_human_verification(
202
+ self, confirmation: HumanConfirmation, last_assistant_message: ChatMessage
203
+ ) -> bool:
204
+ if (
205
+ last_assistant_message.role != ChatMessageRole.ASSISTANT
206
+ or last_assistant_message.content is None
207
+ ):
208
+ self._logger.error(
209
+ "Last assistant message is not an assistant message or content is empty."
210
+ )
211
+ return False
212
+
213
+ return confirmation.payload_hash in last_assistant_message.content
214
+
215
+ def _create_next_user_message(self, payload: PayloadType) -> str:
216
+ # Extract only the modifiable fields from the payload
217
+ payload_dict = payload.model_dump()
218
+ if self._environment_payload_params is not None:
219
+ # Remove environment params from payload to avoid validation errors
220
+ environment_fields = set(
221
+ type(self._environment_payload_params).model_fields.keys()
222
+ )
223
+ modifiable_dict = {
224
+ k: v for k, v in payload_dict.items() if k not in environment_fields
225
+ }
226
+ else:
227
+ modifiable_dict = payload_dict
228
+
229
+ modifiable_params = self._modifiable_payload_params_model.model_validate(
230
+ modifiable_dict,
231
+ by_alias=True,
232
+ by_name=True,
233
+ )
234
+ api_call = self._verification_model(
235
+ modifiable_params=modifiable_params,
236
+ confirmation=HumanConfirmation(
237
+ payload_hash=hashlib.sha256(
238
+ modifiable_params.model_dump_json().encode()
239
+ ).hexdigest(),
240
+ time_stamp=datetime.now(),
241
+ ),
242
+ )
243
+ return NEXT_USER_MESSAGE_JINJA2_TEMPLATE.render(
244
+ api_call_as_json=api_call.model_dump_json(indent=2)
245
+ )
246
+
247
+ def create_assistant_confirmation_message(
248
+ self, *, payload: PayloadType, button_text: str = "Confirm"
249
+ ) -> str:
250
+ return ASSISTANT_CONFIRMATION_MESSAGE_JINJA2_TEMPLATE.render(
251
+ api_call_as_markdown_table=dict_to_markdown_table(payload.model_dump()),
252
+ button_text=button_text,
253
+ next_user_message=self._create_next_user_message(payload),
254
+ )
255
+
256
+ def call_api(
257
+ self,
258
+ *,
259
+ context: RequestContext,
260
+ path_params: PathParamsType | EmptyModel = EmptyModel(),
261
+ payload: PayloadType | EmptyModel = EmptyModel(),
262
+ query_params: QueryParamsType | EmptyModel = EmptyModel(),
263
+ ) -> ResponseType:
264
+ """
265
+ Call the api with the given path params, payload and secured payload params.
266
+
267
+ The `secured payload params` are params that are enforced by the application.
268
+ It should generally be not possible for the user to adapt those but here we
269
+ ensure that the application has the last word.
270
+
271
+ """
272
+ params = path_params.model_dump()
273
+ params.update(payload.model_dump())
274
+ params.update(query_params.model_dump())
275
+
276
+ try:
277
+ response = self._requestor.request(
278
+ context=context,
279
+ **params,
280
+ )
281
+ return response
282
+ except ResponseValidationException as e:
283
+ self._logger.error(f"Error calling api: {e.response}.")
284
+ raise e
285
+
286
+
287
+ if __name__ == "__main__":
288
+ import logging
289
+ from string import Template
290
+
291
+ from unique_toolkit._common.endpoint_builder import (
292
+ EndpointMethods,
293
+ build_api_operation,
294
+ )
295
+
296
+ class GetUserPathParams(BaseModel):
297
+ user_id: int
298
+
299
+ class GetUserRequestBody(BaseModel):
300
+ include_profile: bool = False
301
+
302
+ class UserResponse(BaseModel):
303
+ id: int
304
+ name: str
305
+
306
+ class CombinedParams(GetUserPathParams, GetUserRequestBody):
307
+ pass
308
+
309
+ UserApiOperation = build_api_operation(
310
+ method=EndpointMethods.GET,
311
+ path_template=Template("/users/{user_id}"),
312
+ path_params_constructor=GetUserPathParams,
313
+ payload_constructor=GetUserRequestBody,
314
+ response_model_type=UserResponse,
315
+ )
316
+
317
+ human_verification_manager = HumanVerificationManagerForApiCalling(
318
+ logger=logging.getLogger(__name__),
319
+ operation=UserApiOperation,
320
+ requestor_type=RequestorType.FAKE,
321
+ return_value={"id": 100, "name": "John Doe"},
322
+ )
323
+
324
+ payload = GetUserRequestBody(include_profile=True)
325
+
326
+ api_call = human_verification_manager._verification_model(
327
+ modifiable_params=payload,
328
+ confirmation=HumanConfirmation(
329
+ payload_hash=hashlib.sha256(payload.model_dump_json().encode()).hexdigest(),
330
+ time_stamp=datetime.now(),
331
+ ),
332
+ )
333
+
334
+ last_assistant_message = ChatMessage(
335
+ role=ChatMessageRole.ASSISTANT,
336
+ text=api_call.confirmation.payload_hash,
337
+ chat_id="123",
338
+ )
339
+
340
+ user_message_with_api_call = human_verification_manager._create_next_user_message(
341
+ payload=payload
342
+ )
343
+
344
+ print(user_message_with_api_call)
345
+
346
+ payload = human_verification_manager.detect_api_calls_from_user_message(
347
+ user_message=user_message_with_api_call,
348
+ last_assistant_message=last_assistant_message,
349
+ )
350
+
351
+ if payload is None:
352
+ print("❌ Detection failed - payload is None")
353
+ exit(1)
354
+ else:
355
+ print("✅ Detection successful!")
356
+ print(f"Payload: {payload.model_dump()}")
357
+ print("✅ Dict extraction from string works correctly!")