aiqtoolkit 1.1.0a20250516__py3-none-any.whl → 1.1.0a20251020__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.1.0a20251020.dist-info/METADATA +37 -0
  2. aiqtoolkit-1.1.0a20251020.dist-info/RECORD +4 -0
  3. {aiqtoolkit-1.1.0a20250516.dist-info → aiqtoolkit-1.1.0a20251020.dist-info}/WHEEL +1 -1
  4. aiqtoolkit-1.1.0a20251020.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.0a20250516.dist-info/METADATA +0 -331
  315. aiqtoolkit-1.1.0a20250516.dist-info/RECORD +0 -316
  316. aiqtoolkit-1.1.0a20250516.dist-info/entry_points.txt +0 -17
  317. aiqtoolkit-1.1.0a20250516.dist-info/licenses/LICENSE-3rd-party.txt +0 -3686
  318. aiqtoolkit-1.1.0a20250516.dist-info/licenses/LICENSE.md +0 -201
  319. aiqtoolkit-1.1.0a20250516.dist-info/top_level.txt +0 -1
@@ -1,429 +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
- import re
18
- from contextlib import asynccontextmanager
19
- from contextlib import contextmanager
20
- from typing import Any
21
-
22
- from openinference.semconv.trace import OpenInferenceSpanKindValues
23
- from openinference.semconv.trace import SpanAttributes
24
- from pydantic import TypeAdapter
25
-
26
- from aiq.builder.context import AIQContextState
27
- from aiq.data_models.intermediate_step import IntermediateStep
28
- from aiq.data_models.intermediate_step import IntermediateStepState
29
- from aiq.utils.optional_imports import TelemetryOptionalImportError
30
- from aiq.utils.optional_imports import try_import_opentelemetry
31
-
32
- try:
33
- from weave.trace.context import weave_client_context
34
- from weave.trace.context.call_context import get_current_call
35
- from weave.trace.context.call_context import set_call_stack
36
- from weave.trace.weave_client import Call
37
- WEAVE_AVAILABLE = True
38
- except ImportError:
39
- WEAVE_AVAILABLE = False
40
- # we simply don't do anything if weave is not available
41
- pass
42
-
43
- logger = logging.getLogger(__name__)
44
-
45
- OPENINFERENCE_SPAN_KIND = SpanAttributes.OPENINFERENCE_SPAN_KIND
46
-
47
- # Try to import OpenTelemetry modules
48
- # If the dependencies are not installed, use dummy objects here
49
- try:
50
- opentelemetry = try_import_opentelemetry()
51
- from opentelemetry import trace
52
- from opentelemetry.sdk.trace import TracerProvider
53
- from opentelemetry.trace import Span
54
- from opentelemetry.trace.propagation import set_span_in_context
55
- except TelemetryOptionalImportError:
56
- from aiq.utils.optional_imports import DummySpan # pylint: disable=ungrouped-imports
57
- from aiq.utils.optional_imports import DummyTrace # pylint: disable=ungrouped-imports
58
- from aiq.utils.optional_imports import DummyTracerProvider # pylint: disable=ungrouped-imports
59
- from aiq.utils.optional_imports import dummy_set_span_in_context # pylint: disable=ungrouped-imports
60
-
61
- trace = DummyTrace # pylint: disable=invalid-name
62
- TracerProvider = DummyTracerProvider
63
- Span = DummySpan
64
- set_span_in_context = dummy_set_span_in_context
65
-
66
-
67
- def _ns_timestamp(seconds_float: float) -> int:
68
- """
69
- Convert AIQ Toolkit's float `event_timestamp` (in seconds) into an integer number
70
- of nanoseconds, as OpenTelemetry expects.
71
- """
72
- return int(seconds_float * 1e9)
73
-
74
-
75
- class AsyncOtelSpanListener:
76
- """
77
- A separate, async class that listens to the AIQ Toolkit intermediate step
78
- event stream and creates proper Otel spans:
79
-
80
- - On FUNCTION_START => open a new top-level span
81
- - On any other intermediate step => open a child subspan (immediate open/close)
82
- - On FUNCTION_END => close the function's top-level span
83
-
84
- This runs fully independently from the normal AIQ Toolkit workflow, so that
85
- the workflow is not blocking or entangled by OTel calls.
86
- """
87
-
88
- def __init__(self, context_state: AIQContextState | None = None):
89
- """
90
- :param context_state: Optionally supply a specific AIQContextState.
91
- If None, uses the global singleton.
92
- """
93
- self._context_state = context_state or AIQContextState.get()
94
-
95
- # Maintain a subscription so we can unsubscribe on shutdown
96
- self._subscription = None
97
-
98
- # Outstanding spans which have been opened but not yet closed
99
- self._outstanding_spans: dict[str, Span] = {}
100
-
101
- # Stack of spans, for when we need to create a child span
102
- self._span_stack: dict[str, Span] = {}
103
-
104
- self._running = False
105
-
106
- # Prepare the tracer (optionally you might already have done this)
107
- if trace.get_tracer_provider() is None or not isinstance(trace.get_tracer_provider(), TracerProvider):
108
- tracer_provider = TracerProvider()
109
- trace.set_tracer_provider(tracer_provider)
110
-
111
- # We'll optionally attach exporters if you want (out of scope to do it here).
112
- # Example: tracer_provider.add_span_processor(BatchSpanProcessor(your_exporter))
113
-
114
- self._tracer = trace.get_tracer("aiq-async-otel-listener")
115
-
116
- # Initialize Weave-specific components if available
117
- self.gc = None
118
- self._weave_calls = {}
119
- if WEAVE_AVAILABLE:
120
- try:
121
- # Try to get the weave client, but don't fail if Weave isn't initialized
122
- self.gc = weave_client_context.require_weave_client()
123
- except Exception:
124
- # Weave is not initialized, so we don't do anything
125
- pass
126
-
127
- def _on_next(self, step: IntermediateStep) -> None:
128
- """
129
- The main logic that reacts to each IntermediateStep.
130
- """
131
- if (step.event_state == IntermediateStepState.START):
132
-
133
- self._process_start_event(step)
134
-
135
- elif (step.event_state == IntermediateStepState.END):
136
-
137
- self._process_end_event(step)
138
-
139
- def _on_error(self, exc: Exception) -> None:
140
- logger.error("Error in intermediate step subscription: %s", exc, exc_info=True)
141
-
142
- def _on_complete(self) -> None:
143
- logger.debug("Intermediate step stream completed. No more events will arrive.")
144
-
145
- @asynccontextmanager
146
- async def start(self):
147
- """
148
- Usage::
149
-
150
- otel_listener = AsyncOtelSpanListener()
151
- async with otel_listener.start():
152
- # run your AIQ Toolkit workflow
153
- ...
154
- # cleans up
155
-
156
- This sets up the subscription to the AIQ Toolkit event stream and starts the background loop.
157
- """
158
- try:
159
- # Subscribe to the event stream
160
- subject = self._context_state.event_stream.get()
161
- self._subscription = subject.subscribe(
162
- on_next=self._on_next,
163
- on_error=self._on_error,
164
- on_complete=self._on_complete,
165
- )
166
-
167
- self._running = True
168
-
169
- yield # let the caller do their workflow
170
-
171
- finally:
172
- # Cleanup
173
- self._running = False
174
- # Close out any running spans
175
- await self._cleanup()
176
-
177
- if self._subscription:
178
- self._subscription.unsubscribe()
179
- self._subscription = None
180
-
181
- async def _cleanup(self):
182
- """
183
- Close any remaining open spans.
184
- """
185
- if self._outstanding_spans:
186
- logger.warning(
187
- "Not all spans were closed. Ensure all start events have a corresponding end event. Remaining: %s",
188
- self._outstanding_spans)
189
-
190
- for span_info in self._outstanding_spans.values():
191
- span_info.end()
192
-
193
- self._outstanding_spans.clear()
194
-
195
- self._span_stack.clear()
196
-
197
- # Clean up any lingering Weave calls if Weave is available and initialized
198
- if self.gc is not None and self._weave_calls:
199
- for _, call in list(self._weave_calls.items()):
200
- self.gc.finish_call(call, {"status": "incomplete"})
201
- self._weave_calls.clear()
202
-
203
- def _serialize_payload(self, input_value: Any) -> tuple[str, bool]:
204
- """
205
- Serialize the input value to a string. Returns a tuple with the serialized value and a boolean indicating if the
206
- serialization is JSON or a string
207
- """
208
- try:
209
- return TypeAdapter(type(input_value)).dump_json(input_value).decode('utf-8'), True
210
- except Exception:
211
- # Fallback to string representation if we can't serialize using pydantic
212
- return str(input_value), False
213
-
214
- def _process_start_event(self, step: IntermediateStep):
215
-
216
- parent_ctx = None
217
-
218
- if (len(self._span_stack) > 0):
219
- parent_span = self._span_stack.get(step.function_ancestry.parent_id, None)
220
- if parent_span is None:
221
- logger.warning("No parent span found for step %s", step.UUID)
222
- return
223
-
224
- parent_ctx = set_span_in_context(parent_span)
225
-
226
- # Extract start/end times from the step
227
- # By convention, `span_event_timestamp` is the time we started, `event_timestamp` is the time we ended.
228
- # If span_event_timestamp is missing, we default to event_timestamp (meaning zero-length).
229
- s_ts = step.payload.span_event_timestamp or step.payload.event_timestamp
230
- start_ns = _ns_timestamp(s_ts)
231
-
232
- # Optional: embed the LLM/tool name if present
233
- if step.payload.name:
234
- sub_span_name = f"{step.payload.name}"
235
- else:
236
- sub_span_name = f"{step.payload.event_type}"
237
-
238
- # Start the subspan
239
- sub_span = self._tracer.start_span(
240
- name=sub_span_name,
241
- context=parent_ctx,
242
- attributes={
243
- "aiq.event_type": step.payload.event_type.value,
244
- "aiq.function.id": step.function_ancestry.function_id,
245
- "aiq.function.name": step.function_ancestry.function_name,
246
- "aiq.subspan.name": step.payload.name or "",
247
- "aiq.event_timestamp": step.event_timestamp,
248
- "aiq.framework": step.payload.framework.value if step.payload.framework else "unknown",
249
- },
250
- start_time=start_ns,
251
- )
252
-
253
- event_type_to_span_kind = {
254
- "LLM_START": OpenInferenceSpanKindValues.LLM,
255
- "LLM_END": OpenInferenceSpanKindValues.LLM,
256
- "LLM_NEW_TOKEN": OpenInferenceSpanKindValues.LLM,
257
- "TOOL_START": OpenInferenceSpanKindValues.TOOL,
258
- "TOOL_END": OpenInferenceSpanKindValues.TOOL,
259
- "FUNCTION_START": OpenInferenceSpanKindValues.CHAIN,
260
- "FUNCTION_END": OpenInferenceSpanKindValues.CHAIN,
261
- }
262
-
263
- span_kind = event_type_to_span_kind.get(step.event_type, OpenInferenceSpanKindValues.UNKNOWN)
264
- sub_span.set_attribute(SpanAttributes.OPENINFERENCE_SPAN_KIND, span_kind.value)
265
-
266
- if step.payload.data and step.payload.data.input:
267
- # optional parse
268
- match = re.search(r"Human:\s*Question:\s*(.*)", str(step.payload.data.input))
269
- if match:
270
- human_question = match.group(1).strip()
271
- sub_span.set_attribute(SpanAttributes.INPUT_VALUE, human_question)
272
- else:
273
- serialized_input, is_json = self._serialize_payload(step.payload.data.input)
274
- sub_span.set_attribute(SpanAttributes.INPUT_VALUE, serialized_input)
275
- sub_span.set_attribute(SpanAttributes.INPUT_MIME_TYPE, "application/json" if is_json else "text/plain")
276
-
277
- self._span_stack[step.UUID] = sub_span
278
-
279
- self._outstanding_spans[step.UUID] = sub_span
280
-
281
- # Create corresponding Weave call if Weave is available and initialized
282
- if self.gc is not None:
283
- self._create_weave_call(step, sub_span)
284
-
285
- def _process_end_event(self, step: IntermediateStep):
286
-
287
- # Find the subspan that was created in the start event
288
- sub_span = self._outstanding_spans.pop(step.UUID, None)
289
-
290
- if sub_span is None:
291
- logger.warning("No subspan found for step %s", step.UUID)
292
- return
293
-
294
- self._span_stack.pop(step.UUID, None)
295
-
296
- # Optionally add more attributes from usage_info or data
297
- usage_info = step.payload.usage_info
298
- if usage_info:
299
- sub_span.set_attribute("aiq.usage.num_llm_calls",
300
- usage_info.num_llm_calls if usage_info.num_llm_calls else 0)
301
- sub_span.set_attribute("aiq.usage.seconds_between_calls",
302
- usage_info.seconds_between_calls if usage_info.seconds_between_calls else 0)
303
- sub_span.set_attribute(SpanAttributes.LLM_TOKEN_COUNT_PROMPT,
304
- usage_info.token_usage.prompt_tokens if usage_info.token_usage else 0)
305
- sub_span.set_attribute(SpanAttributes.LLM_TOKEN_COUNT_COMPLETION,
306
- usage_info.token_usage.completion_tokens if usage_info.token_usage else 0)
307
- sub_span.set_attribute(SpanAttributes.LLM_TOKEN_COUNT_TOTAL,
308
- usage_info.token_usage.total_tokens if usage_info.token_usage else 0)
309
-
310
- if step.payload.data and step.payload.data.output is not None:
311
- serialized_output, is_json = self._serialize_payload(step.payload.data.output)
312
- sub_span.set_attribute(SpanAttributes.OUTPUT_VALUE, serialized_output)
313
- sub_span.set_attribute(SpanAttributes.OUTPUT_MIME_TYPE, "application/json" if is_json else "text/plain")
314
-
315
- end_ns = _ns_timestamp(step.payload.event_timestamp)
316
-
317
- # End the subspan
318
- sub_span.end(end_time=end_ns)
319
-
320
- # Finish corresponding Weave call if Weave is available and initialized
321
- if self.gc is not None:
322
- self._finish_weave_call(step)
323
-
324
- @contextmanager
325
- def parent_call(self, trace_id: str, parent_call_id: str):
326
- """Context manager to set a parent call context for Weave.
327
- This allows connecting AIQ spans to existing traces from other frameworks.
328
- """
329
- dummy_call = Call(trace_id=trace_id, id=parent_call_id, _op_name="", project_id="", parent_id=None, inputs={})
330
- with set_call_stack([dummy_call]):
331
- yield
332
-
333
- def _create_weave_call(self, step: IntermediateStep, span: Span) -> None:
334
- """
335
- Create a Weave call directly from the span and step data,
336
- connecting to existing framework traces if available.
337
- """
338
- # Check for existing Weave trace/call
339
- existing_call = get_current_call()
340
-
341
- # Extract parent call if applicable
342
- parent_call = None
343
-
344
- # If we have an existing Weave call from another framework (e.g., LangChain),
345
- # use it as the parent
346
- if existing_call is not None:
347
- parent_call = existing_call
348
- logger.debug("Found existing Weave call: %s from trace: %s", existing_call.id, existing_call.trace_id)
349
- # Otherwise, check our internal stack for parent relationships
350
- elif len(self._weave_calls) > 0 and len(self._span_stack) > 1:
351
- # Get the parent span using stack position (one level up)
352
- parent_span_id = self._span_stack[-2].get_span_context().span_id
353
- # Find the corresponding weave call for this parent span
354
- for call in self._weave_calls.values():
355
- if getattr(call, "span_id", None) == parent_span_id:
356
- parent_call = call
357
- break
358
-
359
- # Generate a meaningful operation name based on event type
360
- event_type = step.payload.event_type.split(".")[-1]
361
- if step.payload.name:
362
- op_name = f"aiq.{event_type}.{step.payload.name}"
363
- else:
364
- op_name = f"aiq.{event_type}"
365
-
366
- # Create input dictionary
367
- inputs = {}
368
- if step.payload.data and step.payload.data.input is not None:
369
- try:
370
- # Add the input to the Weave call
371
- inputs["input"] = step.payload.data.input
372
- except Exception:
373
- # If serialization fails, use string representation
374
- inputs["input"] = str(step.payload.data.input)
375
-
376
- # Create the Weave call
377
- call = self.gc.create_call(
378
- op_name,
379
- inputs=inputs,
380
- parent=parent_call,
381
- attributes=span.attributes,
382
- display_name=op_name,
383
- )
384
-
385
- # Store the call with step UUID as key
386
- self._weave_calls[step.UUID] = call
387
-
388
- # Store span ID for parent reference
389
- setattr(call, "span_id", span.get_span_context().span_id)
390
-
391
- return call
392
-
393
- def _finish_weave_call(self, step: IntermediateStep) -> None:
394
- """
395
- Finish a previously created Weave call
396
- """
397
- # Find the call for this step
398
- call = self._weave_calls.pop(step.UUID, None)
399
-
400
- if call is None:
401
- logger.warning("No Weave call found for step %s", step.UUID)
402
- return
403
-
404
- # Create output dictionary
405
- outputs = {}
406
- if step.payload.data and step.payload.data.output is not None:
407
- try:
408
- # Add the output to the Weave call
409
- outputs["output"] = step.payload.data.output
410
- except Exception:
411
- # If serialization fails, use string representation
412
- outputs["output"] = str(step.payload.data.output)
413
-
414
- # Add usage information if available
415
- usage_info = step.payload.usage_info
416
- if usage_info:
417
- if usage_info.token_usage:
418
- outputs["prompt_tokens"] = usage_info.token_usage.prompt_tokens
419
- outputs["completion_tokens"] = usage_info.token_usage.completion_tokens
420
- outputs["total_tokens"] = usage_info.token_usage.total_tokens
421
-
422
- if usage_info.num_llm_calls:
423
- outputs["num_llm_calls"] = usage_info.num_llm_calls
424
-
425
- if usage_info.seconds_between_calls:
426
- outputs["seconds_between_calls"] = usage_info.seconds_between_calls
427
-
428
- # Finish the call with outputs
429
- self.gc.finish_call(call, outputs)
@@ -1,99 +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 Field
19
-
20
- from aiq.builder.builder import Builder
21
- from aiq.cli.register_workflow import register_logging_method
22
- from aiq.cli.register_workflow import register_telemetry_exporter
23
- from aiq.data_models.logging import LoggingBaseConfig
24
- from aiq.data_models.telemetry_exporter import TelemetryExporterBaseConfig
25
- from aiq.utils.optional_imports import try_import_opentelemetry
26
- from aiq.utils.optional_imports import try_import_phoenix
27
-
28
- logger = logging.getLogger(__name__)
29
-
30
-
31
- class PhoenixTelemetryExporter(TelemetryExporterBaseConfig, name="phoenix"):
32
- """A telemetry exporter to transmit traces to externally hosted phoenix service."""
33
-
34
- endpoint: str = Field(description="The phoenix endpoint to export telemetry traces.")
35
- project: str = Field(description="The project name to group the telemetry traces.")
36
-
37
-
38
- @register_telemetry_exporter(config_type=PhoenixTelemetryExporter)
39
- async def phoenix_telemetry_exporter(config: PhoenixTelemetryExporter, builder: Builder):
40
- """Create a Phoenix telemetry exporter."""
41
- try:
42
- # If the dependencies are not installed, a TelemetryOptionalImportError will be raised
43
- phoenix = try_import_phoenix() # noqa: F841
44
- from phoenix.otel import HTTPSpanExporter
45
- yield HTTPSpanExporter(config.endpoint)
46
- except ConnectionError as ex:
47
- logger.warning("Unable to connect to Phoenix at port 6006. Are you sure Phoenix is running?\n %s",
48
- ex,
49
- exc_info=True)
50
-
51
-
52
- class OtelCollectorTelemetryExporter(TelemetryExporterBaseConfig, name="otelcollector"):
53
- """A telemetry exporter to transmit traces to externally hosted otel collector service."""
54
-
55
- endpoint: str = Field(description="The otel endpoint to export telemetry traces.")
56
- project: str = Field(description="The project name to group the telemetry traces.")
57
-
58
-
59
- @register_telemetry_exporter(config_type=OtelCollectorTelemetryExporter)
60
- async def otel_telemetry_exporter(config: OtelCollectorTelemetryExporter, builder: Builder):
61
- """Create an OpenTelemetry telemetry exporter."""
62
- # If the dependencies are not installed, a TelemetryOptionalImportError will be raised
63
- opentelemetry = try_import_opentelemetry()
64
- yield opentelemetry.sdk.trace.export.OTLPSpanExporter(config.endpoint)
65
-
66
-
67
- class ConsoleLoggingMethod(LoggingBaseConfig, name="console"):
68
- """A logger to write runtime logs to the console."""
69
-
70
- level: str = Field(description="The logging level of console logger.")
71
-
72
-
73
- @register_logging_method(config_type=ConsoleLoggingMethod)
74
- async def console_logging_method(config: ConsoleLoggingMethod, builder: Builder):
75
- """
76
- Build and return a StreamHandler for console-based logging.
77
- """
78
- level = getattr(logging, config.level.upper(), logging.INFO)
79
- handler = logging.StreamHandler()
80
- handler.setLevel(level)
81
- yield handler
82
-
83
-
84
- class FileLoggingMethod(LoggingBaseConfig, name="file"):
85
- """A logger to write runtime logs to a file."""
86
-
87
- path: str = Field(description="The file path to save the logging output.")
88
- level: str = Field(description="The logging level of file logger.")
89
-
90
-
91
- @register_logging_method(config_type=FileLoggingMethod)
92
- async def file_logging_method(config: FileLoggingMethod, builder: Builder):
93
- """
94
- Build and return a FileHandler for file-based logging.
95
- """
96
- level = getattr(logging, config.level.upper(), logging.INFO)
97
- handler = logging.FileHandler(filename=config.path, mode="a", encoding="utf-8")
98
- handler.setLevel(level)
99
- yield handler
aiq/plugins/.namespace DELETED
@@ -1 +0,0 @@
1
- Note: This is a python namespace package and this directory should remain empty. Do NOT add a `__init__.py` file or any other files to this directory. This file is also needed to ensure the directory exists in git.
aiq/profiler/__init__.py DELETED
File without changes
File without changes