nvidia-nat 1.4.0a20251112__py3-none-any.whl → 1.4.0a20260113__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/__init__.py +1 -1
- nat/{front_ends/mcp → agent/auto_memory_wrapper}/__init__.py +1 -1
- nat/agent/auto_memory_wrapper/agent.py +278 -0
- nat/agent/auto_memory_wrapper/register.py +227 -0
- nat/agent/auto_memory_wrapper/state.py +30 -0
- nat/agent/base.py +1 -1
- nat/agent/dual_node.py +1 -1
- nat/agent/prompt_optimizer/prompt.py +1 -1
- nat/agent/prompt_optimizer/register.py +1 -1
- nat/agent/react_agent/agent.py +16 -9
- nat/agent/react_agent/output_parser.py +2 -2
- nat/agent/react_agent/prompt.py +3 -2
- nat/agent/react_agent/register.py +2 -2
- nat/agent/react_agent/register_per_user_agent.py +104 -0
- nat/agent/reasoning_agent/reasoning_agent.py +1 -1
- nat/agent/register.py +3 -1
- nat/agent/responses_api_agent/__init__.py +1 -1
- nat/agent/responses_api_agent/register.py +1 -1
- nat/agent/rewoo_agent/agent.py +9 -4
- nat/agent/rewoo_agent/prompt.py +1 -1
- nat/agent/rewoo_agent/register.py +1 -1
- nat/agent/tool_calling_agent/agent.py +5 -4
- nat/agent/tool_calling_agent/register.py +1 -1
- nat/authentication/__init__.py +1 -1
- nat/authentication/api_key/__init__.py +1 -1
- nat/authentication/api_key/api_key_auth_provider.py +1 -1
- nat/authentication/api_key/api_key_auth_provider_config.py +22 -7
- nat/authentication/api_key/register.py +1 -1
- nat/authentication/credential_validator/__init__.py +1 -1
- nat/authentication/credential_validator/bearer_token_validator.py +1 -1
- nat/authentication/exceptions/__init__.py +1 -1
- nat/authentication/exceptions/api_key_exceptions.py +1 -1
- nat/authentication/http_basic_auth/http_basic_auth_provider.py +1 -1
- nat/authentication/http_basic_auth/register.py +1 -1
- nat/authentication/interfaces.py +1 -1
- nat/authentication/oauth2/__init__.py +1 -1
- nat/authentication/oauth2/oauth2_auth_code_flow_provider.py +1 -1
- nat/authentication/oauth2/oauth2_auth_code_flow_provider_config.py +1 -1
- nat/authentication/oauth2/oauth2_resource_server_config.py +1 -1
- nat/authentication/oauth2/register.py +1 -1
- nat/authentication/register.py +1 -1
- nat/builder/builder.py +563 -1
- nat/builder/child_builder.py +385 -0
- nat/builder/component_utils.py +34 -4
- nat/builder/context.py +34 -1
- nat/builder/embedder.py +1 -1
- nat/builder/eval_builder.py +19 -7
- nat/builder/evaluator.py +1 -1
- nat/builder/framework_enum.py +3 -1
- nat/builder/front_end.py +1 -1
- nat/builder/function.py +113 -5
- nat/builder/function_base.py +1 -1
- nat/builder/function_info.py +1 -1
- nat/builder/intermediate_step_manager.py +1 -1
- nat/builder/llm.py +1 -1
- nat/builder/per_user_workflow_builder.py +843 -0
- nat/builder/retriever.py +1 -1
- nat/builder/sync_builder.py +571 -0
- nat/builder/user_interaction_manager.py +1 -1
- nat/builder/workflow.py +5 -3
- nat/builder/workflow_builder.py +619 -378
- nat/cli/__init__.py +1 -1
- nat/cli/cli_utils/config_override.py +1 -1
- nat/cli/cli_utils/validation.py +32 -1
- nat/cli/commands/configure/channel/add.py +1 -1
- nat/cli/commands/configure/channel/channel.py +1 -1
- nat/cli/commands/configure/channel/remove.py +1 -1
- nat/cli/commands/configure/channel/update.py +1 -1
- nat/cli/commands/configure/configure.py +1 -1
- nat/cli/commands/evaluate.py +87 -13
- nat/cli/commands/finetune.py +132 -0
- nat/cli/commands/info/__init__.py +1 -1
- nat/cli/commands/info/info.py +1 -1
- nat/cli/commands/info/list_channels.py +1 -1
- nat/cli/commands/info/list_components.py +1 -1
- nat/cli/commands/object_store/__init__.py +1 -1
- nat/cli/commands/object_store/object_store.py +1 -1
- nat/cli/commands/optimize.py +1 -1
- nat/cli/commands/{mcp → red_teaming}/__init__.py +1 -1
- nat/cli/commands/red_teaming/red_teaming.py +138 -0
- nat/cli/commands/red_teaming/red_teaming_utils.py +73 -0
- nat/cli/commands/registry/__init__.py +1 -1
- nat/cli/commands/registry/publish.py +1 -1
- nat/cli/commands/registry/pull.py +1 -1
- nat/cli/commands/registry/registry.py +1 -1
- nat/cli/commands/registry/remove.py +1 -1
- nat/cli/commands/registry/search.py +1 -1
- nat/cli/commands/sizing/__init__.py +1 -1
- nat/cli/commands/sizing/calc.py +1 -1
- nat/cli/commands/sizing/sizing.py +1 -1
- nat/cli/commands/start.py +1 -1
- nat/cli/commands/uninstall.py +1 -1
- nat/cli/commands/validate.py +1 -1
- nat/cli/commands/workflow/__init__.py +1 -1
- nat/cli/commands/workflow/workflow.py +1 -1
- nat/cli/commands/workflow/workflow_commands.py +3 -2
- nat/cli/entrypoint.py +15 -37
- nat/cli/main.py +2 -2
- nat/cli/plugin_loader.py +69 -0
- nat/cli/register_workflow.py +233 -5
- nat/cli/type_registry.py +237 -3
- nat/control_flow/register.py +1 -1
- nat/control_flow/router_agent/agent.py +1 -1
- nat/control_flow/router_agent/prompt.py +1 -1
- nat/control_flow/router_agent/register.py +1 -1
- nat/control_flow/sequential_executor.py +28 -7
- nat/data_models/__init__.py +1 -1
- nat/data_models/agent.py +1 -1
- nat/data_models/api_server.py +38 -3
- nat/data_models/authentication.py +1 -1
- nat/data_models/common.py +1 -1
- nat/data_models/component.py +9 -1
- nat/data_models/component_ref.py +45 -1
- nat/data_models/config.py +78 -1
- nat/data_models/dataset_handler.py +15 -2
- nat/data_models/discovery_metadata.py +1 -1
- nat/data_models/embedder.py +1 -1
- nat/data_models/evaluate.py +6 -1
- nat/data_models/evaluator.py +1 -1
- nat/data_models/finetuning.py +260 -0
- nat/data_models/front_end.py +1 -1
- nat/data_models/function.py +15 -2
- nat/data_models/function_dependencies.py +1 -1
- nat/data_models/gated_field_mixin.py +1 -1
- nat/data_models/interactive.py +1 -1
- nat/data_models/intermediate_step.py +29 -2
- nat/data_models/invocation_node.py +1 -1
- nat/data_models/llm.py +1 -1
- nat/data_models/logging.py +1 -1
- nat/data_models/memory.py +1 -1
- nat/data_models/middleware.py +37 -0
- nat/data_models/object_store.py +1 -1
- nat/data_models/openai_mcp.py +1 -1
- nat/data_models/optimizable.py +1 -1
- nat/data_models/optimizer.py +1 -1
- nat/data_models/profiler.py +1 -1
- nat/data_models/registry_handler.py +1 -1
- nat/data_models/retriever.py +1 -1
- nat/data_models/retry_mixin.py +1 -1
- nat/data_models/runtime_enum.py +26 -0
- nat/data_models/span.py +1 -1
- nat/data_models/step_adaptor.py +1 -1
- nat/data_models/streaming.py +1 -1
- nat/data_models/swe_bench_model.py +1 -1
- nat/data_models/telemetry_exporter.py +1 -1
- nat/data_models/thinking_mixin.py +1 -1
- nat/data_models/ttc_strategy.py +1 -1
- nat/embedder/azure_openai_embedder.py +1 -1
- nat/embedder/nim_embedder.py +1 -1
- nat/embedder/openai_embedder.py +1 -1
- nat/embedder/register.py +1 -1
- nat/eval/__init__.py +1 -1
- nat/eval/config.py +8 -1
- nat/eval/dataset_handler/dataset_downloader.py +1 -1
- nat/eval/dataset_handler/dataset_filter.py +1 -1
- nat/eval/dataset_handler/dataset_handler.py +4 -2
- nat/eval/evaluate.py +226 -81
- nat/eval/evaluator/__init__.py +1 -1
- nat/eval/evaluator/base_evaluator.py +2 -2
- nat/eval/evaluator/evaluator_model.py +3 -2
- nat/eval/intermediate_step_adapter.py +1 -1
- nat/eval/llm_validator.py +336 -0
- nat/eval/rag_evaluator/evaluate.py +17 -10
- nat/eval/rag_evaluator/register.py +1 -1
- nat/eval/red_teaming_evaluator/__init__.py +14 -0
- nat/eval/red_teaming_evaluator/data_models.py +66 -0
- nat/eval/red_teaming_evaluator/evaluate.py +327 -0
- nat/eval/red_teaming_evaluator/filter_conditions.py +75 -0
- nat/eval/red_teaming_evaluator/register.py +55 -0
- nat/eval/register.py +2 -1
- nat/eval/remote_workflow.py +1 -1
- nat/eval/runners/__init__.py +1 -1
- nat/eval/runners/config.py +1 -1
- nat/eval/runners/multi_eval_runner.py +1 -1
- nat/eval/runners/red_teaming_runner/__init__.py +24 -0
- nat/eval/runners/red_teaming_runner/config.py +282 -0
- nat/eval/runners/red_teaming_runner/report_utils.py +707 -0
- nat/eval/runners/red_teaming_runner/runner.py +867 -0
- nat/eval/runtime_evaluator/__init__.py +1 -1
- nat/eval/runtime_evaluator/evaluate.py +1 -1
- nat/eval/runtime_evaluator/register.py +1 -1
- nat/eval/runtime_event_subscriber.py +1 -1
- nat/eval/swe_bench_evaluator/evaluate.py +1 -1
- nat/eval/swe_bench_evaluator/register.py +1 -1
- nat/eval/trajectory_evaluator/evaluate.py +2 -2
- nat/eval/trajectory_evaluator/register.py +1 -1
- nat/eval/tunable_rag_evaluator/evaluate.py +5 -5
- nat/eval/tunable_rag_evaluator/register.py +1 -1
- nat/eval/usage_stats.py +1 -1
- nat/eval/utils/eval_trace_ctx.py +1 -1
- nat/eval/utils/output_uploader.py +1 -1
- nat/eval/utils/tqdm_position_registry.py +1 -1
- nat/eval/utils/weave_eval.py +1 -1
- nat/experimental/decorators/experimental_warning_decorator.py +1 -1
- nat/experimental/test_time_compute/editing/iterative_plan_refinement_editor.py +1 -1
- nat/experimental/test_time_compute/editing/llm_as_a_judge_editor.py +1 -1
- nat/experimental/test_time_compute/editing/motivation_aware_summarization.py +1 -1
- nat/experimental/test_time_compute/functions/execute_score_select_function.py +1 -1
- nat/experimental/test_time_compute/functions/multi_llm_judge_function.py +88 -0
- nat/experimental/test_time_compute/functions/plan_select_execute_function.py +1 -1
- nat/experimental/test_time_compute/functions/ttc_tool_orchestration_function.py +1 -1
- nat/experimental/test_time_compute/functions/ttc_tool_wrapper_function.py +1 -1
- nat/experimental/test_time_compute/models/editor_config.py +1 -1
- nat/experimental/test_time_compute/models/scoring_config.py +1 -1
- nat/experimental/test_time_compute/models/search_config.py +20 -2
- nat/experimental/test_time_compute/models/selection_config.py +33 -2
- nat/experimental/test_time_compute/models/stage_enums.py +1 -1
- nat/experimental/test_time_compute/models/strategy_base.py +1 -1
- nat/experimental/test_time_compute/models/tool_use_config.py +1 -1
- nat/experimental/test_time_compute/models/ttc_item.py +1 -1
- nat/experimental/test_time_compute/register.py +4 -1
- nat/experimental/test_time_compute/scoring/llm_based_agent_scorer.py +1 -1
- nat/experimental/test_time_compute/scoring/llm_based_plan_scorer.py +1 -1
- nat/experimental/test_time_compute/scoring/motivation_aware_scorer.py +1 -1
- nat/experimental/test_time_compute/search/multi_llm_generation.py +115 -0
- nat/experimental/test_time_compute/search/multi_llm_planner.py +1 -1
- nat/experimental/test_time_compute/search/multi_query_retrieval_search.py +1 -1
- nat/experimental/test_time_compute/search/single_shot_multi_plan_planner.py +1 -1
- nat/experimental/test_time_compute/selection/best_of_n_selector.py +1 -1
- nat/experimental/test_time_compute/selection/llm_based_agent_output_selector.py +1 -1
- nat/experimental/test_time_compute/selection/llm_based_output_merging_selector.py +1 -1
- nat/experimental/test_time_compute/selection/llm_based_plan_selector.py +1 -1
- nat/experimental/test_time_compute/selection/llm_judge_selection.py +127 -0
- nat/experimental/test_time_compute/selection/threshold_selector.py +1 -1
- nat/finetuning/__init__.py +24 -0
- nat/finetuning/finetuning_runtime.py +143 -0
- nat/finetuning/interfaces/__init__.py +24 -0
- nat/finetuning/interfaces/finetuning_runner.py +261 -0
- nat/finetuning/interfaces/trainer_adapter.py +103 -0
- nat/finetuning/interfaces/trajectory_builder.py +115 -0
- nat/finetuning/utils/__init__.py +15 -0
- nat/finetuning/utils/parsers/__init__.py +15 -0
- nat/finetuning/utils/parsers/adk_parser.py +141 -0
- nat/finetuning/utils/parsers/base_parser.py +238 -0
- nat/finetuning/utils/parsers/common.py +91 -0
- nat/finetuning/utils/parsers/langchain_parser.py +267 -0
- nat/finetuning/utils/parsers/llama_index_parser.py +218 -0
- nat/front_ends/__init__.py +1 -1
- nat/front_ends/console/__init__.py +1 -1
- nat/front_ends/console/authentication_flow_handler.py +1 -1
- nat/front_ends/console/console_front_end_config.py +4 -1
- nat/front_ends/console/console_front_end_plugin.py +5 -4
- nat/front_ends/console/register.py +1 -1
- nat/front_ends/cron/__init__.py +1 -1
- nat/front_ends/fastapi/__init__.py +1 -1
- nat/front_ends/fastapi/async_job.py +128 -0
- nat/front_ends/fastapi/auth_flow_handlers/http_flow_handler.py +1 -1
- nat/front_ends/fastapi/auth_flow_handlers/websocket_flow_handler.py +13 -9
- nat/front_ends/fastapi/dask_client_mixin.py +1 -1
- nat/front_ends/fastapi/fastapi_front_end_config.py +23 -1
- nat/front_ends/fastapi/fastapi_front_end_controller.py +1 -1
- nat/front_ends/fastapi/fastapi_front_end_plugin.py +25 -30
- nat/front_ends/fastapi/fastapi_front_end_plugin_worker.py +318 -59
- nat/front_ends/fastapi/html_snippets/__init__.py +1 -1
- nat/front_ends/fastapi/html_snippets/auth_code_grant_success.py +1 -1
- nat/front_ends/fastapi/intermediate_steps_subscriber.py +12 -1
- nat/front_ends/fastapi/job_store.py +23 -11
- nat/front_ends/fastapi/main.py +1 -1
- nat/front_ends/fastapi/message_handler.py +27 -4
- nat/front_ends/fastapi/message_validator.py +54 -2
- nat/front_ends/fastapi/register.py +1 -1
- nat/front_ends/fastapi/response_helpers.py +16 -15
- nat/front_ends/fastapi/step_adaptor.py +1 -1
- nat/front_ends/fastapi/utils.py +1 -1
- nat/front_ends/register.py +1 -2
- nat/front_ends/simple_base/__init__.py +1 -1
- nat/front_ends/simple_base/simple_front_end_plugin_base.py +6 -4
- nat/llm/aws_bedrock_llm.py +1 -1
- nat/llm/azure_openai_llm.py +10 -1
- nat/llm/dynamo_llm.py +363 -0
- nat/llm/huggingface_llm.py +177 -0
- nat/llm/litellm_llm.py +1 -1
- nat/llm/nim_llm.py +1 -1
- nat/llm/openai_llm.py +1 -1
- nat/llm/register.py +3 -1
- nat/llm/utils/__init__.py +1 -1
- nat/llm/utils/env_config_value.py +1 -1
- nat/llm/utils/error.py +1 -1
- nat/llm/utils/thinking.py +1 -1
- nat/memory/__init__.py +1 -1
- nat/memory/interfaces.py +1 -1
- nat/memory/models.py +1 -1
- nat/meta/pypi.md +1 -1
- nat/middleware/__init__.py +35 -0
- nat/middleware/cache/__init__.py +14 -0
- nat/middleware/cache/cache_middleware.py +253 -0
- nat/middleware/cache/cache_middleware_config.py +44 -0
- nat/middleware/cache/register.py +33 -0
- nat/middleware/defense/__init__.py +14 -0
- nat/middleware/defense/defense_middleware.py +362 -0
- nat/middleware/defense/defense_middleware_content_guard.py +455 -0
- nat/middleware/defense/defense_middleware_data_models.py +91 -0
- nat/middleware/defense/defense_middleware_output_verifier.py +440 -0
- nat/middleware/defense/defense_middleware_pii.py +356 -0
- nat/middleware/defense/register.py +82 -0
- nat/middleware/dynamic/__init__.py +14 -0
- nat/middleware/dynamic/dynamic_function_middleware.py +962 -0
- nat/middleware/dynamic/dynamic_middleware_config.py +132 -0
- nat/middleware/dynamic/register.py +34 -0
- nat/middleware/function_middleware.py +370 -0
- nat/middleware/logging/__init__.py +14 -0
- nat/middleware/logging/logging_middleware.py +67 -0
- nat/middleware/logging/logging_middleware_config.py +28 -0
- nat/middleware/logging/register.py +33 -0
- nat/middleware/middleware.py +298 -0
- nat/middleware/red_teaming/__init__.py +14 -0
- nat/middleware/red_teaming/red_teaming_middleware.py +344 -0
- nat/middleware/red_teaming/red_teaming_middleware_config.py +112 -0
- nat/middleware/red_teaming/register.py +47 -0
- nat/middleware/register.py +22 -0
- nat/middleware/utils/__init__.py +14 -0
- nat/middleware/utils/workflow_inventory.py +155 -0
- nat/object_store/__init__.py +1 -1
- nat/object_store/in_memory_object_store.py +1 -1
- nat/object_store/interfaces.py +1 -1
- nat/object_store/models.py +1 -1
- nat/object_store/register.py +1 -1
- nat/observability/__init__.py +1 -1
- nat/observability/exporter/__init__.py +1 -1
- nat/observability/exporter/base_exporter.py +1 -1
- nat/observability/exporter/exporter.py +1 -1
- nat/observability/exporter/file_exporter.py +1 -1
- nat/observability/exporter/processing_exporter.py +1 -1
- nat/observability/exporter/raw_exporter.py +1 -1
- nat/observability/exporter/span_exporter.py +7 -1
- nat/observability/exporter_manager.py +1 -1
- nat/observability/mixin/__init__.py +1 -1
- nat/observability/mixin/batch_config_mixin.py +1 -1
- nat/observability/mixin/collector_config_mixin.py +1 -1
- nat/observability/mixin/file_mixin.py +1 -1
- nat/observability/mixin/file_mode.py +1 -1
- nat/observability/mixin/redaction_config_mixin.py +1 -1
- nat/observability/mixin/resource_conflict_mixin.py +1 -1
- nat/observability/mixin/serialize_mixin.py +1 -1
- nat/observability/mixin/tagging_config_mixin.py +1 -1
- nat/observability/mixin/type_introspection_mixin.py +1 -1
- nat/observability/processor/__init__.py +1 -1
- nat/observability/processor/batching_processor.py +1 -1
- nat/observability/processor/callback_processor.py +1 -1
- nat/observability/processor/falsy_batch_filter_processor.py +1 -1
- nat/observability/processor/intermediate_step_serializer.py +1 -1
- nat/observability/processor/processor.py +1 -1
- nat/observability/processor/processor_factory.py +1 -1
- nat/observability/processor/redaction/__init__.py +1 -1
- nat/observability/processor/redaction/contextual_redaction_processor.py +1 -1
- nat/observability/processor/redaction/contextual_span_redaction_processor.py +1 -1
- nat/observability/processor/redaction/redaction_processor.py +1 -1
- nat/observability/processor/redaction/span_header_redaction_processor.py +1 -1
- nat/observability/processor/span_tagging_processor.py +1 -1
- nat/observability/register.py +1 -1
- nat/observability/utils/__init__.py +1 -1
- nat/observability/utils/dict_utils.py +1 -1
- nat/observability/utils/time_utils.py +1 -1
- nat/profiler/calc/__init__.py +1 -1
- nat/profiler/calc/calc_runner.py +3 -3
- nat/profiler/calc/calculations.py +1 -1
- nat/profiler/calc/data_models.py +1 -1
- nat/profiler/calc/plot.py +30 -3
- nat/profiler/callbacks/agno_callback_handler.py +1 -1
- nat/profiler/callbacks/base_callback_class.py +1 -1
- nat/profiler/callbacks/langchain_callback_handler.py +33 -3
- nat/profiler/callbacks/llama_index_callback_handler.py +13 -10
- nat/profiler/callbacks/semantic_kernel_callback_handler.py +1 -1
- nat/profiler/callbacks/token_usage_base_model.py +1 -1
- nat/profiler/data_frame_row.py +1 -1
- nat/profiler/data_models.py +1 -1
- nat/profiler/decorators/framework_wrapper.py +32 -1
- nat/profiler/decorators/function_tracking.py +1 -1
- nat/profiler/forecasting/config.py +1 -1
- nat/profiler/forecasting/model_trainer.py +1 -1
- nat/profiler/forecasting/models/__init__.py +1 -1
- nat/profiler/forecasting/models/forecasting_base_model.py +1 -1
- nat/profiler/forecasting/models/linear_model.py +1 -1
- nat/profiler/forecasting/models/random_forest_regressor.py +1 -1
- nat/profiler/inference_metrics_model.py +1 -1
- nat/profiler/inference_optimization/bottleneck_analysis/nested_stack_analysis.py +1 -1
- nat/profiler/inference_optimization/bottleneck_analysis/simple_stack_analysis.py +1 -1
- nat/profiler/inference_optimization/data_models.py +1 -1
- nat/profiler/inference_optimization/experimental/concurrency_spike_analysis.py +1 -1
- nat/profiler/inference_optimization/experimental/prefix_span_analysis.py +1 -1
- nat/profiler/inference_optimization/llm_metrics.py +1 -1
- nat/profiler/inference_optimization/prompt_caching.py +1 -1
- nat/profiler/inference_optimization/token_uniqueness.py +1 -1
- nat/profiler/inference_optimization/workflow_runtimes.py +1 -1
- nat/profiler/intermediate_property_adapter.py +1 -1
- nat/profiler/parameter_optimization/optimizable_utils.py +1 -1
- nat/profiler/parameter_optimization/optimizer_runtime.py +1 -1
- nat/profiler/parameter_optimization/parameter_optimizer.py +1 -1
- nat/profiler/parameter_optimization/parameter_selection.py +1 -1
- nat/profiler/parameter_optimization/pareto_visualizer.py +1 -1
- nat/profiler/parameter_optimization/prompt_optimizer.py +1 -1
- nat/profiler/parameter_optimization/update_helpers.py +1 -1
- nat/profiler/profile_runner.py +1 -1
- nat/profiler/utils.py +1 -1
- nat/registry_handlers/local/local_handler.py +1 -1
- nat/registry_handlers/local/register_local.py +1 -1
- nat/registry_handlers/metadata_factory.py +1 -1
- nat/registry_handlers/package_utils.py +1 -1
- nat/registry_handlers/pypi/pypi_handler.py +1 -1
- nat/registry_handlers/pypi/register_pypi.py +1 -1
- nat/registry_handlers/register.py +1 -1
- nat/registry_handlers/registry_handler_base.py +1 -1
- nat/registry_handlers/rest/register_rest.py +1 -1
- nat/registry_handlers/rest/rest_handler.py +1 -1
- nat/registry_handlers/schemas/headers.py +1 -1
- nat/registry_handlers/schemas/package.py +1 -1
- nat/registry_handlers/schemas/publish.py +1 -1
- nat/registry_handlers/schemas/pull.py +1 -1
- nat/registry_handlers/schemas/remove.py +1 -1
- nat/registry_handlers/schemas/search.py +1 -1
- nat/registry_handlers/schemas/status.py +1 -1
- nat/retriever/interface.py +1 -1
- nat/retriever/milvus/__init__.py +1 -1
- nat/retriever/milvus/register.py +12 -4
- nat/retriever/milvus/retriever.py +103 -41
- nat/retriever/models.py +1 -1
- nat/retriever/nemo_retriever/__init__.py +1 -1
- nat/retriever/nemo_retriever/register.py +1 -1
- nat/retriever/nemo_retriever/retriever.py +5 -5
- nat/retriever/register.py +1 -1
- nat/runtime/__init__.py +1 -1
- nat/runtime/loader.py +10 -3
- nat/runtime/metrics.py +180 -0
- nat/runtime/runner.py +13 -6
- nat/runtime/session.py +458 -32
- nat/runtime/user_metadata.py +1 -1
- nat/settings/global_settings.py +1 -1
- nat/tool/chat_completion.py +1 -1
- nat/tool/code_execution/README.md +1 -1
- nat/tool/code_execution/code_sandbox.py +2 -2
- nat/tool/code_execution/local_sandbox/Dockerfile.sandbox +1 -1
- nat/tool/code_execution/local_sandbox/__init__.py +1 -1
- nat/tool/code_execution/local_sandbox/local_sandbox_server.py +1 -1
- nat/tool/code_execution/local_sandbox/start_local_sandbox.sh +1 -1
- nat/tool/code_execution/register.py +1 -1
- nat/tool/code_execution/utils.py +1 -1
- nat/tool/datetime_tools.py +1 -1
- nat/tool/document_search.py +1 -1
- nat/tool/github_tools.py +1 -1
- nat/tool/memory_tools/add_memory_tool.py +1 -1
- nat/tool/memory_tools/delete_memory_tool.py +1 -1
- nat/tool/memory_tools/get_memory_tool.py +1 -1
- nat/tool/nvidia_rag.py +2 -2
- nat/tool/register.py +1 -1
- nat/tool/retriever.py +1 -1
- nat/tool/server_tools.py +1 -1
- nat/utils/__init__.py +8 -5
- nat/utils/callable_utils.py +1 -1
- nat/utils/data_models/schema_validator.py +1 -1
- nat/utils/debugging_utils.py +1 -1
- nat/utils/decorators.py +1 -1
- nat/utils/dump_distro_mapping.py +1 -1
- nat/utils/exception_handlers/automatic_retries.py +3 -3
- nat/utils/exception_handlers/schemas.py +1 -1
- nat/utils/io/model_processing.py +1 -1
- nat/utils/io/supress_logs.py +33 -0
- nat/utils/io/yaml_tools.py +1 -1
- nat/utils/log_levels.py +1 -1
- nat/utils/log_utils.py +13 -1
- nat/utils/metadata_utils.py +1 -1
- nat/utils/optional_imports.py +1 -1
- nat/utils/producer_consumer_queue.py +1 -1
- nat/utils/reactive/base/observable_base.py +1 -1
- nat/utils/reactive/base/observer_base.py +1 -1
- nat/utils/reactive/base/subject_base.py +1 -1
- nat/utils/reactive/observable.py +1 -1
- nat/utils/reactive/observer.py +1 -1
- nat/utils/reactive/subject.py +1 -1
- nat/utils/reactive/subscription.py +1 -1
- nat/utils/responses_api.py +1 -1
- nat/utils/settings/global_settings.py +1 -1
- nat/utils/string_utils.py +1 -1
- nat/utils/type_converter.py +18 -5
- nat/utils/type_utils.py +1 -1
- nat/utils/url_utils.py +1 -1
- {nvidia_nat-1.4.0a20251112.dist-info → nvidia_nat-1.4.0a20260113.dist-info}/METADATA +46 -15
- nvidia_nat-1.4.0a20260113.dist-info/RECORD +547 -0
- nvidia_nat-1.4.0a20260113.dist-info/entry_points.txt +38 -0
- nat/cli/commands/mcp/mcp.py +0 -986
- nat/front_ends/mcp/introspection_token_verifier.py +0 -73
- nat/front_ends/mcp/mcp_front_end_config.py +0 -109
- nat/front_ends/mcp/mcp_front_end_plugin.py +0 -151
- nat/front_ends/mcp/mcp_front_end_plugin_worker.py +0 -362
- nat/front_ends/mcp/memory_profiler.py +0 -320
- nat/front_ends/mcp/register.py +0 -27
- nat/front_ends/mcp/tool_converter.py +0 -321
- nvidia_nat-1.4.0a20251112.dist-info/RECORD +0 -481
- nvidia_nat-1.4.0a20251112.dist-info/entry_points.txt +0 -22
- {nvidia_nat-1.4.0a20251112.dist-info → nvidia_nat-1.4.0a20260113.dist-info}/WHEEL +0 -0
- {nvidia_nat-1.4.0a20251112.dist-info → nvidia_nat-1.4.0a20260113.dist-info}/licenses/LICENSE-3rd-party.txt +0 -0
- {nvidia_nat-1.4.0a20251112.dist-info → nvidia_nat-1.4.0a20260113.dist-info}/licenses/LICENSE.md +0 -0
- {nvidia_nat-1.4.0a20251112.dist-info → nvidia_nat-1.4.0a20260113.dist-info}/top_level.txt +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# SPDX-FileCopyrightText: Copyright (c) 2025, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
|
1
|
+
# SPDX-FileCopyrightText: Copyright (c) 2025-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
|
2
2
|
# SPDX-License-Identifier: Apache-2.0
|
|
3
3
|
#
|
|
4
4
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
@@ -39,6 +39,9 @@ from pydantic import BaseModel
|
|
|
39
39
|
from pydantic import Field
|
|
40
40
|
from starlette.websockets import WebSocket
|
|
41
41
|
|
|
42
|
+
from nat.builder.context import Context
|
|
43
|
+
from nat.builder.eval_builder import WorkflowEvalBuilder
|
|
44
|
+
from nat.builder.evaluator import EvaluatorInfo
|
|
42
45
|
from nat.builder.function import Function
|
|
43
46
|
from nat.builder.workflow_builder import WorkflowBuilder
|
|
44
47
|
from nat.data_models.api_server import ChatRequest
|
|
@@ -51,11 +54,15 @@ from nat.data_models.object_store import NoSuchKeyError
|
|
|
51
54
|
from nat.eval.config import EvaluationRunOutput
|
|
52
55
|
from nat.eval.evaluate import EvaluationRun
|
|
53
56
|
from nat.eval.evaluate import EvaluationRunConfig
|
|
57
|
+
from nat.eval.evaluator.evaluator_model import EvalInput
|
|
58
|
+
from nat.front_ends.fastapi.async_job import run_generation
|
|
54
59
|
from nat.front_ends.fastapi.auth_flow_handlers.http_flow_handler import HTTPAuthenticationFlowHandler
|
|
55
60
|
from nat.front_ends.fastapi.auth_flow_handlers.websocket_flow_handler import FlowState
|
|
56
61
|
from nat.front_ends.fastapi.auth_flow_handlers.websocket_flow_handler import WebSocketAuthenticationFlowHandler
|
|
57
62
|
from nat.front_ends.fastapi.fastapi_front_end_config import AsyncGenerateResponse
|
|
58
63
|
from nat.front_ends.fastapi.fastapi_front_end_config import AsyncGenerationStatusResponse
|
|
64
|
+
from nat.front_ends.fastapi.fastapi_front_end_config import EvaluateItemRequest
|
|
65
|
+
from nat.front_ends.fastapi.fastapi_front_end_config import EvaluateItemResponse
|
|
59
66
|
from nat.front_ends.fastapi.fastapi_front_end_config import EvaluateRequest
|
|
60
67
|
from nat.front_ends.fastapi.fastapi_front_end_config import EvaluateResponse
|
|
61
68
|
from nat.front_ends.fastapi.fastapi_front_end_config import EvaluateStatusResponse
|
|
@@ -69,6 +76,7 @@ from nat.front_ends.fastapi.utils import get_config_file_path
|
|
|
69
76
|
from nat.object_store.models import ObjectStoreItem
|
|
70
77
|
from nat.runtime.loader import load_workflow
|
|
71
78
|
from nat.runtime.session import SessionManager
|
|
79
|
+
from nat.utils.log_utils import setup_logging
|
|
72
80
|
|
|
73
81
|
logger = logging.getLogger(__name__)
|
|
74
82
|
|
|
@@ -100,6 +108,9 @@ class FastApiFrontEndPluginWorkerBase(ABC):
|
|
|
100
108
|
self._scheduler_address = os.environ.get("NAT_DASK_SCHEDULER_ADDRESS")
|
|
101
109
|
self._db_url = os.environ.get("NAT_JOB_STORE_DB_URL")
|
|
102
110
|
self._config_file_path = get_config_file_path()
|
|
111
|
+
self._use_dask_threads = os.environ.get("NAT_USE_DASK_THREADS", "0") == "1"
|
|
112
|
+
self._log_level = int(os.environ.get("NAT_FASTAPI_LOG_LEVEL", logging.INFO))
|
|
113
|
+
setup_logging(self._log_level)
|
|
103
114
|
|
|
104
115
|
if self._scheduler_address is not None:
|
|
105
116
|
if not _DASK_AVAILABLE:
|
|
@@ -227,6 +238,78 @@ class FastApiFrontEndPluginWorker(FastApiFrontEndPluginWorkerBase):
|
|
|
227
238
|
self._outstanding_flows: dict[str, FlowState] = {}
|
|
228
239
|
self._outstanding_flows_lock = asyncio.Lock()
|
|
229
240
|
|
|
241
|
+
# Track session managers for each route
|
|
242
|
+
self._session_managers: list[SessionManager] = []
|
|
243
|
+
|
|
244
|
+
# Evaluator storage for single-item evaluation
|
|
245
|
+
self._evaluators: dict[str, EvaluatorInfo] = {}
|
|
246
|
+
self._eval_builder: WorkflowEvalBuilder | None = None
|
|
247
|
+
|
|
248
|
+
async def initialize_evaluators(self, config: Config):
|
|
249
|
+
"""Initialize and store evaluators from config for single-item evaluation."""
|
|
250
|
+
if not config.eval or not config.eval.evaluators:
|
|
251
|
+
logger.info("No evaluators configured, skipping evaluator initialization")
|
|
252
|
+
return
|
|
253
|
+
|
|
254
|
+
try:
|
|
255
|
+
# Build evaluators using WorkflowEvalBuilder (same pattern as nat eval)
|
|
256
|
+
# Start with registry=None and let populate_builder set everything up
|
|
257
|
+
self._eval_builder = WorkflowEvalBuilder(general_config=config.general,
|
|
258
|
+
eval_general_config=config.eval.general,
|
|
259
|
+
registry=None)
|
|
260
|
+
|
|
261
|
+
# Enter the async context and keep it alive
|
|
262
|
+
await self._eval_builder.__aenter__()
|
|
263
|
+
|
|
264
|
+
# Populate builder with config (this sets up LLMs, functions, etc.)
|
|
265
|
+
# Skip workflow build since we already have it from the main builder
|
|
266
|
+
await self._eval_builder.populate_builder(config, skip_workflow=True)
|
|
267
|
+
|
|
268
|
+
# Now evaluators should be populated by populate_builder
|
|
269
|
+
for name in config.eval.evaluators.keys():
|
|
270
|
+
self._evaluators[name] = self._eval_builder.get_evaluator(name)
|
|
271
|
+
logger.info(f"Initialized evaluator: {name}")
|
|
272
|
+
|
|
273
|
+
logger.info(f"Successfully initialized {len(self._evaluators)} evaluators")
|
|
274
|
+
|
|
275
|
+
except Exception as e:
|
|
276
|
+
logger.error(f"Failed to initialize evaluators: {e}")
|
|
277
|
+
# Don't fail startup, just log the error
|
|
278
|
+
self._evaluators = {}
|
|
279
|
+
|
|
280
|
+
async def _create_session_manager(self,
|
|
281
|
+
builder: WorkflowBuilder,
|
|
282
|
+
entry_function: str | None = None) -> SessionManager:
|
|
283
|
+
"""Create and register a SessionManager."""
|
|
284
|
+
|
|
285
|
+
sm = await SessionManager.create(config=self._config, shared_builder=builder, entry_function=entry_function)
|
|
286
|
+
self._session_managers.append(sm)
|
|
287
|
+
|
|
288
|
+
return sm
|
|
289
|
+
|
|
290
|
+
async def cleanup_session_managers(self):
|
|
291
|
+
"""Clean up all SessionManager resources on shutdown."""
|
|
292
|
+
for sm in self._session_managers:
|
|
293
|
+
try:
|
|
294
|
+
await sm.shutdown()
|
|
295
|
+
except Exception as e:
|
|
296
|
+
logger.error(f"Error cleaning up SessionManager: {e}")
|
|
297
|
+
|
|
298
|
+
self._session_managers.clear()
|
|
299
|
+
logger.info("All SessionManagers cleaned up")
|
|
300
|
+
|
|
301
|
+
async def cleanup_evaluators(self):
|
|
302
|
+
"""Clean up evaluator resources on shutdown."""
|
|
303
|
+
if self._eval_builder:
|
|
304
|
+
try:
|
|
305
|
+
await self._eval_builder.__aexit__(None, None, None)
|
|
306
|
+
logger.info("Evaluator builder context cleaned up")
|
|
307
|
+
except Exception as e:
|
|
308
|
+
logger.error(f"Error cleaning up evaluator builder: {e}")
|
|
309
|
+
finally:
|
|
310
|
+
self._eval_builder = None
|
|
311
|
+
self._evaluators.clear()
|
|
312
|
+
|
|
230
313
|
def get_step_adaptor(self) -> StepAdaptor:
|
|
231
314
|
|
|
232
315
|
return StepAdaptor(self.front_end_config.step_adaptor)
|
|
@@ -236,21 +319,34 @@ class FastApiFrontEndPluginWorker(FastApiFrontEndPluginWorkerBase):
|
|
|
236
319
|
# Do things like setting the base URL and global configuration options
|
|
237
320
|
app.root_path = self.front_end_config.root_path
|
|
238
321
|
|
|
322
|
+
# Initialize evaluators for single-item evaluation
|
|
323
|
+
# TODO: we need config control over this as it's not always needed
|
|
324
|
+
await self.initialize_evaluators(self._config)
|
|
325
|
+
|
|
326
|
+
# Ensure session manager resources are cleaned up when the app shuts down
|
|
327
|
+
app.add_event_handler("shutdown", self.cleanup_session_managers)
|
|
328
|
+
|
|
329
|
+
# Ensure evaluator resources are cleaned up when the app shuts down
|
|
330
|
+
app.add_event_handler("shutdown", self.cleanup_evaluators)
|
|
331
|
+
|
|
239
332
|
await self.add_routes(app, builder)
|
|
240
333
|
|
|
241
334
|
async def add_routes(self, app: FastAPI, builder: WorkflowBuilder):
|
|
242
335
|
|
|
243
|
-
await self.add_default_route(app,
|
|
244
|
-
await self.add_evaluate_route(app,
|
|
336
|
+
await self.add_default_route(app, await self._create_session_manager(builder))
|
|
337
|
+
await self.add_evaluate_route(app, await self._create_session_manager(builder))
|
|
338
|
+
await self.add_evaluate_item_route(app, await self._create_session_manager(builder))
|
|
339
|
+
|
|
245
340
|
await self.add_static_files_route(app, builder)
|
|
246
341
|
await self.add_authorization_route(app)
|
|
247
342
|
await self.add_mcp_client_tool_list_route(app, builder)
|
|
343
|
+
await self.add_monitor_route(app)
|
|
248
344
|
|
|
249
345
|
for ep in self.front_end_config.endpoints:
|
|
250
346
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
347
|
+
await self.add_route(app,
|
|
348
|
+
endpoint=ep,
|
|
349
|
+
session_manager=await self._create_session_manager(builder, ep.function_name))
|
|
254
350
|
|
|
255
351
|
async def add_default_route(self, app: FastAPI, session_manager: SessionManager):
|
|
256
352
|
|
|
@@ -439,6 +535,69 @@ class FastApiFrontEndPluginWorker(FastApiFrontEndPluginWorkerBase):
|
|
|
439
535
|
else:
|
|
440
536
|
logger.warning("Dask is not available, evaluation endpoints will not be added.")
|
|
441
537
|
|
|
538
|
+
async def add_evaluate_item_route(self, app: FastAPI, session_manager: SessionManager):
|
|
539
|
+
"""Add the single-item evaluation endpoint to the FastAPI app."""
|
|
540
|
+
|
|
541
|
+
async def evaluate_single_item(request: EvaluateItemRequest, http_request: Request) -> EvaluateItemResponse:
|
|
542
|
+
"""Handle single-item evaluation requests."""
|
|
543
|
+
|
|
544
|
+
async with session_manager.session(http_connection=http_request):
|
|
545
|
+
|
|
546
|
+
# Check if evaluator exists
|
|
547
|
+
if request.evaluator_name not in self._evaluators:
|
|
548
|
+
raise HTTPException(status_code=404,
|
|
549
|
+
detail=f"Evaluator '{request.evaluator_name}' not found. "
|
|
550
|
+
f"Available evaluators: {list(self._evaluators.keys())}")
|
|
551
|
+
|
|
552
|
+
try:
|
|
553
|
+
# Get the evaluator
|
|
554
|
+
evaluator = self._evaluators[request.evaluator_name]
|
|
555
|
+
|
|
556
|
+
# Run evaluation on single item
|
|
557
|
+
result = await evaluator.evaluate_fn(EvalInput(eval_input_items=[request.item]))
|
|
558
|
+
|
|
559
|
+
# Extract the single output item
|
|
560
|
+
if result.eval_output_items:
|
|
561
|
+
output_item = result.eval_output_items[0]
|
|
562
|
+
return EvaluateItemResponse(success=True, result=output_item, error=None)
|
|
563
|
+
else:
|
|
564
|
+
return EvaluateItemResponse(success=False, result=None, error="Evaluator returned no results")
|
|
565
|
+
|
|
566
|
+
except Exception as e:
|
|
567
|
+
logger.exception(f"Error evaluating item with {request.evaluator_name}")
|
|
568
|
+
return EvaluateItemResponse(success=False, result=None, error=f"Evaluation failed: {str(e)}")
|
|
569
|
+
|
|
570
|
+
# Register the route
|
|
571
|
+
if self.front_end_config.evaluate_item.path:
|
|
572
|
+
app.add_api_route(path=self.front_end_config.evaluate_item.path,
|
|
573
|
+
endpoint=evaluate_single_item,
|
|
574
|
+
methods=[self.front_end_config.evaluate_item.method],
|
|
575
|
+
response_model=EvaluateItemResponse,
|
|
576
|
+
description=self.front_end_config.evaluate_item.description,
|
|
577
|
+
responses={
|
|
578
|
+
404: {
|
|
579
|
+
"description": "Evaluator not found",
|
|
580
|
+
"content": {
|
|
581
|
+
"application/json": {
|
|
582
|
+
"example": {
|
|
583
|
+
"detail": "Evaluator 'unknown' not found"
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
},
|
|
588
|
+
500: {
|
|
589
|
+
"description": "Internal Server Error",
|
|
590
|
+
"content": {
|
|
591
|
+
"application/json": {
|
|
592
|
+
"example": {
|
|
593
|
+
"detail": "Internal server error occurred"
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
})
|
|
599
|
+
logger.info(f"Added evaluate_item route at {self.front_end_config.evaluate_item.path}")
|
|
600
|
+
|
|
442
601
|
async def add_static_files_route(self, app: FastAPI, builder: WorkflowBuilder):
|
|
443
602
|
|
|
444
603
|
if not self.front_end_config.object_store:
|
|
@@ -538,11 +697,15 @@ class FastApiFrontEndPluginWorker(FastApiFrontEndPluginWorkerBase):
|
|
|
538
697
|
endpoint: FastApiFrontEndConfig.EndpointBase,
|
|
539
698
|
session_manager: SessionManager):
|
|
540
699
|
|
|
541
|
-
|
|
700
|
+
GenerateBodyType = session_manager.get_workflow_input_schema()
|
|
701
|
+
GenerateStreamResponseType = session_manager.get_workflow_streaming_output_schema()
|
|
702
|
+
GenerateSingleResponseType = session_manager.get_workflow_single_output_schema()
|
|
542
703
|
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
704
|
+
def add_context_headers_to_response(response: Response) -> None:
|
|
705
|
+
"""Add context-based headers to response if available."""
|
|
706
|
+
observability_trace_id = Context.get().observability_trace_id
|
|
707
|
+
if observability_trace_id:
|
|
708
|
+
response.headers["Observability-Trace-Id"] = observability_trace_id
|
|
546
709
|
|
|
547
710
|
# Skip async generation for custom routes (those with function_name)
|
|
548
711
|
if self._dask_available and not hasattr(endpoint, 'function_name'):
|
|
@@ -591,10 +754,13 @@ class FastApiFrontEndPluginWorker(FastApiFrontEndPluginWorkerBase):
|
|
|
591
754
|
|
|
592
755
|
response.headers["Content-Type"] = "application/json"
|
|
593
756
|
|
|
594
|
-
async with session_manager.session(
|
|
595
|
-
|
|
757
|
+
async with session_manager.session(
|
|
758
|
+
http_connection=request,
|
|
759
|
+
user_authentication_callback=self._http_flow_handler.authenticate) as session:
|
|
596
760
|
|
|
597
|
-
|
|
761
|
+
result = await generate_single_response(None, session, result_type=result_type)
|
|
762
|
+
add_context_headers_to_response(response)
|
|
763
|
+
return result
|
|
598
764
|
|
|
599
765
|
return get_single
|
|
600
766
|
|
|
@@ -602,13 +768,14 @@ class FastApiFrontEndPluginWorker(FastApiFrontEndPluginWorkerBase):
|
|
|
602
768
|
|
|
603
769
|
async def get_stream(request: Request):
|
|
604
770
|
|
|
605
|
-
async with session_manager.session(
|
|
606
|
-
|
|
771
|
+
async with session_manager.session(
|
|
772
|
+
http_connection=request,
|
|
773
|
+
user_authentication_callback=self._http_flow_handler.authenticate) as session:
|
|
607
774
|
|
|
608
775
|
return StreamingResponse(headers={"Content-Type": "text/event-stream; charset=utf-8"},
|
|
609
776
|
content=generate_streaming_response_as_str(
|
|
610
777
|
None,
|
|
611
|
-
|
|
778
|
+
session=session,
|
|
612
779
|
streaming=streaming,
|
|
613
780
|
step_adaptor=self.get_step_adaptor(),
|
|
614
781
|
result_type=result_type,
|
|
@@ -620,14 +787,14 @@ class FastApiFrontEndPluginWorker(FastApiFrontEndPluginWorkerBase):
|
|
|
620
787
|
|
|
621
788
|
async def get_stream(filter_steps: str | None = None):
|
|
622
789
|
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
None,
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
790
|
+
async with session_manager.session(http_connection=None) as session:
|
|
791
|
+
return StreamingResponse(headers={"Content-Type": "text/event-stream; charset=utf-8"},
|
|
792
|
+
content=generate_streaming_response_full_as_str(None,
|
|
793
|
+
session=session,
|
|
794
|
+
streaming=streaming,
|
|
795
|
+
result_type=result_type,
|
|
796
|
+
output_type=output_type,
|
|
797
|
+
filter_steps=filter_steps))
|
|
631
798
|
|
|
632
799
|
return get_stream
|
|
633
800
|
|
|
@@ -637,10 +804,13 @@ class FastApiFrontEndPluginWorker(FastApiFrontEndPluginWorkerBase):
|
|
|
637
804
|
|
|
638
805
|
response.headers["Content-Type"] = "application/json"
|
|
639
806
|
|
|
640
|
-
async with session_manager.session(
|
|
641
|
-
|
|
807
|
+
async with session_manager.session(
|
|
808
|
+
http_connection=request,
|
|
809
|
+
user_authentication_callback=self._http_flow_handler.authenticate) as session:
|
|
642
810
|
|
|
643
|
-
|
|
811
|
+
result = await generate_single_response(payload, session, result_type=result_type)
|
|
812
|
+
add_context_headers_to_response(response)
|
|
813
|
+
return result
|
|
644
814
|
|
|
645
815
|
return post_single
|
|
646
816
|
|
|
@@ -651,13 +821,14 @@ class FastApiFrontEndPluginWorker(FastApiFrontEndPluginWorkerBase):
|
|
|
651
821
|
|
|
652
822
|
async def post_stream(request: Request, payload: request_type):
|
|
653
823
|
|
|
654
|
-
async with session_manager.session(
|
|
655
|
-
|
|
824
|
+
async with session_manager.session(
|
|
825
|
+
http_connection=request,
|
|
826
|
+
user_authentication_callback=self._http_flow_handler.authenticate) as session:
|
|
656
827
|
|
|
657
828
|
return StreamingResponse(headers={"Content-Type": "text/event-stream; charset=utf-8"},
|
|
658
829
|
content=generate_streaming_response_as_str(
|
|
659
830
|
payload,
|
|
660
|
-
|
|
831
|
+
session=session,
|
|
661
832
|
streaming=streaming,
|
|
662
833
|
step_adaptor=self.get_step_adaptor(),
|
|
663
834
|
result_type=result_type,
|
|
@@ -675,14 +846,14 @@ class FastApiFrontEndPluginWorker(FastApiFrontEndPluginWorkerBase):
|
|
|
675
846
|
|
|
676
847
|
async def post_stream(payload: request_type, filter_steps: str | None = None):
|
|
677
848
|
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
payload,
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
849
|
+
async with session_manager.session(http_connection=None) as session:
|
|
850
|
+
return StreamingResponse(headers={"Content-Type": "text/event-stream; charset=utf-8"},
|
|
851
|
+
content=generate_streaming_response_full_as_str(payload,
|
|
852
|
+
session=session,
|
|
853
|
+
streaming=streaming,
|
|
854
|
+
result_type=result_type,
|
|
855
|
+
output_type=output_type,
|
|
856
|
+
filter_steps=filter_steps))
|
|
686
857
|
|
|
687
858
|
return post_stream
|
|
688
859
|
|
|
@@ -698,20 +869,22 @@ class FastApiFrontEndPluginWorker(FastApiFrontEndPluginWorkerBase):
|
|
|
698
869
|
response.headers["Content-Type"] = "application/json"
|
|
699
870
|
stream_requested = getattr(payload, 'stream', False)
|
|
700
871
|
|
|
701
|
-
async with session_manager.session(http_connection=request):
|
|
872
|
+
async with session_manager.session(http_connection=request) as session:
|
|
702
873
|
if stream_requested:
|
|
703
874
|
|
|
704
875
|
# Return streaming response
|
|
705
876
|
return StreamingResponse(headers={"Content-Type": "text/event-stream; charset=utf-8"},
|
|
706
877
|
content=generate_streaming_response_as_str(
|
|
707
878
|
payload,
|
|
708
|
-
|
|
879
|
+
session=session,
|
|
709
880
|
streaming=True,
|
|
710
881
|
step_adaptor=self.get_step_adaptor(),
|
|
711
882
|
result_type=ChatResponseChunk,
|
|
712
883
|
output_type=ChatResponseChunk))
|
|
713
884
|
|
|
714
|
-
|
|
885
|
+
result = await generate_single_response(payload, session, result_type=ChatResponse)
|
|
886
|
+
add_context_headers_to_response(response)
|
|
887
|
+
return result
|
|
715
888
|
|
|
716
889
|
return post_openai_api_compatible
|
|
717
890
|
|
|
@@ -732,23 +905,6 @@ class FastApiFrontEndPluginWorker(FastApiFrontEndPluginWorkerBase):
|
|
|
732
905
|
updated_at=job.updated_at,
|
|
733
906
|
expires_at=self._job_store.get_expires_at(job))
|
|
734
907
|
|
|
735
|
-
async def run_generation(scheduler_address: str,
|
|
736
|
-
db_url: str,
|
|
737
|
-
config_file_path: str,
|
|
738
|
-
job_id: str,
|
|
739
|
-
payload: typing.Any):
|
|
740
|
-
"""Background task to run the workflow."""
|
|
741
|
-
job_store = JobStore(scheduler_address=scheduler_address, db_url=db_url)
|
|
742
|
-
try:
|
|
743
|
-
async with load_workflow(config_file_path) as local_session_manager:
|
|
744
|
-
result = await generate_single_response(
|
|
745
|
-
payload, local_session_manager, result_type=local_session_manager.workflow.single_output_schema)
|
|
746
|
-
|
|
747
|
-
await job_store.update_status(job_id, JobStatus.SUCCESS, output=result)
|
|
748
|
-
except Exception as e:
|
|
749
|
-
logger.exception("Error in async job %s", job_id)
|
|
750
|
-
await job_store.update_status(job_id, JobStatus.FAILURE, error=str(e))
|
|
751
|
-
|
|
752
908
|
def post_async_generation(request_type: type):
|
|
753
909
|
|
|
754
910
|
async def start_async_generation(
|
|
@@ -771,6 +927,8 @@ class FastApiFrontEndPluginWorker(FastApiFrontEndPluginWorkerBase):
|
|
|
771
927
|
job_fn=run_generation,
|
|
772
928
|
sync_timeout=request.sync_timeout,
|
|
773
929
|
job_args=[
|
|
930
|
+
not self._use_dask_threads,
|
|
931
|
+
self._log_level,
|
|
774
932
|
self._scheduler_address,
|
|
775
933
|
self._db_url,
|
|
776
934
|
self._config_file_path,
|
|
@@ -1104,7 +1262,7 @@ class FastApiFrontEndPluginWorker(FastApiFrontEndPluginWorkerBase):
|
|
|
1104
1262
|
if configured_group.config.type != "mcp_client":
|
|
1105
1263
|
continue
|
|
1106
1264
|
|
|
1107
|
-
from nat.plugins.mcp.client_config import MCPClientConfig
|
|
1265
|
+
from nat.plugins.mcp.client.client_config import MCPClientConfig
|
|
1108
1266
|
|
|
1109
1267
|
config = configured_group.config
|
|
1110
1268
|
assert isinstance(config, MCPClientConfig)
|
|
@@ -1253,6 +1411,107 @@ class FastApiFrontEndPluginWorker(FastApiFrontEndPluginWorkerBase):
|
|
|
1253
1411
|
}
|
|
1254
1412
|
})
|
|
1255
1413
|
|
|
1414
|
+
async def add_monitor_route(self, app: FastAPI):
|
|
1415
|
+
"""Add the per-user monitoring endpoint to the FastAPI app.
|
|
1416
|
+
|
|
1417
|
+
Security Warning:
|
|
1418
|
+
This endpoint exposes per-user identifiers and usage metrics. It should be
|
|
1419
|
+
protected by deploying behind an internal network, a reverse proxy with
|
|
1420
|
+
authentication, or similar access controls to prevent exposure to untrusted callers.
|
|
1421
|
+
"""
|
|
1422
|
+
# Check if monitoring is enabled in config
|
|
1423
|
+
if not self._config.general.enable_per_user_monitoring:
|
|
1424
|
+
logger.debug("Per-user monitoring disabled, skipping /monitor/users endpoint")
|
|
1425
|
+
return
|
|
1426
|
+
|
|
1427
|
+
from nat.runtime.metrics import PerUserMetricsCollector
|
|
1428
|
+
from nat.runtime.metrics import PerUserMonitorResponse
|
|
1429
|
+
from nat.runtime.metrics import PerUserResourceUsage
|
|
1430
|
+
|
|
1431
|
+
async def get_per_user_metrics(user_id: str | None = None) -> PerUserMonitorResponse:
|
|
1432
|
+
"""
|
|
1433
|
+
Get resource usage metrics for per-user workflows.
|
|
1434
|
+
|
|
1435
|
+
Args:
|
|
1436
|
+
user_id: Optional user ID to filter metrics for a specific user
|
|
1437
|
+
|
|
1438
|
+
Returns:
|
|
1439
|
+
PerUserMonitorResponse with metrics for all or specified users
|
|
1440
|
+
"""
|
|
1441
|
+
# Collect metrics from all session managers that have per-user workflows
|
|
1442
|
+
all_users: list[PerUserResourceUsage] = []
|
|
1443
|
+
|
|
1444
|
+
for session_manager in self._session_managers:
|
|
1445
|
+
if not session_manager.is_workflow_per_user:
|
|
1446
|
+
continue
|
|
1447
|
+
|
|
1448
|
+
collector = PerUserMetricsCollector(session_manager)
|
|
1449
|
+
|
|
1450
|
+
if user_id is not None:
|
|
1451
|
+
# Filter for specific user
|
|
1452
|
+
user_metrics = await collector.collect_user_metrics(user_id)
|
|
1453
|
+
if user_metrics:
|
|
1454
|
+
all_users.append(user_metrics)
|
|
1455
|
+
else:
|
|
1456
|
+
# Get all users
|
|
1457
|
+
response = await collector.collect_all_metrics()
|
|
1458
|
+
all_users.extend(response.users)
|
|
1459
|
+
|
|
1460
|
+
from datetime import datetime
|
|
1461
|
+
return PerUserMonitorResponse(
|
|
1462
|
+
timestamp=datetime.now(),
|
|
1463
|
+
total_active_users=len(all_users),
|
|
1464
|
+
users=all_users,
|
|
1465
|
+
)
|
|
1466
|
+
|
|
1467
|
+
# Register the monitoring endpoint
|
|
1468
|
+
app.add_api_route(path="/monitor/users",
|
|
1469
|
+
endpoint=get_per_user_metrics,
|
|
1470
|
+
methods=["GET"],
|
|
1471
|
+
response_model=PerUserMonitorResponse,
|
|
1472
|
+
description="Get resource usage metrics for per-user workflows",
|
|
1473
|
+
tags=["Monitoring"],
|
|
1474
|
+
responses={
|
|
1475
|
+
200: {
|
|
1476
|
+
"description": "Successfully retrieved per-user metrics",
|
|
1477
|
+
"content": {
|
|
1478
|
+
"application/json": {
|
|
1479
|
+
"example": {
|
|
1480
|
+
"timestamp":
|
|
1481
|
+
"2025-12-16T10:30:00Z",
|
|
1482
|
+
"total_active_users":
|
|
1483
|
+
2,
|
|
1484
|
+
"users": [{
|
|
1485
|
+
"user_id": "alice",
|
|
1486
|
+
"session": {
|
|
1487
|
+
"created_at": "2025-12-16T09:00:00Z",
|
|
1488
|
+
"last_activity": "2025-12-16T10:29:55Z",
|
|
1489
|
+
"ref_count": 1,
|
|
1490
|
+
"is_active": True
|
|
1491
|
+
},
|
|
1492
|
+
"requests": {
|
|
1493
|
+
"total_requests": 42,
|
|
1494
|
+
"active_requests": 1,
|
|
1495
|
+
"avg_latency_ms": 1250.5,
|
|
1496
|
+
"error_count": 2
|
|
1497
|
+
},
|
|
1498
|
+
"memory": {
|
|
1499
|
+
"per_user_functions_count": 2,
|
|
1500
|
+
"per_user_function_groups_count": 1,
|
|
1501
|
+
"exit_stack_size": 3
|
|
1502
|
+
}
|
|
1503
|
+
}]
|
|
1504
|
+
}
|
|
1505
|
+
}
|
|
1506
|
+
}
|
|
1507
|
+
},
|
|
1508
|
+
500: {
|
|
1509
|
+
"description": "Internal Server Error"
|
|
1510
|
+
}
|
|
1511
|
+
})
|
|
1512
|
+
|
|
1513
|
+
logger.info("Added per-user monitoring endpoint at /monitor/users")
|
|
1514
|
+
|
|
1256
1515
|
async def _add_flow(self, state: str, flow_state: FlowState):
|
|
1257
1516
|
async with self._outstanding_flows_lock:
|
|
1258
1517
|
self._outstanding_flows[state] = flow_state
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# SPDX-FileCopyrightText: Copyright (c) 2025, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
|
1
|
+
# SPDX-FileCopyrightText: Copyright (c) 2025-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
|
2
2
|
# SPDX-License-Identifier: Apache-2.0
|
|
3
3
|
#
|
|
4
4
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# SPDX-FileCopyrightText: Copyright (c) 2025, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
|
1
|
+
# SPDX-FileCopyrightText: Copyright (c) 2025-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
|
2
2
|
# SPDX-License-Identifier: Apache-2.0
|
|
3
3
|
#
|
|
4
4
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# SPDX-FileCopyrightText: Copyright (c) 2025, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
|
1
|
+
# SPDX-FileCopyrightText: Copyright (c) 2025-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
|
2
2
|
# SPDX-License-Identifier: Apache-2.0
|
|
3
3
|
#
|
|
4
4
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
@@ -32,6 +32,7 @@ async def pull_intermediate(_q, adapter):
|
|
|
32
32
|
intermediate_done = asyncio.Event()
|
|
33
33
|
context = Context.get()
|
|
34
34
|
loop = asyncio.get_running_loop()
|
|
35
|
+
trace_id_emitted = False
|
|
35
36
|
|
|
36
37
|
async def set_intermediate_done():
|
|
37
38
|
intermediate_done.set()
|
|
@@ -43,6 +44,16 @@ async def pull_intermediate(_q, adapter):
|
|
|
43
44
|
If adapter is None, convert the raw IntermediateStep into the complete
|
|
44
45
|
ResponseIntermediateStep and place it into the queue.
|
|
45
46
|
"""
|
|
47
|
+
nonlocal trace_id_emitted
|
|
48
|
+
|
|
49
|
+
# Check if trace ID is now available and emit it once
|
|
50
|
+
if not trace_id_emitted:
|
|
51
|
+
observability_trace_id = context.observability_trace_id
|
|
52
|
+
if observability_trace_id:
|
|
53
|
+
from nat.data_models.api_server import ResponseObservabilityTrace
|
|
54
|
+
loop.create_task(_q.put(ResponseObservabilityTrace(observability_trace_id=observability_trace_id)))
|
|
55
|
+
trace_id_emitted = True
|
|
56
|
+
|
|
46
57
|
if adapter is None:
|
|
47
58
|
adapted = ResponseIntermediateStep(id=item.UUID,
|
|
48
59
|
type=item.event_type,
|