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.
- aiq/agent/__init__.py +0 -0
- aiq/agent/base.py +76 -0
- aiq/agent/dual_node.py +67 -0
- aiq/agent/react_agent/__init__.py +0 -0
- aiq/agent/react_agent/agent.py +322 -0
- aiq/agent/react_agent/output_parser.py +104 -0
- aiq/agent/react_agent/prompt.py +46 -0
- aiq/agent/react_agent/register.py +148 -0
- aiq/agent/reasoning_agent/__init__.py +0 -0
- aiq/agent/reasoning_agent/reasoning_agent.py +224 -0
- aiq/agent/register.py +23 -0
- aiq/agent/rewoo_agent/__init__.py +0 -0
- aiq/agent/rewoo_agent/agent.py +410 -0
- aiq/agent/rewoo_agent/prompt.py +108 -0
- aiq/agent/rewoo_agent/register.py +158 -0
- aiq/agent/tool_calling_agent/__init__.py +0 -0
- aiq/agent/tool_calling_agent/agent.py +123 -0
- aiq/agent/tool_calling_agent/register.py +105 -0
- aiq/builder/__init__.py +0 -0
- aiq/builder/builder.py +223 -0
- aiq/builder/component_utils.py +303 -0
- aiq/builder/context.py +198 -0
- aiq/builder/embedder.py +24 -0
- aiq/builder/eval_builder.py +116 -0
- aiq/builder/evaluator.py +29 -0
- aiq/builder/framework_enum.py +24 -0
- aiq/builder/front_end.py +73 -0
- aiq/builder/function.py +297 -0
- aiq/builder/function_base.py +372 -0
- aiq/builder/function_info.py +627 -0
- aiq/builder/intermediate_step_manager.py +125 -0
- aiq/builder/llm.py +25 -0
- aiq/builder/retriever.py +25 -0
- aiq/builder/user_interaction_manager.py +71 -0
- aiq/builder/workflow.py +134 -0
- aiq/builder/workflow_builder.py +733 -0
- aiq/cli/__init__.py +14 -0
- aiq/cli/cli_utils/__init__.py +0 -0
- aiq/cli/cli_utils/config_override.py +233 -0
- aiq/cli/cli_utils/validation.py +37 -0
- aiq/cli/commands/__init__.py +0 -0
- aiq/cli/commands/configure/__init__.py +0 -0
- aiq/cli/commands/configure/channel/__init__.py +0 -0
- aiq/cli/commands/configure/channel/add.py +28 -0
- aiq/cli/commands/configure/channel/channel.py +34 -0
- aiq/cli/commands/configure/channel/remove.py +30 -0
- aiq/cli/commands/configure/channel/update.py +30 -0
- aiq/cli/commands/configure/configure.py +33 -0
- aiq/cli/commands/evaluate.py +139 -0
- aiq/cli/commands/info/__init__.py +14 -0
- aiq/cli/commands/info/info.py +37 -0
- aiq/cli/commands/info/list_channels.py +32 -0
- aiq/cli/commands/info/list_components.py +129 -0
- aiq/cli/commands/registry/__init__.py +14 -0
- aiq/cli/commands/registry/publish.py +88 -0
- aiq/cli/commands/registry/pull.py +118 -0
- aiq/cli/commands/registry/registry.py +36 -0
- aiq/cli/commands/registry/remove.py +108 -0
- aiq/cli/commands/registry/search.py +155 -0
- aiq/cli/commands/start.py +250 -0
- aiq/cli/commands/uninstall.py +83 -0
- aiq/cli/commands/validate.py +47 -0
- aiq/cli/commands/workflow/__init__.py +14 -0
- aiq/cli/commands/workflow/templates/__init__.py.j2 +0 -0
- aiq/cli/commands/workflow/templates/config.yml.j2 +16 -0
- aiq/cli/commands/workflow/templates/pyproject.toml.j2 +22 -0
- aiq/cli/commands/workflow/templates/register.py.j2 +5 -0
- aiq/cli/commands/workflow/templates/workflow.py.j2 +36 -0
- aiq/cli/commands/workflow/workflow.py +37 -0
- aiq/cli/commands/workflow/workflow_commands.py +307 -0
- aiq/cli/entrypoint.py +133 -0
- aiq/cli/main.py +44 -0
- aiq/cli/register_workflow.py +408 -0
- aiq/cli/type_registry.py +869 -0
- aiq/data_models/__init__.py +14 -0
- aiq/data_models/api_server.py +550 -0
- aiq/data_models/common.py +143 -0
- aiq/data_models/component.py +46 -0
- aiq/data_models/component_ref.py +135 -0
- aiq/data_models/config.py +349 -0
- aiq/data_models/dataset_handler.py +122 -0
- aiq/data_models/discovery_metadata.py +269 -0
- aiq/data_models/embedder.py +26 -0
- aiq/data_models/evaluate.py +101 -0
- aiq/data_models/evaluator.py +26 -0
- aiq/data_models/front_end.py +26 -0
- aiq/data_models/function.py +30 -0
- aiq/data_models/function_dependencies.py +64 -0
- aiq/data_models/interactive.py +237 -0
- aiq/data_models/intermediate_step.py +269 -0
- aiq/data_models/invocation_node.py +38 -0
- aiq/data_models/llm.py +26 -0
- aiq/data_models/logging.py +26 -0
- aiq/data_models/memory.py +26 -0
- aiq/data_models/profiler.py +53 -0
- aiq/data_models/registry_handler.py +26 -0
- aiq/data_models/retriever.py +30 -0
- aiq/data_models/step_adaptor.py +64 -0
- aiq/data_models/streaming.py +33 -0
- aiq/data_models/swe_bench_model.py +54 -0
- aiq/data_models/telemetry_exporter.py +26 -0
- aiq/embedder/__init__.py +0 -0
- aiq/embedder/langchain_client.py +41 -0
- aiq/embedder/nim_embedder.py +58 -0
- aiq/embedder/openai_embedder.py +42 -0
- aiq/embedder/register.py +24 -0
- aiq/eval/__init__.py +14 -0
- aiq/eval/config.py +42 -0
- aiq/eval/dataset_handler/__init__.py +0 -0
- aiq/eval/dataset_handler/dataset_downloader.py +106 -0
- aiq/eval/dataset_handler/dataset_filter.py +52 -0
- aiq/eval/dataset_handler/dataset_handler.py +164 -0
- aiq/eval/evaluate.py +322 -0
- aiq/eval/evaluator/__init__.py +14 -0
- aiq/eval/evaluator/evaluator_model.py +44 -0
- aiq/eval/intermediate_step_adapter.py +93 -0
- aiq/eval/rag_evaluator/__init__.py +0 -0
- aiq/eval/rag_evaluator/evaluate.py +138 -0
- aiq/eval/rag_evaluator/register.py +138 -0
- aiq/eval/register.py +22 -0
- aiq/eval/remote_workflow.py +128 -0
- aiq/eval/runtime_event_subscriber.py +52 -0
- aiq/eval/swe_bench_evaluator/__init__.py +0 -0
- aiq/eval/swe_bench_evaluator/evaluate.py +215 -0
- aiq/eval/swe_bench_evaluator/register.py +36 -0
- aiq/eval/trajectory_evaluator/__init__.py +0 -0
- aiq/eval/trajectory_evaluator/evaluate.py +118 -0
- aiq/eval/trajectory_evaluator/register.py +40 -0
- aiq/eval/utils/__init__.py +0 -0
- aiq/eval/utils/output_uploader.py +131 -0
- aiq/eval/utils/tqdm_position_registry.py +40 -0
- aiq/front_ends/__init__.py +14 -0
- aiq/front_ends/console/__init__.py +14 -0
- aiq/front_ends/console/console_front_end_config.py +32 -0
- aiq/front_ends/console/console_front_end_plugin.py +107 -0
- aiq/front_ends/console/register.py +25 -0
- aiq/front_ends/cron/__init__.py +14 -0
- aiq/front_ends/fastapi/__init__.py +14 -0
- aiq/front_ends/fastapi/fastapi_front_end_config.py +150 -0
- aiq/front_ends/fastapi/fastapi_front_end_plugin.py +103 -0
- aiq/front_ends/fastapi/fastapi_front_end_plugin_worker.py +574 -0
- aiq/front_ends/fastapi/intermediate_steps_subscriber.py +80 -0
- aiq/front_ends/fastapi/job_store.py +161 -0
- aiq/front_ends/fastapi/main.py +70 -0
- aiq/front_ends/fastapi/message_handler.py +279 -0
- aiq/front_ends/fastapi/message_validator.py +345 -0
- aiq/front_ends/fastapi/register.py +25 -0
- aiq/front_ends/fastapi/response_helpers.py +181 -0
- aiq/front_ends/fastapi/step_adaptor.py +315 -0
- aiq/front_ends/fastapi/websocket.py +148 -0
- aiq/front_ends/mcp/__init__.py +14 -0
- aiq/front_ends/mcp/mcp_front_end_config.py +32 -0
- aiq/front_ends/mcp/mcp_front_end_plugin.py +93 -0
- aiq/front_ends/mcp/register.py +27 -0
- aiq/front_ends/mcp/tool_converter.py +242 -0
- aiq/front_ends/register.py +22 -0
- aiq/front_ends/simple_base/__init__.py +14 -0
- aiq/front_ends/simple_base/simple_front_end_plugin_base.py +52 -0
- aiq/llm/__init__.py +0 -0
- aiq/llm/nim_llm.py +45 -0
- aiq/llm/openai_llm.py +45 -0
- aiq/llm/register.py +22 -0
- aiq/llm/utils/__init__.py +14 -0
- aiq/llm/utils/env_config_value.py +94 -0
- aiq/llm/utils/error.py +17 -0
- aiq/memory/__init__.py +20 -0
- aiq/memory/interfaces.py +183 -0
- aiq/memory/models.py +102 -0
- aiq/meta/module_to_distro.json +3 -0
- aiq/meta/pypi.md +59 -0
- aiq/observability/__init__.py +0 -0
- aiq/observability/async_otel_listener.py +270 -0
- aiq/observability/register.py +97 -0
- aiq/plugins/.namespace +1 -0
- aiq/profiler/__init__.py +0 -0
- aiq/profiler/callbacks/__init__.py +0 -0
- aiq/profiler/callbacks/agno_callback_handler.py +295 -0
- aiq/profiler/callbacks/base_callback_class.py +20 -0
- aiq/profiler/callbacks/langchain_callback_handler.py +278 -0
- aiq/profiler/callbacks/llama_index_callback_handler.py +205 -0
- aiq/profiler/callbacks/semantic_kernel_callback_handler.py +238 -0
- aiq/profiler/callbacks/token_usage_base_model.py +27 -0
- aiq/profiler/data_frame_row.py +51 -0
- aiq/profiler/decorators/__init__.py +0 -0
- aiq/profiler/decorators/framework_wrapper.py +131 -0
- aiq/profiler/decorators/function_tracking.py +254 -0
- aiq/profiler/forecasting/__init__.py +0 -0
- aiq/profiler/forecasting/config.py +18 -0
- aiq/profiler/forecasting/model_trainer.py +75 -0
- aiq/profiler/forecasting/models/__init__.py +22 -0
- aiq/profiler/forecasting/models/forecasting_base_model.py +40 -0
- aiq/profiler/forecasting/models/linear_model.py +196 -0
- aiq/profiler/forecasting/models/random_forest_regressor.py +268 -0
- aiq/profiler/inference_metrics_model.py +25 -0
- aiq/profiler/inference_optimization/__init__.py +0 -0
- aiq/profiler/inference_optimization/bottleneck_analysis/__init__.py +0 -0
- aiq/profiler/inference_optimization/bottleneck_analysis/nested_stack_analysis.py +452 -0
- aiq/profiler/inference_optimization/bottleneck_analysis/simple_stack_analysis.py +258 -0
- aiq/profiler/inference_optimization/data_models.py +386 -0
- aiq/profiler/inference_optimization/experimental/__init__.py +0 -0
- aiq/profiler/inference_optimization/experimental/concurrency_spike_analysis.py +468 -0
- aiq/profiler/inference_optimization/experimental/prefix_span_analysis.py +405 -0
- aiq/profiler/inference_optimization/llm_metrics.py +212 -0
- aiq/profiler/inference_optimization/prompt_caching.py +163 -0
- aiq/profiler/inference_optimization/token_uniqueness.py +107 -0
- aiq/profiler/inference_optimization/workflow_runtimes.py +72 -0
- aiq/profiler/intermediate_property_adapter.py +102 -0
- aiq/profiler/profile_runner.py +433 -0
- aiq/profiler/utils.py +184 -0
- aiq/registry_handlers/__init__.py +0 -0
- aiq/registry_handlers/local/__init__.py +0 -0
- aiq/registry_handlers/local/local_handler.py +176 -0
- aiq/registry_handlers/local/register_local.py +37 -0
- aiq/registry_handlers/metadata_factory.py +60 -0
- aiq/registry_handlers/package_utils.py +198 -0
- aiq/registry_handlers/pypi/__init__.py +0 -0
- aiq/registry_handlers/pypi/pypi_handler.py +251 -0
- aiq/registry_handlers/pypi/register_pypi.py +40 -0
- aiq/registry_handlers/register.py +21 -0
- aiq/registry_handlers/registry_handler_base.py +157 -0
- aiq/registry_handlers/rest/__init__.py +0 -0
- aiq/registry_handlers/rest/register_rest.py +56 -0
- aiq/registry_handlers/rest/rest_handler.py +237 -0
- aiq/registry_handlers/schemas/__init__.py +0 -0
- aiq/registry_handlers/schemas/headers.py +42 -0
- aiq/registry_handlers/schemas/package.py +68 -0
- aiq/registry_handlers/schemas/publish.py +63 -0
- aiq/registry_handlers/schemas/pull.py +81 -0
- aiq/registry_handlers/schemas/remove.py +36 -0
- aiq/registry_handlers/schemas/search.py +91 -0
- aiq/registry_handlers/schemas/status.py +47 -0
- aiq/retriever/__init__.py +0 -0
- aiq/retriever/interface.py +37 -0
- aiq/retriever/milvus/__init__.py +14 -0
- aiq/retriever/milvus/register.py +81 -0
- aiq/retriever/milvus/retriever.py +228 -0
- aiq/retriever/models.py +74 -0
- aiq/retriever/nemo_retriever/__init__.py +14 -0
- aiq/retriever/nemo_retriever/register.py +60 -0
- aiq/retriever/nemo_retriever/retriever.py +190 -0
- aiq/retriever/register.py +22 -0
- aiq/runtime/__init__.py +14 -0
- aiq/runtime/loader.py +188 -0
- aiq/runtime/runner.py +176 -0
- aiq/runtime/session.py +116 -0
- aiq/settings/__init__.py +0 -0
- aiq/settings/global_settings.py +318 -0
- aiq/test/.namespace +1 -0
- aiq/tool/__init__.py +0 -0
- aiq/tool/code_execution/__init__.py +0 -0
- aiq/tool/code_execution/code_sandbox.py +188 -0
- aiq/tool/code_execution/local_sandbox/Dockerfile.sandbox +60 -0
- aiq/tool/code_execution/local_sandbox/__init__.py +13 -0
- aiq/tool/code_execution/local_sandbox/local_sandbox_server.py +79 -0
- aiq/tool/code_execution/local_sandbox/sandbox.requirements.txt +4 -0
- aiq/tool/code_execution/local_sandbox/start_local_sandbox.sh +25 -0
- aiq/tool/code_execution/register.py +70 -0
- aiq/tool/code_execution/utils.py +100 -0
- aiq/tool/datetime_tools.py +42 -0
- aiq/tool/document_search.py +141 -0
- aiq/tool/github_tools/__init__.py +0 -0
- aiq/tool/github_tools/create_github_commit.py +133 -0
- aiq/tool/github_tools/create_github_issue.py +87 -0
- aiq/tool/github_tools/create_github_pr.py +106 -0
- aiq/tool/github_tools/get_github_file.py +106 -0
- aiq/tool/github_tools/get_github_issue.py +166 -0
- aiq/tool/github_tools/get_github_pr.py +256 -0
- aiq/tool/github_tools/update_github_issue.py +100 -0
- aiq/tool/mcp/__init__.py +14 -0
- aiq/tool/mcp/mcp_client.py +220 -0
- aiq/tool/mcp/mcp_tool.py +75 -0
- aiq/tool/memory_tools/__init__.py +0 -0
- aiq/tool/memory_tools/add_memory_tool.py +67 -0
- aiq/tool/memory_tools/delete_memory_tool.py +67 -0
- aiq/tool/memory_tools/get_memory_tool.py +72 -0
- aiq/tool/nvidia_rag.py +95 -0
- aiq/tool/register.py +36 -0
- aiq/tool/retriever.py +89 -0
- aiq/utils/__init__.py +0 -0
- aiq/utils/data_models/__init__.py +0 -0
- aiq/utils/data_models/schema_validator.py +58 -0
- aiq/utils/debugging_utils.py +43 -0
- aiq/utils/exception_handlers/__init__.py +0 -0
- aiq/utils/exception_handlers/schemas.py +114 -0
- aiq/utils/io/__init__.py +0 -0
- aiq/utils/io/yaml_tools.py +50 -0
- aiq/utils/metadata_utils.py +74 -0
- aiq/utils/producer_consumer_queue.py +178 -0
- aiq/utils/reactive/__init__.py +0 -0
- aiq/utils/reactive/base/__init__.py +0 -0
- aiq/utils/reactive/base/observable_base.py +65 -0
- aiq/utils/reactive/base/observer_base.py +55 -0
- aiq/utils/reactive/base/subject_base.py +79 -0
- aiq/utils/reactive/observable.py +59 -0
- aiq/utils/reactive/observer.py +76 -0
- aiq/utils/reactive/subject.py +131 -0
- aiq/utils/reactive/subscription.py +49 -0
- aiq/utils/settings/__init__.py +0 -0
- aiq/utils/settings/global_settings.py +197 -0
- aiq/utils/type_converter.py +232 -0
- aiq/utils/type_utils.py +397 -0
- aiq/utils/url_utils.py +27 -0
- aiqtoolkit-1.1.0a20250429.dist-info/METADATA +326 -0
- aiqtoolkit-1.1.0a20250429.dist-info/RECORD +309 -0
- aiqtoolkit-1.1.0a20250429.dist-info/WHEEL +5 -0
- aiqtoolkit-1.1.0a20250429.dist-info/entry_points.txt +17 -0
- aiqtoolkit-1.1.0a20250429.dist-info/licenses/LICENSE-3rd-party.txt +3686 -0
- aiqtoolkit-1.1.0a20250429.dist-info/licenses/LICENSE.md +201 -0
- aiqtoolkit-1.1.0a20250429.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,107 @@
|
|
|
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 asyncio
|
|
17
|
+
import logging
|
|
18
|
+
from io import StringIO
|
|
19
|
+
|
|
20
|
+
import click
|
|
21
|
+
from colorama import Fore
|
|
22
|
+
|
|
23
|
+
from aiq.builder.workflow_builder import WorkflowBuilder
|
|
24
|
+
from aiq.data_models.interactive import HumanPromptModelType
|
|
25
|
+
from aiq.data_models.interactive import HumanResponse
|
|
26
|
+
from aiq.data_models.interactive import HumanResponseText
|
|
27
|
+
from aiq.data_models.interactive import InteractionPrompt
|
|
28
|
+
from aiq.front_ends.console.console_front_end_config import ConsoleFrontEndConfig
|
|
29
|
+
from aiq.front_ends.simple_base.simple_front_end_plugin_base import SimpleFrontEndPluginBase
|
|
30
|
+
from aiq.runtime.session import AIQSessionManager
|
|
31
|
+
|
|
32
|
+
logger = logging.getLogger(__name__)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
async def prompt_for_input_cli(question: InteractionPrompt) -> HumanResponse:
|
|
36
|
+
"""
|
|
37
|
+
A simple CLI-based callback.
|
|
38
|
+
Takes question as str, returns the typed line as str.
|
|
39
|
+
"""
|
|
40
|
+
|
|
41
|
+
if question.content.input_type == HumanPromptModelType.TEXT:
|
|
42
|
+
user_response = click.prompt(text=question.content.text)
|
|
43
|
+
|
|
44
|
+
return HumanResponseText(text=user_response)
|
|
45
|
+
|
|
46
|
+
raise ValueError("Unsupported human propmt input type. The run command only supports the 'HumanPromptText' "
|
|
47
|
+
"input type. Please use the 'serve' command to ensure full support for all input types.")
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class ConsoleFrontEndPlugin(SimpleFrontEndPluginBase[ConsoleFrontEndConfig]):
|
|
51
|
+
|
|
52
|
+
async def pre_run(self):
|
|
53
|
+
|
|
54
|
+
if (not self.front_end_config.input_query and not self.front_end_config.input_file):
|
|
55
|
+
raise click.UsageError("Must specify either --input_query or --input_file")
|
|
56
|
+
|
|
57
|
+
async def run(self):
|
|
58
|
+
|
|
59
|
+
# Must yield the workflow function otherwise it cleans up
|
|
60
|
+
async with WorkflowBuilder.from_config(config=self.full_config) as builder:
|
|
61
|
+
|
|
62
|
+
session_manager: AIQSessionManager = None
|
|
63
|
+
|
|
64
|
+
if logger.isEnabledFor(logging.INFO):
|
|
65
|
+
stream = StringIO()
|
|
66
|
+
|
|
67
|
+
self.full_config.print_summary(stream=stream)
|
|
68
|
+
|
|
69
|
+
click.echo(stream.getvalue())
|
|
70
|
+
|
|
71
|
+
workflow = builder.build()
|
|
72
|
+
session_manager = AIQSessionManager(workflow)
|
|
73
|
+
|
|
74
|
+
await self.run_workflow(session_manager)
|
|
75
|
+
|
|
76
|
+
async def run_workflow(self, session_manager: AIQSessionManager = None):
|
|
77
|
+
|
|
78
|
+
runner_outputs = None
|
|
79
|
+
|
|
80
|
+
if (self.front_end_config.input_query):
|
|
81
|
+
|
|
82
|
+
async def run_single_query(query):
|
|
83
|
+
|
|
84
|
+
async with session_manager.session(user_input_callback=prompt_for_input_cli) as session:
|
|
85
|
+
async with session.run(query) as runner:
|
|
86
|
+
base_output = await runner.result(to_type=str)
|
|
87
|
+
|
|
88
|
+
return base_output
|
|
89
|
+
|
|
90
|
+
# Convert to a list
|
|
91
|
+
input_list = list(self.front_end_config.input_query)
|
|
92
|
+
logger.debug("Processing input: %s", self.front_end_config.input_query)
|
|
93
|
+
|
|
94
|
+
runner_outputs = await asyncio.gather(*[run_single_query(query) for query in input_list])
|
|
95
|
+
|
|
96
|
+
elif (self.front_end_config.input_file):
|
|
97
|
+
|
|
98
|
+
# Run the workflow
|
|
99
|
+
with open(self.front_end_config.input_file, "r", encoding="utf-8") as f:
|
|
100
|
+
|
|
101
|
+
async with session_manager.workflow.run(f) as runner:
|
|
102
|
+
runner_outputs = await runner.result(to_type=str)
|
|
103
|
+
else:
|
|
104
|
+
assert False, "Should not reach here. Should have been caught by pre_run"
|
|
105
|
+
|
|
106
|
+
# Print result
|
|
107
|
+
logger.info(f"\n{'-' * 50}\n{Fore.GREEN}Workflow Result:\n%s{Fore.RESET}\n{'-' * 50}", runner_outputs)
|
|
@@ -0,0 +1,25 @@
|
|
|
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
|
+
from aiq.cli.register_workflow import register_front_end
|
|
17
|
+
from aiq.data_models.config import AIQConfig
|
|
18
|
+
from aiq.front_ends.console.console_front_end_config import ConsoleFrontEndConfig
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@register_front_end(config_type=ConsoleFrontEndConfig)
|
|
22
|
+
async def register_fastapi_front_end(config: ConsoleFrontEndConfig, full_config: AIQConfig):
|
|
23
|
+
from aiq.front_ends.console.console_front_end_plugin import ConsoleFrontEndPlugin
|
|
24
|
+
|
|
25
|
+
yield ConsoleFrontEndPlugin(full_config=full_config)
|
|
@@ -0,0 +1,14 @@
|
|
|
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.
|
|
@@ -0,0 +1,14 @@
|
|
|
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.
|
|
@@ -0,0 +1,150 @@
|
|
|
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 typing
|
|
18
|
+
from datetime import datetime
|
|
19
|
+
|
|
20
|
+
from pydantic import BaseModel
|
|
21
|
+
from pydantic import Field
|
|
22
|
+
|
|
23
|
+
from aiq.data_models.front_end import FrontEndBaseConfig
|
|
24
|
+
from aiq.data_models.step_adaptor import StepAdaptorConfig
|
|
25
|
+
|
|
26
|
+
logger = logging.getLogger(__name__)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class AIQEvaluateRequest(BaseModel):
|
|
30
|
+
"""Request model for the evaluate endpoint."""
|
|
31
|
+
config_file: str = Field(description="Path to the configuration file for evaluation")
|
|
32
|
+
job_id: str | None = Field(default=None, description="Unique identifier for the evaluation job")
|
|
33
|
+
reps: int = Field(default=1, description="Number of repetitions for the evaluation, defaults to 1")
|
|
34
|
+
expiry_seconds: int = Field(
|
|
35
|
+
default=3600,
|
|
36
|
+
description="Optional time (in seconds) before the job expires. Clamped between 600 (10 min) and 86400 (24h).")
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class AIQEvaluateResponse(BaseModel):
|
|
40
|
+
"""Response model for the evaluate endpoint."""
|
|
41
|
+
job_id: str = Field(description="Unique identifier for the evaluation job")
|
|
42
|
+
status: str = Field(description="Current status of the evaluation job")
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class AIQEvaluateStatusResponse(BaseModel):
|
|
46
|
+
"""Response model for the evaluate status endpoint."""
|
|
47
|
+
job_id: str = Field(description="Unique identifier for the evaluation job")
|
|
48
|
+
status: str = Field(description="Current status of the evaluation job")
|
|
49
|
+
config_file: str = Field(description="Path to the configuration file used for evaluation")
|
|
50
|
+
error: str | None = Field(default=None, description="Error message if the job failed")
|
|
51
|
+
output_path: str | None = Field(default=None,
|
|
52
|
+
description="Path to the output file if the job completed successfully")
|
|
53
|
+
created_at: datetime = Field(description="Timestamp when the job was created")
|
|
54
|
+
updated_at: datetime = Field(description="Timestamp when the job was last updated")
|
|
55
|
+
expires_at: datetime | None = Field(default=None, description="Timestamp when the job will expire")
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class FastApiFrontEndConfig(FrontEndBaseConfig, name="fastapi"):
|
|
59
|
+
"""
|
|
60
|
+
A FastAPI based front end that allows an AgentIQ workflow to be served as a microservice.
|
|
61
|
+
"""
|
|
62
|
+
|
|
63
|
+
class EndpointBase(BaseModel):
|
|
64
|
+
|
|
65
|
+
method: typing.Literal["GET", "POST", "PUT", "DELETE"]
|
|
66
|
+
description: str
|
|
67
|
+
path: str | None = Field(
|
|
68
|
+
default=None,
|
|
69
|
+
description=("Path for the default workflow. If None, no workflow endpoint is created."),
|
|
70
|
+
)
|
|
71
|
+
websocket_path: str | None = Field(
|
|
72
|
+
default=None,
|
|
73
|
+
description=("Path for the websocket. If None, no websocket is created."),
|
|
74
|
+
)
|
|
75
|
+
openai_api_path: str | None = Field(
|
|
76
|
+
default=None,
|
|
77
|
+
description=("Path for the default workflow using the OpenAI API Specification. "
|
|
78
|
+
"If None, no workflow endpoint with the OpenAI API Specification is created."),
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
class Endpoint(EndpointBase):
|
|
82
|
+
function_name: str = Field(description="The name of the function to call for this endpoint")
|
|
83
|
+
|
|
84
|
+
class CrossOriginResourceSharing(BaseModel):
|
|
85
|
+
allow_origins: list[str] | None = Field(
|
|
86
|
+
default=None, description=" A list of origins that should be permitted to make cross-origin requests.")
|
|
87
|
+
allow_origin_regex: str | None = Field(
|
|
88
|
+
default=None,
|
|
89
|
+
description="A permitted regex string to match against origins to make cross-origin requests",
|
|
90
|
+
)
|
|
91
|
+
allow_methods: list[str] | None = Field(
|
|
92
|
+
default_factory=lambda: ['GET'],
|
|
93
|
+
description="A list of HTTP methods that should be allowed for cross-origin requests.")
|
|
94
|
+
allow_headers: list[str] | None = Field(
|
|
95
|
+
default_factory=list,
|
|
96
|
+
description="A list of HTTP request headers that should be supported for cross-origin requests.")
|
|
97
|
+
allow_credentials: bool | None = Field(
|
|
98
|
+
default=False,
|
|
99
|
+
description="Indicate that cookies should be supported for cross-origin requests.",
|
|
100
|
+
)
|
|
101
|
+
expose_headers: list[str] | None = Field(
|
|
102
|
+
default_factory=list,
|
|
103
|
+
description="Indicate any response headers that should be made accessible to the browser.",
|
|
104
|
+
)
|
|
105
|
+
max_age: int | None = Field(
|
|
106
|
+
default=600,
|
|
107
|
+
description="Sets a maximum time in seconds for browsers to cache CORS responses.",
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
root_path: str = Field(default="", description="The root path for the API")
|
|
111
|
+
host: str = Field(default="localhost", description="Host to bind the server to")
|
|
112
|
+
port: int = Field(default=8000, description="Port to bind the server to", ge=0, le=65535)
|
|
113
|
+
reload: bool = Field(default=False, description="Enable auto-reload for development")
|
|
114
|
+
workers: int = Field(default=1, description="Number of workers to run", ge=1)
|
|
115
|
+
step_adaptor: StepAdaptorConfig = StepAdaptorConfig()
|
|
116
|
+
|
|
117
|
+
workflow: typing.Annotated[EndpointBase, Field(description="Endpoint for the default workflow.")] = EndpointBase(
|
|
118
|
+
method="POST",
|
|
119
|
+
path="/generate",
|
|
120
|
+
websocket_path="/websocket",
|
|
121
|
+
openai_api_path="/chat",
|
|
122
|
+
description="Executes the default AgentIQ workflow from the loaded configuration ",
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
evaluate: typing.Annotated[EndpointBase, Field(description="Endpoint for evaluating workflows.")] = EndpointBase(
|
|
126
|
+
method="POST",
|
|
127
|
+
path="/evaluate",
|
|
128
|
+
description="Evaluates the performance and accuracy of the workflow on a dataset",
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
endpoints: list[Endpoint] = Field(
|
|
132
|
+
default_factory=list,
|
|
133
|
+
description=(
|
|
134
|
+
"Additional endpoints to add to the FastAPI app which run functions within the AgentIQ configuration. "
|
|
135
|
+
"Each endpoint must have a unique path."))
|
|
136
|
+
|
|
137
|
+
cors: CrossOriginResourceSharing = Field(
|
|
138
|
+
default_factory=CrossOriginResourceSharing,
|
|
139
|
+
description="Cross origin resource sharing configuration for the FastAPI app")
|
|
140
|
+
|
|
141
|
+
use_gunicorn: bool = Field(
|
|
142
|
+
default=False,
|
|
143
|
+
description="Use Gunicorn to run the FastAPI app",
|
|
144
|
+
)
|
|
145
|
+
runner_class: str | None = Field(
|
|
146
|
+
default=None,
|
|
147
|
+
description=("The AgentIQ runner class to use when launching the FastAPI app from multiple processes. "
|
|
148
|
+
"Each runner is responsible for loading and running the AgentIQ workflow. "
|
|
149
|
+
"Note: This is different from the worker class used by Gunicorn."),
|
|
150
|
+
)
|
|
@@ -0,0 +1,103 @@
|
|
|
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 os
|
|
17
|
+
import tempfile
|
|
18
|
+
import typing
|
|
19
|
+
|
|
20
|
+
from aiq.builder.front_end import FrontEndBase
|
|
21
|
+
from aiq.front_ends.fastapi.fastapi_front_end_config import FastApiFrontEndConfig
|
|
22
|
+
from aiq.front_ends.fastapi.fastapi_front_end_plugin_worker import FastApiFrontEndPluginWorkerBase
|
|
23
|
+
from aiq.front_ends.fastapi.main import get_app
|
|
24
|
+
from aiq.utils.io.yaml_tools import yaml_dump
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class FastApiFrontEndPlugin(FrontEndBase[FastApiFrontEndConfig]):
|
|
28
|
+
|
|
29
|
+
def get_worker_class(self) -> type[FastApiFrontEndPluginWorkerBase]:
|
|
30
|
+
from aiq.front_ends.fastapi.fastapi_front_end_plugin_worker import FastApiFrontEndPluginWorker
|
|
31
|
+
|
|
32
|
+
return FastApiFrontEndPluginWorker
|
|
33
|
+
|
|
34
|
+
@typing.final
|
|
35
|
+
def get_worker_class_name(self) -> str:
|
|
36
|
+
|
|
37
|
+
if (self.front_end_config.runner_class):
|
|
38
|
+
return self.front_end_config.runner_class
|
|
39
|
+
|
|
40
|
+
worker_class = self.get_worker_class()
|
|
41
|
+
|
|
42
|
+
return f"{worker_class.__module__}.{worker_class.__qualname__}"
|
|
43
|
+
|
|
44
|
+
async def run(self):
|
|
45
|
+
|
|
46
|
+
# Write the entire config to a temporary file
|
|
47
|
+
with tempfile.NamedTemporaryFile(mode="w", prefix="aiq_config", suffix=".yml", delete=True) as config_file:
|
|
48
|
+
|
|
49
|
+
# Get as dict
|
|
50
|
+
config_dict = self.full_config.model_dump(mode="json", by_alias=True, round_trip=True)
|
|
51
|
+
|
|
52
|
+
# Write to YAML file
|
|
53
|
+
yaml_dump(config_dict, config_file)
|
|
54
|
+
|
|
55
|
+
# Set the config file in the environment
|
|
56
|
+
os.environ["AIQ_CONFIG_FILE"] = str(config_file.name)
|
|
57
|
+
|
|
58
|
+
# Set the worker class in the environment
|
|
59
|
+
os.environ["AIQ_FRONT_END_WORKER"] = self.get_worker_class_name()
|
|
60
|
+
|
|
61
|
+
if not self.front_end_config.use_gunicorn:
|
|
62
|
+
import uvicorn
|
|
63
|
+
|
|
64
|
+
reload_excludes = ["./.*"]
|
|
65
|
+
|
|
66
|
+
uvicorn.run("aiq.front_ends.fastapi.main:get_app",
|
|
67
|
+
host=self.front_end_config.host,
|
|
68
|
+
port=self.front_end_config.port,
|
|
69
|
+
workers=self.front_end_config.workers,
|
|
70
|
+
reload=self.front_end_config.reload,
|
|
71
|
+
factory=True,
|
|
72
|
+
reload_excludes=reload_excludes)
|
|
73
|
+
|
|
74
|
+
else:
|
|
75
|
+
app = get_app()
|
|
76
|
+
|
|
77
|
+
from gunicorn.app.wsgiapp import WSGIApplication
|
|
78
|
+
|
|
79
|
+
class StandaloneApplication(WSGIApplication):
|
|
80
|
+
|
|
81
|
+
def __init__(self, app, options=None):
|
|
82
|
+
self.options = options or {}
|
|
83
|
+
self.app = app
|
|
84
|
+
super().__init__()
|
|
85
|
+
|
|
86
|
+
def load_config(self):
|
|
87
|
+
config = {
|
|
88
|
+
key: value
|
|
89
|
+
for key, value in self.options.items() if key in self.cfg.settings and value is not None
|
|
90
|
+
}
|
|
91
|
+
for key, value in config.items():
|
|
92
|
+
self.cfg.set(key.lower(), value)
|
|
93
|
+
|
|
94
|
+
def load(self):
|
|
95
|
+
return self.app
|
|
96
|
+
|
|
97
|
+
options = {
|
|
98
|
+
"bind": f"{self.front_end_config.host}:{self.front_end_config.port}",
|
|
99
|
+
"workers": self.front_end_config.workers,
|
|
100
|
+
"worker_class": "uvicorn.workers.UvicornWorker",
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
StandaloneApplication(app, options=options).run()
|