unique_toolkit 1.8.1__tar.gz → 1.9.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 (152) hide show
  1. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/CHANGELOG.md +3 -0
  2. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/PKG-INFO +4 -1
  3. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/pyproject.toml +2 -1
  4. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/_common/api_calling/human_verification_manager.py +3 -2
  5. unique_toolkit-1.9.0/unique_toolkit/_common/endpoint_requestor.py +395 -0
  6. unique_toolkit-1.8.1/unique_toolkit/_common/endpoint_requestor.py +0 -204
  7. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/LICENSE +0 -0
  8. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/README.md +0 -0
  9. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/__init__.py +0 -0
  10. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/_common/_base_service.py +0 -0
  11. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/_common/_time_utils.py +0 -0
  12. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/_common/base_model_type_attribute.py +0 -0
  13. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/_common/chunk_relevancy_sorter/config.py +0 -0
  14. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/_common/chunk_relevancy_sorter/exception.py +0 -0
  15. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/_common/chunk_relevancy_sorter/schemas.py +0 -0
  16. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/_common/chunk_relevancy_sorter/service.py +0 -0
  17. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/_common/chunk_relevancy_sorter/tests/test_service.py +0 -0
  18. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/_common/default_language_model.py +0 -0
  19. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/_common/endpoint_builder.py +0 -0
  20. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/_common/exception.py +0 -0
  21. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/_common/feature_flags/schema.py +0 -0
  22. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/_common/pydantic/rjsf_tags.py +0 -0
  23. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/_common/pydantic_helpers.py +0 -0
  24. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/_common/string_utilities.py +0 -0
  25. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/_common/token/image_token_counting.py +0 -0
  26. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/_common/token/token_counting.py +0 -0
  27. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/_common/utils/__init__.py +0 -0
  28. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/_common/utils/structured_output/__init__.py +0 -0
  29. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/_common/utils/structured_output/schema.py +0 -0
  30. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/_common/utils/write_configuration.py +0 -0
  31. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/_common/validate_required_values.py +0 -0
  32. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/_common/validators.py +0 -0
  33. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/agentic/__init__.py +0 -0
  34. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/agentic/debug_info_manager/debug_info_manager.py +0 -0
  35. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/agentic/evaluation/config.py +0 -0
  36. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/agentic/evaluation/context_relevancy/prompts.py +0 -0
  37. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/agentic/evaluation/context_relevancy/schema.py +0 -0
  38. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/agentic/evaluation/context_relevancy/service.py +0 -0
  39. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/agentic/evaluation/evaluation_manager.py +0 -0
  40. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/agentic/evaluation/exception.py +0 -0
  41. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/agentic/evaluation/hallucination/constants.py +0 -0
  42. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/agentic/evaluation/hallucination/hallucination_evaluation.py +0 -0
  43. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/agentic/evaluation/hallucination/prompts.py +0 -0
  44. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/agentic/evaluation/hallucination/service.py +0 -0
  45. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/agentic/evaluation/hallucination/utils.py +0 -0
  46. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/agentic/evaluation/output_parser.py +0 -0
  47. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/agentic/evaluation/schemas.py +0 -0
  48. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/agentic/evaluation/tests/test_context_relevancy_service.py +0 -0
  49. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/agentic/evaluation/tests/test_output_parser.py +0 -0
  50. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/agentic/history_manager/history_construction_with_contents.py +0 -0
  51. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/agentic/history_manager/history_manager.py +0 -0
  52. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/agentic/history_manager/loop_token_reducer.py +0 -0
  53. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/agentic/history_manager/utils.py +0 -0
  54. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/agentic/postprocessor/postprocessor_manager.py +0 -0
  55. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/agentic/reference_manager/reference_manager.py +0 -0
  56. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/agentic/short_term_memory_manager/persistent_short_term_memory_manager.py +0 -0
  57. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/agentic/thinking_manager/thinking_manager.py +0 -0
  58. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/agentic/tools/__init__.py +0 -0
  59. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/agentic/tools/a2a/__init__.py +0 -0
  60. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/agentic/tools/a2a/config.py +0 -0
  61. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/agentic/tools/a2a/evaluation/__init__.py +0 -0
  62. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/agentic/tools/a2a/evaluation/_utils.py +0 -0
  63. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/agentic/tools/a2a/evaluation/config.py +0 -0
  64. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/agentic/tools/a2a/evaluation/evaluator.py +0 -0
  65. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/agentic/tools/a2a/evaluation/summarization_user_message.j2 +0 -0
  66. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/agentic/tools/a2a/manager.py +0 -0
  67. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/agentic/tools/a2a/postprocessing/__init__.py +0 -0
  68. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/agentic/tools/a2a/postprocessing/_display.py +0 -0
  69. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/agentic/tools/a2a/postprocessing/_utils.py +0 -0
  70. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/agentic/tools/a2a/postprocessing/config.py +0 -0
  71. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/agentic/tools/a2a/postprocessing/postprocessor.py +0 -0
  72. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/agentic/tools/a2a/postprocessing/test/test_consolidate_references.py +0 -0
  73. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/agentic/tools/a2a/postprocessing/test/test_display.py +0 -0
  74. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/agentic/tools/a2a/postprocessing/test/test_postprocessor_reference_functions.py +0 -0
  75. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/agentic/tools/a2a/tool/__init__.py +0 -0
  76. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/agentic/tools/a2a/tool/_memory.py +0 -0
  77. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/agentic/tools/a2a/tool/_schema.py +0 -0
  78. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/agentic/tools/a2a/tool/config.py +0 -0
  79. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/agentic/tools/a2a/tool/service.py +0 -0
  80. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/agentic/tools/agent_chunks_hanlder.py +0 -0
  81. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/agentic/tools/config.py +0 -0
  82. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/agentic/tools/factory.py +0 -0
  83. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/agentic/tools/mcp/__init__.py +0 -0
  84. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/agentic/tools/mcp/manager.py +0 -0
  85. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/agentic/tools/mcp/models.py +0 -0
  86. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/agentic/tools/mcp/tool_wrapper.py +0 -0
  87. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/agentic/tools/schemas.py +0 -0
  88. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/agentic/tools/test/test_mcp_manager.py +0 -0
  89. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/agentic/tools/test/test_tool_progress_reporter.py +0 -0
  90. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/agentic/tools/tool.py +0 -0
  91. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/agentic/tools/tool_manager.py +0 -0
  92. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/agentic/tools/tool_progress_reporter.py +0 -0
  93. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/agentic/tools/utils/__init__.py +0 -0
  94. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/agentic/tools/utils/execution/__init__.py +0 -0
  95. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/agentic/tools/utils/execution/execution.py +0 -0
  96. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/agentic/tools/utils/source_handling/__init__.py +0 -0
  97. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/agentic/tools/utils/source_handling/schema.py +0 -0
  98. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/agentic/tools/utils/source_handling/source_formatting.py +0 -0
  99. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/agentic/tools/utils/source_handling/tests/test_source_formatting.py +0 -0
  100. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/app/__init__.py +0 -0
  101. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/app/dev_util.py +0 -0
  102. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/app/init_logging.py +0 -0
  103. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/app/init_sdk.py +0 -0
  104. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/app/performance/async_tasks.py +0 -0
  105. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/app/performance/async_wrapper.py +0 -0
  106. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/app/schemas.py +0 -0
  107. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/app/unique_settings.py +0 -0
  108. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/app/verification.py +0 -0
  109. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/chat/__init__.py +0 -0
  110. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/chat/constants.py +0 -0
  111. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/chat/functions.py +0 -0
  112. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/chat/schemas.py +0 -0
  113. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/chat/service.py +0 -0
  114. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/chat/state.py +0 -0
  115. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/chat/utils.py +0 -0
  116. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/content/__init__.py +0 -0
  117. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/content/constants.py +0 -0
  118. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/content/functions.py +0 -0
  119. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/content/schemas.py +0 -0
  120. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/content/service.py +0 -0
  121. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/content/utils.py +0 -0
  122. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/embedding/__init__.py +0 -0
  123. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/embedding/constants.py +0 -0
  124. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/embedding/functions.py +0 -0
  125. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/embedding/schemas.py +0 -0
  126. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/embedding/service.py +0 -0
  127. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/embedding/utils.py +0 -0
  128. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/framework_utilities/__init__.py +0 -0
  129. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/framework_utilities/langchain/client.py +0 -0
  130. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/framework_utilities/langchain/history.py +0 -0
  131. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/framework_utilities/openai/__init__.py +0 -0
  132. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/framework_utilities/openai/client.py +0 -0
  133. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/framework_utilities/openai/message_builder.py +0 -0
  134. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/framework_utilities/utils.py +0 -0
  135. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/language_model/__init__.py +0 -0
  136. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/language_model/builder.py +0 -0
  137. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/language_model/constants.py +0 -0
  138. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/language_model/functions.py +0 -0
  139. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/language_model/infos.py +0 -0
  140. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/language_model/prompt.py +0 -0
  141. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/language_model/reference.py +0 -0
  142. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/language_model/schemas.py +0 -0
  143. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/language_model/service.py +0 -0
  144. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/language_model/utils.py +0 -0
  145. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/protocols/support.py +0 -0
  146. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/short_term_memory/__init__.py +0 -0
  147. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/short_term_memory/constants.py +0 -0
  148. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/short_term_memory/functions.py +0 -0
  149. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/short_term_memory/schemas.py +0 -0
  150. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/short_term_memory/service.py +0 -0
  151. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/smart_rules/__init__.py +0 -0
  152. {unique_toolkit-1.8.1 → unique_toolkit-1.9.0}/unique_toolkit/smart_rules/compile.py +0 -0
@@ -5,6 +5,9 @@ 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.9.0] - 2026-10-04
9
+ - Define the RequestContext and add aihttp/httpx requestors
10
+
8
11
  ## [1.8.1] - 2026-10-03
9
12
  - Fix bug where sub agent evaluation config variable `include_evaluation` did not include aliases for previous names.
10
13
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: unique_toolkit
3
- Version: 1.8.1
3
+ Version: 1.9.0
4
4
  Summary:
5
5
  License: Proprietary
6
6
  Author: Cedric Klinkert
@@ -118,6 +118,9 @@ All notable changes to this project will be documented in this file.
118
118
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
119
119
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
120
120
 
121
+ ## [1.9.0] - 2026-10-04
122
+ - Define the RequestContext and add aihttp/httpx requestors
123
+
121
124
  ## [1.8.1] - 2026-10-03
122
125
  - Fix bug where sub agent evaluation config variable `include_evaluation` did not include aliases for previous names.
123
126
 
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "unique_toolkit"
3
- version = "1.8.1"
3
+ version = "1.9.0"
4
4
  description = ""
5
5
  authors = [
6
6
  "Cedric Klinkert <cedric.klinkert@unique.ch>",
@@ -62,6 +62,7 @@ entangled-cli = "^2.1.13"
62
62
  mkdocs-entangled-plugin = "^0.4.0"
63
63
  isort = "^6.0.1"
64
64
  mkdocs-codeinclude-plugin = "^0.2.1"
65
+ aiohttp = "^3.12.15"
65
66
 
66
67
  [build-system]
67
68
  requires = ["poetry-core"]
@@ -15,6 +15,7 @@ from unique_toolkit._common.endpoint_builder import (
15
15
  ResponseType,
16
16
  )
17
17
  from unique_toolkit._common.endpoint_requestor import (
18
+ RequestContext,
18
19
  RequestorType,
19
20
  build_requestor,
20
21
  )
@@ -163,7 +164,7 @@ class HumanVerificationManagerForApiCalling(
163
164
  def call_api(
164
165
  self,
165
166
  *,
166
- headers: dict[str, str],
167
+ context: RequestContext,
167
168
  path_params: PathParamsType,
168
169
  payload: PayloadType,
169
170
  ) -> ResponseType:
@@ -171,7 +172,7 @@ class HumanVerificationManagerForApiCalling(
171
172
  params.update(payload.model_dump())
172
173
 
173
174
  response = self._requestor.request(
174
- headers=headers,
175
+ context=context,
175
176
  **params,
176
177
  )
177
178
  return self._operation.handle_response(response)
@@ -0,0 +1,395 @@
1
+ from enum import StrEnum
2
+ from typing import Any, Callable, Generic, Protocol, TypeVar
3
+ from urllib.parse import urljoin, urlparse
4
+
5
+ from pydantic import BaseModel
6
+ from typing_extensions import ParamSpec
7
+
8
+ from unique_toolkit._common.endpoint_builder import (
9
+ ApiOperationProtocol,
10
+ HttpMethods,
11
+ PathParamsSpec,
12
+ PathParamsType,
13
+ PayloadParamSpec,
14
+ PayloadType,
15
+ ResponseType,
16
+ )
17
+
18
+ # Paramspecs
19
+ CombinedParamsSpec = ParamSpec("CombinedParamsSpec")
20
+
21
+ # Type variables
22
+ CombinedParamsType = TypeVar("CombinedParamsType", bound=BaseModel)
23
+
24
+
25
+ ResponseT_co = TypeVar("ResponseT_co", bound=BaseModel, covariant=True)
26
+
27
+
28
+ def _construct_full_url(base_url: str, url: str) -> str:
29
+ """
30
+ Construct full URL from base_url and url.
31
+ If base_url is provided and url is absolute, strip the scheme/netloc from url.
32
+ """
33
+ if not base_url:
34
+ return url
35
+
36
+ parsed = urlparse(url)
37
+ if parsed.scheme:
38
+ # URL is absolute, extract only path + query + fragment
39
+ url = parsed._replace(scheme="", netloc="").geturl()
40
+
41
+ return urljoin(base_url, url)
42
+
43
+
44
+ class RequestContext(BaseModel):
45
+ base_url: str = ""
46
+ headers: dict[str, str] | None = None
47
+
48
+
49
+ class EndpointRequestorProtocol(Protocol, Generic[CombinedParamsSpec, ResponseT_co]):
50
+ @classmethod
51
+ def request(
52
+ cls,
53
+ context: RequestContext,
54
+ *args: CombinedParamsSpec.args,
55
+ **kwargs: CombinedParamsSpec.kwargs,
56
+ ) -> ResponseT_co: ...
57
+
58
+ @classmethod
59
+ async def request_async(
60
+ cls,
61
+ context: RequestContext,
62
+ *args: CombinedParamsSpec.args,
63
+ **kwargs: CombinedParamsSpec.kwargs,
64
+ ) -> ResponseT_co: ...
65
+
66
+
67
+ def build_fake_requestor(
68
+ operation_type: type[
69
+ ApiOperationProtocol[
70
+ PathParamsSpec,
71
+ PathParamsType,
72
+ PayloadParamSpec,
73
+ PayloadType,
74
+ ResponseType,
75
+ ]
76
+ ],
77
+ combined_model: Callable[CombinedParamsSpec, CombinedParamsType],
78
+ return_value: dict[str, Any],
79
+ ) -> type[EndpointRequestorProtocol[CombinedParamsSpec, ResponseType]]:
80
+ class FakeRequestor(EndpointRequestorProtocol):
81
+ _operation = operation_type
82
+
83
+ @classmethod
84
+ def request(
85
+ cls,
86
+ context: RequestContext,
87
+ *args: CombinedParamsSpec.args,
88
+ **kwargs: CombinedParamsSpec.kwargs,
89
+ ) -> ResponseType:
90
+ try:
91
+ path_params, payload_model = cls._operation.models_from_combined(
92
+ combined=kwargs
93
+ )
94
+ except Exception as e:
95
+ raise ValueError(
96
+ f"Invalid parameters passed to combined model {combined_model.__name__}: {e}"
97
+ )
98
+
99
+ return cls._operation.handle_response(return_value)
100
+
101
+ @classmethod
102
+ async def request_async(
103
+ cls,
104
+ context: RequestContext,
105
+ headers: dict[str, str] | None = None,
106
+ *args: CombinedParamsSpec.args,
107
+ **kwargs: CombinedParamsSpec.kwargs,
108
+ ) -> ResponseType:
109
+ raise NotImplementedError(
110
+ "Async request not implemented for fake requestor"
111
+ )
112
+
113
+ return FakeRequestor
114
+
115
+
116
+ def build_request_requestor(
117
+ operation_type: type[
118
+ ApiOperationProtocol[
119
+ PathParamsSpec,
120
+ PathParamsType,
121
+ PayloadParamSpec,
122
+ PayloadType,
123
+ ResponseType,
124
+ ]
125
+ ],
126
+ combined_model: Callable[CombinedParamsSpec, CombinedParamsType],
127
+ ) -> type[EndpointRequestorProtocol[CombinedParamsSpec, ResponseType]]:
128
+ import requests
129
+
130
+ class RequestRequestor(EndpointRequestorProtocol):
131
+ _operation = operation_type
132
+
133
+ @classmethod
134
+ def request(
135
+ cls,
136
+ context: RequestContext,
137
+ *args: CombinedParamsSpec.args,
138
+ **kwargs: CombinedParamsSpec.kwargs,
139
+ ) -> ResponseType:
140
+ # Create separate instances for path params and payload using endpoint helper
141
+ path_params, payload_model = cls._operation.models_from_combined(
142
+ combined=kwargs
143
+ )
144
+
145
+ url = cls._operation.create_url_from_model(path_params)
146
+ payload = cls._operation.create_payload_from_model(payload_model)
147
+
148
+ response = requests.request(
149
+ method=cls._operation.request_method(),
150
+ url=_construct_full_url(context.base_url, url),
151
+ headers=context.headers,
152
+ json=payload,
153
+ )
154
+ return cls._operation.handle_response(response.json())
155
+
156
+ @classmethod
157
+ async def request_async(
158
+ cls,
159
+ base_url: str = "",
160
+ headers: dict[str, str] | None = None,
161
+ *args: CombinedParamsSpec.args,
162
+ **kwargs: CombinedParamsSpec.kwargs,
163
+ ) -> ResponseType:
164
+ raise NotImplementedError(
165
+ "Async request not implemented for request requestor"
166
+ )
167
+
168
+ return RequestRequestor
169
+
170
+
171
+ def build_httpx_requestor(
172
+ operation_type: type[
173
+ ApiOperationProtocol[
174
+ PathParamsSpec,
175
+ PathParamsType,
176
+ PayloadParamSpec,
177
+ PayloadType,
178
+ ResponseType,
179
+ ]
180
+ ],
181
+ combined_model: Callable[CombinedParamsSpec, CombinedParamsType],
182
+ ) -> type[EndpointRequestorProtocol[CombinedParamsSpec, ResponseType]]:
183
+ import httpx
184
+
185
+ class HttpxRequestor(EndpointRequestorProtocol):
186
+ _operation = operation_type
187
+
188
+ @classmethod
189
+ def request(
190
+ cls,
191
+ context: RequestContext,
192
+ *args: CombinedParamsSpec.args,
193
+ **kwargs: CombinedParamsSpec.kwargs,
194
+ ) -> ResponseType:
195
+ headers = context.headers or {}
196
+
197
+ path_params, payload_model = cls._operation.models_from_combined(
198
+ combined=kwargs
199
+ )
200
+
201
+ with httpx.Client() as client:
202
+ response = client.request(
203
+ method=cls._operation.request_method(),
204
+ url=_construct_full_url(
205
+ base_url=context.base_url,
206
+ url=cls._operation.create_url_from_model(path_params),
207
+ ),
208
+ headers=headers,
209
+ json=cls._operation.create_payload_from_model(payload_model),
210
+ )
211
+ return cls._operation.handle_response(response.json())
212
+
213
+ @classmethod
214
+ async def request_async(
215
+ cls,
216
+ context: RequestContext,
217
+ *args: CombinedParamsSpec.args,
218
+ **kwargs: CombinedParamsSpec.kwargs,
219
+ ) -> ResponseType:
220
+ headers = context.headers or {}
221
+
222
+ path_params, payload_model = cls._operation.models_from_combined(
223
+ combined=kwargs
224
+ )
225
+
226
+ async with httpx.AsyncClient() as client:
227
+ response = await client.request(
228
+ method=cls._operation.request_method(),
229
+ url=_construct_full_url(
230
+ base_url=context.base_url,
231
+ url=cls._operation.create_url_from_model(path_params),
232
+ ),
233
+ headers=headers,
234
+ json=cls._operation.create_payload_from_model(payload_model),
235
+ )
236
+ return cls._operation.handle_response(response.json())
237
+
238
+ return HttpxRequestor
239
+
240
+
241
+ def build_aiohttp_requestor(
242
+ operation_type: type[
243
+ ApiOperationProtocol[
244
+ PathParamsSpec,
245
+ PathParamsType,
246
+ PayloadParamSpec,
247
+ PayloadType,
248
+ ResponseType,
249
+ ]
250
+ ],
251
+ combined_model: Callable[CombinedParamsSpec, CombinedParamsType],
252
+ ) -> type[EndpointRequestorProtocol[CombinedParamsSpec, ResponseType]]:
253
+ import aiohttp
254
+
255
+ class AiohttpRequestor(EndpointRequestorProtocol):
256
+ _operation = operation_type
257
+
258
+ @classmethod
259
+ def request(
260
+ cls,
261
+ context: RequestContext,
262
+ *args: CombinedParamsSpec.args,
263
+ **kwargs: CombinedParamsSpec.kwargs,
264
+ ) -> ResponseType:
265
+ raise NotImplementedError(
266
+ "Sync request not implemented for aiohttp requestor"
267
+ )
268
+
269
+ @classmethod
270
+ async def request_async(
271
+ cls,
272
+ context: RequestContext,
273
+ headers: dict[str, str] | None = None,
274
+ *args: CombinedParamsSpec.args,
275
+ **kwargs: CombinedParamsSpec.kwargs,
276
+ ) -> ResponseType:
277
+ headers = context.headers or {}
278
+
279
+ path_params, payload_model = cls._operation.models_from_combined(
280
+ combined=kwargs
281
+ )
282
+
283
+ async with aiohttp.ClientSession() as session:
284
+ response = await session.request(
285
+ method=cls._operation.request_method(),
286
+ url=_construct_full_url(
287
+ base_url=context.base_url,
288
+ url=cls._operation.create_url_from_model(path_params),
289
+ ),
290
+ headers=headers,
291
+ json=cls._operation.create_payload_from_model(payload_model),
292
+ )
293
+ return cls._operation.handle_response(await response.json())
294
+
295
+ return AiohttpRequestor
296
+
297
+
298
+ class RequestorType(StrEnum):
299
+ REQUESTS = "requests"
300
+ FAKE = "fake"
301
+ HTTPIX = "httpx"
302
+ AIOHTTP = "aiohttp"
303
+
304
+
305
+ def build_requestor(
306
+ requestor_type: RequestorType,
307
+ operation_type: type[
308
+ ApiOperationProtocol[
309
+ PathParamsSpec,
310
+ PathParamsType,
311
+ PayloadParamSpec,
312
+ PayloadType,
313
+ ResponseType,
314
+ ]
315
+ ],
316
+ combined_model: Callable[CombinedParamsSpec, CombinedParamsType],
317
+ return_value: dict[str, Any] | None = None,
318
+ **kwargs: Any,
319
+ ) -> type[EndpointRequestorProtocol]:
320
+ match requestor_type:
321
+ case RequestorType.REQUESTS:
322
+ return build_request_requestor(
323
+ operation_type=operation_type, combined_model=combined_model
324
+ )
325
+ case RequestorType.FAKE:
326
+ if return_value is None:
327
+ raise ValueError("return_value is required for fake requestor")
328
+ return build_fake_requestor(
329
+ operation_type=operation_type,
330
+ combined_model=combined_model,
331
+ return_value=return_value,
332
+ )
333
+ case RequestorType.HTTPIX:
334
+ return build_httpx_requestor(
335
+ operation_type=operation_type, combined_model=combined_model
336
+ )
337
+ case RequestorType.AIOHTTP:
338
+ return build_aiohttp_requestor(
339
+ operation_type=operation_type, combined_model=combined_model
340
+ )
341
+
342
+
343
+ if __name__ == "__main__":
344
+ from string import Template
345
+
346
+ from unique_toolkit._common.endpoint_builder import build_api_operation
347
+
348
+ class GetUserPathParams(BaseModel):
349
+ user_id: int
350
+
351
+ class GetUserRequestBody(BaseModel):
352
+ include_profile: bool = False
353
+
354
+ class UserResponse(BaseModel):
355
+ id: int
356
+ name: str
357
+
358
+ class CombinedParams(GetUserPathParams, GetUserRequestBody):
359
+ pass
360
+
361
+ UserEndpoint = build_api_operation(
362
+ method=HttpMethods.GET,
363
+ url_template=Template("https://api.example.com/users/{user_id}"),
364
+ path_params_constructor=GetUserPathParams,
365
+ payload_constructor=GetUserRequestBody,
366
+ response_model_type=UserResponse,
367
+ )
368
+
369
+ FakeUserRequestor = build_fake_requestor(
370
+ operation_type=UserEndpoint,
371
+ combined_model=CombinedParams,
372
+ return_value={"id": 100, "name": "John Doe"},
373
+ )
374
+
375
+ # Note that the return value is a pydantic UserResponse object
376
+ response = FakeUserRequestor().request(
377
+ context=RequestContext(headers={"a": "b"}),
378
+ user_id=123,
379
+ include_profile=True,
380
+ )
381
+
382
+ RequestRequestor = build_request_requestor(
383
+ operation_type=UserEndpoint,
384
+ combined_model=CombinedParams,
385
+ )
386
+
387
+ # Check type hints
388
+ response = RequestRequestor().request(
389
+ context=RequestContext(headers={"a": "b"}), user_id=123, include_profile=True
390
+ )
391
+
392
+ print(response.model_dump())
393
+ print(response.model_json_schema())
394
+ print(response.id)
395
+ print(response.name)
@@ -1,204 +0,0 @@
1
- from enum import StrEnum
2
- from typing import Any, Callable, Generic, Protocol, TypeVar
3
-
4
- from pydantic import BaseModel
5
- from typing_extensions import ParamSpec
6
-
7
- from unique_toolkit._common.endpoint_builder import (
8
- ApiOperationProtocol,
9
- HttpMethods,
10
- PathParamsSpec,
11
- PathParamsType,
12
- PayloadParamSpec,
13
- PayloadType,
14
- ResponseType,
15
- )
16
-
17
- # Paramspecs
18
- CombinedParamsSpec = ParamSpec("CombinedParamsSpec")
19
-
20
- # Type variables
21
- CombinedParamsType = TypeVar("CombinedParamsType", bound=BaseModel)
22
-
23
-
24
- ResponseT_co = TypeVar("ResponseT_co", bound=BaseModel, covariant=True)
25
-
26
-
27
- class EndpointRequestorProtocol(Protocol, Generic[CombinedParamsSpec, ResponseT_co]):
28
- @classmethod
29
- def request(
30
- cls,
31
- headers: dict[str, str],
32
- *args: CombinedParamsSpec.args,
33
- **kwargs: CombinedParamsSpec.kwargs,
34
- ) -> ResponseT_co: ...
35
-
36
-
37
- def build_fake_requestor(
38
- operation_type: type[
39
- ApiOperationProtocol[
40
- PathParamsSpec,
41
- PathParamsType,
42
- PayloadParamSpec,
43
- PayloadType,
44
- ResponseType,
45
- ]
46
- ],
47
- combined_model: Callable[CombinedParamsSpec, CombinedParamsType],
48
- return_value: dict[str, Any],
49
- ) -> type[EndpointRequestorProtocol[CombinedParamsSpec, ResponseType]]:
50
- class FakeRequestor(EndpointRequestorProtocol):
51
- _operation = operation_type
52
-
53
- @classmethod
54
- def request(
55
- cls,
56
- headers: dict[str, str],
57
- *args: CombinedParamsSpec.args,
58
- **kwargs: CombinedParamsSpec.kwargs,
59
- ) -> ResponseType:
60
- try:
61
- path_params, payload_model = cls._operation.models_from_combined(
62
- combined=kwargs
63
- )
64
- except Exception as e:
65
- raise ValueError(
66
- f"Invalid parameters passed to combined model {combined_model.__name__}: {e}"
67
- )
68
-
69
- return cls._operation.handle_response(return_value)
70
-
71
- return FakeRequestor
72
-
73
-
74
- def build_request_requestor(
75
- operation_type: type[
76
- ApiOperationProtocol[
77
- PathParamsSpec,
78
- PathParamsType,
79
- PayloadParamSpec,
80
- PayloadType,
81
- ResponseType,
82
- ]
83
- ],
84
- combined_model: Callable[CombinedParamsSpec, CombinedParamsType],
85
- ) -> type[EndpointRequestorProtocol[CombinedParamsSpec, ResponseType]]:
86
- import requests
87
-
88
- class RequestRequestor(EndpointRequestorProtocol):
89
- _operation = operation_type
90
-
91
- @classmethod
92
- def request(
93
- cls,
94
- headers: dict[str, str],
95
- *args: CombinedParamsSpec.args,
96
- **kwargs: CombinedParamsSpec.kwargs,
97
- ) -> ResponseType:
98
- # Create separate instances for path params and payload using endpoint helper
99
- path_params, payload_model = cls._operation.models_from_combined(
100
- combined=kwargs
101
- )
102
-
103
- url = cls._operation.create_url_from_model(path_params)
104
- payload = cls._operation.create_payload_from_model(payload_model)
105
-
106
- response = requests.request(
107
- method=cls._operation.request_method(),
108
- url=url,
109
- headers=headers,
110
- json=payload,
111
- )
112
- return cls._operation.handle_response(response.json())
113
-
114
- return RequestRequestor
115
-
116
-
117
- class RequestorType(StrEnum):
118
- REQUESTS = "requests"
119
- FAKE = "fake"
120
-
121
-
122
- def build_requestor(
123
- requestor_type: RequestorType,
124
- operation_type: type[
125
- ApiOperationProtocol[
126
- PathParamsSpec,
127
- PathParamsType,
128
- PayloadParamSpec,
129
- PayloadType,
130
- ResponseType,
131
- ]
132
- ],
133
- combined_model: Callable[CombinedParamsSpec, CombinedParamsType],
134
- return_value: dict[str, Any] | None = None,
135
- **kwargs: Any,
136
- ) -> type[EndpointRequestorProtocol]:
137
- match requestor_type:
138
- case RequestorType.REQUESTS:
139
- return build_request_requestor(
140
- operation_type=operation_type, combined_model=combined_model
141
- )
142
- case RequestorType.FAKE:
143
- if return_value is None:
144
- raise ValueError("return_value is required for fake requestor")
145
- return build_fake_requestor(
146
- operation_type=operation_type,
147
- combined_model=combined_model,
148
- return_value=return_value,
149
- )
150
-
151
-
152
- if __name__ == "__main__":
153
- from string import Template
154
-
155
- from unique_toolkit._common.endpoint_builder import build_api_operation
156
-
157
- class GetUserPathParams(BaseModel):
158
- user_id: int
159
-
160
- class GetUserRequestBody(BaseModel):
161
- include_profile: bool = False
162
-
163
- class UserResponse(BaseModel):
164
- id: int
165
- name: str
166
-
167
- class CombinedParams(GetUserPathParams, GetUserRequestBody):
168
- pass
169
-
170
- UserEndpoint = build_api_operation(
171
- method=HttpMethods.GET,
172
- url_template=Template("https://api.example.com/users/{user_id}"),
173
- path_params_constructor=GetUserPathParams,
174
- payload_constructor=GetUserRequestBody,
175
- response_model_type=UserResponse,
176
- )
177
-
178
- FakeUserRequestor = build_fake_requestor(
179
- operation_type=UserEndpoint,
180
- combined_model=CombinedParams,
181
- return_value={"id": 100, "name": "John Doe"},
182
- )
183
-
184
- # Note that the return value is a pydantic UserResponse object
185
- response = FakeUserRequestor().request(
186
- headers={"a": "b"},
187
- user_id=123,
188
- include_profile=True,
189
- )
190
-
191
- RequestRequstor = build_request_requestor(
192
- operation_type=UserEndpoint,
193
- combined_model=CombinedParams,
194
- )
195
-
196
- # Check type hints
197
- response = RequestRequstor().request(
198
- headers={"a": "b"}, user_id=123, include_profile=True
199
- )
200
-
201
- print(response.model_dump())
202
- print(response.model_json_schema())
203
- print(response.id)
204
- print(response.name)
File without changes
File without changes