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,104 @@
|
|
|
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 re
|
|
17
|
+
|
|
18
|
+
from langchain.agents.agent import AgentOutputParser
|
|
19
|
+
from langchain_core.agents import AgentAction
|
|
20
|
+
from langchain_core.agents import AgentFinish
|
|
21
|
+
from langchain_core.exceptions import LangChainException
|
|
22
|
+
|
|
23
|
+
from .prompt import SYSTEM_PROMPT
|
|
24
|
+
|
|
25
|
+
FINAL_ANSWER_ACTION = "Final Answer:"
|
|
26
|
+
MISSING_ACTION_AFTER_THOUGHT_ERROR_MESSAGE = "Invalid Format: Missing 'Action:' after 'Thought:'"
|
|
27
|
+
MISSING_ACTION_INPUT_AFTER_ACTION_ERROR_MESSAGE = "Invalid Format: Missing 'Action Input:' after 'Action:'"
|
|
28
|
+
FINAL_ANSWER_AND_PARSABLE_ACTION_ERROR_MESSAGE = ("Parsing LLM output produced both a final answer and a parse-able "
|
|
29
|
+
"action:")
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class ReActOutputParserException(ValueError, LangChainException):
|
|
33
|
+
|
|
34
|
+
def __init__(self,
|
|
35
|
+
observation=None,
|
|
36
|
+
missing_action=False,
|
|
37
|
+
missing_action_input=False,
|
|
38
|
+
final_answer_and_action=False):
|
|
39
|
+
self.observation = observation
|
|
40
|
+
self.missing_action = missing_action
|
|
41
|
+
self.missing_action_input = missing_action_input
|
|
42
|
+
self.final_answer_and_action = final_answer_and_action
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class ReActOutputParser(AgentOutputParser):
|
|
46
|
+
"""Parses ReAct-style LLM calls that have a single tool input.
|
|
47
|
+
|
|
48
|
+
Expects output to be in one of two formats.
|
|
49
|
+
|
|
50
|
+
If the output signals that an action should be taken,
|
|
51
|
+
should be in the below format. This will result in an AgentAction
|
|
52
|
+
being returned.
|
|
53
|
+
|
|
54
|
+
```
|
|
55
|
+
Thought: agent thought here
|
|
56
|
+
Action: search
|
|
57
|
+
Action Input: what is the temperature in SF?
|
|
58
|
+
Observation: Waiting for the tool response...
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
If the output signals that a final answer should be given,
|
|
62
|
+
should be in the below format. This will result in an AgentFinish
|
|
63
|
+
being returned.
|
|
64
|
+
|
|
65
|
+
```
|
|
66
|
+
Thought: agent thought here
|
|
67
|
+
Final Answer: The temperature is 100 degrees
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
"""
|
|
71
|
+
|
|
72
|
+
def get_format_instructions(self) -> str:
|
|
73
|
+
return SYSTEM_PROMPT
|
|
74
|
+
|
|
75
|
+
def parse(self, text: str) -> AgentAction | AgentFinish:
|
|
76
|
+
includes_answer = FINAL_ANSWER_ACTION in text
|
|
77
|
+
regex = r"Action\s*\d*\s*:[\s]*(.*?)\s*Action\s*\d*\s*Input\s*\d*\s*:[\s]*(.*?)(?=\s*[\n|\s]\s*Observation\b|$)"
|
|
78
|
+
action_match = re.search(regex, text, re.DOTALL)
|
|
79
|
+
if action_match:
|
|
80
|
+
if includes_answer:
|
|
81
|
+
raise ReActOutputParserException(
|
|
82
|
+
final_answer_and_action=True,
|
|
83
|
+
observation=f"{FINAL_ANSWER_AND_PARSABLE_ACTION_ERROR_MESSAGE}: {text}")
|
|
84
|
+
action = action_match.group(1).strip()
|
|
85
|
+
action_input = action_match.group(2)
|
|
86
|
+
tool_input = action_input.strip(" ")
|
|
87
|
+
tool_input = tool_input.strip('"')
|
|
88
|
+
|
|
89
|
+
return AgentAction(action, tool_input, text)
|
|
90
|
+
|
|
91
|
+
if includes_answer:
|
|
92
|
+
return AgentFinish({"output": text.split(FINAL_ANSWER_ACTION)[-1].strip()}, text)
|
|
93
|
+
|
|
94
|
+
if not re.search(r"Action\s*\d*\s*:[\s]*(.*?)", text, re.DOTALL):
|
|
95
|
+
raise ReActOutputParserException(observation=MISSING_ACTION_AFTER_THOUGHT_ERROR_MESSAGE,
|
|
96
|
+
missing_action=True)
|
|
97
|
+
if not re.search(r"[\s]*Action\s*\d*\s*Input\s*\d*\s*:[\s]*(.*)", text, re.DOTALL):
|
|
98
|
+
raise ReActOutputParserException(observation=MISSING_ACTION_INPUT_AFTER_ACTION_ERROR_MESSAGE,
|
|
99
|
+
missing_action_input=True)
|
|
100
|
+
raise ReActOutputParserException(f"Could not parse LLM output: `{text}`")
|
|
101
|
+
|
|
102
|
+
@property
|
|
103
|
+
def _type(self) -> str:
|
|
104
|
+
return "react-input"
|
|
@@ -0,0 +1,41 @@
|
|
|
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
|
+
# flake8: noqa
|
|
17
|
+
|
|
18
|
+
SYSTEM_PROMPT = """
|
|
19
|
+
Answer the following questions as best you can. You may ask the human to use the following tools:
|
|
20
|
+
|
|
21
|
+
{tools}
|
|
22
|
+
|
|
23
|
+
You may respond in one of two formats.
|
|
24
|
+
Use the following format exactly to ask the human to use a tool:
|
|
25
|
+
|
|
26
|
+
Question: the input question you must answer
|
|
27
|
+
Thought: you should always think about what to do
|
|
28
|
+
Action: the action to take, should be one of [{tool_names}]
|
|
29
|
+
Action Input: the input to the action (if there is no required input, include "Action Input: None")
|
|
30
|
+
Observation: wait for the human to respond with the result from the tool, do not assume the response
|
|
31
|
+
|
|
32
|
+
... (this Thought/Action/Action Input/Observation can repeat N times. If you do not need to use a tool, or after asking the human to use any tools and waiting for the human to respond, you might know the final answer.)
|
|
33
|
+
Use the following format once you have the final answer:
|
|
34
|
+
|
|
35
|
+
Thought: I now know the final answer
|
|
36
|
+
Final Answer: the final answer to the original input question
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
USER_PROMPT = """
|
|
40
|
+
Question: {question}
|
|
41
|
+
"""
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: Copyright (c) 2025, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
|
2
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
#
|
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
# you may not use this file except in compliance with the License.
|
|
6
|
+
# You may obtain a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
# See the License for the specific language governing permissions and
|
|
14
|
+
# limitations under the License.
|
|
15
|
+
|
|
16
|
+
import logging
|
|
17
|
+
|
|
18
|
+
from pydantic import AliasChoices
|
|
19
|
+
from pydantic import Field
|
|
20
|
+
|
|
21
|
+
from aiq.builder.builder import Builder
|
|
22
|
+
from aiq.builder.framework_enum import LLMFrameworkEnum
|
|
23
|
+
from aiq.builder.function_info import FunctionInfo
|
|
24
|
+
from aiq.cli.register_workflow import register_function
|
|
25
|
+
from aiq.data_models.api_server import AIQChatRequest
|
|
26
|
+
from aiq.data_models.api_server import AIQChatResponse
|
|
27
|
+
from aiq.data_models.component_ref import FunctionRef
|
|
28
|
+
from aiq.data_models.component_ref import LLMRef
|
|
29
|
+
from aiq.data_models.function import FunctionBaseConfig
|
|
30
|
+
from aiq.utils.type_converter import GlobalTypeConverter
|
|
31
|
+
|
|
32
|
+
logger = logging.getLogger(__name__)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class ReActAgentWorkflowConfig(FunctionBaseConfig, name="react_agent"):
|
|
36
|
+
"""
|
|
37
|
+
Defines an AIQ Toolkit function that uses a ReAct Agent performs reasoning inbetween tool calls, and utilizes the
|
|
38
|
+
tool names and descriptions to select the optimal tool.
|
|
39
|
+
"""
|
|
40
|
+
|
|
41
|
+
tool_names: list[FunctionRef] = Field(default_factory=list,
|
|
42
|
+
description="The list of tools to provide to the react agent.")
|
|
43
|
+
llm_name: LLMRef = Field(description="The LLM model to use with the react agent.")
|
|
44
|
+
verbose: bool = Field(default=False, description="Set the verbosity of the react agent's logging.")
|
|
45
|
+
retry_agent_response_parsing_errors: bool = Field(
|
|
46
|
+
default=True,
|
|
47
|
+
validation_alias=AliasChoices("retry_agent_response_parsing_errors", "retry_parsing_errors"),
|
|
48
|
+
description="Whether to retry when encountering parsing errors in the agent's response.")
|
|
49
|
+
parse_agent_response_max_retries: int = Field(
|
|
50
|
+
default=1,
|
|
51
|
+
validation_alias=AliasChoices("parse_agent_response_max_retries", "max_retries"),
|
|
52
|
+
description="Maximum number of times the Agent may retry parsing errors. "
|
|
53
|
+
"Prevents the Agent from getting into infinite hallucination loops.")
|
|
54
|
+
tool_call_max_retries: int = Field(default=1, description="The number of retries before raising a tool call error.")
|
|
55
|
+
max_tool_calls: int = Field(default=15,
|
|
56
|
+
validation_alias=AliasChoices("max_tool_calls", "max_iterations"),
|
|
57
|
+
description="Maximum number of tool calls before stopping the agent.")
|
|
58
|
+
pass_tool_call_errors_to_agent: bool = Field(
|
|
59
|
+
default=True,
|
|
60
|
+
description="Whether to pass tool call errors to agent. If False, failed tool calls will raise an exception.")
|
|
61
|
+
include_tool_input_schema_in_tool_description: bool = Field(
|
|
62
|
+
default=True, description="Specify inclusion of tool input schemas in the prompt.")
|
|
63
|
+
description: str = Field(default="ReAct Agent Workflow", description="The description of this functions use.")
|
|
64
|
+
system_prompt: str | None = Field(
|
|
65
|
+
default=None,
|
|
66
|
+
description="Provides the SYSTEM_PROMPT to use with the agent") # defaults to SYSTEM_PROMPT in prompt.py
|
|
67
|
+
max_history: int = Field(default=15, description="Maximum number of messages to keep in the conversation history.")
|
|
68
|
+
use_openai_api: bool = Field(default=False,
|
|
69
|
+
description=("Use OpenAI API for the input/output types to the function. "
|
|
70
|
+
"If False, strings will be used."))
|
|
71
|
+
additional_instructions: str | None = Field(
|
|
72
|
+
default=None, description="Additional instructions to provide to the agent in addition to the base prompt.")
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
@register_function(config_type=ReActAgentWorkflowConfig, framework_wrappers=[LLMFrameworkEnum.LANGCHAIN])
|
|
76
|
+
async def react_agent_workflow(config: ReActAgentWorkflowConfig, builder: Builder):
|
|
77
|
+
from langchain.schema import BaseMessage
|
|
78
|
+
from langchain_core.messages import trim_messages
|
|
79
|
+
from langgraph.graph.graph import CompiledGraph
|
|
80
|
+
|
|
81
|
+
from aiq.agent.base import AGENT_LOG_PREFIX
|
|
82
|
+
from aiq.agent.react_agent.agent import ReActAgentGraph
|
|
83
|
+
from aiq.agent.react_agent.agent import ReActGraphState
|
|
84
|
+
from aiq.agent.react_agent.agent import create_react_agent_prompt
|
|
85
|
+
|
|
86
|
+
prompt = create_react_agent_prompt(config)
|
|
87
|
+
|
|
88
|
+
# we can choose an LLM for the ReAct agent in the config file
|
|
89
|
+
llm = await builder.get_llm(config.llm_name, wrapper_type=LLMFrameworkEnum.LANGCHAIN)
|
|
90
|
+
# the agent can run any installed tool, simply install the tool and add it to the config file
|
|
91
|
+
# the sample tool provided can easily be copied or changed
|
|
92
|
+
tools = builder.get_tools(tool_names=config.tool_names, wrapper_type=LLMFrameworkEnum.LANGCHAIN)
|
|
93
|
+
if not tools:
|
|
94
|
+
raise ValueError(f"No tools specified for ReAct Agent '{config.llm_name}'")
|
|
95
|
+
# configure callbacks, for sending intermediate steps
|
|
96
|
+
# construct the ReAct Agent Graph from the configured llm, prompt, and tools
|
|
97
|
+
graph: CompiledGraph = await ReActAgentGraph(
|
|
98
|
+
llm=llm,
|
|
99
|
+
prompt=prompt,
|
|
100
|
+
tools=tools,
|
|
101
|
+
use_tool_schema=config.include_tool_input_schema_in_tool_description,
|
|
102
|
+
detailed_logs=config.verbose,
|
|
103
|
+
retry_agent_response_parsing_errors=config.retry_agent_response_parsing_errors,
|
|
104
|
+
parse_agent_response_max_retries=config.parse_agent_response_max_retries,
|
|
105
|
+
tool_call_max_retries=config.tool_call_max_retries,
|
|
106
|
+
pass_tool_call_errors_to_agent=config.pass_tool_call_errors_to_agent).build_graph()
|
|
107
|
+
|
|
108
|
+
async def _response_fn(input_message: AIQChatRequest) -> AIQChatResponse:
|
|
109
|
+
try:
|
|
110
|
+
# initialize the starting state with the user query
|
|
111
|
+
messages: list[BaseMessage] = trim_messages(messages=[m.model_dump() for m in input_message.messages],
|
|
112
|
+
max_tokens=config.max_history,
|
|
113
|
+
strategy="last",
|
|
114
|
+
token_counter=len,
|
|
115
|
+
start_on="human",
|
|
116
|
+
include_system=True)
|
|
117
|
+
|
|
118
|
+
state = ReActGraphState(messages=messages)
|
|
119
|
+
|
|
120
|
+
# run the ReAct Agent Graph
|
|
121
|
+
state = await graph.ainvoke(state, config={'recursion_limit': (config.max_tool_calls + 1) * 2})
|
|
122
|
+
# setting recursion_limit: 4 allows 1 tool call
|
|
123
|
+
# - allows the ReAct Agent to perform 1 cycle / call 1 single tool,
|
|
124
|
+
# - but stops the agent when it tries to call a tool a second time
|
|
125
|
+
|
|
126
|
+
# get and return the output from the state
|
|
127
|
+
state = ReActGraphState(**state)
|
|
128
|
+
output_message = state.messages[-1] # pylint: disable=E1136
|
|
129
|
+
return AIQChatResponse.from_string(str(output_message.content))
|
|
130
|
+
|
|
131
|
+
except Exception as ex:
|
|
132
|
+
logger.exception("%s ReAct Agent failed with exception: %s", AGENT_LOG_PREFIX, ex, exc_info=ex)
|
|
133
|
+
# here, we can implement custom error messages
|
|
134
|
+
if config.verbose:
|
|
135
|
+
return AIQChatResponse.from_string(str(ex))
|
|
136
|
+
return AIQChatResponse.from_string("I seem to be having a problem.")
|
|
137
|
+
|
|
138
|
+
if (config.use_openai_api):
|
|
139
|
+
yield FunctionInfo.from_fn(_response_fn, description=config.description)
|
|
140
|
+
else:
|
|
141
|
+
|
|
142
|
+
async def _str_api_fn(input_message: str) -> str:
|
|
143
|
+
oai_input = GlobalTypeConverter.get().try_convert(input_message, to_type=AIQChatRequest)
|
|
144
|
+
|
|
145
|
+
oai_output = await _response_fn(oai_input)
|
|
146
|
+
|
|
147
|
+
return GlobalTypeConverter.get().try_convert(oai_output, to_type=str)
|
|
148
|
+
|
|
149
|
+
yield FunctionInfo.from_fn(_str_api_fn, description=config.description)
|
|
File without changes
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: Copyright (c) 2025, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
|
2
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
#
|
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
# you may not use this file except in compliance with the License.
|
|
6
|
+
# You may obtain a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
# See the License for the specific language governing permissions and
|
|
14
|
+
# limitations under the License.
|
|
15
|
+
|
|
16
|
+
import logging
|
|
17
|
+
import re
|
|
18
|
+
from collections.abc import AsyncGenerator
|
|
19
|
+
|
|
20
|
+
from pydantic import Field
|
|
21
|
+
|
|
22
|
+
from aiq.builder.builder import Builder
|
|
23
|
+
from aiq.builder.framework_enum import LLMFrameworkEnum
|
|
24
|
+
from aiq.builder.function_info import FunctionInfo
|
|
25
|
+
from aiq.cli.register_workflow import register_function
|
|
26
|
+
from aiq.data_models.api_server import AIQChatRequest
|
|
27
|
+
from aiq.data_models.component_ref import FunctionRef
|
|
28
|
+
from aiq.data_models.component_ref import LLMRef
|
|
29
|
+
from aiq.data_models.function import FunctionBaseConfig
|
|
30
|
+
|
|
31
|
+
logger = logging.getLogger(__name__)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class ReasoningFunctionConfig(FunctionBaseConfig, name="reasoning_agent"):
|
|
35
|
+
"""
|
|
36
|
+
Defines an AIQ Toolkit function that performs reasoning on the input data.
|
|
37
|
+
Output is passed to the next function in the workflow.
|
|
38
|
+
|
|
39
|
+
Designed to be used with an InterceptingFunction.
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
llm_name: LLMRef = Field(description="The name of the LLM to use for reasoning.")
|
|
43
|
+
augmented_fn: FunctionRef = Field(description="The name of the function to reason on.")
|
|
44
|
+
verbose: bool = Field(default=False, description="Whether to log detailed information.")
|
|
45
|
+
reasoning_prompt_template: str = Field(
|
|
46
|
+
default=("You are an expert reasoning model task with creating a detailed execution plan"
|
|
47
|
+
" for a system that has the following description:\n\n"
|
|
48
|
+
"**Description:** \n{augmented_function_desc}\n\n"
|
|
49
|
+
"Given the following input and a list of available tools, please provide a detailed step-by-step plan"
|
|
50
|
+
" that an instruction following system can use to address the input. Ensure the plan includes:\n\n"
|
|
51
|
+
"1. Identifying the key components of the input.\n"
|
|
52
|
+
"2. Determining the most suitable tools for each task.\n"
|
|
53
|
+
"3. Outlining the sequence of actions to be taken.\n\n"
|
|
54
|
+
"**Input:** \n{input_text}\n\n"
|
|
55
|
+
"**Tools and description of the tool:** \n{tools}\n\n"
|
|
56
|
+
"An example plan could look like this:\n\n"
|
|
57
|
+
"1. Call tool A with input X\n"
|
|
58
|
+
"2. Call tool B with input Y\n"
|
|
59
|
+
"3. Interpret the output of tool A and B\n"
|
|
60
|
+
"4. Return the final result"
|
|
61
|
+
"\n\n **PLAN:**\n"),
|
|
62
|
+
description="The reasoning model prompt template.")
|
|
63
|
+
|
|
64
|
+
instruction_prompt_template: str = Field(
|
|
65
|
+
default=("Answer the following question based on message history: {input_text}"
|
|
66
|
+
"\n\nHere is a plan for execution that you could use to guide you if you wanted to:"
|
|
67
|
+
"\n\n{reasoning_output}"
|
|
68
|
+
"\n\nNOTE: Remember to follow your guidance on how to format output, etc."
|
|
69
|
+
"\n\n You must respond with the answer to the original question directly to the user."),
|
|
70
|
+
description="The instruction prompt template.")
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
@register_function(config_type=ReasoningFunctionConfig, framework_wrappers=[LLMFrameworkEnum.LANGCHAIN])
|
|
74
|
+
async def build_reasoning_function(config: ReasoningFunctionConfig, builder: Builder):
|
|
75
|
+
"""
|
|
76
|
+
Build a ReasoningFunction from the provided config.
|
|
77
|
+
|
|
78
|
+
Args:
|
|
79
|
+
config (ReasoningFunctionConfig): The config for the ReasoningFunction.
|
|
80
|
+
builder (Builder): The Builder instance to use for building the function.
|
|
81
|
+
|
|
82
|
+
Returns:
|
|
83
|
+
ReasoningFunction: The built ReasoningFunction.
|
|
84
|
+
"""
|
|
85
|
+
from langchain_core.language_models import BaseChatModel
|
|
86
|
+
from langchain_core.prompts import PromptTemplate
|
|
87
|
+
|
|
88
|
+
from aiq.agent.base import AGENT_LOG_PREFIX
|
|
89
|
+
|
|
90
|
+
def remove_r1_think_tags(text: str):
|
|
91
|
+
pattern = r'(<think>)?.*?</think>\s*(.*)'
|
|
92
|
+
|
|
93
|
+
# Add re.DOTALL flag to make . match newlines
|
|
94
|
+
match = re.match(pattern, text, re.DOTALL)
|
|
95
|
+
|
|
96
|
+
if match:
|
|
97
|
+
return match.group(2)
|
|
98
|
+
|
|
99
|
+
return text
|
|
100
|
+
|
|
101
|
+
# Get the LLM to use for reasoning
|
|
102
|
+
llm: BaseChatModel = await builder.get_llm(config.llm_name, wrapper_type=LLMFrameworkEnum.LANGCHAIN)
|
|
103
|
+
|
|
104
|
+
# Get the augmented function's description
|
|
105
|
+
augmented_function = builder.get_function(config.augmented_fn)
|
|
106
|
+
|
|
107
|
+
# For now, we rely on runtime checking for type conversion
|
|
108
|
+
|
|
109
|
+
if augmented_function.description and augmented_function.description != "":
|
|
110
|
+
augmented_function_desc = augmented_function.description
|
|
111
|
+
else:
|
|
112
|
+
raise ValueError(f"Function {config.augmented_fn} does not have a description. Cannot augment "
|
|
113
|
+
f"function without a description.")
|
|
114
|
+
|
|
115
|
+
# Get the function dependencies of the augmented function
|
|
116
|
+
function_used_tools = builder.get_function_dependencies(config.augmented_fn).functions
|
|
117
|
+
tool_names_with_desc: list[tuple[str, str]] = []
|
|
118
|
+
|
|
119
|
+
for tool in function_used_tools:
|
|
120
|
+
tool_impl = builder.get_function(tool)
|
|
121
|
+
tool_names_with_desc.append((tool, tool_impl.description if hasattr(tool_impl, "description") else ""))
|
|
122
|
+
|
|
123
|
+
# Draft the reasoning prompt for the augmented function
|
|
124
|
+
template = PromptTemplate(template=config.reasoning_prompt_template,
|
|
125
|
+
input_variables=["augmented_function_desc", "input_text", "tools"],
|
|
126
|
+
validate_template=True)
|
|
127
|
+
|
|
128
|
+
downstream_template = PromptTemplate(template=config.instruction_prompt_template,
|
|
129
|
+
input_variables=["input_text", "reasoning_output"],
|
|
130
|
+
validate_template=True)
|
|
131
|
+
|
|
132
|
+
streaming_inner_fn = None
|
|
133
|
+
single_inner_fn = None
|
|
134
|
+
|
|
135
|
+
if augmented_function.has_streaming_output:
|
|
136
|
+
|
|
137
|
+
async def streaming_inner(
|
|
138
|
+
input_message: AIQChatRequest) -> AsyncGenerator[augmented_function.streaming_output_type]:
|
|
139
|
+
"""
|
|
140
|
+
Perform reasoning on the input text.
|
|
141
|
+
|
|
142
|
+
Args:
|
|
143
|
+
input_message (AIQChatRequest): The input text to reason on.
|
|
144
|
+
"""
|
|
145
|
+
|
|
146
|
+
input_text = "".join([str(message.model_dump()) + "\n" for message in input_message.messages])
|
|
147
|
+
|
|
148
|
+
prompt = await template.ainvoke(
|
|
149
|
+
input={
|
|
150
|
+
"augmented_function_desc": augmented_function_desc,
|
|
151
|
+
"input_text": input_text,
|
|
152
|
+
"tools": "\n".join([f"- {tool[0]}: {tool[1]}" for tool in tool_names_with_desc])
|
|
153
|
+
})
|
|
154
|
+
|
|
155
|
+
prompt = prompt.to_string()
|
|
156
|
+
|
|
157
|
+
# Get the reasoning output from the LLM
|
|
158
|
+
reasoning_output = ""
|
|
159
|
+
|
|
160
|
+
async for chunk in llm.astream(prompt):
|
|
161
|
+
reasoning_output += chunk.content
|
|
162
|
+
|
|
163
|
+
reasoning_output = remove_r1_think_tags(reasoning_output)
|
|
164
|
+
|
|
165
|
+
output = await downstream_template.ainvoke(input={
|
|
166
|
+
"input_text": input_text, "reasoning_output": reasoning_output
|
|
167
|
+
})
|
|
168
|
+
|
|
169
|
+
output = output.to_string()
|
|
170
|
+
|
|
171
|
+
if config.verbose:
|
|
172
|
+
logger.info("%s Reasoning plan and input to agent: \n\n%s", AGENT_LOG_PREFIX, output)
|
|
173
|
+
|
|
174
|
+
async for chunk in augmented_function.acall_stream(output):
|
|
175
|
+
yield chunk
|
|
176
|
+
|
|
177
|
+
streaming_inner_fn = streaming_inner
|
|
178
|
+
|
|
179
|
+
if augmented_function.has_single_output:
|
|
180
|
+
|
|
181
|
+
async def single_inner(input_message: AIQChatRequest) -> augmented_function.single_output_type:
|
|
182
|
+
"""
|
|
183
|
+
Perform reasoning on the input text.
|
|
184
|
+
|
|
185
|
+
Args:
|
|
186
|
+
input_message (AIQChatRequest): The input text to reason on.
|
|
187
|
+
"""
|
|
188
|
+
|
|
189
|
+
input_text = "".join([str(message.model_dump()) + "\n" for message in input_message.messages])
|
|
190
|
+
|
|
191
|
+
prompt = await template.ainvoke(
|
|
192
|
+
input={
|
|
193
|
+
"augmented_function_desc": augmented_function_desc,
|
|
194
|
+
"input_text": input_text,
|
|
195
|
+
"tools": "\n".join([f"- {tool[0]}: {tool[1]}" for tool in tool_names_with_desc])
|
|
196
|
+
})
|
|
197
|
+
|
|
198
|
+
prompt = prompt.to_string()
|
|
199
|
+
|
|
200
|
+
# Get the reasoning output from the LLM
|
|
201
|
+
reasoning_output = ""
|
|
202
|
+
|
|
203
|
+
async for chunk in llm.astream(prompt):
|
|
204
|
+
reasoning_output += chunk.content
|
|
205
|
+
|
|
206
|
+
reasoning_output = remove_r1_think_tags(reasoning_output)
|
|
207
|
+
|
|
208
|
+
output = await downstream_template.ainvoke(input={
|
|
209
|
+
"input_text": input_text, "reasoning_output": reasoning_output
|
|
210
|
+
})
|
|
211
|
+
|
|
212
|
+
output = output.to_string()
|
|
213
|
+
|
|
214
|
+
if config.verbose:
|
|
215
|
+
logger.info("%s Reasoning plan and input to agent: \n\n%s", AGENT_LOG_PREFIX, output)
|
|
216
|
+
|
|
217
|
+
return await augmented_function.acall_invoke(output)
|
|
218
|
+
|
|
219
|
+
single_inner_fn = single_inner
|
|
220
|
+
|
|
221
|
+
yield FunctionInfo.create(
|
|
222
|
+
single_fn=single_inner_fn,
|
|
223
|
+
stream_fn=streaming_inner_fn,
|
|
224
|
+
description=("Reasoning function that generates a detailed execution plan for a system based on the input."),
|
|
225
|
+
converters=augmented_function.converter_list)
|
aiq/agent/register.py
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
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
|
+
# pylint: disable=unused-import
|
|
17
|
+
# flake8: noqa
|
|
18
|
+
|
|
19
|
+
# Import any workflows which need to be automatically registered here
|
|
20
|
+
from .react_agent import register as react_agent
|
|
21
|
+
from .reasoning_agent import reasoning_agent
|
|
22
|
+
from .rewoo_agent import register as rewoo_agent
|
|
23
|
+
from .tool_calling_agent import register as tool_calling_agent
|
|
File without changes
|