nvidia-nat 1.2.0rc5__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.
- aiq/agent/__init__.py +0 -0
- aiq/agent/base.py +239 -0
- aiq/agent/dual_node.py +67 -0
- aiq/agent/react_agent/__init__.py +0 -0
- aiq/agent/react_agent/agent.py +355 -0
- aiq/agent/react_agent/output_parser.py +104 -0
- aiq/agent/react_agent/prompt.py +41 -0
- aiq/agent/react_agent/register.py +149 -0
- aiq/agent/reasoning_agent/__init__.py +0 -0
- aiq/agent/reasoning_agent/reasoning_agent.py +225 -0
- aiq/agent/register.py +23 -0
- aiq/agent/rewoo_agent/__init__.py +0 -0
- aiq/agent/rewoo_agent/agent.py +411 -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 +119 -0
- aiq/agent/tool_calling_agent/register.py +106 -0
- aiq/authentication/__init__.py +14 -0
- aiq/authentication/api_key/__init__.py +14 -0
- aiq/authentication/api_key/api_key_auth_provider.py +96 -0
- aiq/authentication/api_key/api_key_auth_provider_config.py +124 -0
- aiq/authentication/api_key/register.py +26 -0
- aiq/authentication/exceptions/__init__.py +14 -0
- aiq/authentication/exceptions/api_key_exceptions.py +38 -0
- aiq/authentication/http_basic_auth/__init__.py +0 -0
- aiq/authentication/http_basic_auth/http_basic_auth_provider.py +81 -0
- aiq/authentication/http_basic_auth/register.py +30 -0
- aiq/authentication/interfaces.py +93 -0
- aiq/authentication/oauth2/__init__.py +14 -0
- aiq/authentication/oauth2/oauth2_auth_code_flow_provider.py +107 -0
- aiq/authentication/oauth2/oauth2_auth_code_flow_provider_config.py +39 -0
- aiq/authentication/oauth2/register.py +25 -0
- aiq/authentication/register.py +21 -0
- aiq/builder/__init__.py +0 -0
- aiq/builder/builder.py +285 -0
- aiq/builder/component_utils.py +316 -0
- aiq/builder/context.py +264 -0
- aiq/builder/embedder.py +24 -0
- aiq/builder/eval_builder.py +161 -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 +344 -0
- aiq/builder/function_base.py +380 -0
- aiq/builder/function_info.py +627 -0
- aiq/builder/intermediate_step_manager.py +174 -0
- aiq/builder/llm.py +25 -0
- aiq/builder/retriever.py +25 -0
- aiq/builder/user_interaction_manager.py +74 -0
- aiq/builder/workflow.py +148 -0
- aiq/builder/workflow_builder.py +1117 -0
- aiq/cli/__init__.py +14 -0
- aiq/cli/cli_utils/__init__.py +0 -0
- aiq/cli/cli_utils/config_override.py +231 -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 +36 -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 +39 -0
- aiq/cli/commands/info/list_channels.py +32 -0
- aiq/cli/commands/info/list_components.py +129 -0
- aiq/cli/commands/info/list_mcp.py +213 -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 +38 -0
- aiq/cli/commands/registry/remove.py +108 -0
- aiq/cli/commands/registry/search.py +155 -0
- aiq/cli/commands/sizing/__init__.py +14 -0
- aiq/cli/commands/sizing/calc.py +297 -0
- aiq/cli/commands/sizing/sizing.py +27 -0
- aiq/cli/commands/start.py +246 -0
- aiq/cli/commands/uninstall.py +81 -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 +313 -0
- aiq/cli/entrypoint.py +135 -0
- aiq/cli/main.py +44 -0
- aiq/cli/register_workflow.py +488 -0
- aiq/cli/type_registry.py +1000 -0
- aiq/data_models/__init__.py +14 -0
- aiq/data_models/api_server.py +694 -0
- aiq/data_models/authentication.py +231 -0
- aiq/data_models/common.py +171 -0
- aiq/data_models/component.py +54 -0
- aiq/data_models/component_ref.py +168 -0
- aiq/data_models/config.py +406 -0
- aiq/data_models/dataset_handler.py +123 -0
- aiq/data_models/discovery_metadata.py +335 -0
- aiq/data_models/embedder.py +27 -0
- aiq/data_models/evaluate.py +127 -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 +72 -0
- aiq/data_models/interactive.py +246 -0
- aiq/data_models/intermediate_step.py +302 -0
- aiq/data_models/invocation_node.py +38 -0
- aiq/data_models/llm.py +27 -0
- aiq/data_models/logging.py +26 -0
- aiq/data_models/memory.py +27 -0
- aiq/data_models/object_store.py +44 -0
- aiq/data_models/profiler.py +54 -0
- aiq/data_models/registry_handler.py +26 -0
- aiq/data_models/retriever.py +30 -0
- aiq/data_models/retry_mixin.py +35 -0
- aiq/data_models/span.py +187 -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/data_models/ttc_strategy.py +30 -0
- aiq/embedder/__init__.py +0 -0
- aiq/embedder/langchain_client.py +41 -0
- aiq/embedder/nim_embedder.py +59 -0
- aiq/embedder/openai_embedder.py +43 -0
- aiq/embedder/register.py +24 -0
- aiq/eval/__init__.py +14 -0
- aiq/eval/config.py +60 -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 +254 -0
- aiq/eval/evaluate.py +506 -0
- aiq/eval/evaluator/__init__.py +14 -0
- aiq/eval/evaluator/base_evaluator.py +73 -0
- aiq/eval/evaluator/evaluator_model.py +45 -0
- aiq/eval/intermediate_step_adapter.py +99 -0
- aiq/eval/rag_evaluator/__init__.py +0 -0
- aiq/eval/rag_evaluator/evaluate.py +178 -0
- aiq/eval/rag_evaluator/register.py +143 -0
- aiq/eval/register.py +23 -0
- aiq/eval/remote_workflow.py +133 -0
- aiq/eval/runners/__init__.py +14 -0
- aiq/eval/runners/config.py +39 -0
- aiq/eval/runners/multi_eval_runner.py +54 -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 +75 -0
- aiq/eval/trajectory_evaluator/register.py +40 -0
- aiq/eval/tunable_rag_evaluator/__init__.py +0 -0
- aiq/eval/tunable_rag_evaluator/evaluate.py +245 -0
- aiq/eval/tunable_rag_evaluator/register.py +52 -0
- aiq/eval/usage_stats.py +41 -0
- aiq/eval/utils/__init__.py +0 -0
- aiq/eval/utils/output_uploader.py +140 -0
- aiq/eval/utils/tqdm_position_registry.py +40 -0
- aiq/eval/utils/weave_eval.py +184 -0
- aiq/experimental/__init__.py +0 -0
- aiq/experimental/decorators/__init__.py +0 -0
- aiq/experimental/decorators/experimental_warning_decorator.py +130 -0
- aiq/experimental/test_time_compute/__init__.py +0 -0
- aiq/experimental/test_time_compute/editing/__init__.py +0 -0
- aiq/experimental/test_time_compute/editing/iterative_plan_refinement_editor.py +147 -0
- aiq/experimental/test_time_compute/editing/llm_as_a_judge_editor.py +204 -0
- aiq/experimental/test_time_compute/editing/motivation_aware_summarization.py +107 -0
- aiq/experimental/test_time_compute/functions/__init__.py +0 -0
- aiq/experimental/test_time_compute/functions/execute_score_select_function.py +105 -0
- aiq/experimental/test_time_compute/functions/its_tool_orchestration_function.py +205 -0
- aiq/experimental/test_time_compute/functions/its_tool_wrapper_function.py +146 -0
- aiq/experimental/test_time_compute/functions/plan_select_execute_function.py +224 -0
- aiq/experimental/test_time_compute/models/__init__.py +0 -0
- aiq/experimental/test_time_compute/models/editor_config.py +132 -0
- aiq/experimental/test_time_compute/models/scoring_config.py +112 -0
- aiq/experimental/test_time_compute/models/search_config.py +120 -0
- aiq/experimental/test_time_compute/models/selection_config.py +154 -0
- aiq/experimental/test_time_compute/models/stage_enums.py +43 -0
- aiq/experimental/test_time_compute/models/strategy_base.py +66 -0
- aiq/experimental/test_time_compute/models/tool_use_config.py +41 -0
- aiq/experimental/test_time_compute/models/ttc_item.py +48 -0
- aiq/experimental/test_time_compute/register.py +36 -0
- aiq/experimental/test_time_compute/scoring/__init__.py +0 -0
- aiq/experimental/test_time_compute/scoring/llm_based_agent_scorer.py +168 -0
- aiq/experimental/test_time_compute/scoring/llm_based_plan_scorer.py +168 -0
- aiq/experimental/test_time_compute/scoring/motivation_aware_scorer.py +111 -0
- aiq/experimental/test_time_compute/search/__init__.py +0 -0
- aiq/experimental/test_time_compute/search/multi_llm_planner.py +128 -0
- aiq/experimental/test_time_compute/search/multi_query_retrieval_search.py +122 -0
- aiq/experimental/test_time_compute/search/single_shot_multi_plan_planner.py +128 -0
- aiq/experimental/test_time_compute/selection/__init__.py +0 -0
- aiq/experimental/test_time_compute/selection/best_of_n_selector.py +63 -0
- aiq/experimental/test_time_compute/selection/llm_based_agent_output_selector.py +131 -0
- aiq/experimental/test_time_compute/selection/llm_based_output_merging_selector.py +159 -0
- aiq/experimental/test_time_compute/selection/llm_based_plan_selector.py +128 -0
- aiq/experimental/test_time_compute/selection/threshold_selector.py +58 -0
- aiq/front_ends/__init__.py +14 -0
- aiq/front_ends/console/__init__.py +14 -0
- aiq/front_ends/console/authentication_flow_handler.py +233 -0
- aiq/front_ends/console/console_front_end_config.py +32 -0
- aiq/front_ends/console/console_front_end_plugin.py +96 -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/auth_flow_handlers/__init__.py +0 -0
- aiq/front_ends/fastapi/auth_flow_handlers/http_flow_handler.py +27 -0
- aiq/front_ends/fastapi/auth_flow_handlers/websocket_flow_handler.py +107 -0
- aiq/front_ends/fastapi/fastapi_front_end_config.py +234 -0
- aiq/front_ends/fastapi/fastapi_front_end_controller.py +68 -0
- aiq/front_ends/fastapi/fastapi_front_end_plugin.py +116 -0
- aiq/front_ends/fastapi/fastapi_front_end_plugin_worker.py +1092 -0
- aiq/front_ends/fastapi/html_snippets/__init__.py +14 -0
- aiq/front_ends/fastapi/html_snippets/auth_code_grant_success.py +35 -0
- aiq/front_ends/fastapi/intermediate_steps_subscriber.py +80 -0
- aiq/front_ends/fastapi/job_store.py +183 -0
- aiq/front_ends/fastapi/main.py +72 -0
- aiq/front_ends/fastapi/message_handler.py +298 -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 +195 -0
- aiq/front_ends/fastapi/step_adaptor.py +321 -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 +54 -0
- aiq/llm/__init__.py +0 -0
- aiq/llm/aws_bedrock_llm.py +57 -0
- aiq/llm/nim_llm.py +46 -0
- aiq/llm/openai_llm.py +46 -0
- aiq/llm/register.py +23 -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 +112 -0
- aiq/meta/module_to_distro.json +3 -0
- aiq/meta/pypi.md +58 -0
- aiq/object_store/__init__.py +20 -0
- aiq/object_store/in_memory_object_store.py +76 -0
- aiq/object_store/interfaces.py +84 -0
- aiq/object_store/models.py +36 -0
- aiq/object_store/register.py +20 -0
- aiq/observability/__init__.py +14 -0
- aiq/observability/exporter/__init__.py +14 -0
- aiq/observability/exporter/base_exporter.py +449 -0
- aiq/observability/exporter/exporter.py +78 -0
- aiq/observability/exporter/file_exporter.py +33 -0
- aiq/observability/exporter/processing_exporter.py +322 -0
- aiq/observability/exporter/raw_exporter.py +52 -0
- aiq/observability/exporter/span_exporter.py +265 -0
- aiq/observability/exporter_manager.py +335 -0
- aiq/observability/mixin/__init__.py +14 -0
- aiq/observability/mixin/batch_config_mixin.py +26 -0
- aiq/observability/mixin/collector_config_mixin.py +23 -0
- aiq/observability/mixin/file_mixin.py +288 -0
- aiq/observability/mixin/file_mode.py +23 -0
- aiq/observability/mixin/resource_conflict_mixin.py +134 -0
- aiq/observability/mixin/serialize_mixin.py +61 -0
- aiq/observability/mixin/type_introspection_mixin.py +183 -0
- aiq/observability/processor/__init__.py +14 -0
- aiq/observability/processor/batching_processor.py +310 -0
- aiq/observability/processor/callback_processor.py +42 -0
- aiq/observability/processor/intermediate_step_serializer.py +28 -0
- aiq/observability/processor/processor.py +71 -0
- aiq/observability/register.py +96 -0
- aiq/observability/utils/__init__.py +14 -0
- aiq/observability/utils/dict_utils.py +236 -0
- aiq/observability/utils/time_utils.py +31 -0
- aiq/plugins/.namespace +1 -0
- aiq/profiler/__init__.py +0 -0
- aiq/profiler/calc/__init__.py +14 -0
- aiq/profiler/calc/calc_runner.py +627 -0
- aiq/profiler/calc/calculations.py +288 -0
- aiq/profiler/calc/data_models.py +188 -0
- aiq/profiler/calc/plot.py +345 -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 +290 -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/data_models.py +24 -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 +28 -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 +460 -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 +473 -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 +567 -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 +82 -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 +215 -0
- aiq/runtime/runner.py +190 -0
- aiq/runtime/session.py +158 -0
- aiq/runtime/user_metadata.py +130 -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/chat_completion.py +74 -0
- aiq/tool/code_execution/README.md +151 -0
- aiq/tool/code_execution/__init__.py +0 -0
- aiq/tool/code_execution/code_sandbox.py +267 -0
- aiq/tool/code_execution/local_sandbox/.gitignore +1 -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 +198 -0
- aiq/tool/code_execution/local_sandbox/sandbox.requirements.txt +6 -0
- aiq/tool/code_execution/local_sandbox/start_local_sandbox.sh +50 -0
- aiq/tool/code_execution/register.py +74 -0
- aiq/tool/code_execution/test_code_execution_sandbox.py +414 -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/exceptions.py +142 -0
- aiq/tool/mcp/mcp_client.py +255 -0
- aiq/tool/mcp/mcp_tool.py +96 -0
- aiq/tool/memory_tools/__init__.py +0 -0
- aiq/tool/memory_tools/add_memory_tool.py +79 -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 +38 -0
- aiq/tool/retriever.py +89 -0
- aiq/tool/server_tools.py +66 -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/dump_distro_mapping.py +32 -0
- aiq/utils/exception_handlers/__init__.py +0 -0
- aiq/utils/exception_handlers/automatic_retries.py +289 -0
- aiq/utils/exception_handlers/mcp.py +211 -0
- aiq/utils/exception_handlers/schemas.py +114 -0
- aiq/utils/io/__init__.py +0 -0
- aiq/utils/io/model_processing.py +28 -0
- aiq/utils/io/yaml_tools.py +119 -0
- aiq/utils/log_utils.py +37 -0
- aiq/utils/metadata_utils.py +74 -0
- aiq/utils/optional_imports.py +142 -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/string_utils.py +38 -0
- aiq/utils/type_converter.py +290 -0
- aiq/utils/type_utils.py +484 -0
- aiq/utils/url_utils.py +27 -0
- nvidia_nat-1.2.0rc5.dist-info/METADATA +363 -0
- nvidia_nat-1.2.0rc5.dist-info/RECORD +435 -0
- nvidia_nat-1.2.0rc5.dist-info/WHEEL +5 -0
- nvidia_nat-1.2.0rc5.dist-info/entry_points.txt +20 -0
- nvidia_nat-1.2.0rc5.dist-info/licenses/LICENSE-3rd-party.txt +3686 -0
- nvidia_nat-1.2.0rc5.dist-info/licenses/LICENSE.md +201 -0
- nvidia_nat-1.2.0rc5.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,321 @@
|
|
|
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 html
|
|
17
|
+
import logging
|
|
18
|
+
from functools import reduce
|
|
19
|
+
from textwrap import dedent
|
|
20
|
+
|
|
21
|
+
from aiq.data_models.api_server import AIQResponseIntermediateStep
|
|
22
|
+
from aiq.data_models.api_server import AIQResponseSerializable
|
|
23
|
+
from aiq.data_models.intermediate_step import IntermediateStep
|
|
24
|
+
from aiq.data_models.intermediate_step import IntermediateStepCategory
|
|
25
|
+
from aiq.data_models.intermediate_step import IntermediateStepPayload
|
|
26
|
+
from aiq.data_models.intermediate_step import IntermediateStepType
|
|
27
|
+
from aiq.data_models.invocation_node import InvocationNode
|
|
28
|
+
from aiq.data_models.step_adaptor import StepAdaptorConfig
|
|
29
|
+
from aiq.data_models.step_adaptor import StepAdaptorMode
|
|
30
|
+
from aiq.utils.type_utils import is_valid_json
|
|
31
|
+
|
|
32
|
+
logger = logging.getLogger(__name__)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class StepAdaptor:
|
|
36
|
+
|
|
37
|
+
def __init__(self, config: StepAdaptorConfig):
|
|
38
|
+
|
|
39
|
+
self._history: list[IntermediateStep] = []
|
|
40
|
+
self.config = config
|
|
41
|
+
|
|
42
|
+
def _step_matches_filter(self, step: IntermediateStep, config: StepAdaptorConfig) -> bool:
|
|
43
|
+
"""
|
|
44
|
+
Returns True if this intermediate step should be included (based on the config.mode).
|
|
45
|
+
"""
|
|
46
|
+
|
|
47
|
+
if config.mode == StepAdaptorMode.OFF:
|
|
48
|
+
return False
|
|
49
|
+
|
|
50
|
+
if config.mode == StepAdaptorMode.DEFAULT:
|
|
51
|
+
# default existing behavior: show LLM events + TOOL_END + FUNCTION events
|
|
52
|
+
if step.event_category == IntermediateStepCategory.LLM:
|
|
53
|
+
return True
|
|
54
|
+
if step.event_category == IntermediateStepCategory.TOOL:
|
|
55
|
+
return True
|
|
56
|
+
if step.event_category == IntermediateStepCategory.FUNCTION:
|
|
57
|
+
return True
|
|
58
|
+
return False
|
|
59
|
+
|
|
60
|
+
if config.mode == StepAdaptorMode.CUSTOM:
|
|
61
|
+
# pass only what the user explicitly listed
|
|
62
|
+
return step.event_type in config.custom_event_types
|
|
63
|
+
|
|
64
|
+
return False
|
|
65
|
+
|
|
66
|
+
def _handle_llm(self, step: IntermediateStepPayload, ancestry: InvocationNode) -> AIQResponseSerializable | None:
|
|
67
|
+
input_str: str | None = None
|
|
68
|
+
output_str: str | None = None
|
|
69
|
+
|
|
70
|
+
# Find the start in the history with matching run_id
|
|
71
|
+
start_step = next(
|
|
72
|
+
(x for x in self._history if x.event_type == IntermediateStepType.LLM_START and x.UUID == step.UUID), None)
|
|
73
|
+
|
|
74
|
+
if not start_step:
|
|
75
|
+
# If we don't have a start step, we can't do anything
|
|
76
|
+
return None
|
|
77
|
+
|
|
78
|
+
input_str = str(start_step.data.input)
|
|
79
|
+
|
|
80
|
+
if step.event_type == IntermediateStepType.LLM_NEW_TOKEN:
|
|
81
|
+
|
|
82
|
+
# Find all of the previous LLM chunks and concatenate them
|
|
83
|
+
output_str = reduce(
|
|
84
|
+
lambda x, y: x + y,
|
|
85
|
+
(str(x.data.chunk)
|
|
86
|
+
for x in self._history if x.event_type == IntermediateStepType.LLM_NEW_TOKEN and x.UUID == step.UUID),
|
|
87
|
+
"")
|
|
88
|
+
|
|
89
|
+
elif step.event_type == IntermediateStepType.LLM_END:
|
|
90
|
+
output_str = str(step.data.output)
|
|
91
|
+
|
|
92
|
+
if not input_str and not output_str:
|
|
93
|
+
return None
|
|
94
|
+
|
|
95
|
+
escaped_input = html.escape(input_str, quote=False)
|
|
96
|
+
|
|
97
|
+
# Dont use f-strings here because the payload is markdown and screws up the dedent
|
|
98
|
+
payload = dedent("""
|
|
99
|
+
**Input:**
|
|
100
|
+
```python
|
|
101
|
+
{input_value}
|
|
102
|
+
```
|
|
103
|
+
""").strip("\n").format(input_value=escaped_input)
|
|
104
|
+
|
|
105
|
+
if (output_str):
|
|
106
|
+
escaped_output = html.escape(output_str, quote=False) if output_str else ""
|
|
107
|
+
|
|
108
|
+
# Dont use f-strings here because the payload is markdown and screws up the dedent
|
|
109
|
+
payload = dedent("""
|
|
110
|
+
{payload}
|
|
111
|
+
|
|
112
|
+
**Output:**
|
|
113
|
+
{output_value}
|
|
114
|
+
""").strip("\n").format(payload=payload, output_value=escaped_output)
|
|
115
|
+
|
|
116
|
+
event = AIQResponseIntermediateStep(id=step.UUID,
|
|
117
|
+
name=step.name or "",
|
|
118
|
+
payload=payload,
|
|
119
|
+
parent_id=ancestry.function_id)
|
|
120
|
+
|
|
121
|
+
return event
|
|
122
|
+
|
|
123
|
+
def _handle_tool(self, step: IntermediateStepPayload, ancestry: InvocationNode) -> AIQResponseSerializable | None:
|
|
124
|
+
"""
|
|
125
|
+
Handles both TOOL_START and TOOL_END events
|
|
126
|
+
"""
|
|
127
|
+
input_str: str | None = None
|
|
128
|
+
output_str: str | None = None
|
|
129
|
+
|
|
130
|
+
# Find the start in the history with matching run_id
|
|
131
|
+
start_step = next(
|
|
132
|
+
(x for x in self._history if x.event_type == IntermediateStepType.TOOL_START and x.UUID == step.UUID), None)
|
|
133
|
+
|
|
134
|
+
if not start_step:
|
|
135
|
+
# If we don't have a start step, we can't do anything
|
|
136
|
+
return None
|
|
137
|
+
|
|
138
|
+
input_str = str(start_step.data.input)
|
|
139
|
+
|
|
140
|
+
if step.event_type == IntermediateStepType.TOOL_END:
|
|
141
|
+
output_str = str(step.data.output)
|
|
142
|
+
|
|
143
|
+
if not input_str and not output_str:
|
|
144
|
+
return None
|
|
145
|
+
|
|
146
|
+
escaped_input = html.escape(input_str, quote=False)
|
|
147
|
+
format_input_type = "json" if is_valid_json(escaped_input) else "python"
|
|
148
|
+
|
|
149
|
+
# Dont use f-strings here because the payload is markdown and screws up the dedent
|
|
150
|
+
payload = dedent("""
|
|
151
|
+
**Input:**
|
|
152
|
+
```{format_input_type}
|
|
153
|
+
{input_value}
|
|
154
|
+
```
|
|
155
|
+
""").strip("\n").format(input_value=escaped_input, format_input_type=format_input_type)
|
|
156
|
+
|
|
157
|
+
if output_str:
|
|
158
|
+
escaped_output = html.escape(output_str, quote=False)
|
|
159
|
+
format_output_type = "json" if is_valid_json(escaped_output) else "python"
|
|
160
|
+
|
|
161
|
+
# Dont use f-strings here because the payload is markdown and screws up the dedent
|
|
162
|
+
payload = dedent("""
|
|
163
|
+
{payload}
|
|
164
|
+
|
|
165
|
+
**Output:**
|
|
166
|
+
```{format_output_type}
|
|
167
|
+
{output_value}
|
|
168
|
+
```
|
|
169
|
+
""").strip("\n").format(payload=payload, output_value=escaped_output, format_output_type=format_output_type)
|
|
170
|
+
|
|
171
|
+
event = AIQResponseIntermediateStep(id=step.UUID,
|
|
172
|
+
name=f"Tool: {step.name}",
|
|
173
|
+
payload=payload,
|
|
174
|
+
parent_id=ancestry.function_id)
|
|
175
|
+
|
|
176
|
+
return event
|
|
177
|
+
|
|
178
|
+
def _handle_function(self, step: IntermediateStepPayload,
|
|
179
|
+
ancestry: InvocationNode) -> AIQResponseSerializable | None:
|
|
180
|
+
"""
|
|
181
|
+
Handles the FUNCTION_START and FUNCTION_END events
|
|
182
|
+
"""
|
|
183
|
+
input_str: str | None = None
|
|
184
|
+
output_str: str | None = None
|
|
185
|
+
|
|
186
|
+
if step.event_type == IntermediateStepType.FUNCTION_START:
|
|
187
|
+
# For function start events, display input data
|
|
188
|
+
if step.data and hasattr(step.data, 'input'):
|
|
189
|
+
input_str = str(step.data.input)
|
|
190
|
+
elif step.data:
|
|
191
|
+
input_str = str(step.data)
|
|
192
|
+
|
|
193
|
+
if not input_str:
|
|
194
|
+
return None
|
|
195
|
+
|
|
196
|
+
escaped_input = html.escape(input_str, quote=False)
|
|
197
|
+
format_input_type = "json" if is_valid_json(escaped_input) else "python"
|
|
198
|
+
|
|
199
|
+
# Create payload for function start
|
|
200
|
+
payload_str = dedent("""
|
|
201
|
+
**Function Input:**
|
|
202
|
+
```{format_input_type}
|
|
203
|
+
{input_value}
|
|
204
|
+
```
|
|
205
|
+
""").strip("\n").format(input_value=escaped_input, format_input_type=format_input_type)
|
|
206
|
+
|
|
207
|
+
event = AIQResponseIntermediateStep(id=step.UUID,
|
|
208
|
+
name=f"Function Start: {step.name}",
|
|
209
|
+
payload=payload_str,
|
|
210
|
+
parent_id=ancestry.parent_id)
|
|
211
|
+
return event
|
|
212
|
+
|
|
213
|
+
if step.event_type == IntermediateStepType.FUNCTION_END:
|
|
214
|
+
# Find the start event with matching UUID
|
|
215
|
+
start_step = next(
|
|
216
|
+
(x
|
|
217
|
+
for x in self._history if x.event_type == IntermediateStepType.FUNCTION_START and x.UUID == step.UUID),
|
|
218
|
+
None)
|
|
219
|
+
|
|
220
|
+
# For function end events, display output data
|
|
221
|
+
if step.data and hasattr(step.data, 'output'):
|
|
222
|
+
output_str = str(step.data.output)
|
|
223
|
+
elif step.data:
|
|
224
|
+
output_str = str(step.data)
|
|
225
|
+
|
|
226
|
+
if not output_str:
|
|
227
|
+
return None
|
|
228
|
+
|
|
229
|
+
escaped_output = html.escape(output_str, quote=False)
|
|
230
|
+
format_output_type = "json" if is_valid_json(escaped_output) else "python"
|
|
231
|
+
|
|
232
|
+
# Get input from start step if available
|
|
233
|
+
input_payload = ""
|
|
234
|
+
if start_step and start_step.data:
|
|
235
|
+
if hasattr(start_step.data, 'input'):
|
|
236
|
+
input_str = str(start_step.data.input)
|
|
237
|
+
else:
|
|
238
|
+
input_str = str(start_step.data)
|
|
239
|
+
|
|
240
|
+
if input_str:
|
|
241
|
+
escaped_input = html.escape(input_str, quote=False)
|
|
242
|
+
format_input_type = "json" if is_valid_json(escaped_input) else "python"
|
|
243
|
+
input_payload = dedent("""
|
|
244
|
+
**Function Input:**
|
|
245
|
+
```{format_input_type}
|
|
246
|
+
{input_value}
|
|
247
|
+
```
|
|
248
|
+
""").strip("\n").format(input_value=escaped_input, format_input_type=format_input_type)
|
|
249
|
+
|
|
250
|
+
# Create payload for function end
|
|
251
|
+
payload_str = dedent("""
|
|
252
|
+
{input_payload}**Function Output:**
|
|
253
|
+
```{format_output_type}
|
|
254
|
+
{output_value}
|
|
255
|
+
```
|
|
256
|
+
""").strip("\n").format(input_payload=input_payload,
|
|
257
|
+
output_value=escaped_output,
|
|
258
|
+
format_output_type=format_output_type)
|
|
259
|
+
|
|
260
|
+
event = AIQResponseIntermediateStep(id=step.UUID,
|
|
261
|
+
name=f"Function Complete: {step.name}",
|
|
262
|
+
payload=payload_str,
|
|
263
|
+
parent_id=ancestry.parent_id)
|
|
264
|
+
return event
|
|
265
|
+
|
|
266
|
+
return None
|
|
267
|
+
|
|
268
|
+
def _handle_custom(self, payload: IntermediateStepPayload,
|
|
269
|
+
ancestry: InvocationNode) -> AIQResponseSerializable | None:
|
|
270
|
+
"""
|
|
271
|
+
Handles the CUSTOM event
|
|
272
|
+
"""
|
|
273
|
+
escaped_payload = html.escape(str(payload), quote=False)
|
|
274
|
+
escaped_payload = escaped_payload.replace("\n", "")
|
|
275
|
+
|
|
276
|
+
# Attempt to determine type
|
|
277
|
+
format_type = "json" if is_valid_json(escaped_payload) else "python"
|
|
278
|
+
|
|
279
|
+
# Don't use f-strings here because the payload is markdown and screws up the dedent
|
|
280
|
+
payload_str = dedent("""
|
|
281
|
+
```{format_type}
|
|
282
|
+
{payload}
|
|
283
|
+
```
|
|
284
|
+
""").strip("\n").format(payload=escaped_payload, format_type=format_type)
|
|
285
|
+
|
|
286
|
+
# Return the event
|
|
287
|
+
event = AIQResponseIntermediateStep(id=payload.UUID,
|
|
288
|
+
name=f"{payload.event_type}",
|
|
289
|
+
payload=payload_str,
|
|
290
|
+
parent_id=ancestry.function_id)
|
|
291
|
+
|
|
292
|
+
return event
|
|
293
|
+
|
|
294
|
+
def process(self, step: IntermediateStep) -> AIQResponseSerializable | None: # pylint: disable=R1710
|
|
295
|
+
|
|
296
|
+
# Track the chunk
|
|
297
|
+
self._history.append(step)
|
|
298
|
+
payload = step.payload
|
|
299
|
+
ancestry = step.function_ancestry
|
|
300
|
+
|
|
301
|
+
if not self._step_matches_filter(step, self.config):
|
|
302
|
+
return None
|
|
303
|
+
|
|
304
|
+
try:
|
|
305
|
+
|
|
306
|
+
if step.event_category == IntermediateStepCategory.LLM:
|
|
307
|
+
return self._handle_llm(payload, ancestry)
|
|
308
|
+
|
|
309
|
+
if step.event_category == IntermediateStepCategory.TOOL:
|
|
310
|
+
return self._handle_tool(payload, ancestry)
|
|
311
|
+
|
|
312
|
+
if step.event_category == IntermediateStepCategory.FUNCTION:
|
|
313
|
+
return self._handle_function(payload, ancestry)
|
|
314
|
+
|
|
315
|
+
if step.event_category == IntermediateStepCategory.CUSTOM:
|
|
316
|
+
return self._handle_custom(payload, ancestry)
|
|
317
|
+
|
|
318
|
+
except Exception as e:
|
|
319
|
+
logger.error("Error processing intermediate step: %s", e, exc_info=True)
|
|
320
|
+
|
|
321
|
+
return None
|
|
@@ -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,32 @@
|
|
|
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 pydantic import Field
|
|
17
|
+
|
|
18
|
+
from aiq.data_models.front_end import FrontEndBaseConfig
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class MCPFrontEndConfig(FrontEndBaseConfig, name="mcp"):
|
|
22
|
+
"""MCP front end configuration.
|
|
23
|
+
|
|
24
|
+
A simple MCP (Modular Communication Protocol) front end for AIQ.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
name: str = Field(default="AIQ MCP", description="Name of the MCP server")
|
|
28
|
+
host: str = Field(default="localhost", description="Host to bind the server to")
|
|
29
|
+
port: int = Field(default=9901, description="Port to bind the server to", ge=0, le=65535)
|
|
30
|
+
debug: bool = Field(default=False, description="Enable debug mode")
|
|
31
|
+
log_level: str = Field(default="INFO", description="Log level for the MCP server")
|
|
32
|
+
tool_names: list[str] = Field(default_factory=list, description="The list of tools MCP server will expose.")
|
|
@@ -0,0 +1,93 @@
|
|
|
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 aiq.builder.front_end import FrontEndBase
|
|
19
|
+
from aiq.builder.function import Function
|
|
20
|
+
from aiq.builder.workflow import Workflow
|
|
21
|
+
from aiq.builder.workflow_builder import WorkflowBuilder
|
|
22
|
+
from aiq.front_ends.mcp.mcp_front_end_config import MCPFrontEndConfig
|
|
23
|
+
|
|
24
|
+
logger = logging.getLogger(__name__)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class MCPFrontEndPlugin(FrontEndBase[MCPFrontEndConfig]):
|
|
28
|
+
"""MCP front end plugin implementation."""
|
|
29
|
+
|
|
30
|
+
async def run(self) -> None:
|
|
31
|
+
"""Run the MCP server."""
|
|
32
|
+
# Import FastMCP
|
|
33
|
+
from mcp.server.fastmcp import FastMCP
|
|
34
|
+
|
|
35
|
+
from aiq.front_ends.mcp.tool_converter import register_function_with_mcp
|
|
36
|
+
|
|
37
|
+
# Create an MCP server with the configured parameters
|
|
38
|
+
mcp = FastMCP(
|
|
39
|
+
self.front_end_config.name,
|
|
40
|
+
host=self.front_end_config.host,
|
|
41
|
+
port=self.front_end_config.port,
|
|
42
|
+
debug=self.front_end_config.debug,
|
|
43
|
+
log_level=self.front_end_config.log_level,
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
# Build the workflow and register all functions with MCP
|
|
47
|
+
async with WorkflowBuilder.from_config(config=self.full_config) as builder:
|
|
48
|
+
# Build the workflow
|
|
49
|
+
workflow = builder.build()
|
|
50
|
+
|
|
51
|
+
# Get all functions from the workflow
|
|
52
|
+
functions = self._get_all_functions(workflow)
|
|
53
|
+
|
|
54
|
+
# Filter functions based on tool_names if provided
|
|
55
|
+
if self.front_end_config.tool_names:
|
|
56
|
+
logger.info(f"Filtering functions based on tool_names: {self.front_end_config.tool_names}")
|
|
57
|
+
filtered_functions: dict[str, Function] = {}
|
|
58
|
+
for function_name, function in functions.items():
|
|
59
|
+
if function_name in self.front_end_config.tool_names:
|
|
60
|
+
filtered_functions[function_name] = function
|
|
61
|
+
else:
|
|
62
|
+
logger.debug(f"Skipping function {function_name} as it's not in tool_names")
|
|
63
|
+
functions = filtered_functions
|
|
64
|
+
|
|
65
|
+
# Register each function with MCP
|
|
66
|
+
for function_name, function in functions.items():
|
|
67
|
+
register_function_with_mcp(mcp, function_name, function)
|
|
68
|
+
|
|
69
|
+
# Add a simple fallback function if no functions were found
|
|
70
|
+
if not functions:
|
|
71
|
+
raise RuntimeError("No functions found in workflow. Please check your configuration.")
|
|
72
|
+
|
|
73
|
+
# Start the MCP server
|
|
74
|
+
await mcp.run_sse_async()
|
|
75
|
+
|
|
76
|
+
def _get_all_functions(self, workflow: Workflow) -> dict[str, Function]:
|
|
77
|
+
"""Get all functions from the workflow.
|
|
78
|
+
|
|
79
|
+
Args:
|
|
80
|
+
workflow: The AIQ workflow.
|
|
81
|
+
|
|
82
|
+
Returns:
|
|
83
|
+
Dict mapping function names to Function objects.
|
|
84
|
+
"""
|
|
85
|
+
functions: dict[str, Function] = {}
|
|
86
|
+
|
|
87
|
+
# Extract all functions from the workflow
|
|
88
|
+
for function_name, function in workflow.functions.items():
|
|
89
|
+
functions[function_name] = function
|
|
90
|
+
|
|
91
|
+
functions[workflow.config.workflow.type] = workflow
|
|
92
|
+
|
|
93
|
+
return functions
|
|
@@ -0,0 +1,27 @@
|
|
|
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 collections.abc import AsyncIterator
|
|
17
|
+
|
|
18
|
+
from aiq.cli.register_workflow import register_front_end
|
|
19
|
+
from aiq.data_models.config import AIQConfig
|
|
20
|
+
from aiq.front_ends.mcp.mcp_front_end_config import MCPFrontEndConfig
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@register_front_end(config_type=MCPFrontEndConfig)
|
|
24
|
+
async def register_mcp_front_end(config: MCPFrontEndConfig, full_config: AIQConfig) -> AsyncIterator:
|
|
25
|
+
from aiq.front_ends.mcp.mcp_front_end_plugin import MCPFrontEndPlugin
|
|
26
|
+
|
|
27
|
+
yield MCPFrontEndPlugin(full_config=full_config)
|