unique_toolkit 0.7.7__py3-none-any.whl → 1.23.0__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.

Potentially problematic release.


This version of unique_toolkit might be problematic. Click here for more details.

Files changed (166) hide show
  1. unique_toolkit/__init__.py +28 -1
  2. unique_toolkit/_common/api_calling/human_verification_manager.py +343 -0
  3. unique_toolkit/_common/base_model_type_attribute.py +303 -0
  4. unique_toolkit/_common/chunk_relevancy_sorter/config.py +49 -0
  5. unique_toolkit/_common/chunk_relevancy_sorter/exception.py +5 -0
  6. unique_toolkit/_common/chunk_relevancy_sorter/schemas.py +46 -0
  7. unique_toolkit/_common/chunk_relevancy_sorter/service.py +374 -0
  8. unique_toolkit/_common/chunk_relevancy_sorter/tests/test_service.py +275 -0
  9. unique_toolkit/_common/default_language_model.py +12 -0
  10. unique_toolkit/_common/docx_generator/__init__.py +7 -0
  11. unique_toolkit/_common/docx_generator/config.py +12 -0
  12. unique_toolkit/_common/docx_generator/schemas.py +80 -0
  13. unique_toolkit/_common/docx_generator/service.py +252 -0
  14. unique_toolkit/_common/docx_generator/template/Doc Template.docx +0 -0
  15. unique_toolkit/_common/endpoint_builder.py +305 -0
  16. unique_toolkit/_common/endpoint_requestor.py +430 -0
  17. unique_toolkit/_common/exception.py +24 -0
  18. unique_toolkit/_common/feature_flags/schema.py +9 -0
  19. unique_toolkit/_common/pydantic/rjsf_tags.py +936 -0
  20. unique_toolkit/_common/pydantic_helpers.py +154 -0
  21. unique_toolkit/_common/referencing.py +53 -0
  22. unique_toolkit/_common/string_utilities.py +140 -0
  23. unique_toolkit/_common/tests/test_referencing.py +521 -0
  24. unique_toolkit/_common/tests/test_string_utilities.py +506 -0
  25. unique_toolkit/_common/token/image_token_counting.py +67 -0
  26. unique_toolkit/_common/token/token_counting.py +204 -0
  27. unique_toolkit/_common/utils/__init__.py +1 -0
  28. unique_toolkit/_common/utils/files.py +43 -0
  29. unique_toolkit/_common/utils/structured_output/__init__.py +1 -0
  30. unique_toolkit/_common/utils/structured_output/schema.py +5 -0
  31. unique_toolkit/_common/utils/write_configuration.py +51 -0
  32. unique_toolkit/_common/validators.py +101 -4
  33. unique_toolkit/agentic/__init__.py +1 -0
  34. unique_toolkit/agentic/debug_info_manager/debug_info_manager.py +28 -0
  35. unique_toolkit/agentic/debug_info_manager/test/test_debug_info_manager.py +278 -0
  36. unique_toolkit/agentic/evaluation/config.py +36 -0
  37. unique_toolkit/{evaluators → agentic/evaluation}/context_relevancy/prompts.py +25 -0
  38. unique_toolkit/agentic/evaluation/context_relevancy/schema.py +80 -0
  39. unique_toolkit/agentic/evaluation/context_relevancy/service.py +273 -0
  40. unique_toolkit/agentic/evaluation/evaluation_manager.py +218 -0
  41. unique_toolkit/agentic/evaluation/hallucination/constants.py +61 -0
  42. unique_toolkit/agentic/evaluation/hallucination/hallucination_evaluation.py +111 -0
  43. unique_toolkit/{evaluators → agentic/evaluation}/hallucination/prompts.py +1 -1
  44. unique_toolkit/{evaluators → agentic/evaluation}/hallucination/service.py +16 -15
  45. unique_toolkit/{evaluators → agentic/evaluation}/hallucination/utils.py +30 -20
  46. unique_toolkit/{evaluators → agentic/evaluation}/output_parser.py +20 -2
  47. unique_toolkit/{evaluators → agentic/evaluation}/schemas.py +27 -7
  48. unique_toolkit/agentic/evaluation/tests/test_context_relevancy_service.py +253 -0
  49. unique_toolkit/agentic/evaluation/tests/test_output_parser.py +87 -0
  50. unique_toolkit/agentic/history_manager/history_construction_with_contents.py +297 -0
  51. unique_toolkit/agentic/history_manager/history_manager.py +242 -0
  52. unique_toolkit/agentic/history_manager/loop_token_reducer.py +484 -0
  53. unique_toolkit/agentic/history_manager/utils.py +96 -0
  54. unique_toolkit/agentic/postprocessor/postprocessor_manager.py +212 -0
  55. unique_toolkit/agentic/reference_manager/reference_manager.py +103 -0
  56. unique_toolkit/agentic/responses_api/__init__.py +19 -0
  57. unique_toolkit/agentic/responses_api/postprocessors/code_display.py +63 -0
  58. unique_toolkit/agentic/responses_api/postprocessors/generated_files.py +145 -0
  59. unique_toolkit/agentic/responses_api/stream_handler.py +15 -0
  60. unique_toolkit/agentic/short_term_memory_manager/persistent_short_term_memory_manager.py +141 -0
  61. unique_toolkit/agentic/thinking_manager/thinking_manager.py +103 -0
  62. unique_toolkit/agentic/tools/__init__.py +1 -0
  63. unique_toolkit/agentic/tools/a2a/__init__.py +36 -0
  64. unique_toolkit/agentic/tools/a2a/config.py +17 -0
  65. unique_toolkit/agentic/tools/a2a/evaluation/__init__.py +15 -0
  66. unique_toolkit/agentic/tools/a2a/evaluation/_utils.py +66 -0
  67. unique_toolkit/agentic/tools/a2a/evaluation/config.py +55 -0
  68. unique_toolkit/agentic/tools/a2a/evaluation/evaluator.py +260 -0
  69. unique_toolkit/agentic/tools/a2a/evaluation/summarization_user_message.j2 +9 -0
  70. unique_toolkit/agentic/tools/a2a/manager.py +55 -0
  71. unique_toolkit/agentic/tools/a2a/postprocessing/__init__.py +21 -0
  72. unique_toolkit/agentic/tools/a2a/postprocessing/_display_utils.py +185 -0
  73. unique_toolkit/agentic/tools/a2a/postprocessing/_ref_utils.py +73 -0
  74. unique_toolkit/agentic/tools/a2a/postprocessing/config.py +45 -0
  75. unique_toolkit/agentic/tools/a2a/postprocessing/display.py +180 -0
  76. unique_toolkit/agentic/tools/a2a/postprocessing/references.py +101 -0
  77. unique_toolkit/agentic/tools/a2a/postprocessing/test/test_display_utils.py +1335 -0
  78. unique_toolkit/agentic/tools/a2a/postprocessing/test/test_ref_utils.py +603 -0
  79. unique_toolkit/agentic/tools/a2a/prompts.py +46 -0
  80. unique_toolkit/agentic/tools/a2a/response_watcher/__init__.py +6 -0
  81. unique_toolkit/agentic/tools/a2a/response_watcher/service.py +91 -0
  82. unique_toolkit/agentic/tools/a2a/tool/__init__.py +4 -0
  83. unique_toolkit/agentic/tools/a2a/tool/_memory.py +26 -0
  84. unique_toolkit/agentic/tools/a2a/tool/_schema.py +9 -0
  85. unique_toolkit/agentic/tools/a2a/tool/config.py +73 -0
  86. unique_toolkit/agentic/tools/a2a/tool/service.py +306 -0
  87. unique_toolkit/agentic/tools/agent_chunks_hanlder.py +65 -0
  88. unique_toolkit/agentic/tools/config.py +167 -0
  89. unique_toolkit/agentic/tools/factory.py +44 -0
  90. unique_toolkit/agentic/tools/mcp/__init__.py +4 -0
  91. unique_toolkit/agentic/tools/mcp/manager.py +71 -0
  92. unique_toolkit/agentic/tools/mcp/models.py +28 -0
  93. unique_toolkit/agentic/tools/mcp/tool_wrapper.py +234 -0
  94. unique_toolkit/agentic/tools/openai_builtin/__init__.py +11 -0
  95. unique_toolkit/agentic/tools/openai_builtin/base.py +30 -0
  96. unique_toolkit/agentic/tools/openai_builtin/code_interpreter/__init__.py +8 -0
  97. unique_toolkit/agentic/tools/openai_builtin/code_interpreter/config.py +57 -0
  98. unique_toolkit/agentic/tools/openai_builtin/code_interpreter/service.py +230 -0
  99. unique_toolkit/agentic/tools/openai_builtin/manager.py +62 -0
  100. unique_toolkit/agentic/tools/schemas.py +141 -0
  101. unique_toolkit/agentic/tools/test/test_mcp_manager.py +536 -0
  102. unique_toolkit/agentic/tools/test/test_tool_progress_reporter.py +445 -0
  103. unique_toolkit/agentic/tools/tool.py +183 -0
  104. unique_toolkit/agentic/tools/tool_manager.py +523 -0
  105. unique_toolkit/agentic/tools/tool_progress_reporter.py +285 -0
  106. unique_toolkit/agentic/tools/utils/__init__.py +19 -0
  107. unique_toolkit/agentic/tools/utils/execution/__init__.py +1 -0
  108. unique_toolkit/agentic/tools/utils/execution/execution.py +286 -0
  109. unique_toolkit/agentic/tools/utils/source_handling/__init__.py +0 -0
  110. unique_toolkit/agentic/tools/utils/source_handling/schema.py +21 -0
  111. unique_toolkit/agentic/tools/utils/source_handling/source_formatting.py +207 -0
  112. unique_toolkit/agentic/tools/utils/source_handling/tests/test_source_formatting.py +216 -0
  113. unique_toolkit/app/__init__.py +6 -0
  114. unique_toolkit/app/dev_util.py +180 -0
  115. unique_toolkit/app/init_sdk.py +32 -1
  116. unique_toolkit/app/schemas.py +198 -31
  117. unique_toolkit/app/unique_settings.py +367 -0
  118. unique_toolkit/chat/__init__.py +8 -1
  119. unique_toolkit/chat/deprecated/service.py +232 -0
  120. unique_toolkit/chat/functions.py +642 -77
  121. unique_toolkit/chat/rendering.py +34 -0
  122. unique_toolkit/chat/responses_api.py +461 -0
  123. unique_toolkit/chat/schemas.py +133 -2
  124. unique_toolkit/chat/service.py +115 -767
  125. unique_toolkit/content/functions.py +153 -4
  126. unique_toolkit/content/schemas.py +122 -15
  127. unique_toolkit/content/service.py +278 -44
  128. unique_toolkit/content/smart_rules.py +301 -0
  129. unique_toolkit/content/utils.py +8 -3
  130. unique_toolkit/embedding/service.py +102 -11
  131. unique_toolkit/framework_utilities/__init__.py +1 -0
  132. unique_toolkit/framework_utilities/langchain/client.py +71 -0
  133. unique_toolkit/framework_utilities/langchain/history.py +19 -0
  134. unique_toolkit/framework_utilities/openai/__init__.py +6 -0
  135. unique_toolkit/framework_utilities/openai/client.py +83 -0
  136. unique_toolkit/framework_utilities/openai/message_builder.py +229 -0
  137. unique_toolkit/framework_utilities/utils.py +23 -0
  138. unique_toolkit/language_model/__init__.py +3 -0
  139. unique_toolkit/language_model/builder.py +27 -11
  140. unique_toolkit/language_model/default_language_model.py +3 -0
  141. unique_toolkit/language_model/functions.py +327 -43
  142. unique_toolkit/language_model/infos.py +992 -50
  143. unique_toolkit/language_model/reference.py +242 -0
  144. unique_toolkit/language_model/schemas.py +475 -48
  145. unique_toolkit/language_model/service.py +228 -27
  146. unique_toolkit/protocols/support.py +145 -0
  147. unique_toolkit/services/__init__.py +7 -0
  148. unique_toolkit/services/chat_service.py +1630 -0
  149. unique_toolkit/services/knowledge_base.py +861 -0
  150. unique_toolkit/short_term_memory/service.py +178 -41
  151. unique_toolkit/smart_rules/__init__.py +0 -0
  152. unique_toolkit/smart_rules/compile.py +56 -0
  153. unique_toolkit/test_utilities/events.py +197 -0
  154. {unique_toolkit-0.7.7.dist-info → unique_toolkit-1.23.0.dist-info}/METADATA +606 -7
  155. unique_toolkit-1.23.0.dist-info/RECORD +182 -0
  156. unique_toolkit/evaluators/__init__.py +0 -1
  157. unique_toolkit/evaluators/config.py +0 -35
  158. unique_toolkit/evaluators/constants.py +0 -1
  159. unique_toolkit/evaluators/context_relevancy/constants.py +0 -32
  160. unique_toolkit/evaluators/context_relevancy/service.py +0 -53
  161. unique_toolkit/evaluators/context_relevancy/utils.py +0 -142
  162. unique_toolkit/evaluators/hallucination/constants.py +0 -41
  163. unique_toolkit-0.7.7.dist-info/RECORD +0 -64
  164. /unique_toolkit/{evaluators → agentic/evaluation}/exception.py +0 -0
  165. {unique_toolkit-0.7.7.dist-info → unique_toolkit-1.23.0.dist-info}/LICENSE +0 -0
  166. {unique_toolkit-0.7.7.dist-info → unique_toolkit-1.23.0.dist-info}/WHEEL +0 -0
@@ -0,0 +1,430 @@
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, Field
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
+ class RequestContext(BaseModel):
29
+ base_url: str
30
+ headers: dict[str, str] = Field(default_factory=dict)
31
+
32
+
33
+ def _verify_url(url: str) -> None:
34
+ parse_result = urlparse(url)
35
+ if not (parse_result.netloc and parse_result.scheme):
36
+ raise ValueError("Scheme and netloc are required for url")
37
+
38
+
39
+ class EndpointRequestorProtocol(Protocol, Generic[CombinedParamsSpec, ResponseT_co]):
40
+ @classmethod
41
+ def request(
42
+ cls,
43
+ context: RequestContext,
44
+ *args: CombinedParamsSpec.args,
45
+ **kwargs: CombinedParamsSpec.kwargs,
46
+ ) -> ResponseT_co: ...
47
+
48
+ @classmethod
49
+ async def request_async(
50
+ cls,
51
+ context: RequestContext,
52
+ *args: CombinedParamsSpec.args,
53
+ **kwargs: CombinedParamsSpec.kwargs,
54
+ ) -> ResponseT_co: ...
55
+
56
+
57
+ def build_fake_requestor(
58
+ operation_type: type[
59
+ ApiOperationProtocol[
60
+ PathParamsSpec,
61
+ PathParamsType,
62
+ PayloadParamSpec,
63
+ PayloadType,
64
+ ResponseType,
65
+ ]
66
+ ],
67
+ combined_model: Callable[CombinedParamsSpec, CombinedParamsType],
68
+ return_value: dict[str, Any],
69
+ ) -> type[EndpointRequestorProtocol[CombinedParamsSpec, ResponseType]]:
70
+ class FakeRequestor(EndpointRequestorProtocol):
71
+ _operation = operation_type
72
+
73
+ @classmethod
74
+ def request(
75
+ cls,
76
+ context: RequestContext,
77
+ *args: CombinedParamsSpec.args,
78
+ **kwargs: CombinedParamsSpec.kwargs,
79
+ ) -> ResponseType:
80
+ try:
81
+ path_params, payload_model = cls._operation.models_from_combined(
82
+ combined=kwargs
83
+ )
84
+ except Exception as e:
85
+ raise ValueError(
86
+ f"Invalid parameters passed to combined model {combined_model.__name__}: {e}"
87
+ )
88
+
89
+ return cls._operation.handle_response(
90
+ return_value,
91
+ model_validate_options=cls._operation.response_validate_options(),
92
+ )
93
+
94
+ @classmethod
95
+ async def request_async(
96
+ cls,
97
+ context: RequestContext,
98
+ headers: dict[str, str] | None = None,
99
+ *args: CombinedParamsSpec.args,
100
+ **kwargs: CombinedParamsSpec.kwargs,
101
+ ) -> ResponseType:
102
+ raise NotImplementedError(
103
+ "Async request not implemented for fake requestor"
104
+ )
105
+
106
+ return FakeRequestor
107
+
108
+
109
+ def build_request_requestor(
110
+ operation_type: type[
111
+ ApiOperationProtocol[
112
+ PathParamsSpec,
113
+ PathParamsType,
114
+ PayloadParamSpec,
115
+ PayloadType,
116
+ ResponseType,
117
+ ]
118
+ ],
119
+ combined_model: Callable[CombinedParamsSpec, CombinedParamsType],
120
+ ) -> type[EndpointRequestorProtocol[CombinedParamsSpec, ResponseType]]:
121
+ import requests
122
+
123
+ class RequestRequestor(EndpointRequestorProtocol):
124
+ _operation = operation_type
125
+
126
+ @classmethod
127
+ def request(
128
+ cls,
129
+ context: RequestContext,
130
+ *args: CombinedParamsSpec.args,
131
+ **kwargs: CombinedParamsSpec.kwargs,
132
+ ) -> ResponseType:
133
+ # Create separate instances for path params and payload using endpoint helper
134
+ path_params, payload_model = cls._operation.models_from_combined(
135
+ combined=kwargs
136
+ )
137
+
138
+ path = cls._operation.create_path_from_model(
139
+ path_params, model_dump_options=cls._operation.path_dump_options()
140
+ )
141
+ url = urljoin(context.base_url, path)
142
+ _verify_url(url)
143
+
144
+ payload = cls._operation.create_payload_from_model(
145
+ payload_model, model_dump_options=cls._operation.payload_dump_options()
146
+ )
147
+
148
+ response = requests.request(
149
+ method=cls._operation.request_method(),
150
+ url=url,
151
+ headers=context.headers,
152
+ json=payload,
153
+ )
154
+
155
+ response_json = response.json()
156
+
157
+ return cls._operation.handle_response(
158
+ response_json,
159
+ model_validate_options=cls._operation.response_validate_options(),
160
+ )
161
+
162
+ @classmethod
163
+ async def request_async(
164
+ cls,
165
+ base_url: str = "",
166
+ headers: dict[str, str] | None = None,
167
+ *args: CombinedParamsSpec.args,
168
+ **kwargs: CombinedParamsSpec.kwargs,
169
+ ) -> ResponseType:
170
+ raise NotImplementedError(
171
+ "Async request not implemented for request requestor"
172
+ )
173
+
174
+ return RequestRequestor
175
+
176
+
177
+ def build_httpx_requestor(
178
+ operation_type: type[
179
+ ApiOperationProtocol[
180
+ PathParamsSpec,
181
+ PathParamsType,
182
+ PayloadParamSpec,
183
+ PayloadType,
184
+ ResponseType,
185
+ ]
186
+ ],
187
+ combined_model: Callable[CombinedParamsSpec, CombinedParamsType],
188
+ ) -> type[EndpointRequestorProtocol[CombinedParamsSpec, ResponseType]]:
189
+ import httpx
190
+
191
+ class HttpxRequestor(EndpointRequestorProtocol):
192
+ _operation = operation_type
193
+
194
+ @classmethod
195
+ def request(
196
+ cls,
197
+ context: RequestContext,
198
+ *args: CombinedParamsSpec.args,
199
+ **kwargs: CombinedParamsSpec.kwargs,
200
+ ) -> ResponseType:
201
+ headers = context.headers or {}
202
+
203
+ path_params, payload_model = cls._operation.models_from_combined(
204
+ combined=kwargs
205
+ )
206
+
207
+ path = cls._operation.create_path_from_model(
208
+ path_params, model_dump_options=cls._operation.path_dump_options()
209
+ )
210
+ url = urljoin(context.base_url, path)
211
+ _verify_url(url)
212
+ with httpx.Client() as client:
213
+ response = client.request(
214
+ method=cls._operation.request_method(),
215
+ url=url,
216
+ headers=headers,
217
+ json=cls._operation.create_payload_from_model(
218
+ payload_model,
219
+ model_dump_options=cls._operation.payload_dump_options(),
220
+ ),
221
+ )
222
+ response_json = response.json()
223
+ return cls._operation.handle_response(
224
+ response_json,
225
+ model_validate_options=cls._operation.response_validate_options(),
226
+ )
227
+
228
+ @classmethod
229
+ async def request_async(
230
+ cls,
231
+ context: RequestContext,
232
+ *args: CombinedParamsSpec.args,
233
+ **kwargs: CombinedParamsSpec.kwargs,
234
+ ) -> ResponseType:
235
+ headers = context.headers or {}
236
+
237
+ path_params, payload_model = cls._operation.models_from_combined(
238
+ combined=kwargs
239
+ )
240
+
241
+ path = cls._operation.create_path_from_model(
242
+ path_params, model_dump_options=cls._operation.path_dump_options()
243
+ )
244
+ url = urljoin(context.base_url, path)
245
+ _verify_url(url)
246
+ async with httpx.AsyncClient() as client:
247
+ response = await client.request(
248
+ method=cls._operation.request_method(),
249
+ url=url,
250
+ headers=headers,
251
+ json=cls._operation.create_payload_from_model(
252
+ payload_model,
253
+ model_dump_options=cls._operation.payload_dump_options(),
254
+ ),
255
+ )
256
+ response_json = response.json()
257
+ return cls._operation.handle_response(
258
+ response_json,
259
+ model_validate_options=cls._operation.response_validate_options(),
260
+ )
261
+
262
+ return HttpxRequestor
263
+
264
+
265
+ def build_aiohttp_requestor(
266
+ operation_type: type[
267
+ ApiOperationProtocol[
268
+ PathParamsSpec,
269
+ PathParamsType,
270
+ PayloadParamSpec,
271
+ PayloadType,
272
+ ResponseType,
273
+ ]
274
+ ],
275
+ combined_model: Callable[CombinedParamsSpec, CombinedParamsType],
276
+ ) -> type[EndpointRequestorProtocol[CombinedParamsSpec, ResponseType]]:
277
+ import aiohttp
278
+
279
+ class AiohttpRequestor(EndpointRequestorProtocol):
280
+ _operation = operation_type
281
+
282
+ @classmethod
283
+ def request(
284
+ cls,
285
+ context: RequestContext,
286
+ *args: CombinedParamsSpec.args,
287
+ **kwargs: CombinedParamsSpec.kwargs,
288
+ ) -> ResponseType:
289
+ raise NotImplementedError(
290
+ "Sync request not implemented for aiohttp requestor"
291
+ )
292
+
293
+ @classmethod
294
+ async def request_async(
295
+ cls,
296
+ context: RequestContext,
297
+ headers: dict[str, str] | None = None,
298
+ *args: CombinedParamsSpec.args,
299
+ **kwargs: CombinedParamsSpec.kwargs,
300
+ ) -> ResponseType:
301
+ headers = context.headers or {}
302
+
303
+ path_params, payload_model = cls._operation.models_from_combined(
304
+ combined=kwargs
305
+ )
306
+ path = cls._operation.create_path_from_model(
307
+ path_params, model_dump_options=cls._operation.path_dump_options()
308
+ )
309
+ url = urljoin(context.base_url, path)
310
+ _verify_url(url)
311
+
312
+ async with aiohttp.ClientSession() as session:
313
+ response = await session.request(
314
+ method=cls._operation.request_method(),
315
+ url=url,
316
+ headers=headers,
317
+ json=cls._operation.create_payload_from_model(
318
+ payload=payload_model,
319
+ model_dump_options=cls._operation.payload_dump_options(),
320
+ ),
321
+ )
322
+ response_json = await response.json()
323
+ return cls._operation.handle_response(
324
+ response=response_json,
325
+ model_validate_options=cls._operation.response_validate_options(),
326
+ )
327
+
328
+ return AiohttpRequestor
329
+
330
+
331
+ class RequestorType(StrEnum):
332
+ REQUESTS = "requests"
333
+ FAKE = "fake"
334
+ HTTPIX = "httpx"
335
+ AIOHTTP = "aiohttp"
336
+
337
+
338
+ def build_requestor(
339
+ requestor_type: RequestorType,
340
+ operation_type: type[
341
+ ApiOperationProtocol[
342
+ PathParamsSpec,
343
+ PathParamsType,
344
+ PayloadParamSpec,
345
+ PayloadType,
346
+ ResponseType,
347
+ ]
348
+ ],
349
+ combined_model: Callable[CombinedParamsSpec, CombinedParamsType],
350
+ return_value: dict[str, Any] | None = None,
351
+ **kwargs: Any,
352
+ ) -> type[EndpointRequestorProtocol]:
353
+ match requestor_type:
354
+ case RequestorType.REQUESTS:
355
+ return build_request_requestor(
356
+ operation_type=operation_type, combined_model=combined_model
357
+ )
358
+ case RequestorType.FAKE:
359
+ if return_value is None:
360
+ raise ValueError("return_value is required for fake requestor")
361
+ return build_fake_requestor(
362
+ operation_type=operation_type,
363
+ combined_model=combined_model,
364
+ return_value=return_value,
365
+ )
366
+ case RequestorType.HTTPIX:
367
+ return build_httpx_requestor(
368
+ operation_type=operation_type, combined_model=combined_model
369
+ )
370
+ case RequestorType.AIOHTTP:
371
+ return build_aiohttp_requestor(
372
+ operation_type=operation_type, combined_model=combined_model
373
+ )
374
+
375
+
376
+ if __name__ == "__main__":
377
+ from string import Template
378
+
379
+ from unique_toolkit._common.endpoint_builder import build_api_operation
380
+
381
+ class GetUserPathParams(BaseModel):
382
+ user_id: int
383
+
384
+ class GetUserRequestBody(BaseModel):
385
+ include_profile: bool = False
386
+
387
+ class UserResponse(BaseModel):
388
+ id: int
389
+ name: str
390
+
391
+ class CombinedParams(GetUserPathParams, GetUserRequestBody):
392
+ pass
393
+
394
+ UserEndpoint = build_api_operation(
395
+ method=HttpMethods.GET,
396
+ path_template=Template("/users/{user_id}"),
397
+ path_params_constructor=GetUserPathParams,
398
+ payload_constructor=GetUserRequestBody,
399
+ response_model_type=UserResponse,
400
+ )
401
+
402
+ FakeUserRequestor = build_fake_requestor(
403
+ operation_type=UserEndpoint,
404
+ combined_model=CombinedParams,
405
+ return_value={"id": 100, "name": "John Doe"},
406
+ )
407
+
408
+ # Note that the return value is a pydantic UserResponse object
409
+ response = FakeUserRequestor().request(
410
+ context=RequestContext(base_url="https://example.com", headers={"a": "b"}),
411
+ user_id=123,
412
+ include_profile=True,
413
+ )
414
+
415
+ RequestRequestor = build_request_requestor(
416
+ operation_type=UserEndpoint,
417
+ combined_model=CombinedParams,
418
+ )
419
+
420
+ # Check type hints
421
+ response = RequestRequestor().request(
422
+ context=RequestContext(base_url="https://example.com", headers={"a": "b"}),
423
+ user_id=123,
424
+ include_profile=True,
425
+ )
426
+
427
+ print(response.model_dump())
428
+ print(response.model_json_schema())
429
+ print(response.id)
430
+ print(response.name)
@@ -31,3 +31,27 @@ class CommonException(Exception):
31
31
 
32
32
  def __str__(self):
33
33
  return self._error_message
34
+
35
+
36
+ class ConfigurationException(Exception):
37
+ pass
38
+
39
+
40
+ class InfoExceptionForAi(Exception):
41
+ """
42
+ This exception is raised as information to the AI.
43
+ Such that it can be used to inform the user about the error.
44
+ In a meaningful way.
45
+ """
46
+
47
+ def __init__(
48
+ self,
49
+ error_message: str,
50
+ message_for_ai: str,
51
+ ):
52
+ super().__init__(error_message)
53
+ self._message_for_ai = message_for_ai
54
+
55
+ @property
56
+ def message_for_ai(self):
57
+ return self._message_for_ai
@@ -0,0 +1,9 @@
1
+ from pydantic import BaseModel
2
+
3
+ from unique_toolkit.agentic.tools.config import get_configuration_dict
4
+
5
+
6
+ class FeatureExtendedSourceSerialization(BaseModel):
7
+ """Mixin for experimental feature in Source serialization"""
8
+
9
+ model_config = get_configuration_dict()