aiqtoolkit 1.1.0a20250429__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 (309) hide show
  1. aiq/agent/__init__.py +0 -0
  2. aiq/agent/base.py +76 -0
  3. aiq/agent/dual_node.py +67 -0
  4. aiq/agent/react_agent/__init__.py +0 -0
  5. aiq/agent/react_agent/agent.py +322 -0
  6. aiq/agent/react_agent/output_parser.py +104 -0
  7. aiq/agent/react_agent/prompt.py +46 -0
  8. aiq/agent/react_agent/register.py +148 -0
  9. aiq/agent/reasoning_agent/__init__.py +0 -0
  10. aiq/agent/reasoning_agent/reasoning_agent.py +224 -0
  11. aiq/agent/register.py +23 -0
  12. aiq/agent/rewoo_agent/__init__.py +0 -0
  13. aiq/agent/rewoo_agent/agent.py +410 -0
  14. aiq/agent/rewoo_agent/prompt.py +108 -0
  15. aiq/agent/rewoo_agent/register.py +158 -0
  16. aiq/agent/tool_calling_agent/__init__.py +0 -0
  17. aiq/agent/tool_calling_agent/agent.py +123 -0
  18. aiq/agent/tool_calling_agent/register.py +105 -0
  19. aiq/builder/__init__.py +0 -0
  20. aiq/builder/builder.py +223 -0
  21. aiq/builder/component_utils.py +303 -0
  22. aiq/builder/context.py +198 -0
  23. aiq/builder/embedder.py +24 -0
  24. aiq/builder/eval_builder.py +116 -0
  25. aiq/builder/evaluator.py +29 -0
  26. aiq/builder/framework_enum.py +24 -0
  27. aiq/builder/front_end.py +73 -0
  28. aiq/builder/function.py +297 -0
  29. aiq/builder/function_base.py +372 -0
  30. aiq/builder/function_info.py +627 -0
  31. aiq/builder/intermediate_step_manager.py +125 -0
  32. aiq/builder/llm.py +25 -0
  33. aiq/builder/retriever.py +25 -0
  34. aiq/builder/user_interaction_manager.py +71 -0
  35. aiq/builder/workflow.py +134 -0
  36. aiq/builder/workflow_builder.py +733 -0
  37. aiq/cli/__init__.py +14 -0
  38. aiq/cli/cli_utils/__init__.py +0 -0
  39. aiq/cli/cli_utils/config_override.py +233 -0
  40. aiq/cli/cli_utils/validation.py +37 -0
  41. aiq/cli/commands/__init__.py +0 -0
  42. aiq/cli/commands/configure/__init__.py +0 -0
  43. aiq/cli/commands/configure/channel/__init__.py +0 -0
  44. aiq/cli/commands/configure/channel/add.py +28 -0
  45. aiq/cli/commands/configure/channel/channel.py +34 -0
  46. aiq/cli/commands/configure/channel/remove.py +30 -0
  47. aiq/cli/commands/configure/channel/update.py +30 -0
  48. aiq/cli/commands/configure/configure.py +33 -0
  49. aiq/cli/commands/evaluate.py +139 -0
  50. aiq/cli/commands/info/__init__.py +14 -0
  51. aiq/cli/commands/info/info.py +37 -0
  52. aiq/cli/commands/info/list_channels.py +32 -0
  53. aiq/cli/commands/info/list_components.py +129 -0
  54. aiq/cli/commands/registry/__init__.py +14 -0
  55. aiq/cli/commands/registry/publish.py +88 -0
  56. aiq/cli/commands/registry/pull.py +118 -0
  57. aiq/cli/commands/registry/registry.py +36 -0
  58. aiq/cli/commands/registry/remove.py +108 -0
  59. aiq/cli/commands/registry/search.py +155 -0
  60. aiq/cli/commands/start.py +250 -0
  61. aiq/cli/commands/uninstall.py +83 -0
  62. aiq/cli/commands/validate.py +47 -0
  63. aiq/cli/commands/workflow/__init__.py +14 -0
  64. aiq/cli/commands/workflow/templates/__init__.py.j2 +0 -0
  65. aiq/cli/commands/workflow/templates/config.yml.j2 +16 -0
  66. aiq/cli/commands/workflow/templates/pyproject.toml.j2 +22 -0
  67. aiq/cli/commands/workflow/templates/register.py.j2 +5 -0
  68. aiq/cli/commands/workflow/templates/workflow.py.j2 +36 -0
  69. aiq/cli/commands/workflow/workflow.py +37 -0
  70. aiq/cli/commands/workflow/workflow_commands.py +307 -0
  71. aiq/cli/entrypoint.py +133 -0
  72. aiq/cli/main.py +44 -0
  73. aiq/cli/register_workflow.py +408 -0
  74. aiq/cli/type_registry.py +869 -0
  75. aiq/data_models/__init__.py +14 -0
  76. aiq/data_models/api_server.py +550 -0
  77. aiq/data_models/common.py +143 -0
  78. aiq/data_models/component.py +46 -0
  79. aiq/data_models/component_ref.py +135 -0
  80. aiq/data_models/config.py +349 -0
  81. aiq/data_models/dataset_handler.py +122 -0
  82. aiq/data_models/discovery_metadata.py +269 -0
  83. aiq/data_models/embedder.py +26 -0
  84. aiq/data_models/evaluate.py +101 -0
  85. aiq/data_models/evaluator.py +26 -0
  86. aiq/data_models/front_end.py +26 -0
  87. aiq/data_models/function.py +30 -0
  88. aiq/data_models/function_dependencies.py +64 -0
  89. aiq/data_models/interactive.py +237 -0
  90. aiq/data_models/intermediate_step.py +269 -0
  91. aiq/data_models/invocation_node.py +38 -0
  92. aiq/data_models/llm.py +26 -0
  93. aiq/data_models/logging.py +26 -0
  94. aiq/data_models/memory.py +26 -0
  95. aiq/data_models/profiler.py +53 -0
  96. aiq/data_models/registry_handler.py +26 -0
  97. aiq/data_models/retriever.py +30 -0
  98. aiq/data_models/step_adaptor.py +64 -0
  99. aiq/data_models/streaming.py +33 -0
  100. aiq/data_models/swe_bench_model.py +54 -0
  101. aiq/data_models/telemetry_exporter.py +26 -0
  102. aiq/embedder/__init__.py +0 -0
  103. aiq/embedder/langchain_client.py +41 -0
  104. aiq/embedder/nim_embedder.py +58 -0
  105. aiq/embedder/openai_embedder.py +42 -0
  106. aiq/embedder/register.py +24 -0
  107. aiq/eval/__init__.py +14 -0
  108. aiq/eval/config.py +42 -0
  109. aiq/eval/dataset_handler/__init__.py +0 -0
  110. aiq/eval/dataset_handler/dataset_downloader.py +106 -0
  111. aiq/eval/dataset_handler/dataset_filter.py +52 -0
  112. aiq/eval/dataset_handler/dataset_handler.py +164 -0
  113. aiq/eval/evaluate.py +322 -0
  114. aiq/eval/evaluator/__init__.py +14 -0
  115. aiq/eval/evaluator/evaluator_model.py +44 -0
  116. aiq/eval/intermediate_step_adapter.py +93 -0
  117. aiq/eval/rag_evaluator/__init__.py +0 -0
  118. aiq/eval/rag_evaluator/evaluate.py +138 -0
  119. aiq/eval/rag_evaluator/register.py +138 -0
  120. aiq/eval/register.py +22 -0
  121. aiq/eval/remote_workflow.py +128 -0
  122. aiq/eval/runtime_event_subscriber.py +52 -0
  123. aiq/eval/swe_bench_evaluator/__init__.py +0 -0
  124. aiq/eval/swe_bench_evaluator/evaluate.py +215 -0
  125. aiq/eval/swe_bench_evaluator/register.py +36 -0
  126. aiq/eval/trajectory_evaluator/__init__.py +0 -0
  127. aiq/eval/trajectory_evaluator/evaluate.py +118 -0
  128. aiq/eval/trajectory_evaluator/register.py +40 -0
  129. aiq/eval/utils/__init__.py +0 -0
  130. aiq/eval/utils/output_uploader.py +131 -0
  131. aiq/eval/utils/tqdm_position_registry.py +40 -0
  132. aiq/front_ends/__init__.py +14 -0
  133. aiq/front_ends/console/__init__.py +14 -0
  134. aiq/front_ends/console/console_front_end_config.py +32 -0
  135. aiq/front_ends/console/console_front_end_plugin.py +107 -0
  136. aiq/front_ends/console/register.py +25 -0
  137. aiq/front_ends/cron/__init__.py +14 -0
  138. aiq/front_ends/fastapi/__init__.py +14 -0
  139. aiq/front_ends/fastapi/fastapi_front_end_config.py +150 -0
  140. aiq/front_ends/fastapi/fastapi_front_end_plugin.py +103 -0
  141. aiq/front_ends/fastapi/fastapi_front_end_plugin_worker.py +574 -0
  142. aiq/front_ends/fastapi/intermediate_steps_subscriber.py +80 -0
  143. aiq/front_ends/fastapi/job_store.py +161 -0
  144. aiq/front_ends/fastapi/main.py +70 -0
  145. aiq/front_ends/fastapi/message_handler.py +279 -0
  146. aiq/front_ends/fastapi/message_validator.py +345 -0
  147. aiq/front_ends/fastapi/register.py +25 -0
  148. aiq/front_ends/fastapi/response_helpers.py +181 -0
  149. aiq/front_ends/fastapi/step_adaptor.py +315 -0
  150. aiq/front_ends/fastapi/websocket.py +148 -0
  151. aiq/front_ends/mcp/__init__.py +14 -0
  152. aiq/front_ends/mcp/mcp_front_end_config.py +32 -0
  153. aiq/front_ends/mcp/mcp_front_end_plugin.py +93 -0
  154. aiq/front_ends/mcp/register.py +27 -0
  155. aiq/front_ends/mcp/tool_converter.py +242 -0
  156. aiq/front_ends/register.py +22 -0
  157. aiq/front_ends/simple_base/__init__.py +14 -0
  158. aiq/front_ends/simple_base/simple_front_end_plugin_base.py +52 -0
  159. aiq/llm/__init__.py +0 -0
  160. aiq/llm/nim_llm.py +45 -0
  161. aiq/llm/openai_llm.py +45 -0
  162. aiq/llm/register.py +22 -0
  163. aiq/llm/utils/__init__.py +14 -0
  164. aiq/llm/utils/env_config_value.py +94 -0
  165. aiq/llm/utils/error.py +17 -0
  166. aiq/memory/__init__.py +20 -0
  167. aiq/memory/interfaces.py +183 -0
  168. aiq/memory/models.py +102 -0
  169. aiq/meta/module_to_distro.json +3 -0
  170. aiq/meta/pypi.md +59 -0
  171. aiq/observability/__init__.py +0 -0
  172. aiq/observability/async_otel_listener.py +270 -0
  173. aiq/observability/register.py +97 -0
  174. aiq/plugins/.namespace +1 -0
  175. aiq/profiler/__init__.py +0 -0
  176. aiq/profiler/callbacks/__init__.py +0 -0
  177. aiq/profiler/callbacks/agno_callback_handler.py +295 -0
  178. aiq/profiler/callbacks/base_callback_class.py +20 -0
  179. aiq/profiler/callbacks/langchain_callback_handler.py +278 -0
  180. aiq/profiler/callbacks/llama_index_callback_handler.py +205 -0
  181. aiq/profiler/callbacks/semantic_kernel_callback_handler.py +238 -0
  182. aiq/profiler/callbacks/token_usage_base_model.py +27 -0
  183. aiq/profiler/data_frame_row.py +51 -0
  184. aiq/profiler/decorators/__init__.py +0 -0
  185. aiq/profiler/decorators/framework_wrapper.py +131 -0
  186. aiq/profiler/decorators/function_tracking.py +254 -0
  187. aiq/profiler/forecasting/__init__.py +0 -0
  188. aiq/profiler/forecasting/config.py +18 -0
  189. aiq/profiler/forecasting/model_trainer.py +75 -0
  190. aiq/profiler/forecasting/models/__init__.py +22 -0
  191. aiq/profiler/forecasting/models/forecasting_base_model.py +40 -0
  192. aiq/profiler/forecasting/models/linear_model.py +196 -0
  193. aiq/profiler/forecasting/models/random_forest_regressor.py +268 -0
  194. aiq/profiler/inference_metrics_model.py +25 -0
  195. aiq/profiler/inference_optimization/__init__.py +0 -0
  196. aiq/profiler/inference_optimization/bottleneck_analysis/__init__.py +0 -0
  197. aiq/profiler/inference_optimization/bottleneck_analysis/nested_stack_analysis.py +452 -0
  198. aiq/profiler/inference_optimization/bottleneck_analysis/simple_stack_analysis.py +258 -0
  199. aiq/profiler/inference_optimization/data_models.py +386 -0
  200. aiq/profiler/inference_optimization/experimental/__init__.py +0 -0
  201. aiq/profiler/inference_optimization/experimental/concurrency_spike_analysis.py +468 -0
  202. aiq/profiler/inference_optimization/experimental/prefix_span_analysis.py +405 -0
  203. aiq/profiler/inference_optimization/llm_metrics.py +212 -0
  204. aiq/profiler/inference_optimization/prompt_caching.py +163 -0
  205. aiq/profiler/inference_optimization/token_uniqueness.py +107 -0
  206. aiq/profiler/inference_optimization/workflow_runtimes.py +72 -0
  207. aiq/profiler/intermediate_property_adapter.py +102 -0
  208. aiq/profiler/profile_runner.py +433 -0
  209. aiq/profiler/utils.py +184 -0
  210. aiq/registry_handlers/__init__.py +0 -0
  211. aiq/registry_handlers/local/__init__.py +0 -0
  212. aiq/registry_handlers/local/local_handler.py +176 -0
  213. aiq/registry_handlers/local/register_local.py +37 -0
  214. aiq/registry_handlers/metadata_factory.py +60 -0
  215. aiq/registry_handlers/package_utils.py +198 -0
  216. aiq/registry_handlers/pypi/__init__.py +0 -0
  217. aiq/registry_handlers/pypi/pypi_handler.py +251 -0
  218. aiq/registry_handlers/pypi/register_pypi.py +40 -0
  219. aiq/registry_handlers/register.py +21 -0
  220. aiq/registry_handlers/registry_handler_base.py +157 -0
  221. aiq/registry_handlers/rest/__init__.py +0 -0
  222. aiq/registry_handlers/rest/register_rest.py +56 -0
  223. aiq/registry_handlers/rest/rest_handler.py +237 -0
  224. aiq/registry_handlers/schemas/__init__.py +0 -0
  225. aiq/registry_handlers/schemas/headers.py +42 -0
  226. aiq/registry_handlers/schemas/package.py +68 -0
  227. aiq/registry_handlers/schemas/publish.py +63 -0
  228. aiq/registry_handlers/schemas/pull.py +81 -0
  229. aiq/registry_handlers/schemas/remove.py +36 -0
  230. aiq/registry_handlers/schemas/search.py +91 -0
  231. aiq/registry_handlers/schemas/status.py +47 -0
  232. aiq/retriever/__init__.py +0 -0
  233. aiq/retriever/interface.py +37 -0
  234. aiq/retriever/milvus/__init__.py +14 -0
  235. aiq/retriever/milvus/register.py +81 -0
  236. aiq/retriever/milvus/retriever.py +228 -0
  237. aiq/retriever/models.py +74 -0
  238. aiq/retriever/nemo_retriever/__init__.py +14 -0
  239. aiq/retriever/nemo_retriever/register.py +60 -0
  240. aiq/retriever/nemo_retriever/retriever.py +190 -0
  241. aiq/retriever/register.py +22 -0
  242. aiq/runtime/__init__.py +14 -0
  243. aiq/runtime/loader.py +188 -0
  244. aiq/runtime/runner.py +176 -0
  245. aiq/runtime/session.py +116 -0
  246. aiq/settings/__init__.py +0 -0
  247. aiq/settings/global_settings.py +318 -0
  248. aiq/test/.namespace +1 -0
  249. aiq/tool/__init__.py +0 -0
  250. aiq/tool/code_execution/__init__.py +0 -0
  251. aiq/tool/code_execution/code_sandbox.py +188 -0
  252. aiq/tool/code_execution/local_sandbox/Dockerfile.sandbox +60 -0
  253. aiq/tool/code_execution/local_sandbox/__init__.py +13 -0
  254. aiq/tool/code_execution/local_sandbox/local_sandbox_server.py +79 -0
  255. aiq/tool/code_execution/local_sandbox/sandbox.requirements.txt +4 -0
  256. aiq/tool/code_execution/local_sandbox/start_local_sandbox.sh +25 -0
  257. aiq/tool/code_execution/register.py +70 -0
  258. aiq/tool/code_execution/utils.py +100 -0
  259. aiq/tool/datetime_tools.py +42 -0
  260. aiq/tool/document_search.py +141 -0
  261. aiq/tool/github_tools/__init__.py +0 -0
  262. aiq/tool/github_tools/create_github_commit.py +133 -0
  263. aiq/tool/github_tools/create_github_issue.py +87 -0
  264. aiq/tool/github_tools/create_github_pr.py +106 -0
  265. aiq/tool/github_tools/get_github_file.py +106 -0
  266. aiq/tool/github_tools/get_github_issue.py +166 -0
  267. aiq/tool/github_tools/get_github_pr.py +256 -0
  268. aiq/tool/github_tools/update_github_issue.py +100 -0
  269. aiq/tool/mcp/__init__.py +14 -0
  270. aiq/tool/mcp/mcp_client.py +220 -0
  271. aiq/tool/mcp/mcp_tool.py +75 -0
  272. aiq/tool/memory_tools/__init__.py +0 -0
  273. aiq/tool/memory_tools/add_memory_tool.py +67 -0
  274. aiq/tool/memory_tools/delete_memory_tool.py +67 -0
  275. aiq/tool/memory_tools/get_memory_tool.py +72 -0
  276. aiq/tool/nvidia_rag.py +95 -0
  277. aiq/tool/register.py +36 -0
  278. aiq/tool/retriever.py +89 -0
  279. aiq/utils/__init__.py +0 -0
  280. aiq/utils/data_models/__init__.py +0 -0
  281. aiq/utils/data_models/schema_validator.py +58 -0
  282. aiq/utils/debugging_utils.py +43 -0
  283. aiq/utils/exception_handlers/__init__.py +0 -0
  284. aiq/utils/exception_handlers/schemas.py +114 -0
  285. aiq/utils/io/__init__.py +0 -0
  286. aiq/utils/io/yaml_tools.py +50 -0
  287. aiq/utils/metadata_utils.py +74 -0
  288. aiq/utils/producer_consumer_queue.py +178 -0
  289. aiq/utils/reactive/__init__.py +0 -0
  290. aiq/utils/reactive/base/__init__.py +0 -0
  291. aiq/utils/reactive/base/observable_base.py +65 -0
  292. aiq/utils/reactive/base/observer_base.py +55 -0
  293. aiq/utils/reactive/base/subject_base.py +79 -0
  294. aiq/utils/reactive/observable.py +59 -0
  295. aiq/utils/reactive/observer.py +76 -0
  296. aiq/utils/reactive/subject.py +131 -0
  297. aiq/utils/reactive/subscription.py +49 -0
  298. aiq/utils/settings/__init__.py +0 -0
  299. aiq/utils/settings/global_settings.py +197 -0
  300. aiq/utils/type_converter.py +232 -0
  301. aiq/utils/type_utils.py +397 -0
  302. aiq/utils/url_utils.py +27 -0
  303. aiqtoolkit-1.1.0a20250429.dist-info/METADATA +326 -0
  304. aiqtoolkit-1.1.0a20250429.dist-info/RECORD +309 -0
  305. aiqtoolkit-1.1.0a20250429.dist-info/WHEEL +5 -0
  306. aiqtoolkit-1.1.0a20250429.dist-info/entry_points.txt +17 -0
  307. aiqtoolkit-1.1.0a20250429.dist-info/licenses/LICENSE-3rd-party.txt +3686 -0
  308. aiqtoolkit-1.1.0a20250429.dist-info/licenses/LICENSE.md +201 -0
  309. aiqtoolkit-1.1.0a20250429.dist-info/top_level.txt +1 -0
@@ -0,0 +1,733 @@
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 dataclasses
17
+ import inspect
18
+ import logging
19
+ import warnings
20
+ from contextlib import AbstractAsyncContextManager
21
+ from contextlib import AsyncExitStack
22
+ from contextlib import asynccontextmanager
23
+
24
+ from opentelemetry import trace
25
+ from opentelemetry.sdk.trace import TracerProvider
26
+ from opentelemetry.sdk.trace.export import BatchSpanProcessor
27
+ from opentelemetry.sdk.trace.export import SpanExporter
28
+
29
+ from aiq.builder.builder import Builder
30
+ from aiq.builder.builder import UserManagerHolder
31
+ from aiq.builder.component_utils import build_dependency_sequence
32
+ from aiq.builder.context import AIQContext
33
+ from aiq.builder.context import AIQContextState
34
+ from aiq.builder.embedder import EmbedderProviderInfo
35
+ from aiq.builder.framework_enum import LLMFrameworkEnum
36
+ from aiq.builder.function import Function
37
+ from aiq.builder.function import LambdaFunction
38
+ from aiq.builder.function_info import FunctionInfo
39
+ from aiq.builder.llm import LLMProviderInfo
40
+ from aiq.builder.retriever import RetrieverProviderInfo
41
+ from aiq.builder.workflow import Workflow
42
+ from aiq.cli.type_registry import GlobalTypeRegistry
43
+ from aiq.cli.type_registry import TypeRegistry
44
+ from aiq.data_models.component import ComponentGroup
45
+ from aiq.data_models.component_ref import EmbedderRef
46
+ from aiq.data_models.component_ref import FunctionRef
47
+ from aiq.data_models.component_ref import LLMRef
48
+ from aiq.data_models.component_ref import MemoryRef
49
+ from aiq.data_models.component_ref import RetrieverRef
50
+ from aiq.data_models.config import AIQConfig
51
+ from aiq.data_models.config import GeneralConfig
52
+ from aiq.data_models.embedder import EmbedderBaseConfig
53
+ from aiq.data_models.function import FunctionBaseConfig
54
+ from aiq.data_models.function_dependencies import FunctionDependencies
55
+ from aiq.data_models.llm import LLMBaseConfig
56
+ from aiq.data_models.memory import MemoryBaseConfig
57
+ from aiq.data_models.retriever import RetrieverBaseConfig
58
+ from aiq.data_models.telemetry_exporter import TelemetryExporterBaseConfig
59
+ from aiq.memory.interfaces import MemoryEditor
60
+ from aiq.profiler.decorators.framework_wrapper import chain_wrapped_build_fn
61
+ from aiq.profiler.utils import detect_llm_frameworks_in_build_fn
62
+ from aiq.utils.type_utils import override
63
+
64
+ logger = logging.getLogger(__name__)
65
+
66
+
67
+ @dataclasses.dataclass
68
+ class ConfiguredExporter:
69
+ config: TelemetryExporterBaseConfig
70
+ instance: SpanExporter
71
+
72
+
73
+ @dataclasses.dataclass
74
+ class ConfiguredFunction:
75
+ config: FunctionBaseConfig
76
+ instance: Function
77
+
78
+
79
+ @dataclasses.dataclass
80
+ class ConfiguredLLM:
81
+ config: LLMBaseConfig
82
+ instance: LLMProviderInfo
83
+
84
+
85
+ @dataclasses.dataclass
86
+ class ConfiguredEmbedder:
87
+ config: EmbedderBaseConfig
88
+ instance: EmbedderProviderInfo
89
+
90
+
91
+ @dataclasses.dataclass
92
+ class ConfiguredMemory:
93
+ config: MemoryBaseConfig
94
+ instance: MemoryEditor
95
+
96
+
97
+ @dataclasses.dataclass
98
+ class ConfiguredRetriever:
99
+ config: RetrieverBaseConfig
100
+ instance: RetrieverProviderInfo
101
+
102
+
103
+ # pylint: disable=too-many-public-methods
104
+ class WorkflowBuilder(Builder, AbstractAsyncContextManager):
105
+
106
+ def __init__(self, *, general_config: GeneralConfig | None = None, registry: TypeRegistry | None = None):
107
+
108
+ if general_config is None:
109
+ general_config = GeneralConfig()
110
+
111
+ if registry is None:
112
+ registry = GlobalTypeRegistry.get()
113
+
114
+ self.general_config = general_config
115
+
116
+ self._registry = registry
117
+
118
+ self._logging_handlers: dict[str, logging.Handler] = {}
119
+ self._exporters: dict[str, ConfiguredExporter] = {}
120
+
121
+ self._functions: dict[str, ConfiguredFunction] = {}
122
+ self._workflow: ConfiguredFunction | None = None
123
+
124
+ self._llms: dict[str, ConfiguredLLM] = {}
125
+ self._embedders: dict[str, ConfiguredEmbedder] = {}
126
+ self._memory_clients: dict[str, ConfiguredMemory] = {}
127
+ self._retrievers: dict[str, ConfiguredRetriever] = {}
128
+
129
+ self._context_state = AIQContextState.get()
130
+
131
+ self._exit_stack: AsyncExitStack | None = None
132
+
133
+ # Create a mapping to track function name -> other function names it depends on
134
+ self.function_dependencies: dict[str, FunctionDependencies] = {}
135
+ self.current_function_building: str | None = None
136
+
137
+ async def __aenter__(self):
138
+
139
+ self._exit_stack = AsyncExitStack()
140
+
141
+ # Get the exporter info from the config
142
+ telemetry_config = self.general_config.telemetry
143
+
144
+ for key, logging_config in telemetry_config.logging.items():
145
+ # Use the same pattern as tracing, but for logging
146
+ logging_info = self._registry.get_logging_method(type(logging_config))
147
+ handler = await self._exit_stack.enter_async_context(logging_info.build_fn(logging_config, self))
148
+
149
+ # Type check
150
+ if not isinstance(handler, logging.Handler):
151
+ raise TypeError(f"Expected a logging.Handler from {key}, got {type(handler)}")
152
+
153
+ # Store them in a dict so we can un-register them if needed
154
+ self._logging_handlers[key] = handler
155
+
156
+ # Now attach to AgentIQ's root logger
157
+ logging.getLogger().addHandler(handler)
158
+
159
+ provider = TracerProvider()
160
+ trace.set_tracer_provider(provider)
161
+
162
+ for key, trace_exporter_config in telemetry_config.tracing.items():
163
+
164
+ exporter_info = self._registry.get_telemetry_exporter(type(trace_exporter_config))
165
+
166
+ instance = await self._exit_stack.enter_async_context(exporter_info.build_fn(trace_exporter_config, self))
167
+
168
+ span_processor_instance = BatchSpanProcessor(instance)
169
+ provider.add_span_processor(span_processor_instance)
170
+
171
+ self._exporters[key] = ConfiguredExporter(config=trace_exporter_config, instance=instance)
172
+
173
+ return self
174
+
175
+ async def __aexit__(self, *exc_details):
176
+
177
+ assert self._exit_stack is not None, "Exit stack not initialized"
178
+
179
+ for _, handler in self._logging_handlers.items():
180
+ logging.getLogger().removeHandler(handler)
181
+
182
+ await self._exit_stack.__aexit__(*exc_details)
183
+
184
+ def build(self, entry_function: str | None = None) -> Workflow:
185
+ """
186
+ Creates an instance of a workflow object using the added components and the desired entry function.
187
+
188
+ Parameters
189
+ ----------
190
+ entry_function : str | None, optional
191
+ The function name to use as the entry point for the created workflow. If None, the entry point will be the
192
+ specified workflow function. By default None
193
+
194
+ Returns
195
+ -------
196
+ Workflow
197
+ A created workflow.
198
+
199
+ Raises
200
+ ------
201
+ ValueError
202
+ If the workflow has not been set before building.
203
+ """
204
+
205
+ if (self._workflow is None):
206
+ raise ValueError("Must set a workflow before building")
207
+
208
+ # Build the config from the added objects
209
+ config = AIQConfig(general=self.general_config,
210
+ functions={
211
+ k: v.config
212
+ for k, v in self._functions.items()
213
+ },
214
+ workflow=self._workflow.config,
215
+ llms={
216
+ k: v.config
217
+ for k, v in self._llms.items()
218
+ },
219
+ embedders={
220
+ k: v.config
221
+ for k, v in self._embedders.items()
222
+ },
223
+ memory={
224
+ k: v.config
225
+ for k, v in self._memory_clients.items()
226
+ },
227
+ retrievers={
228
+ k: v.config
229
+ for k, v in self._retrievers.items()
230
+ })
231
+
232
+ if (entry_function is None):
233
+ entry_fn_obj = self.get_workflow()
234
+ else:
235
+ entry_fn_obj = self.get_function(entry_function)
236
+
237
+ workflow = Workflow.from_entry_fn(config=config,
238
+ entry_fn=entry_fn_obj,
239
+ functions={
240
+ k: v.instance
241
+ for k, v in self._functions.items()
242
+ },
243
+ llms={
244
+ k: v.instance
245
+ for k, v in self._llms.items()
246
+ },
247
+ embeddings={
248
+ k: v.instance
249
+ for k, v in self._embedders.items()
250
+ },
251
+ memory={
252
+ k: v.instance
253
+ for k, v in self._memory_clients.items()
254
+ },
255
+ exporters={
256
+ k: v.instance
257
+ for k, v in self._exporters.items()
258
+ },
259
+ retrievers={
260
+ k: v.instance
261
+ for k, v in self._retrievers.items()
262
+ },
263
+ context_state=self._context_state)
264
+
265
+ return workflow
266
+
267
+ def _get_exit_stack(self) -> AsyncExitStack:
268
+
269
+ if self._exit_stack is None:
270
+ raise ValueError(
271
+ "Exit stack not initialized. Did you forget to call `async with WorkflowBuilder() as builder`?")
272
+
273
+ return self._exit_stack
274
+
275
+ async def _build_function(self, name: str, config: FunctionBaseConfig) -> ConfiguredFunction:
276
+ registration = self._registry.get_function(type(config))
277
+
278
+ inner_builder = ChildBuilder(self)
279
+
280
+ # We need to do this for every function because we don't know
281
+ # Where LLama Index Agents are Instantiated and Settings need to
282
+ # be set before the function is built
283
+ # It's only slower the first time because of the import
284
+ # So we can afford to do this for every function
285
+
286
+ llms = {k: v.instance for k, v in self._llms.items()}
287
+ function_frameworks = detect_llm_frameworks_in_build_fn(registration)
288
+
289
+ build_fn = chain_wrapped_build_fn(registration.build_fn, llms, function_frameworks)
290
+
291
+ # Set the currently building function so the ChildBuilder can track dependencies
292
+ self.current_function_building = config.type
293
+ # Empty set of dependencies for the current function
294
+ self.function_dependencies[config.type] = FunctionDependencies()
295
+
296
+ build_result = await self._get_exit_stack().enter_async_context(build_fn(config, inner_builder))
297
+
298
+ self.function_dependencies[name] = inner_builder.dependencies
299
+
300
+ # If the build result is a function, wrap it in a FunctionInfo
301
+ if inspect.isfunction(build_result):
302
+
303
+ build_result = FunctionInfo.from_fn(build_result)
304
+
305
+ if (isinstance(build_result, FunctionInfo)):
306
+ # Create the function object
307
+ build_result = LambdaFunction.from_info(config=config, info=build_result)
308
+
309
+ if (not isinstance(build_result, Function)):
310
+ raise ValueError("Expected a function, FunctionInfo object, or FunctionBase object to be "
311
+ f"returned from the function builder. Got {type(build_result)}")
312
+
313
+ return ConfiguredFunction(config=config, instance=build_result)
314
+
315
+ @override
316
+ async def add_function(self, name: str | FunctionRef, config: FunctionBaseConfig) -> Function:
317
+
318
+ if (name in self._functions):
319
+ raise ValueError(f"Function `{name}` already exists in the list of functions")
320
+
321
+ build_result = await self._build_function(name=name, config=config)
322
+
323
+ self._functions[name] = build_result
324
+
325
+ return build_result.instance
326
+
327
+ @override
328
+ def get_function(self, name: str | FunctionRef) -> Function:
329
+
330
+ if name not in self._functions:
331
+ raise ValueError(f"Function `{name}` not found")
332
+
333
+ return self._functions[name].instance
334
+
335
+ @override
336
+ def get_function_config(self, name: str | FunctionRef) -> FunctionBaseConfig:
337
+ if name not in self._functions:
338
+ raise ValueError(f"Function `{name}` not found")
339
+
340
+ return self._functions[name].config
341
+
342
+ @override
343
+ async def set_workflow(self, config: FunctionBaseConfig) -> Function:
344
+
345
+ if self._workflow is not None:
346
+ warnings.warn("Overwriting existing workflow")
347
+
348
+ build_result = await self._build_function(name="<workflow>", config=config)
349
+
350
+ self._workflow = build_result
351
+
352
+ return build_result.instance
353
+
354
+ @override
355
+ def get_workflow(self) -> Function:
356
+
357
+ if self._workflow is None:
358
+ raise ValueError("No workflow set")
359
+
360
+ return self._workflow.instance
361
+
362
+ @override
363
+ def get_workflow_config(self) -> FunctionBaseConfig:
364
+ if self._workflow is None:
365
+ raise ValueError("No workflow set")
366
+
367
+ return self._workflow.config
368
+
369
+ @override
370
+ def get_function_dependencies(self, fn_name: str | FunctionRef) -> FunctionDependencies:
371
+ return self.function_dependencies[fn_name]
372
+
373
+ @override
374
+ def get_tool(self, fn_name: str | FunctionRef, wrapper_type: LLMFrameworkEnum | str):
375
+
376
+ if fn_name not in self._functions:
377
+ raise ValueError(f"Function `{fn_name}` not found in list of functions")
378
+
379
+ fn = self._functions[fn_name]
380
+
381
+ try:
382
+ # Using the registry, get the tool wrapper for the requested framework
383
+ tool_wrapper_reg = self._registry.get_tool_wrapper(llm_framework=wrapper_type)
384
+
385
+ # Wrap in the correct wrapper
386
+ return tool_wrapper_reg.build_fn(fn_name, fn.instance, self)
387
+ except Exception as e:
388
+ logger.error("Error fetching tool `%s`", fn_name, exc_info=True)
389
+ raise e
390
+
391
+ @override
392
+ async def add_llm(self, name: str | LLMRef, config: LLMBaseConfig):
393
+
394
+ if (name in self._llms):
395
+ raise ValueError(f"LLM `{name}` already exists in the list of LLMs")
396
+
397
+ try:
398
+ llm_info = self._registry.get_llm_provider(type(config))
399
+
400
+ info_obj = await self._get_exit_stack().enter_async_context(llm_info.build_fn(config, self))
401
+
402
+ self._llms[name] = ConfiguredLLM(config=config, instance=info_obj)
403
+ except Exception as e:
404
+ logger.error("Error adding llm `%s` with config `%s`", name, config, exc_info=True)
405
+ raise e
406
+
407
+ @override
408
+ async def get_llm(self, llm_name: str | LLMRef, wrapper_type: LLMFrameworkEnum | str):
409
+
410
+ if (llm_name not in self._llms):
411
+ raise ValueError(f"LLM `{llm_name}` not found")
412
+
413
+ try:
414
+ # Get llm info
415
+ llm_info = self._llms[llm_name]
416
+
417
+ # Generate wrapped client from registered client info
418
+ client_info = self._registry.get_llm_client(config_type=type(llm_info.config), wrapper_type=wrapper_type)
419
+
420
+ client = await self._get_exit_stack().enter_async_context(client_info.build_fn(llm_info.config, self))
421
+
422
+ # Return a frameworks specific client
423
+ return client
424
+ except Exception as e:
425
+ logger.error("Error getting llm `%s` with wrapper `%s`", llm_name, wrapper_type, exc_info=True)
426
+ raise e
427
+
428
+ @override
429
+ def get_llm_config(self, llm_name: str | LLMRef) -> LLMBaseConfig:
430
+
431
+ if llm_name not in self._llms:
432
+ raise ValueError(f"LLM `{llm_name}` not found")
433
+
434
+ # Return the tool configuration object
435
+ return self._llms[llm_name].config
436
+
437
+ @override
438
+ async def add_embedder(self, name: str | EmbedderRef, config: EmbedderBaseConfig):
439
+
440
+ if (name in self._embedders):
441
+ raise ValueError(f"Embedder `{name}` already exists in the list of embedders")
442
+
443
+ try:
444
+ embedder_info = self._registry.get_embedder_provider(type(config))
445
+
446
+ info_obj = await self._get_exit_stack().enter_async_context(embedder_info.build_fn(config, self))
447
+
448
+ self._embedders[name] = ConfiguredEmbedder(config=config, instance=info_obj)
449
+ except Exception as e:
450
+ logger.error("Error adding embedder `%s` with config `%s`", name, config, exc_info=True)
451
+
452
+ raise e
453
+
454
+ @override
455
+ async def get_embedder(self, embedder_name: str | EmbedderRef, wrapper_type: LLMFrameworkEnum | str):
456
+
457
+ if (embedder_name not in self._embedders):
458
+ raise ValueError(f"Embedder `{embedder_name}` not found")
459
+
460
+ try:
461
+ # Get embedder info
462
+ embedder_info = self._embedders[embedder_name]
463
+
464
+ # Generate wrapped client from registered client info
465
+ client_info = self._registry.get_embedder_client(config_type=type(embedder_info.config),
466
+ wrapper_type=wrapper_type)
467
+ client = await self._get_exit_stack().enter_async_context(client_info.build_fn(embedder_info.config, self))
468
+
469
+ # Return a frameworks specific client
470
+ return client
471
+ except Exception as e:
472
+ logger.error("Error getting embedder `%s` with wrapper `%s`", embedder_name, wrapper_type, exc_info=True)
473
+ raise e
474
+
475
+ @override
476
+ def get_embedder_config(self, embedder_name: str | EmbedderRef) -> EmbedderBaseConfig:
477
+
478
+ if embedder_name not in self._embedders:
479
+ raise ValueError(f"Tool `{embedder_name}` not found")
480
+
481
+ # Return the tool configuration object
482
+ return self._embedders[embedder_name].config
483
+
484
+ @override
485
+ async def add_memory_client(self, name: str | MemoryRef, config: MemoryBaseConfig) -> MemoryEditor:
486
+
487
+ if (name in self._memory_clients):
488
+ raise ValueError(f"Memory `{name}` already exists in the list of memories")
489
+
490
+ memory_info = self._registry.get_memory(type(config))
491
+
492
+ info_obj = await self._get_exit_stack().enter_async_context(memory_info.build_fn(config, self))
493
+
494
+ self._memory_clients[name] = ConfiguredMemory(config=config, instance=info_obj)
495
+
496
+ return info_obj
497
+
498
+ @override
499
+ def get_memory_client(self, memory_name: str | MemoryRef) -> MemoryEditor:
500
+ """
501
+ Return the instantiated memory client for the given name.
502
+ """
503
+ if memory_name not in self._memory_clients:
504
+ raise ValueError(f"Memory `{memory_name}` not found")
505
+
506
+ return self._memory_clients[memory_name].instance
507
+
508
+ @override
509
+ def get_memory_client_config(self, memory_name: str | MemoryRef) -> MemoryBaseConfig:
510
+
511
+ if memory_name not in self._memory_clients:
512
+ raise ValueError(f"Memory `{memory_name}` not found")
513
+
514
+ # Return the tool configuration object
515
+ return self._memory_clients[memory_name].config
516
+
517
+ @override
518
+ async def add_retriever(self, name: str | RetrieverRef, config: RetrieverBaseConfig):
519
+
520
+ if (name in self._retrievers):
521
+ raise ValueError(f"Retriever '{name}' already exists in the list of retrievers")
522
+
523
+ try:
524
+ retriever_info = self._registry.get_retriever_provider(type(config))
525
+
526
+ info_obj = await self._get_exit_stack().enter_async_context(retriever_info.build_fn(config, self))
527
+
528
+ self._retrievers[name] = ConfiguredRetriever(config=config, instance=info_obj)
529
+
530
+ except Exception as e:
531
+ logger.error("Error adding retriever `%s` with config `%s`", name, config, exc_info=True)
532
+
533
+ raise e
534
+
535
+ # return info_obj
536
+
537
+ @override
538
+ async def get_retriever(self,
539
+ retriever_name: str | RetrieverRef,
540
+ wrapper_type: LLMFrameworkEnum | str | None = None):
541
+
542
+ if retriever_name not in self._retrievers:
543
+ raise ValueError(f"Retriever '{retriever_name}' not found")
544
+
545
+ try:
546
+ # Get retriever info
547
+ retriever_info = self._retrievers[retriever_name]
548
+
549
+ # Generate wrapped client from registered client info
550
+ client_info = self._registry.get_retriever_client(config_type=type(retriever_info.config),
551
+ wrapper_type=wrapper_type)
552
+
553
+ client = await self._get_exit_stack().enter_async_context(client_info.build_fn(retriever_info.config, self))
554
+
555
+ # Return a frameworks specific client
556
+ return client
557
+ except Exception as e:
558
+ logger.error("Error getting retriever `%s` with wrapper `%s`", retriever_name, wrapper_type, exc_info=True)
559
+ raise e
560
+
561
+ @override
562
+ async def get_retriever_config(self, retriever_name: str | RetrieverRef) -> RetrieverBaseConfig:
563
+
564
+ if retriever_name not in self._retrievers:
565
+ raise ValueError(f"Retriever `{retriever_name}` not found")
566
+
567
+ return self._retrievers[retriever_name].config
568
+
569
+ @override
570
+ def get_user_manager(self):
571
+ return UserManagerHolder(context=AIQContext(self._context_state))
572
+
573
+ async def populate_builder(self, config: AIQConfig):
574
+
575
+ # Generate the build sequence
576
+ build_sequence = build_dependency_sequence(config)
577
+
578
+ # Loop over all objects and add to the workflow builder
579
+ for component_instance in build_sequence:
580
+ # Instantiate a the llm
581
+ if component_instance.component_group == ComponentGroup.LLMS:
582
+ await self.add_llm(component_instance.name, component_instance.config)
583
+ # Instantiate a the embedder
584
+ elif component_instance.component_group == ComponentGroup.EMBEDDERS:
585
+ await self.add_embedder(component_instance.name, component_instance.config)
586
+ # Instantiate a memory client
587
+ elif component_instance.component_group == ComponentGroup.MEMORY:
588
+ await self.add_memory_client(component_instance.name, component_instance.config)
589
+ # Instantiate a retriever client
590
+ elif component_instance.component_group == ComponentGroup.RETRIEVERS:
591
+ await self.add_retriever(component_instance.name, component_instance.config)
592
+ # Instantiate a function
593
+ elif component_instance.component_group == ComponentGroup.FUNCTIONS:
594
+ # If the function is the root, set it as the workflow later
595
+ if (not component_instance.is_root):
596
+ await self.add_function(component_instance.name, component_instance.config)
597
+ else:
598
+ raise ValueError(f"Unknown component group {component_instance.component_group}")
599
+
600
+ # Instantiate the workflow
601
+ await self.set_workflow(config.workflow)
602
+
603
+ @classmethod
604
+ @asynccontextmanager
605
+ async def from_config(cls, config: AIQConfig):
606
+
607
+ async with cls(general_config=config.general) as builder:
608
+ await builder.populate_builder(config)
609
+ yield builder
610
+
611
+
612
+ class ChildBuilder(Builder):
613
+
614
+ def __init__(self, workflow_builder: WorkflowBuilder) -> None:
615
+
616
+ self._workflow_builder = workflow_builder
617
+
618
+ self._dependencies = FunctionDependencies()
619
+
620
+ @property
621
+ def dependencies(self) -> FunctionDependencies:
622
+ return self._dependencies
623
+
624
+ @override
625
+ async def add_function(self, name: str, config: FunctionBaseConfig) -> Function:
626
+ return await self._workflow_builder.add_function(name, config)
627
+
628
+ @override
629
+ def get_function(self, name: str) -> Function:
630
+ # If a function tries to get another function, we assume it uses it
631
+ fn = self._workflow_builder.get_function(name)
632
+
633
+ self._dependencies.add_function(name)
634
+
635
+ return fn
636
+
637
+ @override
638
+ def get_function_config(self, name: str) -> FunctionBaseConfig:
639
+ return self._workflow_builder.get_function_config(name)
640
+
641
+ @override
642
+ async def set_workflow(self, config: FunctionBaseConfig) -> Function:
643
+ return await self._workflow_builder.set_workflow(config)
644
+
645
+ @override
646
+ def get_workflow(self) -> Function:
647
+ return self._workflow_builder.get_workflow()
648
+
649
+ @override
650
+ def get_workflow_config(self) -> FunctionBaseConfig:
651
+ return self._workflow_builder.get_workflow_config()
652
+
653
+ @override
654
+ def get_tool(self, fn_name: str, wrapper_type: LLMFrameworkEnum | str):
655
+ # If a function tries to get another function as a tool, we assume it uses it
656
+ fn = self._workflow_builder.get_tool(fn_name, wrapper_type)
657
+
658
+ self._dependencies.add_function(fn_name)
659
+
660
+ return fn
661
+
662
+ @override
663
+ async def add_llm(self, name: str, config: LLMBaseConfig):
664
+ return await self._workflow_builder.add_llm(name, config)
665
+
666
+ @override
667
+ async def get_llm(self, llm_name: str, wrapper_type: LLMFrameworkEnum | str):
668
+ llm = await self._workflow_builder.get_llm(llm_name, wrapper_type)
669
+
670
+ self._dependencies.add_llm(llm_name)
671
+
672
+ return llm
673
+
674
+ @override
675
+ def get_llm_config(self, llm_name: str) -> LLMBaseConfig:
676
+ return self._workflow_builder.get_llm_config(llm_name)
677
+
678
+ @override
679
+ async def add_embedder(self, name: str, config: EmbedderBaseConfig):
680
+ return await self._workflow_builder.add_embedder(name, config)
681
+
682
+ @override
683
+ async def get_embedder(self, embedder_name: str, wrapper_type: LLMFrameworkEnum | str):
684
+ embedder = await self._workflow_builder.get_embedder(embedder_name, wrapper_type)
685
+
686
+ self._dependencies.add_embedder(embedder_name)
687
+
688
+ return embedder
689
+
690
+ @override
691
+ def get_embedder_config(self, embedder_name: str) -> EmbedderBaseConfig:
692
+ return self._workflow_builder.get_embedder_config(embedder_name)
693
+
694
+ @override
695
+ async def add_memory_client(self, name: str, config: MemoryBaseConfig) -> MemoryEditor:
696
+ return await self._workflow_builder.add_memory_client(name, config)
697
+
698
+ @override
699
+ def get_memory_client(self, memory_name: str) -> MemoryEditor:
700
+ """
701
+ Return the instantiated memory client for the given name.
702
+ """
703
+ memory_client = self._workflow_builder.get_memory_client(memory_name)
704
+
705
+ self._dependencies.add_memory_client(memory_name)
706
+
707
+ return memory_client
708
+
709
+ @override
710
+ def get_memory_client_config(self, memory_name: str) -> MemoryBaseConfig:
711
+ return self._workflow_builder.get_memory_client_config(memory_name=memory_name)
712
+
713
+ @override
714
+ async def add_retriever(self, name: str, config: RetrieverBaseConfig):
715
+ return await self._workflow_builder.add_retriever(name, config)
716
+
717
+ @override
718
+ async def get_retriever(self, retriever_name: str, wrapper_type: LLMFrameworkEnum | str | None = None):
719
+ if not wrapper_type:
720
+ return await self._workflow_builder.get_retriever(retriever_name=retriever_name)
721
+ return await self._workflow_builder.get_retriever(retriever_name=retriever_name, wrapper_type=wrapper_type)
722
+
723
+ @override
724
+ async def get_retriever_config(self, retriever_name: str) -> RetrieverBaseConfig:
725
+ return await self._workflow_builder.get_retriever_config(retriever_name=retriever_name)
726
+
727
+ @override
728
+ def get_user_manager(self) -> UserManagerHolder:
729
+ return self._workflow_builder.get_user_manager()
730
+
731
+ @override
732
+ def get_function_dependencies(self, fn_name: str) -> FunctionDependencies:
733
+ return self._workflow_builder.get_function_dependencies(fn_name)