aiqtoolkit 1.2.0a20250707__py3-none-any.whl → 1.2.0a20250731__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 (198) hide show
  1. aiq/agent/base.py +171 -8
  2. aiq/agent/dual_node.py +1 -1
  3. aiq/agent/react_agent/agent.py +113 -113
  4. aiq/agent/react_agent/register.py +31 -14
  5. aiq/agent/rewoo_agent/agent.py +36 -35
  6. aiq/agent/rewoo_agent/register.py +2 -2
  7. aiq/agent/tool_calling_agent/agent.py +3 -7
  8. aiq/authentication/__init__.py +14 -0
  9. aiq/authentication/api_key/__init__.py +14 -0
  10. aiq/authentication/api_key/api_key_auth_provider.py +92 -0
  11. aiq/authentication/api_key/api_key_auth_provider_config.py +124 -0
  12. aiq/authentication/api_key/register.py +26 -0
  13. aiq/authentication/exceptions/__init__.py +14 -0
  14. aiq/authentication/exceptions/api_key_exceptions.py +38 -0
  15. aiq/authentication/exceptions/auth_code_grant_exceptions.py +86 -0
  16. aiq/authentication/exceptions/call_back_exceptions.py +38 -0
  17. aiq/authentication/exceptions/request_exceptions.py +54 -0
  18. aiq/authentication/http_basic_auth/__init__.py +0 -0
  19. aiq/authentication/http_basic_auth/http_basic_auth_provider.py +81 -0
  20. aiq/authentication/http_basic_auth/register.py +30 -0
  21. aiq/authentication/interfaces.py +93 -0
  22. aiq/authentication/oauth2/__init__.py +14 -0
  23. aiq/authentication/oauth2/oauth2_auth_code_flow_provider.py +107 -0
  24. aiq/authentication/oauth2/oauth2_auth_code_flow_provider_config.py +39 -0
  25. aiq/authentication/oauth2/register.py +25 -0
  26. aiq/authentication/register.py +21 -0
  27. aiq/builder/builder.py +64 -2
  28. aiq/builder/component_utils.py +16 -3
  29. aiq/builder/context.py +26 -0
  30. aiq/builder/eval_builder.py +43 -2
  31. aiq/builder/function.py +32 -4
  32. aiq/builder/function_base.py +1 -1
  33. aiq/builder/intermediate_step_manager.py +6 -8
  34. aiq/builder/user_interaction_manager.py +3 -0
  35. aiq/builder/workflow.py +23 -18
  36. aiq/builder/workflow_builder.py +420 -73
  37. aiq/cli/commands/info/list_mcp.py +103 -16
  38. aiq/cli/commands/sizing/__init__.py +14 -0
  39. aiq/cli/commands/sizing/calc.py +294 -0
  40. aiq/cli/commands/sizing/sizing.py +27 -0
  41. aiq/cli/commands/start.py +1 -0
  42. aiq/cli/entrypoint.py +2 -0
  43. aiq/cli/register_workflow.py +80 -0
  44. aiq/cli/type_registry.py +151 -30
  45. aiq/data_models/api_server.py +117 -11
  46. aiq/data_models/authentication.py +231 -0
  47. aiq/data_models/common.py +35 -7
  48. aiq/data_models/component.py +17 -9
  49. aiq/data_models/component_ref.py +33 -0
  50. aiq/data_models/config.py +60 -3
  51. aiq/data_models/embedder.py +1 -0
  52. aiq/data_models/function_dependencies.py +8 -0
  53. aiq/data_models/interactive.py +10 -1
  54. aiq/data_models/intermediate_step.py +15 -5
  55. aiq/data_models/its_strategy.py +30 -0
  56. aiq/data_models/llm.py +1 -0
  57. aiq/data_models/memory.py +1 -0
  58. aiq/data_models/object_store.py +44 -0
  59. aiq/data_models/retry_mixin.py +35 -0
  60. aiq/data_models/span.py +187 -0
  61. aiq/data_models/telemetry_exporter.py +2 -2
  62. aiq/embedder/nim_embedder.py +2 -1
  63. aiq/embedder/openai_embedder.py +2 -1
  64. aiq/eval/config.py +19 -1
  65. aiq/eval/dataset_handler/dataset_handler.py +75 -1
  66. aiq/eval/evaluate.py +53 -10
  67. aiq/eval/rag_evaluator/evaluate.py +23 -12
  68. aiq/eval/remote_workflow.py +7 -2
  69. aiq/eval/runners/__init__.py +14 -0
  70. aiq/eval/runners/config.py +39 -0
  71. aiq/eval/runners/multi_eval_runner.py +54 -0
  72. aiq/eval/usage_stats.py +6 -0
  73. aiq/eval/utils/weave_eval.py +5 -1
  74. aiq/experimental/__init__.py +0 -0
  75. aiq/experimental/decorators/__init__.py +0 -0
  76. aiq/experimental/decorators/experimental_warning_decorator.py +130 -0
  77. aiq/experimental/inference_time_scaling/__init__.py +0 -0
  78. aiq/experimental/inference_time_scaling/editing/__init__.py +0 -0
  79. aiq/experimental/inference_time_scaling/editing/iterative_plan_refinement_editor.py +147 -0
  80. aiq/experimental/inference_time_scaling/editing/llm_as_a_judge_editor.py +204 -0
  81. aiq/experimental/inference_time_scaling/editing/motivation_aware_summarization.py +107 -0
  82. aiq/experimental/inference_time_scaling/functions/__init__.py +0 -0
  83. aiq/experimental/inference_time_scaling/functions/execute_score_select_function.py +105 -0
  84. aiq/experimental/inference_time_scaling/functions/its_tool_orchestration_function.py +205 -0
  85. aiq/experimental/inference_time_scaling/functions/its_tool_wrapper_function.py +146 -0
  86. aiq/experimental/inference_time_scaling/functions/plan_select_execute_function.py +224 -0
  87. aiq/experimental/inference_time_scaling/models/__init__.py +0 -0
  88. aiq/experimental/inference_time_scaling/models/editor_config.py +132 -0
  89. aiq/experimental/inference_time_scaling/models/its_item.py +48 -0
  90. aiq/experimental/inference_time_scaling/models/scoring_config.py +112 -0
  91. aiq/experimental/inference_time_scaling/models/search_config.py +120 -0
  92. aiq/experimental/inference_time_scaling/models/selection_config.py +154 -0
  93. aiq/experimental/inference_time_scaling/models/stage_enums.py +43 -0
  94. aiq/experimental/inference_time_scaling/models/strategy_base.py +66 -0
  95. aiq/experimental/inference_time_scaling/models/tool_use_config.py +41 -0
  96. aiq/experimental/inference_time_scaling/register.py +36 -0
  97. aiq/experimental/inference_time_scaling/scoring/__init__.py +0 -0
  98. aiq/experimental/inference_time_scaling/scoring/llm_based_agent_scorer.py +168 -0
  99. aiq/experimental/inference_time_scaling/scoring/llm_based_plan_scorer.py +168 -0
  100. aiq/experimental/inference_time_scaling/scoring/motivation_aware_scorer.py +111 -0
  101. aiq/experimental/inference_time_scaling/search/__init__.py +0 -0
  102. aiq/experimental/inference_time_scaling/search/multi_llm_planner.py +128 -0
  103. aiq/experimental/inference_time_scaling/search/multi_query_retrieval_search.py +122 -0
  104. aiq/experimental/inference_time_scaling/search/single_shot_multi_plan_planner.py +128 -0
  105. aiq/experimental/inference_time_scaling/selection/__init__.py +0 -0
  106. aiq/experimental/inference_time_scaling/selection/best_of_n_selector.py +63 -0
  107. aiq/experimental/inference_time_scaling/selection/llm_based_agent_output_selector.py +131 -0
  108. aiq/experimental/inference_time_scaling/selection/llm_based_output_merging_selector.py +159 -0
  109. aiq/experimental/inference_time_scaling/selection/llm_based_plan_selector.py +128 -0
  110. aiq/experimental/inference_time_scaling/selection/threshold_selector.py +58 -0
  111. aiq/front_ends/console/authentication_flow_handler.py +233 -0
  112. aiq/front_ends/console/console_front_end_plugin.py +13 -24
  113. aiq/front_ends/fastapi/auth_flow_handlers/__init__.py +0 -0
  114. aiq/front_ends/fastapi/auth_flow_handlers/http_flow_handler.py +27 -0
  115. aiq/front_ends/fastapi/auth_flow_handlers/websocket_flow_handler.py +107 -0
  116. aiq/front_ends/fastapi/fastapi_front_end_config.py +20 -0
  117. aiq/front_ends/fastapi/fastapi_front_end_controller.py +68 -0
  118. aiq/front_ends/fastapi/fastapi_front_end_plugin.py +14 -1
  119. aiq/front_ends/fastapi/fastapi_front_end_plugin_worker.py +353 -31
  120. aiq/front_ends/fastapi/html_snippets/__init__.py +14 -0
  121. aiq/front_ends/fastapi/html_snippets/auth_code_grant_success.py +35 -0
  122. aiq/front_ends/fastapi/main.py +2 -0
  123. aiq/front_ends/fastapi/message_handler.py +102 -84
  124. aiq/front_ends/fastapi/step_adaptor.py +2 -1
  125. aiq/front_ends/simple_base/simple_front_end_plugin_base.py +4 -2
  126. aiq/llm/aws_bedrock_llm.py +2 -1
  127. aiq/llm/nim_llm.py +2 -1
  128. aiq/llm/openai_llm.py +2 -1
  129. aiq/object_store/__init__.py +20 -0
  130. aiq/object_store/in_memory_object_store.py +74 -0
  131. aiq/object_store/interfaces.py +84 -0
  132. aiq/object_store/models.py +36 -0
  133. aiq/object_store/register.py +20 -0
  134. aiq/observability/__init__.py +14 -0
  135. aiq/observability/exporter/__init__.py +14 -0
  136. aiq/observability/exporter/base_exporter.py +449 -0
  137. aiq/observability/exporter/exporter.py +78 -0
  138. aiq/observability/exporter/file_exporter.py +33 -0
  139. aiq/observability/exporter/processing_exporter.py +269 -0
  140. aiq/observability/exporter/raw_exporter.py +52 -0
  141. aiq/observability/exporter/span_exporter.py +264 -0
  142. aiq/observability/exporter_manager.py +335 -0
  143. aiq/observability/mixin/__init__.py +14 -0
  144. aiq/observability/mixin/batch_config_mixin.py +26 -0
  145. aiq/observability/mixin/collector_config_mixin.py +23 -0
  146. aiq/observability/mixin/file_mixin.py +288 -0
  147. aiq/observability/mixin/file_mode.py +23 -0
  148. aiq/observability/mixin/resource_conflict_mixin.py +134 -0
  149. aiq/observability/mixin/serialize_mixin.py +61 -0
  150. aiq/observability/mixin/type_introspection_mixin.py +183 -0
  151. aiq/observability/processor/__init__.py +14 -0
  152. aiq/observability/processor/batching_processor.py +316 -0
  153. aiq/observability/processor/intermediate_step_serializer.py +28 -0
  154. aiq/observability/processor/processor.py +68 -0
  155. aiq/observability/register.py +32 -116
  156. aiq/observability/utils/__init__.py +14 -0
  157. aiq/observability/utils/dict_utils.py +236 -0
  158. aiq/observability/utils/time_utils.py +31 -0
  159. aiq/profiler/calc/__init__.py +14 -0
  160. aiq/profiler/calc/calc_runner.py +623 -0
  161. aiq/profiler/calc/calculations.py +288 -0
  162. aiq/profiler/calc/data_models.py +176 -0
  163. aiq/profiler/calc/plot.py +345 -0
  164. aiq/profiler/data_models.py +2 -0
  165. aiq/profiler/profile_runner.py +16 -13
  166. aiq/runtime/loader.py +8 -2
  167. aiq/runtime/runner.py +23 -9
  168. aiq/runtime/session.py +16 -5
  169. aiq/tool/chat_completion.py +74 -0
  170. aiq/tool/code_execution/README.md +152 -0
  171. aiq/tool/code_execution/code_sandbox.py +151 -72
  172. aiq/tool/code_execution/local_sandbox/.gitignore +1 -0
  173. aiq/tool/code_execution/local_sandbox/local_sandbox_server.py +139 -24
  174. aiq/tool/code_execution/local_sandbox/sandbox.requirements.txt +3 -1
  175. aiq/tool/code_execution/local_sandbox/start_local_sandbox.sh +27 -2
  176. aiq/tool/code_execution/register.py +7 -3
  177. aiq/tool/code_execution/test_code_execution_sandbox.py +414 -0
  178. aiq/tool/mcp/exceptions.py +142 -0
  179. aiq/tool/mcp/mcp_client.py +17 -3
  180. aiq/tool/mcp/mcp_tool.py +1 -1
  181. aiq/tool/register.py +1 -0
  182. aiq/tool/server_tools.py +2 -2
  183. aiq/utils/exception_handlers/automatic_retries.py +289 -0
  184. aiq/utils/exception_handlers/mcp.py +211 -0
  185. aiq/utils/io/model_processing.py +28 -0
  186. aiq/utils/log_utils.py +37 -0
  187. aiq/utils/string_utils.py +38 -0
  188. aiq/utils/type_converter.py +18 -2
  189. aiq/utils/type_utils.py +87 -0
  190. {aiqtoolkit-1.2.0a20250707.dist-info → aiqtoolkit-1.2.0a20250731.dist-info}/METADATA +37 -9
  191. {aiqtoolkit-1.2.0a20250707.dist-info → aiqtoolkit-1.2.0a20250731.dist-info}/RECORD +196 -81
  192. {aiqtoolkit-1.2.0a20250707.dist-info → aiqtoolkit-1.2.0a20250731.dist-info}/entry_points.txt +3 -0
  193. aiq/front_ends/fastapi/websocket.py +0 -153
  194. aiq/observability/async_otel_listener.py +0 -470
  195. {aiqtoolkit-1.2.0a20250707.dist-info → aiqtoolkit-1.2.0a20250731.dist-info}/WHEEL +0 -0
  196. {aiqtoolkit-1.2.0a20250707.dist-info → aiqtoolkit-1.2.0a20250731.dist-info}/licenses/LICENSE-3rd-party.txt +0 -0
  197. {aiqtoolkit-1.2.0a20250707.dist-info → aiqtoolkit-1.2.0a20250731.dist-info}/licenses/LICENSE.md +0 -0
  198. {aiqtoolkit-1.2.0a20250707.dist-info → aiqtoolkit-1.2.0a20250731.dist-info}/top_level.txt +0 -0
aiq/builder/context.py CHANGED
@@ -22,6 +22,9 @@ from contextvars import ContextVar
22
22
 
23
23
  from aiq.builder.intermediate_step_manager import IntermediateStepManager
24
24
  from aiq.builder.user_interaction_manager import AIQUserInteractionManager
25
+ from aiq.data_models.authentication import AuthenticatedContext
26
+ from aiq.data_models.authentication import AuthFlowType
27
+ from aiq.data_models.authentication import AuthProviderBaseConfig
25
28
  from aiq.data_models.interactive import HumanResponse
26
29
  from aiq.data_models.interactive import InteractionPrompt
27
30
  from aiq.data_models.intermediate_step import IntermediateStep
@@ -76,6 +79,9 @@ class AIQContextState(metaclass=Singleton):
76
79
  | None] = ContextVar(
77
80
  "user_input_callback",
78
81
  default=AIQUserInteractionManager.default_callback_handler)
82
+ self.user_auth_callback: ContextVar[Callable[[AuthProviderBaseConfig, AuthFlowType],
83
+ Awaitable[AuthenticatedContext]]
84
+ | None] = ContextVar("user_auth_callback", default=None)
79
85
 
80
86
  @staticmethod
81
87
  def get() -> "AIQContextState":
@@ -224,6 +230,26 @@ class AIQContext:
224
230
  """
225
231
  return self._context_state.active_span_id_stack.get()[-1]
226
232
 
233
+ @property
234
+ def user_auth_callback(self) -> Callable[[AuthProviderBaseConfig, AuthFlowType], Awaitable[AuthenticatedContext]]:
235
+ """
236
+ Retrieves the user authentication callback function from the context state.
237
+
238
+ This property provides access to the user authentication callback function stored in the context state.
239
+ The callback function is responsible for handling user authentication based on the provided configuration.
240
+
241
+ Returns:
242
+ Callable[[AuthenticationBaseConfig], Awaitable[AuthenticatedContext]]: The user authentication
243
+ callback function.
244
+
245
+ Raises:
246
+ RuntimeError: If the user authentication callback is not set in the context.
247
+ """
248
+ callback = self._context_state.user_auth_callback.get()
249
+ if callback is None:
250
+ raise RuntimeError("User authentication callback is not set in the context.")
251
+ return callback
252
+
227
253
  @staticmethod
228
254
  def get() -> "AIQContext":
229
255
  """
@@ -102,14 +102,55 @@ class WorkflowEvalBuilder(WorkflowBuilder, EvalBuilder):
102
102
 
103
103
  return tools
104
104
 
105
+ def _log_build_failure_evaluator(self,
106
+ failing_evaluator_name: str,
107
+ completed_evaluators: list[str],
108
+ remaining_evaluators: list[str],
109
+ original_error: Exception) -> None:
110
+ """
111
+ Log comprehensive evaluator build failure information.
112
+
113
+ Args:
114
+ failing_evaluator_name (str): The name of the evaluator that failed to build
115
+ completed_evaluators (list[str]): List of evaluator names that were successfully built
116
+ remaining_evaluators (list[str]): List of evaluator names still to be built
117
+ original_error (Exception): The original exception that caused the failure
118
+ """
119
+ # Convert evaluator names to (name, type) tuples for consistent logging
120
+ completed_components = [(name, "evaluator") for name in completed_evaluators]
121
+ remaining_components = [(name, "evaluator") for name in remaining_evaluators]
122
+
123
+ # Use the inherited common logging method from WorkflowBuilder
124
+ self._log_build_failure(failing_evaluator_name,
125
+ "evaluator",
126
+ completed_components,
127
+ remaining_components,
128
+ original_error)
129
+
105
130
  async def populate_builder(self, config: AIQConfig):
106
131
  # Skip setting workflow if workflow config is EmptyFunctionConfig
107
132
  skip_workflow = isinstance(config.workflow, EmptyFunctionConfig)
108
133
 
109
134
  await super().populate_builder(config, skip_workflow)
110
- # Instantiate the evaluators
135
+
136
+ # Initialize progress tracking for evaluators
137
+ completed_evaluators = []
138
+ remaining_evaluators = list(config.eval.evaluators.keys())
139
+
140
+ # Instantiate the evaluators with enhanced error logging
111
141
  for name, evaluator_config in config.eval.evaluators.items():
112
- await self.add_evaluator(name, evaluator_config)
142
+ try:
143
+ # Remove from remaining as we start building
144
+ remaining_evaluators.remove(name)
145
+
146
+ await self.add_evaluator(name, evaluator_config)
147
+
148
+ # Add to completed after successful build
149
+ completed_evaluators.append(name)
150
+
151
+ except Exception as e:
152
+ self._log_build_failure_evaluator(name, completed_evaluators, remaining_evaluators, e)
153
+ raise
113
154
 
114
155
  @classmethod
115
156
  @asynccontextmanager
aiq/builder/function.py CHANGED
@@ -80,6 +80,25 @@ class Function(FunctionBase[InputT, StreamingOutputT, SingleOutputT], ABC):
80
80
 
81
81
  return self._converter.convert(value, to_type=to_type)
82
82
 
83
+ def try_convert(self, value: typing.Any, to_type: type[_T]) -> _T:
84
+ """
85
+ Converts the given value to the specified type using graceful error handling.
86
+ If conversion fails, returns the original value and continues processing.
87
+
88
+ Parameters
89
+ ----------
90
+ value : typing.Any
91
+ The value to convert.
92
+ to_type : type
93
+ The type to convert the value to.
94
+
95
+ Returns
96
+ -------
97
+ _T
98
+ The converted value, or original value if conversion fails.
99
+ """
100
+ return self._converter.try_convert(value, to_type=to_type)
101
+
83
102
  @abstractmethod
84
103
  async def _ainvoke(self, value: InputT) -> SingleOutputT:
85
104
  pass
@@ -120,7 +139,7 @@ class Function(FunctionBase[InputT, StreamingOutputT, SingleOutputT], ABC):
120
139
  result = await self._ainvoke(converted_input)
121
140
 
122
141
  if to_type is not None and not isinstance(result, to_type):
123
- result = self._converter.convert(result, to_type=to_type)
142
+ result = self._converter.try_convert(result, to_type=to_type)
124
143
 
125
144
  manager.set_output(result)
126
145
 
@@ -198,16 +217,25 @@ class Function(FunctionBase[InputT, StreamingOutputT, SingleOutputT], ABC):
198
217
  The output of the function optionally converted to the specified type.
199
218
  """
200
219
 
201
- with self._context.push_active_function(self.config.type, input_data=value):
220
+ with self._context.push_active_function(self.instance_name, input_data=value) as manager:
202
221
  try:
203
222
  converted_input: InputT = self._convert_input(value) # type: ignore
204
223
 
205
- async for data in self._astream(converted_input):
224
+ # Collect streaming outputs to capture the final result
225
+ final_output: list[typing.Any] = []
206
226
 
227
+ async for data in self._astream(converted_input):
207
228
  if to_type is not None and not isinstance(data, to_type):
208
- yield self._converter.convert(data, to_type=to_type)
229
+ converted_data = self._converter.try_convert(data, to_type=to_type)
230
+ final_output.append(converted_data)
231
+ yield converted_data
209
232
  else:
233
+ final_output.append(data)
210
234
  yield data
235
+
236
+ # Set the final output for intermediate step tracking
237
+ manager.set_output(final_output)
238
+
211
239
  except Exception as e:
212
240
  logger.error("Error with astream in function with input: %s.", value, exc_info=True)
213
241
  raise e
@@ -373,4 +373,4 @@ class FunctionBase(typing.Generic[InputT, StreamingOutputT, SingleOutputT], ABC)
373
373
  return value
374
374
 
375
375
  # Fallback to the converter
376
- return self._converter.convert(value, to_type=self.input_class)
376
+ return self._converter.try_convert(value, to_type=self.input_class)
@@ -20,7 +20,6 @@ import typing
20
20
  from aiq.data_models.intermediate_step import IntermediateStep
21
21
  from aiq.data_models.intermediate_step import IntermediateStepPayload
22
22
  from aiq.data_models.intermediate_step import IntermediateStepState
23
- from aiq.data_models.invocation_node import InvocationNode
24
23
  from aiq.utils.reactive.observable import OnComplete
25
24
  from aiq.utils.reactive.observable import OnError
26
25
  from aiq.utils.reactive.observable import OnNext
@@ -37,7 +36,7 @@ class OpenStep:
37
36
  step_id: str
38
37
  step_name: str
39
38
  step_type: str
40
- step_parent_id: str | None
39
+ step_parent_id: str
41
40
  prev_stack: list[str]
42
41
  active_stack: list[str]
43
42
 
@@ -153,15 +152,14 @@ class IntermediateStepManager:
153
152
  return
154
153
 
155
154
  parent_step_id = open_step.step_parent_id
155
+ else:
156
+ assert False, "Invalid event state"
156
157
 
157
158
  active_function = self._context_state.active_function.get()
158
159
 
159
- function_ancestry = InvocationNode(function_name=active_function.function_name,
160
- function_id=active_function.function_id,
161
- parent_id=parent_step_id,
162
- parent_name=active_function.parent_name)
163
-
164
- intermediate_step = IntermediateStep(function_ancestry=function_ancestry, payload=payload)
160
+ intermediate_step = IntermediateStep(parent_id=parent_step_id,
161
+ function_ancestry=active_function,
162
+ payload=payload)
165
163
 
166
164
  self._context_state.event_stream.get().on_next(intermediate_step)
167
165
 
@@ -13,6 +13,7 @@
13
13
  # See the License for the specific language governing permissions and
14
14
  # limitations under the License.
15
15
 
16
+ import logging
16
17
  import time
17
18
  import uuid
18
19
 
@@ -22,6 +23,8 @@ from aiq.data_models.interactive import InteractionPrompt
22
23
  from aiq.data_models.interactive import InteractionResponse
23
24
  from aiq.data_models.interactive import InteractionStatus
24
25
 
26
+ logger = logging.getLogger(__name__)
27
+
25
28
 
26
29
  class AIQUserInteractionManager:
27
30
  """
aiq/builder/workflow.py CHANGED
@@ -27,19 +27,12 @@ from aiq.builder.function_base import StreamingOutputT
27
27
  from aiq.builder.llm import LLMProviderInfo
28
28
  from aiq.builder.retriever import RetrieverProviderInfo
29
29
  from aiq.data_models.config import AIQConfig
30
+ from aiq.experimental.inference_time_scaling.models.strategy_base import StrategyBase
30
31
  from aiq.memory.interfaces import MemoryEditor
32
+ from aiq.object_store.interfaces import ObjectStore
33
+ from aiq.observability.exporter.base_exporter import BaseExporter
34
+ from aiq.observability.exporter_manager import ExporterManager
31
35
  from aiq.runtime.runner import AIQRunner
32
- from aiq.utils.optional_imports import TelemetryOptionalImportError
33
- from aiq.utils.optional_imports import try_import_opentelemetry
34
-
35
- # Try to import OpenTelemetry modules
36
- # If the dependencies are not installed, use a dummy span exporter here
37
- try:
38
- opentelemetry = try_import_opentelemetry()
39
- from opentelemetry.sdk.trace.export import SpanExporter
40
- except TelemetryOptionalImportError:
41
- from aiq.utils.optional_imports import DummySpanExporter # pylint: disable=ungrouped-imports
42
- SpanExporter = DummySpanExporter
43
36
 
44
37
  callback_handler_var: ContextVar[Any | None] = ContextVar("callback_handler_var", default=None)
45
38
 
@@ -54,8 +47,10 @@ class Workflow(FunctionBase[InputT, StreamingOutputT, SingleOutputT]):
54
47
  llms: dict[str, LLMProviderInfo] | None = None,
55
48
  embeddings: dict[str, EmbedderProviderInfo] | None = None,
56
49
  memory: dict[str, MemoryEditor] | None = None,
57
- exporters: dict[str, SpanExporter] | None = None,
50
+ object_stores: dict[str, ObjectStore] | None = None,
51
+ telemetry_exporters: dict[str, BaseExporter] | None = None,
58
52
  retrievers: dict[str | None, RetrieverProviderInfo] | None = None,
53
+ its_strategies: dict[str, StrategyBase] | None = None,
59
54
  context_state: AIQContextState):
60
55
 
61
56
  super().__init__(input_schema=entry_fn.input_schema,
@@ -67,14 +62,17 @@ class Workflow(FunctionBase[InputT, StreamingOutputT, SingleOutputT]):
67
62
  self.llms = llms or {}
68
63
  self.embeddings = embeddings or {}
69
64
  self.memory = memory or {}
65
+ self.telemetry_exporters = telemetry_exporters or {}
66
+ self.object_stores = object_stores or {}
70
67
  self.retrievers = retrievers or {}
71
68
 
69
+ self._exporter_manager = ExporterManager.from_exporters(self.telemetry_exporters)
70
+ self.its_strategies = its_strategies or {}
71
+
72
72
  self._entry_fn = entry_fn
73
73
 
74
74
  self._context_state = context_state
75
75
 
76
- self._exporters = exporters or {}
77
-
78
76
  @property
79
77
  def has_streaming_output(self) -> bool:
80
78
 
@@ -91,8 +89,11 @@ class Workflow(FunctionBase[InputT, StreamingOutputT, SingleOutputT]):
91
89
  Called each time we start a new workflow run. We'll create
92
90
  a new top-level workflow span here.
93
91
  """
94
- async with AIQRunner(input_message=message, entry_fn=self._entry_fn,
95
- context_state=self._context_state) as runner:
92
+
93
+ async with AIQRunner(input_message=message,
94
+ entry_fn=self._entry_fn,
95
+ context_state=self._context_state,
96
+ exporter_manager=self._exporter_manager.get()) as runner:
96
97
 
97
98
  # The caller can `yield runner` so they can do `runner.result()` or `runner.result_stream()`
98
99
  yield runner
@@ -121,8 +122,10 @@ class Workflow(FunctionBase[InputT, StreamingOutputT, SingleOutputT]):
121
122
  llms: dict[str, LLMProviderInfo] | None = None,
122
123
  embeddings: dict[str, EmbedderProviderInfo] | None = None,
123
124
  memory: dict[str, MemoryEditor] | None = None,
124
- exporters: dict[str, SpanExporter] | None = None,
125
+ object_stores: dict[str, ObjectStore] | None = None,
126
+ telemetry_exporters: dict[str, BaseExporter] | None = None,
125
127
  retrievers: dict[str | None, RetrieverProviderInfo] | None = None,
128
+ its_strategies: dict[str, StrategyBase] | None = None,
126
129
  context_state: AIQContextState) -> 'Workflow[InputT, StreamingOutputT, SingleOutputT]':
127
130
 
128
131
  input_type: type = entry_fn.input_type
@@ -138,6 +141,8 @@ class Workflow(FunctionBase[InputT, StreamingOutputT, SingleOutputT]):
138
141
  llms=llms,
139
142
  embeddings=embeddings,
140
143
  memory=memory,
141
- exporters=exporters,
144
+ object_stores=object_stores,
145
+ telemetry_exporters=telemetry_exporters,
142
146
  retrievers=retrievers,
147
+ its_strategies=its_strategies,
143
148
  context_state=context_state)