aiqtoolkit 1.1.0rc6__py3-none-any.whl → 1.2.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 aiqtoolkit might be problematic. Click here for more details.

Files changed (319) hide show
  1. aiqtoolkit-1.2.0.dist-info/METADATA +29 -0
  2. aiqtoolkit-1.2.0.dist-info/RECORD +4 -0
  3. {aiqtoolkit-1.1.0rc6.dist-info → aiqtoolkit-1.2.0.dist-info}/WHEEL +1 -1
  4. aiqtoolkit-1.2.0.dist-info/top_level.txt +1 -0
  5. aiq/agent/__init__.py +0 -0
  6. aiq/agent/base.py +0 -76
  7. aiq/agent/dual_node.py +0 -67
  8. aiq/agent/react_agent/__init__.py +0 -0
  9. aiq/agent/react_agent/agent.py +0 -322
  10. aiq/agent/react_agent/output_parser.py +0 -104
  11. aiq/agent/react_agent/prompt.py +0 -46
  12. aiq/agent/react_agent/register.py +0 -148
  13. aiq/agent/reasoning_agent/__init__.py +0 -0
  14. aiq/agent/reasoning_agent/reasoning_agent.py +0 -224
  15. aiq/agent/register.py +0 -23
  16. aiq/agent/rewoo_agent/__init__.py +0 -0
  17. aiq/agent/rewoo_agent/agent.py +0 -410
  18. aiq/agent/rewoo_agent/prompt.py +0 -108
  19. aiq/agent/rewoo_agent/register.py +0 -158
  20. aiq/agent/tool_calling_agent/__init__.py +0 -0
  21. aiq/agent/tool_calling_agent/agent.py +0 -123
  22. aiq/agent/tool_calling_agent/register.py +0 -105
  23. aiq/builder/__init__.py +0 -0
  24. aiq/builder/builder.py +0 -223
  25. aiq/builder/component_utils.py +0 -303
  26. aiq/builder/context.py +0 -227
  27. aiq/builder/embedder.py +0 -24
  28. aiq/builder/eval_builder.py +0 -120
  29. aiq/builder/evaluator.py +0 -29
  30. aiq/builder/framework_enum.py +0 -24
  31. aiq/builder/front_end.py +0 -73
  32. aiq/builder/function.py +0 -297
  33. aiq/builder/function_base.py +0 -376
  34. aiq/builder/function_info.py +0 -627
  35. aiq/builder/intermediate_step_manager.py +0 -176
  36. aiq/builder/llm.py +0 -25
  37. aiq/builder/retriever.py +0 -25
  38. aiq/builder/user_interaction_manager.py +0 -71
  39. aiq/builder/workflow.py +0 -143
  40. aiq/builder/workflow_builder.py +0 -757
  41. aiq/cli/__init__.py +0 -14
  42. aiq/cli/cli_utils/__init__.py +0 -0
  43. aiq/cli/cli_utils/config_override.py +0 -231
  44. aiq/cli/cli_utils/validation.py +0 -37
  45. aiq/cli/commands/__init__.py +0 -0
  46. aiq/cli/commands/configure/__init__.py +0 -0
  47. aiq/cli/commands/configure/channel/__init__.py +0 -0
  48. aiq/cli/commands/configure/channel/add.py +0 -28
  49. aiq/cli/commands/configure/channel/channel.py +0 -36
  50. aiq/cli/commands/configure/channel/remove.py +0 -30
  51. aiq/cli/commands/configure/channel/update.py +0 -30
  52. aiq/cli/commands/configure/configure.py +0 -33
  53. aiq/cli/commands/evaluate.py +0 -139
  54. aiq/cli/commands/info/__init__.py +0 -14
  55. aiq/cli/commands/info/info.py +0 -39
  56. aiq/cli/commands/info/list_channels.py +0 -32
  57. aiq/cli/commands/info/list_components.py +0 -129
  58. aiq/cli/commands/info/list_mcp.py +0 -126
  59. aiq/cli/commands/registry/__init__.py +0 -14
  60. aiq/cli/commands/registry/publish.py +0 -88
  61. aiq/cli/commands/registry/pull.py +0 -118
  62. aiq/cli/commands/registry/registry.py +0 -38
  63. aiq/cli/commands/registry/remove.py +0 -108
  64. aiq/cli/commands/registry/search.py +0 -155
  65. aiq/cli/commands/start.py +0 -250
  66. aiq/cli/commands/uninstall.py +0 -83
  67. aiq/cli/commands/validate.py +0 -47
  68. aiq/cli/commands/workflow/__init__.py +0 -14
  69. aiq/cli/commands/workflow/templates/__init__.py.j2 +0 -0
  70. aiq/cli/commands/workflow/templates/config.yml.j2 +0 -16
  71. aiq/cli/commands/workflow/templates/pyproject.toml.j2 +0 -22
  72. aiq/cli/commands/workflow/templates/register.py.j2 +0 -5
  73. aiq/cli/commands/workflow/templates/workflow.py.j2 +0 -36
  74. aiq/cli/commands/workflow/workflow.py +0 -37
  75. aiq/cli/commands/workflow/workflow_commands.py +0 -313
  76. aiq/cli/entrypoint.py +0 -133
  77. aiq/cli/main.py +0 -44
  78. aiq/cli/register_workflow.py +0 -408
  79. aiq/cli/type_registry.py +0 -879
  80. aiq/data_models/__init__.py +0 -14
  81. aiq/data_models/api_server.py +0 -588
  82. aiq/data_models/common.py +0 -143
  83. aiq/data_models/component.py +0 -46
  84. aiq/data_models/component_ref.py +0 -135
  85. aiq/data_models/config.py +0 -349
  86. aiq/data_models/dataset_handler.py +0 -122
  87. aiq/data_models/discovery_metadata.py +0 -286
  88. aiq/data_models/embedder.py +0 -26
  89. aiq/data_models/evaluate.py +0 -104
  90. aiq/data_models/evaluator.py +0 -26
  91. aiq/data_models/front_end.py +0 -26
  92. aiq/data_models/function.py +0 -30
  93. aiq/data_models/function_dependencies.py +0 -64
  94. aiq/data_models/interactive.py +0 -237
  95. aiq/data_models/intermediate_step.py +0 -269
  96. aiq/data_models/invocation_node.py +0 -38
  97. aiq/data_models/llm.py +0 -26
  98. aiq/data_models/logging.py +0 -26
  99. aiq/data_models/memory.py +0 -26
  100. aiq/data_models/profiler.py +0 -53
  101. aiq/data_models/registry_handler.py +0 -26
  102. aiq/data_models/retriever.py +0 -30
  103. aiq/data_models/step_adaptor.py +0 -64
  104. aiq/data_models/streaming.py +0 -33
  105. aiq/data_models/swe_bench_model.py +0 -54
  106. aiq/data_models/telemetry_exporter.py +0 -26
  107. aiq/embedder/__init__.py +0 -0
  108. aiq/embedder/langchain_client.py +0 -41
  109. aiq/embedder/nim_embedder.py +0 -58
  110. aiq/embedder/openai_embedder.py +0 -42
  111. aiq/embedder/register.py +0 -24
  112. aiq/eval/__init__.py +0 -14
  113. aiq/eval/config.py +0 -42
  114. aiq/eval/dataset_handler/__init__.py +0 -0
  115. aiq/eval/dataset_handler/dataset_downloader.py +0 -106
  116. aiq/eval/dataset_handler/dataset_filter.py +0 -52
  117. aiq/eval/dataset_handler/dataset_handler.py +0 -169
  118. aiq/eval/evaluate.py +0 -325
  119. aiq/eval/evaluator/__init__.py +0 -14
  120. aiq/eval/evaluator/evaluator_model.py +0 -44
  121. aiq/eval/intermediate_step_adapter.py +0 -93
  122. aiq/eval/rag_evaluator/__init__.py +0 -0
  123. aiq/eval/rag_evaluator/evaluate.py +0 -138
  124. aiq/eval/rag_evaluator/register.py +0 -138
  125. aiq/eval/register.py +0 -23
  126. aiq/eval/remote_workflow.py +0 -128
  127. aiq/eval/runtime_event_subscriber.py +0 -52
  128. aiq/eval/swe_bench_evaluator/__init__.py +0 -0
  129. aiq/eval/swe_bench_evaluator/evaluate.py +0 -215
  130. aiq/eval/swe_bench_evaluator/register.py +0 -36
  131. aiq/eval/trajectory_evaluator/__init__.py +0 -0
  132. aiq/eval/trajectory_evaluator/evaluate.py +0 -118
  133. aiq/eval/trajectory_evaluator/register.py +0 -40
  134. aiq/eval/tunable_rag_evaluator/__init__.py +0 -0
  135. aiq/eval/tunable_rag_evaluator/evaluate.py +0 -263
  136. aiq/eval/tunable_rag_evaluator/register.py +0 -50
  137. aiq/eval/utils/__init__.py +0 -0
  138. aiq/eval/utils/output_uploader.py +0 -131
  139. aiq/eval/utils/tqdm_position_registry.py +0 -40
  140. aiq/front_ends/__init__.py +0 -14
  141. aiq/front_ends/console/__init__.py +0 -14
  142. aiq/front_ends/console/console_front_end_config.py +0 -32
  143. aiq/front_ends/console/console_front_end_plugin.py +0 -107
  144. aiq/front_ends/console/register.py +0 -25
  145. aiq/front_ends/cron/__init__.py +0 -14
  146. aiq/front_ends/fastapi/__init__.py +0 -14
  147. aiq/front_ends/fastapi/fastapi_front_end_config.py +0 -150
  148. aiq/front_ends/fastapi/fastapi_front_end_plugin.py +0 -103
  149. aiq/front_ends/fastapi/fastapi_front_end_plugin_worker.py +0 -607
  150. aiq/front_ends/fastapi/intermediate_steps_subscriber.py +0 -80
  151. aiq/front_ends/fastapi/job_store.py +0 -161
  152. aiq/front_ends/fastapi/main.py +0 -70
  153. aiq/front_ends/fastapi/message_handler.py +0 -279
  154. aiq/front_ends/fastapi/message_validator.py +0 -345
  155. aiq/front_ends/fastapi/register.py +0 -25
  156. aiq/front_ends/fastapi/response_helpers.py +0 -195
  157. aiq/front_ends/fastapi/step_adaptor.py +0 -320
  158. aiq/front_ends/fastapi/websocket.py +0 -148
  159. aiq/front_ends/mcp/__init__.py +0 -14
  160. aiq/front_ends/mcp/mcp_front_end_config.py +0 -32
  161. aiq/front_ends/mcp/mcp_front_end_plugin.py +0 -93
  162. aiq/front_ends/mcp/register.py +0 -27
  163. aiq/front_ends/mcp/tool_converter.py +0 -242
  164. aiq/front_ends/register.py +0 -22
  165. aiq/front_ends/simple_base/__init__.py +0 -14
  166. aiq/front_ends/simple_base/simple_front_end_plugin_base.py +0 -52
  167. aiq/llm/__init__.py +0 -0
  168. aiq/llm/nim_llm.py +0 -45
  169. aiq/llm/openai_llm.py +0 -45
  170. aiq/llm/register.py +0 -22
  171. aiq/llm/utils/__init__.py +0 -14
  172. aiq/llm/utils/env_config_value.py +0 -94
  173. aiq/llm/utils/error.py +0 -17
  174. aiq/memory/__init__.py +0 -20
  175. aiq/memory/interfaces.py +0 -183
  176. aiq/memory/models.py +0 -112
  177. aiq/meta/module_to_distro.json +0 -3
  178. aiq/meta/pypi.md +0 -58
  179. aiq/observability/__init__.py +0 -0
  180. aiq/observability/async_otel_listener.py +0 -429
  181. aiq/observability/register.py +0 -99
  182. aiq/plugins/.namespace +0 -1
  183. aiq/profiler/__init__.py +0 -0
  184. aiq/profiler/callbacks/__init__.py +0 -0
  185. aiq/profiler/callbacks/agno_callback_handler.py +0 -295
  186. aiq/profiler/callbacks/base_callback_class.py +0 -20
  187. aiq/profiler/callbacks/langchain_callback_handler.py +0 -278
  188. aiq/profiler/callbacks/llama_index_callback_handler.py +0 -205
  189. aiq/profiler/callbacks/semantic_kernel_callback_handler.py +0 -238
  190. aiq/profiler/callbacks/token_usage_base_model.py +0 -27
  191. aiq/profiler/data_frame_row.py +0 -51
  192. aiq/profiler/decorators/__init__.py +0 -0
  193. aiq/profiler/decorators/framework_wrapper.py +0 -131
  194. aiq/profiler/decorators/function_tracking.py +0 -254
  195. aiq/profiler/forecasting/__init__.py +0 -0
  196. aiq/profiler/forecasting/config.py +0 -18
  197. aiq/profiler/forecasting/model_trainer.py +0 -75
  198. aiq/profiler/forecasting/models/__init__.py +0 -22
  199. aiq/profiler/forecasting/models/forecasting_base_model.py +0 -40
  200. aiq/profiler/forecasting/models/linear_model.py +0 -196
  201. aiq/profiler/forecasting/models/random_forest_regressor.py +0 -268
  202. aiq/profiler/inference_metrics_model.py +0 -25
  203. aiq/profiler/inference_optimization/__init__.py +0 -0
  204. aiq/profiler/inference_optimization/bottleneck_analysis/__init__.py +0 -0
  205. aiq/profiler/inference_optimization/bottleneck_analysis/nested_stack_analysis.py +0 -452
  206. aiq/profiler/inference_optimization/bottleneck_analysis/simple_stack_analysis.py +0 -258
  207. aiq/profiler/inference_optimization/data_models.py +0 -386
  208. aiq/profiler/inference_optimization/experimental/__init__.py +0 -0
  209. aiq/profiler/inference_optimization/experimental/concurrency_spike_analysis.py +0 -468
  210. aiq/profiler/inference_optimization/experimental/prefix_span_analysis.py +0 -405
  211. aiq/profiler/inference_optimization/llm_metrics.py +0 -212
  212. aiq/profiler/inference_optimization/prompt_caching.py +0 -163
  213. aiq/profiler/inference_optimization/token_uniqueness.py +0 -107
  214. aiq/profiler/inference_optimization/workflow_runtimes.py +0 -72
  215. aiq/profiler/intermediate_property_adapter.py +0 -102
  216. aiq/profiler/profile_runner.py +0 -433
  217. aiq/profiler/utils.py +0 -184
  218. aiq/registry_handlers/__init__.py +0 -0
  219. aiq/registry_handlers/local/__init__.py +0 -0
  220. aiq/registry_handlers/local/local_handler.py +0 -176
  221. aiq/registry_handlers/local/register_local.py +0 -37
  222. aiq/registry_handlers/metadata_factory.py +0 -60
  223. aiq/registry_handlers/package_utils.py +0 -198
  224. aiq/registry_handlers/pypi/__init__.py +0 -0
  225. aiq/registry_handlers/pypi/pypi_handler.py +0 -251
  226. aiq/registry_handlers/pypi/register_pypi.py +0 -40
  227. aiq/registry_handlers/register.py +0 -21
  228. aiq/registry_handlers/registry_handler_base.py +0 -157
  229. aiq/registry_handlers/rest/__init__.py +0 -0
  230. aiq/registry_handlers/rest/register_rest.py +0 -56
  231. aiq/registry_handlers/rest/rest_handler.py +0 -237
  232. aiq/registry_handlers/schemas/__init__.py +0 -0
  233. aiq/registry_handlers/schemas/headers.py +0 -42
  234. aiq/registry_handlers/schemas/package.py +0 -68
  235. aiq/registry_handlers/schemas/publish.py +0 -63
  236. aiq/registry_handlers/schemas/pull.py +0 -82
  237. aiq/registry_handlers/schemas/remove.py +0 -36
  238. aiq/registry_handlers/schemas/search.py +0 -91
  239. aiq/registry_handlers/schemas/status.py +0 -47
  240. aiq/retriever/__init__.py +0 -0
  241. aiq/retriever/interface.py +0 -37
  242. aiq/retriever/milvus/__init__.py +0 -14
  243. aiq/retriever/milvus/register.py +0 -81
  244. aiq/retriever/milvus/retriever.py +0 -228
  245. aiq/retriever/models.py +0 -74
  246. aiq/retriever/nemo_retriever/__init__.py +0 -14
  247. aiq/retriever/nemo_retriever/register.py +0 -60
  248. aiq/retriever/nemo_retriever/retriever.py +0 -190
  249. aiq/retriever/register.py +0 -22
  250. aiq/runtime/__init__.py +0 -14
  251. aiq/runtime/loader.py +0 -188
  252. aiq/runtime/runner.py +0 -176
  253. aiq/runtime/session.py +0 -140
  254. aiq/runtime/user_metadata.py +0 -131
  255. aiq/settings/__init__.py +0 -0
  256. aiq/settings/global_settings.py +0 -318
  257. aiq/test/.namespace +0 -1
  258. aiq/tool/__init__.py +0 -0
  259. aiq/tool/code_execution/__init__.py +0 -0
  260. aiq/tool/code_execution/code_sandbox.py +0 -188
  261. aiq/tool/code_execution/local_sandbox/Dockerfile.sandbox +0 -60
  262. aiq/tool/code_execution/local_sandbox/__init__.py +0 -13
  263. aiq/tool/code_execution/local_sandbox/local_sandbox_server.py +0 -83
  264. aiq/tool/code_execution/local_sandbox/sandbox.requirements.txt +0 -4
  265. aiq/tool/code_execution/local_sandbox/start_local_sandbox.sh +0 -25
  266. aiq/tool/code_execution/register.py +0 -70
  267. aiq/tool/code_execution/utils.py +0 -100
  268. aiq/tool/datetime_tools.py +0 -42
  269. aiq/tool/document_search.py +0 -141
  270. aiq/tool/github_tools/__init__.py +0 -0
  271. aiq/tool/github_tools/create_github_commit.py +0 -133
  272. aiq/tool/github_tools/create_github_issue.py +0 -87
  273. aiq/tool/github_tools/create_github_pr.py +0 -106
  274. aiq/tool/github_tools/get_github_file.py +0 -106
  275. aiq/tool/github_tools/get_github_issue.py +0 -166
  276. aiq/tool/github_tools/get_github_pr.py +0 -256
  277. aiq/tool/github_tools/update_github_issue.py +0 -100
  278. aiq/tool/mcp/__init__.py +0 -14
  279. aiq/tool/mcp/mcp_client.py +0 -220
  280. aiq/tool/mcp/mcp_tool.py +0 -95
  281. aiq/tool/memory_tools/__init__.py +0 -0
  282. aiq/tool/memory_tools/add_memory_tool.py +0 -79
  283. aiq/tool/memory_tools/delete_memory_tool.py +0 -67
  284. aiq/tool/memory_tools/get_memory_tool.py +0 -72
  285. aiq/tool/nvidia_rag.py +0 -95
  286. aiq/tool/register.py +0 -37
  287. aiq/tool/retriever.py +0 -89
  288. aiq/tool/server_tools.py +0 -63
  289. aiq/utils/__init__.py +0 -0
  290. aiq/utils/data_models/__init__.py +0 -0
  291. aiq/utils/data_models/schema_validator.py +0 -58
  292. aiq/utils/debugging_utils.py +0 -43
  293. aiq/utils/exception_handlers/__init__.py +0 -0
  294. aiq/utils/exception_handlers/schemas.py +0 -114
  295. aiq/utils/io/__init__.py +0 -0
  296. aiq/utils/io/yaml_tools.py +0 -119
  297. aiq/utils/metadata_utils.py +0 -74
  298. aiq/utils/optional_imports.py +0 -142
  299. aiq/utils/producer_consumer_queue.py +0 -178
  300. aiq/utils/reactive/__init__.py +0 -0
  301. aiq/utils/reactive/base/__init__.py +0 -0
  302. aiq/utils/reactive/base/observable_base.py +0 -65
  303. aiq/utils/reactive/base/observer_base.py +0 -55
  304. aiq/utils/reactive/base/subject_base.py +0 -79
  305. aiq/utils/reactive/observable.py +0 -59
  306. aiq/utils/reactive/observer.py +0 -76
  307. aiq/utils/reactive/subject.py +0 -131
  308. aiq/utils/reactive/subscription.py +0 -49
  309. aiq/utils/settings/__init__.py +0 -0
  310. aiq/utils/settings/global_settings.py +0 -197
  311. aiq/utils/type_converter.py +0 -232
  312. aiq/utils/type_utils.py +0 -397
  313. aiq/utils/url_utils.py +0 -27
  314. aiqtoolkit-1.1.0rc6.dist-info/METADATA +0 -331
  315. aiqtoolkit-1.1.0rc6.dist-info/RECORD +0 -316
  316. aiqtoolkit-1.1.0rc6.dist-info/entry_points.txt +0 -17
  317. aiqtoolkit-1.1.0rc6.dist-info/licenses/LICENSE-3rd-party.txt +0 -3686
  318. aiqtoolkit-1.1.0rc6.dist-info/licenses/LICENSE.md +0 -201
  319. aiqtoolkit-1.1.0rc6.dist-info/top_level.txt +0 -1
@@ -1,131 +0,0 @@
1
- # SPDX-FileCopyrightText: Copyright (c) 2025, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2
- # SPDX-License-Identifier: Apache-2.0
3
- #
4
- # Licensed under the Apache License, Version 2.0 (the "License");
5
- # you may not use this file except in compliance with the License.
6
- # You may obtain a copy of the License at
7
- #
8
- # http://www.apache.org/licenses/LICENSE-2.0
9
- #
10
- # Unless required by applicable law or agreed to in writing, software
11
- # distributed under the License is distributed on an "AS IS" BASIS,
12
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
- # See the License for the specific language governing permissions and
14
- # limitations under the License.
15
-
16
- import threading
17
- from collections.abc import Callable
18
- from typing import TypeVar
19
-
20
- from aiq.utils.reactive.base.subject_base import SubjectBase
21
- from aiq.utils.reactive.observable import Observable
22
- from aiq.utils.reactive.observer import Observer
23
- from aiq.utils.reactive.subscription import Subscription
24
-
25
- T = TypeVar("T")
26
-
27
- OnNext = Callable[[T], None]
28
- OnError = Callable[[Exception], None]
29
- OnComplete = Callable[[], None]
30
-
31
-
32
- class Subject(Observable[T], Observer[T], SubjectBase[T]):
33
- """
34
- A Subject is both an Observer (receives events) and an Observable (sends events).
35
- - Maintains a list of ObserverBase[T].
36
- - No internal buffering or replay; events are only delivered to current subscribers.
37
- - Thread-safe via a lock.
38
-
39
- Once on_error or on_complete is called, the Subject is closed.
40
- """
41
-
42
- def __init__(self) -> None:
43
- super().__init__()
44
- self._lock = threading.RLock()
45
- self._closed = False
46
- self._error: Exception | None = None
47
- self._observers: list[Observer[T]] = []
48
- self._disposed = False
49
-
50
- # ==========================================================================
51
- # Observable[T] - for consumers
52
- # ==========================================================================
53
- def _subscribe_core(self, observer: Observer[T]) -> Subscription:
54
- """
55
- Subscribe to this subject. If disposed, returns a dummy subscription.
56
- Otherwise, registers the given observer.
57
- """
58
- with self._lock:
59
- if self._disposed:
60
- # Already disposed => no subscription
61
- return Subscription(self, None)
62
-
63
- self._observers.append(observer)
64
- return Subscription(self, observer)
65
-
66
- # ==========================================================================
67
- # ObserverBase[T] - for producers
68
- # ==========================================================================
69
- def on_next(self, value: T) -> None:
70
- """
71
- Called by producers to emit an item. Delivers synchronously to each observer.
72
- If closed or disposed, do nothing.
73
- """
74
- with self._lock:
75
- if self._closed or self._disposed:
76
- return
77
- # Copy the current observers to avoid mutation issues
78
- current_observers = list(self._observers)
79
-
80
- # Deliver outside the lock
81
- for obs in current_observers:
82
- obs.on_next(value)
83
-
84
- def on_error(self, exc: Exception) -> None:
85
- """
86
- Called by producers to signal an error. Notifies all observers.
87
- """
88
- with self._lock:
89
- if self._closed or self._disposed:
90
- return
91
- current_obs = list(self._observers)
92
-
93
- for obs in current_obs:
94
- obs.on_error(exc)
95
-
96
- def on_complete(self) -> None:
97
- """
98
- Called by producers to signal completion. Notifies all observers, then
99
- clears them. Subject is closed.
100
- """
101
- with self._lock:
102
- if self._closed or self._disposed:
103
- return
104
- current_observers = list(self._observers)
105
- self.dispose()
106
-
107
- for obs in current_observers:
108
- obs.on_complete()
109
-
110
- # ==========================================================================
111
- # SubjectBase - internal unsubscribing
112
- # ==========================================================================
113
- def _unsubscribe_observer(self, observer: Observer[T]) -> None:
114
- with self._lock:
115
- if not self._disposed and observer in self._observers:
116
- self._observers.remove(observer)
117
-
118
- # ==========================================================================
119
- # Disposal
120
- # ==========================================================================
121
- def dispose(self) -> None:
122
- """
123
- Immediately close the Subject. No future on_next, on_error, or on_complete.
124
- Clears all observers.
125
- """
126
- with self._lock:
127
- if not self._disposed:
128
- self._disposed = True
129
- self._observers.clear()
130
- self._closed = True
131
- self._error = None
@@ -1,49 +0,0 @@
1
- # SPDX-FileCopyrightText: Copyright (c) 2025, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2
- # SPDX-License-Identifier: Apache-2.0
3
- #
4
- # Licensed under the Apache License, Version 2.0 (the "License");
5
- # you may not use this file except in compliance with the License.
6
- # You may obtain a copy of the License at
7
- #
8
- # http://www.apache.org/licenses/LICENSE-2.0
9
- #
10
- # Unless required by applicable law or agreed to in writing, software
11
- # distributed under the License is distributed on an "AS IS" BASIS,
12
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
- # See the License for the specific language governing permissions and
14
- # limitations under the License.
15
-
16
- import typing
17
- from collections.abc import Callable
18
- from typing import Generic
19
- from typing import TypeVar
20
-
21
- if typing.TYPE_CHECKING:
22
- from aiq.utils.reactive.base.subject_base import SubjectBase
23
-
24
- _T = TypeVar("_T") # pylint: disable=invalid-name
25
-
26
- OnNext = Callable[[_T], None]
27
- OnError = Callable[[Exception], None]
28
- OnComplete = Callable[[], None]
29
-
30
-
31
- class Subscription(Generic[_T]):
32
- """
33
- Represents a subscription to a Subject.
34
- Unsubscribing removes the associated observer from the Subject's subscriber list.
35
- """
36
-
37
- def __init__(self, subject: "SubjectBase", observer: object | None): # noqa: F821
38
- self._subject = subject
39
- self._observer = observer
40
- self._unsubscribed = False
41
-
42
- def unsubscribe(self) -> None:
43
- """
44
- Stop receiving further events.
45
- """
46
- if not self._unsubscribed and self._observer is not None:
47
- self._subject._unsubscribe_observer(self._observer)
48
- self._observer = None
49
- self._unsubscribed = True
File without changes
@@ -1,197 +0,0 @@
1
- # SPDX-FileCopyrightText: Copyright (c) 2025, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2
- # SPDX-License-Identifier: Apache-2.0
3
- #
4
- # Licensed under the Apache License, Version 2.0 (the "License");
5
- # you may not use this file except in compliance with the License.
6
- # You may obtain a copy of the License at
7
- #
8
- # http://www.apache.org/licenses/LICENSE-2.0
9
- #
10
- # Unless required by applicable law or agreed to in writing, software
11
- # distributed under the License is distributed on an "AS IS" BASIS,
12
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
- # See the License for the specific language governing permissions and
14
- # limitations under the License.
15
-
16
- import logging
17
-
18
- from pydantic import create_model
19
-
20
- from aiq.cli.type_registry import GlobalTypeRegistry
21
- from aiq.data_models.registry_handler import RegistryHandlerBaseConfig
22
- from aiq.settings.global_settings import GlobalSettings
23
-
24
- logger = logging.getLogger(__name__)
25
-
26
-
27
- def configure_registry_channel(config_type: RegistryHandlerBaseConfig, channel_name: str) -> None:
28
- """Perform channel updates, gathering input from user and validatinig against the global settings data model.
29
-
30
- Args:
31
- config_type (RegistryHandlerBaseConfig): The registry handler configuration object to ensure valid channel
32
- settings
33
- channel_name (str): The name to use to reference the remote registry channel.
34
- """
35
-
36
- settings = GlobalSettings.get()
37
-
38
- channel_registry_pre = {}
39
-
40
- for field, info in config_type.model_fields.items():
41
-
42
- if (field == "type"):
43
- continue
44
-
45
- while (True):
46
- human_prompt = " ".join(field.title().split("_"))
47
- user_input = input(f"{human_prompt}: ")
48
- model_fields = {}
49
- model_fields[field] = (info.annotation, ...)
50
- DynamicFieldModel = create_model("DynamicFieldModel", **model_fields) # pylint: disable=C0103
51
- dynamic_inputs = {field: user_input}
52
-
53
- try:
54
- validated_field_model = DynamicFieldModel(**dynamic_inputs)
55
- channel_registry_pre[field] = getattr(validated_field_model, field)
56
- break
57
- except Exception as e:
58
- logger.exception(e, exc_info=True)
59
- logger.warning("Invalid '%s' input, input must be of type %s.", field, info.annotation)
60
-
61
- validated_model = config_type(**channel_registry_pre)
62
- settings_dict = settings.model_dump(serialize_as_any=True, by_alias=True)
63
- settings_dict["channels"] = {**settings_dict["channels"], **{channel_name: validated_model}}
64
-
65
- settings.update_settings(config_obj=settings_dict)
66
-
67
-
68
- def add_channel_interative(channel_type: str) -> None:
69
- """Add a remote registry channel to publish/search/pull AIQ Toolkit plugin packages.
70
-
71
- Args:
72
- channel_type (str): They type of channel to configure.
73
- """
74
-
75
- settings = GlobalSettings.get()
76
- registry = GlobalTypeRegistry.get()
77
-
78
- try:
79
- ChannelConfigType = registry.get_registered_channel_info_by_channel_type( # pylint: disable=C0103
80
- channel_type=channel_type).config_type
81
- except Exception as e:
82
- logger.exception("Invalid channel type: %s", e, exc_info=True)
83
- return
84
-
85
- while (True):
86
- channel_name = input("Channel Name: ").strip()
87
- if len(channel_name) < 1:
88
- logger.warning("Invalid channel name, cannot be empty or whitespace.")
89
- if (channel_name in settings.channels):
90
- logger.warning("Channel name '%s' already exists, choose a different name.", channel_name)
91
- else:
92
- settings.channels[channel_name] = {}
93
- break
94
-
95
- ChannelConfigType = registry.get_registered_channel_info_by_channel_type( # pylint: disable=C0103
96
- channel_type=channel_type).config_type
97
-
98
- configure_registry_channel(config_type=ChannelConfigType, channel_name=channel_name)
99
-
100
-
101
- def get_existing_channel_interactive(channel_name: str) -> tuple[str, bool]:
102
- """Retrieve an existing channel by configured name.
103
-
104
- Args:
105
- channel_name (str): The name to use to reference the remote registry channel.
106
-
107
- Returns:
108
- tuple[str, bool]: A tuple containing the retrieved channel name and a boolean representing a
109
- valid match was or was not successful.
110
- """
111
-
112
- settings = GlobalSettings.get()
113
- valid_channel = False
114
- remote_channels = settings.channels
115
-
116
- if (len(remote_channels) == 0):
117
- logger.warning("No are configured channels to remove.")
118
- return channel_name, valid_channel
119
-
120
- while (not valid_channel):
121
-
122
- if (channel_name not in remote_channels):
123
- logger.warning("Channel name '%s' does not exist, choose a name from %s",
124
- channel_name,
125
- settings.channel_names)
126
- channel_name = input("Channel Name: ").strip()
127
- continue
128
-
129
- valid_channel = True
130
-
131
- return channel_name, valid_channel
132
-
133
-
134
- def remove_channel(channel_name: str) -> None:
135
- """Remove a configured registry channel from the global settings.
136
-
137
- Args:
138
- channel_name (str): The name to use to reference the remote registry channel.
139
- """
140
-
141
- settings = GlobalSettings.get()
142
- settings_dict = settings.model_dump(serialize_as_any=True, by_alias=True).copy()
143
- settings_dict["channels"].pop(channel_name)
144
- settings.update_settings(config_obj=settings_dict)
145
-
146
-
147
- def remove_channel_interactive(channel_name: str) -> None:
148
- channel_name, valid_channel = get_existing_channel_interactive(channel_name=channel_name)
149
- if (not valid_channel):
150
- return
151
- remove_channel(channel_name=channel_name)
152
-
153
-
154
- def match_valid_channel(channel_name: str) -> None:
155
- """Performs a match by registry channel to perform a channel configuration update.
156
-
157
- Args:
158
- channel_name (str): The name to use to reference the remote registry channel.
159
- """
160
-
161
- settings = GlobalSettings.get()
162
- registry = GlobalTypeRegistry.get()
163
-
164
- if len(settings.channel_names) == 0:
165
- logger.warning("No channels have been configured, first add a channel.")
166
- return
167
-
168
- if (channel_name not in settings.channel_names):
169
- logger.warning("Provided channel has not yet been configured, choose a different name "
170
- "from %s .",
171
- settings.channel_names)
172
- while (True):
173
- channel_name = input("Channel Name: ").strip()
174
- if len(channel_name) < 1:
175
- logger.warning("Invalid channel name, cannot be empty or whitespace.")
176
- if (channel_name in settings.channel_names):
177
- logger.warning("Channel name '%s' already exists, choose a different name.", channel_name)
178
- else:
179
- settings.channels[channel_name] = {}
180
- break
181
-
182
- channals_settings = settings.channels
183
- channel_settings = channals_settings.get(channel_name)
184
- ChannelConfigType = registry.get_registered_channel_info_by_channel_type( # pylint: disable=C0103
185
- channel_type=channel_settings.static_type()).config_type
186
-
187
- configure_registry_channel(config_type=ChannelConfigType, channel_name=channel_name)
188
-
189
-
190
- def update_channel_interactive(channel_name: str):
191
- """Launch an interactive session to update a configured channels settings.
192
-
193
- Args:
194
- channel_name (str): The name to use to reference the remote registry channel.
195
- """
196
-
197
- match_valid_channel(channel_name=channel_name)
@@ -1,232 +0,0 @@
1
- # SPDX-FileCopyrightText: Copyright (c) 2024-2025, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2
- # SPDX-License-Identifier: Apache-2.0
3
- #
4
- # Licensed under the Apache License, Version 2.0 (the "License");
5
- # you may not use this file except in compliance with the License.
6
- # You may obtain a copy of the License at
7
- #
8
- # http://www.apache.org/licenses/LICENSE-2.0
9
- #
10
- # Unless required by applicable law or agreed to in writing, software
11
- # distributed under the License is distributed on an "AS IS" BASIS,
12
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
- # See the License for the specific language governing permissions and
14
- # limitations under the License.
15
-
16
- import logging
17
- import typing
18
- from collections import OrderedDict
19
- from collections.abc import Callable
20
- from io import TextIOWrapper
21
-
22
- from aiq.utils.type_utils import DecomposedType
23
-
24
- logger = logging.getLogger(__name__)
25
-
26
- _T = typing.TypeVar("_T")
27
-
28
-
29
- class ConvertException(Exception):
30
- pass
31
-
32
-
33
- class TypeConverter:
34
- _global_initialized = False
35
-
36
- def __init__(self, converters: list[Callable[[typing.Any], typing.Any]], parent: "TypeConverter | None" = None):
37
- """
38
- :param converters: A list of single-argument converter callables
39
- annotated with their input param and return type.
40
- :param parent: An optional parent TypeConverter for fallback.
41
- """
42
- # dict[to_type, dict[from_type, converter]]
43
- self._converters: OrderedDict[type, OrderedDict[type, Callable]] = OrderedDict()
44
- self._indirect_warnings_shown: set[tuple[type, type]] = set()
45
-
46
- for converter in converters:
47
- self.add_converter(converter)
48
-
49
- if parent is None and TypeConverter._global_initialized:
50
- parent = GlobalTypeConverter.get()
51
- self._parent = parent
52
-
53
- def add_converter(self, converter: Callable) -> None:
54
- """
55
- Registers a converter. Must have exactly one parameter
56
- and an annotated return type.
57
- """
58
- sig = typing.get_type_hints(converter)
59
- to_type = sig.pop("return", None)
60
- if to_type is None:
61
- raise ValueError("Converter must have a return type.")
62
-
63
- if len(sig) != 1:
64
- raise ValueError("Converter must have exactly one argument.")
65
-
66
- from_type = next(iter(sig.values()))
67
- if from_type is None:
68
- raise ValueError("Converter's argument must have a data type.")
69
-
70
- self._converters.setdefault(to_type, OrderedDict())[from_type] = converter
71
- # to do(MDD): If needed, sort by specificity here.
72
-
73
- def try_convert(self, data, to_type: type[_T]) -> _T | None:
74
- """
75
- Attempts to convert `data` into `to_type`. Returns None if no path is found.
76
- """
77
- decomposed = DecomposedType(to_type)
78
-
79
- # 1) If data is already correct type, return it
80
- if to_type is None or decomposed.is_instance((data, to_type)):
81
- return data
82
-
83
- root = decomposed.root
84
-
85
- # 2) Attempt direct in *this* converter
86
- direct_result = self._try_direct_conversion(data, root)
87
- if direct_result is not None:
88
- return direct_result
89
-
90
- # 3) If direct fails entirely, do indirect in *this* converter
91
- indirect_result = self._try_indirect_convert(data, to_type)
92
- if indirect_result is not None:
93
- return indirect_result
94
-
95
- # 4) If we still haven't succeeded, return None
96
- return None
97
-
98
- def convert(self, data, to_type: type[_T]) -> _T:
99
- """
100
- Converts or raises ValueError if no path is found.
101
- We also give the parent a chance if self fails.
102
- """
103
- result = self.try_convert(data, to_type)
104
- if result is None and self._parent:
105
- # fallback on parent entirely
106
- return self._parent.convert(data, to_type)
107
-
108
- if result is not None:
109
- return result
110
- raise ValueError(f"Cannot convert type {type(data)} to {to_type}. No match found.")
111
-
112
- # -------------------------------------------------
113
- # INTERNAL DIRECT CONVERSION (with parent fallback)
114
- # -------------------------------------------------
115
- def _try_direct_conversion(self, data, target_root_type: type) -> typing.Any | None:
116
- """
117
- Tries direct conversion in *this* converter's registry.
118
- If no match here, we forward to parent's direct conversion
119
- for recursion up the chain.
120
- """
121
- for convert_to_type, to_type_converters in self._converters.items():
122
- # e.g. if Derived is a subclass of Base, this is valid
123
- if issubclass(DecomposedType(convert_to_type).root, target_root_type):
124
- for convert_from_type, from_type_converter in to_type_converters.items():
125
- if isinstance(data, DecomposedType(convert_from_type).root):
126
- try:
127
- return from_type_converter(data)
128
- except ConvertException:
129
- pass
130
-
131
- # If we can't convert directly here, try parent
132
- if self._parent is not None:
133
- return self._parent._try_direct_conversion(data, target_root_type)
134
-
135
- return None
136
-
137
- # -------------------------------------------------
138
- # INTERNAL INDIRECT CONVERSION (with parent fallback)
139
- # -------------------------------------------------
140
- def _try_indirect_convert(self, data, to_type: type[_T]) -> _T | None:
141
- """
142
- Attempt indirect conversion (DFS) in *this* converter.
143
- If no success, fallback to parent's indirect attempt.
144
- """
145
- visited = set()
146
- final = self._try_indirect_conversion(data, to_type, visited)
147
- if final is not None:
148
- # Warn once if found a chain
149
- self._maybe_warn_indirect(type(data), to_type)
150
- return final
151
-
152
- # If no success, try parent's indirect
153
- if self._parent is not None:
154
- parent_final = self._parent._try_indirect_convert(data, to_type)
155
- if parent_final is not None:
156
- self._maybe_warn_indirect(type(data), to_type)
157
- return parent_final
158
-
159
- return None
160
-
161
- def _try_indirect_conversion(self, data: typing.Any, to_type: type[_T], visited: set[type]) -> _T | None:
162
- """
163
- DFS attempt to find a chain of conversions from type(data) to to_type,
164
- ignoring parent. If not found, returns None.
165
- """
166
- # 1) If data is already correct type
167
- if isinstance(data, to_type):
168
- return data
169
-
170
- current_type = type(data)
171
- if current_type in visited:
172
- return None
173
-
174
- visited.add(current_type)
175
-
176
- # 2) Attempt each known converter from current_type -> ???, then recurse
177
- for _, to_type_converters in self._converters.items():
178
- for convert_from_type, from_type_converter in to_type_converters.items():
179
- if isinstance(data, convert_from_type):
180
- try:
181
- next_data = from_type_converter(data)
182
- if isinstance(next_data, to_type):
183
- return next_data
184
- # else keep going
185
- deeper = self._try_indirect_conversion(next_data, to_type, visited)
186
- if deeper is not None:
187
- return deeper
188
- except ConvertException:
189
- pass
190
-
191
- return None
192
-
193
- def _maybe_warn_indirect(self, source_type: type, to_type: type):
194
- """
195
- Warn once if an indirect path was used between these two types.
196
- """
197
- pair = (source_type, to_type)
198
- if pair not in self._indirect_warnings_shown:
199
- logger.warning(
200
- "Indirect type conversion used to convert %s to %s, which may lead to unintended conversions. "
201
- "Consider adding a direct converter from %s to %s to ensure correctness.",
202
- source_type,
203
- to_type,
204
- source_type,
205
- to_type)
206
- self._indirect_warnings_shown.add(pair)
207
-
208
-
209
- class GlobalTypeConverter:
210
- _global_converter: TypeConverter = TypeConverter([])
211
-
212
- @staticmethod
213
- def get() -> TypeConverter:
214
- return GlobalTypeConverter._global_converter
215
-
216
- @staticmethod
217
- def register_converter(converter: Callable) -> None:
218
- GlobalTypeConverter._global_converter.add_converter(converter)
219
-
220
- @staticmethod
221
- def convert(data, to_type: type[_T]) -> _T:
222
- return GlobalTypeConverter._global_converter.convert(data, to_type)
223
-
224
-
225
- TypeConverter._global_initialized = True
226
-
227
-
228
- def _text_io_wrapper_to_string(data: TextIOWrapper) -> str:
229
- return data.read()
230
-
231
-
232
- GlobalTypeConverter.register_converter(_text_io_wrapper_to_string)