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
aiq/__init__.py
CHANGED
|
@@ -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) 2024-
|
|
1
|
+
# SPDX-FileCopyrightText: Copyright (c) 2024-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");
|
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: Copyright (c) 2024-2026, 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
|
+
from collections.abc import Awaitable
|
|
18
|
+
from collections.abc import Callable
|
|
19
|
+
from typing import Any
|
|
20
|
+
|
|
21
|
+
from langchain_core.messages import AIMessage
|
|
22
|
+
from langchain_core.messages import BaseMessage
|
|
23
|
+
from langchain_core.messages import HumanMessage
|
|
24
|
+
from langchain_core.messages import SystemMessage
|
|
25
|
+
from langgraph.graph import StateGraph
|
|
26
|
+
from langgraph.graph.state import CompiledStateGraph
|
|
27
|
+
|
|
28
|
+
from nat.builder.context import Context
|
|
29
|
+
from nat.data_models.api_server import ChatRequest
|
|
30
|
+
from nat.data_models.api_server import Message
|
|
31
|
+
from nat.data_models.api_server import UserMessageContentRoleType
|
|
32
|
+
from nat.memory.interfaces import MemoryEditor
|
|
33
|
+
from nat.memory.models import MemoryItem
|
|
34
|
+
|
|
35
|
+
from .state import AutoMemoryWrapperState
|
|
36
|
+
|
|
37
|
+
logger = logging.getLogger(__name__)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class AutoMemoryWrapperGraph:
|
|
41
|
+
"""
|
|
42
|
+
Wraps any NAT agent to add automatic memory capture and retrieval.
|
|
43
|
+
|
|
44
|
+
The wrapper treats the inner agent as a black-box function that receives
|
|
45
|
+
a ChatRequest with multiple messages (including system messages with memory
|
|
46
|
+
context). The inner agent manages its own internal state (ReActGraphState,
|
|
47
|
+
ReWOOGraphState, etc.) - the wrapper never sees it.
|
|
48
|
+
"""
|
|
49
|
+
|
|
50
|
+
def __init__(
|
|
51
|
+
self,
|
|
52
|
+
inner_agent_fn: Callable[
|
|
53
|
+
[ChatRequest], Awaitable[Any]], # Inner agent as a Function (receives ChatRequest with multiple messages)
|
|
54
|
+
memory_editor: MemoryEditor, # Zep/Mem0/Redis memory client
|
|
55
|
+
save_user_messages: bool = True, # Auto-save user messages
|
|
56
|
+
retrieve_memory: bool = True, # Auto-retrieve before agent
|
|
57
|
+
save_ai_responses: bool = True, # Auto-save agent responses
|
|
58
|
+
search_params: dict[str, Any] | None = None, # Backend-specific search parameters
|
|
59
|
+
add_params: dict[str, Any] | None = None # Backend-specific add parameters
|
|
60
|
+
):
|
|
61
|
+
self.inner_agent_fn = inner_agent_fn
|
|
62
|
+
self.memory_editor = memory_editor
|
|
63
|
+
self.save_user_messages = save_user_messages
|
|
64
|
+
self.retrieve_memory = retrieve_memory
|
|
65
|
+
self.save_ai_responses = save_ai_responses
|
|
66
|
+
self.search_params = search_params or {}
|
|
67
|
+
self.add_params = add_params or {}
|
|
68
|
+
self._context = Context.get()
|
|
69
|
+
|
|
70
|
+
def _get_user_id_from_context(self) -> str:
|
|
71
|
+
"""
|
|
72
|
+
Extract user_id from runtime context.
|
|
73
|
+
|
|
74
|
+
Priority order:
|
|
75
|
+
1. user_manager.get_id() - For authenticated sessions (set via SessionManager.session())
|
|
76
|
+
2. X-User-ID HTTP header - For testing/simple auth without middleware
|
|
77
|
+
3. "default_user" - Fallback for development/testing without authentication
|
|
78
|
+
|
|
79
|
+
Returns:
|
|
80
|
+
str: The user ID for memory operations
|
|
81
|
+
"""
|
|
82
|
+
# Priority 1: Get user_id from user_manager (for authenticated sessions)
|
|
83
|
+
user_manager = self._context.user_manager
|
|
84
|
+
if user_manager and hasattr(user_manager, 'get_id'):
|
|
85
|
+
try:
|
|
86
|
+
user_id = user_manager.get_id()
|
|
87
|
+
if user_id:
|
|
88
|
+
logger.debug(f"Using user_id from user_manager: {user_id}")
|
|
89
|
+
return user_id
|
|
90
|
+
except Exception as e:
|
|
91
|
+
logger.debug(f"Failed to get user_id from user_manager: {e}")
|
|
92
|
+
|
|
93
|
+
# Priority 2: Extract from X-User-ID HTTP header (temporary workaround for testing)
|
|
94
|
+
if self._context.metadata and self._context.metadata.headers:
|
|
95
|
+
user_id = self._context.metadata.headers.get("x-user-id")
|
|
96
|
+
if user_id:
|
|
97
|
+
logger.debug(f"Using user_id from X-User-ID header: {user_id}")
|
|
98
|
+
return user_id
|
|
99
|
+
|
|
100
|
+
# Fallback: default for development/testing
|
|
101
|
+
logger.debug("Using default user_id: default_user")
|
|
102
|
+
return "default_user"
|
|
103
|
+
|
|
104
|
+
def get_wrapper_node_count(self) -> int:
|
|
105
|
+
"""
|
|
106
|
+
Calculate the number of wrapper nodes that will be added to the graph.
|
|
107
|
+
|
|
108
|
+
This is used to determine the recursion_limit overhead that the wrapper
|
|
109
|
+
adds on top of the inner agent's recursion needs.
|
|
110
|
+
|
|
111
|
+
Returns:
|
|
112
|
+
int: Number of nodes in the wrapper graph (1-4 depending on configuration)
|
|
113
|
+
"""
|
|
114
|
+
count = 1 # inner_agent node is always present
|
|
115
|
+
if self.save_user_messages:
|
|
116
|
+
count += 1 # capture_user_message node
|
|
117
|
+
if self.retrieve_memory:
|
|
118
|
+
count += 1 # memory_retrieve node
|
|
119
|
+
if self.save_ai_responses:
|
|
120
|
+
count += 1 # capture_ai_response node
|
|
121
|
+
return count
|
|
122
|
+
|
|
123
|
+
@staticmethod
|
|
124
|
+
def _langchain_message_to_nat_message(lc_message: BaseMessage) -> Message:
|
|
125
|
+
"""
|
|
126
|
+
Convert LangChain message to NAT Message format.
|
|
127
|
+
|
|
128
|
+
This is necessary to construct a proper ChatRequest with all messages
|
|
129
|
+
(including system messages with memory context) to pass to the inner agent.
|
|
130
|
+
"""
|
|
131
|
+
if isinstance(lc_message, HumanMessage):
|
|
132
|
+
role = UserMessageContentRoleType.USER
|
|
133
|
+
elif isinstance(lc_message, AIMessage):
|
|
134
|
+
role = UserMessageContentRoleType.ASSISTANT
|
|
135
|
+
elif isinstance(lc_message, SystemMessage):
|
|
136
|
+
role = UserMessageContentRoleType.SYSTEM
|
|
137
|
+
else:
|
|
138
|
+
# Default to user for unknown message types
|
|
139
|
+
role = UserMessageContentRoleType.USER
|
|
140
|
+
|
|
141
|
+
return Message(role=role, content=str(lc_message.content))
|
|
142
|
+
|
|
143
|
+
async def capture_user_message_node(self, state: AutoMemoryWrapperState) -> AutoMemoryWrapperState:
|
|
144
|
+
"""Captures user message to memory thread"""
|
|
145
|
+
if not self.save_user_messages or not state.messages:
|
|
146
|
+
return state
|
|
147
|
+
|
|
148
|
+
# Get the latest user message
|
|
149
|
+
user_message = state.messages[-1]
|
|
150
|
+
if isinstance(user_message, HumanMessage):
|
|
151
|
+
# Get user_id from runtime context
|
|
152
|
+
user_id = self._get_user_id_from_context()
|
|
153
|
+
|
|
154
|
+
# Add to memory
|
|
155
|
+
await self.memory_editor.add_items(
|
|
156
|
+
[MemoryItem(conversation=[{
|
|
157
|
+
"role": "user", "content": str(user_message.content)
|
|
158
|
+
}], user_id=user_id)],
|
|
159
|
+
**self.add_params)
|
|
160
|
+
return state
|
|
161
|
+
|
|
162
|
+
async def memory_retrieve_node(self, state: AutoMemoryWrapperState) -> AutoMemoryWrapperState:
|
|
163
|
+
"""Retrieves relevant memory from memory store"""
|
|
164
|
+
if not self.retrieve_memory or not state.messages:
|
|
165
|
+
return state
|
|
166
|
+
|
|
167
|
+
# Get the latest user message
|
|
168
|
+
user_message = state.messages[-1]
|
|
169
|
+
|
|
170
|
+
# Get user_id from runtime context
|
|
171
|
+
user_id = self._get_user_id_from_context()
|
|
172
|
+
|
|
173
|
+
# Retrieve memory from memory provider
|
|
174
|
+
memory_items = await self.memory_editor.search(
|
|
175
|
+
query=user_message.content, # Reasonable default for memory retrieval
|
|
176
|
+
user_id=user_id,
|
|
177
|
+
**self.search_params # User-configured params (e.g., top_k, mode)
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
# Extract memory strings and inject as system message if available
|
|
181
|
+
if memory_items:
|
|
182
|
+
# Extract memory field from each MemoryItem
|
|
183
|
+
memory_strings = [item.memory for item in memory_items if item.memory]
|
|
184
|
+
if memory_strings:
|
|
185
|
+
memory_text = "\n".join(memory_strings)
|
|
186
|
+
memory_message = SystemMessage(content=f"Relevant context from memory:\n{memory_text}")
|
|
187
|
+
# Insert before the last user message
|
|
188
|
+
state.messages.insert(-1, memory_message)
|
|
189
|
+
|
|
190
|
+
return state
|
|
191
|
+
|
|
192
|
+
async def inner_agent_node(self, state: AutoMemoryWrapperState) -> AutoMemoryWrapperState:
|
|
193
|
+
"""
|
|
194
|
+
Calls the inner agent with a ChatRequest containing all messages.
|
|
195
|
+
|
|
196
|
+
The inner agent receives a ChatRequest with multiple messages (including
|
|
197
|
+
system messages with memory context), processes them using its own internal
|
|
198
|
+
state (ReActGraphState, ReWOOGraphState, etc.), and returns a ChatResponse.
|
|
199
|
+
"""
|
|
200
|
+
# Convert all LangChain messages to NAT Message format
|
|
201
|
+
nat_messages = [self._langchain_message_to_nat_message(msg) for msg in state.messages]
|
|
202
|
+
chat_request = ChatRequest(messages=nat_messages)
|
|
203
|
+
|
|
204
|
+
# Call inner agent with ChatRequest - it manages its own state internally
|
|
205
|
+
response = await self.inner_agent_fn.ainvoke(chat_request)
|
|
206
|
+
|
|
207
|
+
# Extract content from response based on type
|
|
208
|
+
if hasattr(response, 'choices') and response.choices:
|
|
209
|
+
# ChatResponse object - extract from choices[0].message.content
|
|
210
|
+
response_text = response.choices[0].message.content or ""
|
|
211
|
+
elif hasattr(response, 'output'):
|
|
212
|
+
# GenerateResponse object - use output field
|
|
213
|
+
response_text = response.output
|
|
214
|
+
elif hasattr(response, 'value'):
|
|
215
|
+
# Some other response type with value field
|
|
216
|
+
response_text = str(response.value)
|
|
217
|
+
elif isinstance(response, str):
|
|
218
|
+
# Already a string
|
|
219
|
+
response_text = response
|
|
220
|
+
else:
|
|
221
|
+
# Last resort: convert to string
|
|
222
|
+
response_text = str(response)
|
|
223
|
+
|
|
224
|
+
# Add response to wrapper state
|
|
225
|
+
state.messages.append(AIMessage(content=response_text))
|
|
226
|
+
return state
|
|
227
|
+
|
|
228
|
+
async def capture_ai_response_node(self, state: AutoMemoryWrapperState) -> AutoMemoryWrapperState:
|
|
229
|
+
"""Captures agent response to memory"""
|
|
230
|
+
if not self.save_ai_responses or not state.messages:
|
|
231
|
+
return state
|
|
232
|
+
|
|
233
|
+
# Get the latest AI message
|
|
234
|
+
ai_message = state.messages[-1]
|
|
235
|
+
if isinstance(ai_message, AIMessage):
|
|
236
|
+
# Get user_id from runtime context
|
|
237
|
+
user_id = self._get_user_id_from_context()
|
|
238
|
+
|
|
239
|
+
# Add to memory
|
|
240
|
+
await self.memory_editor.add_items(
|
|
241
|
+
[MemoryItem(conversation=[{
|
|
242
|
+
"role": "assistant", "content": str(ai_message.content)
|
|
243
|
+
}], user_id=user_id)],
|
|
244
|
+
**self.add_params)
|
|
245
|
+
return state
|
|
246
|
+
|
|
247
|
+
def build_graph(self) -> CompiledStateGraph:
|
|
248
|
+
"""Wraps inner agent with memory nodes"""
|
|
249
|
+
workflow = StateGraph(AutoMemoryWrapperState)
|
|
250
|
+
|
|
251
|
+
# Add nodes
|
|
252
|
+
if self.save_user_messages:
|
|
253
|
+
workflow.add_node("capture_user_message", self.capture_user_message_node)
|
|
254
|
+
if self.retrieve_memory:
|
|
255
|
+
workflow.add_node("memory_retrieve", self.memory_retrieve_node)
|
|
256
|
+
workflow.add_node("inner_agent", self.inner_agent_node)
|
|
257
|
+
if self.save_ai_responses:
|
|
258
|
+
workflow.add_node("capture_ai_response", self.capture_ai_response_node)
|
|
259
|
+
|
|
260
|
+
# Connect nodes based on enabled features
|
|
261
|
+
workflow.set_entry_point("capture_user_message" if self.save_user_messages else "memory_retrieve" if self.
|
|
262
|
+
retrieve_memory else "inner_agent")
|
|
263
|
+
|
|
264
|
+
if self.save_user_messages and self.retrieve_memory:
|
|
265
|
+
workflow.add_edge("capture_user_message", "memory_retrieve")
|
|
266
|
+
workflow.add_edge("memory_retrieve", "inner_agent")
|
|
267
|
+
elif self.save_user_messages:
|
|
268
|
+
workflow.add_edge("capture_user_message", "inner_agent")
|
|
269
|
+
elif self.retrieve_memory:
|
|
270
|
+
workflow.add_edge("memory_retrieve", "inner_agent")
|
|
271
|
+
|
|
272
|
+
if self.save_ai_responses:
|
|
273
|
+
workflow.add_edge("inner_agent", "capture_ai_response")
|
|
274
|
+
workflow.set_finish_point("capture_ai_response")
|
|
275
|
+
else:
|
|
276
|
+
workflow.set_finish_point("inner_agent")
|
|
277
|
+
|
|
278
|
+
return workflow.compile()
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: Copyright (c) 2024-2026, 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
|
+
from collections.abc import AsyncGenerator
|
|
18
|
+
from typing import Any
|
|
19
|
+
|
|
20
|
+
from pydantic import Field
|
|
21
|
+
|
|
22
|
+
from nat.builder.builder import Builder
|
|
23
|
+
from nat.builder.framework_enum import LLMFrameworkEnum
|
|
24
|
+
from nat.builder.function_info import FunctionInfo
|
|
25
|
+
from nat.cli.register_workflow import register_function
|
|
26
|
+
from nat.data_models.agent import AgentBaseConfig
|
|
27
|
+
from nat.data_models.component_ref import FunctionRef
|
|
28
|
+
from nat.data_models.component_ref import MemoryRef
|
|
29
|
+
|
|
30
|
+
logger = logging.getLogger(__name__)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class AutoMemoryAgentConfig(AgentBaseConfig, name="auto_memory_agent"):
|
|
34
|
+
"""
|
|
35
|
+
Wraps any NAT agent to provide automatic memory capture and retrieval.
|
|
36
|
+
|
|
37
|
+
This agent automatically captures user messages, retrieves relevant context,
|
|
38
|
+
and stores agent responses without requiring the LLM to invoke memory tools.
|
|
39
|
+
|
|
40
|
+
**Use this when:**
|
|
41
|
+
- You want guaranteed memory capture (not dependent on LLM tool calling)
|
|
42
|
+
- You need consistent memory operations across all interactions
|
|
43
|
+
- Your memory backend (Zep, Mem0) is designed for automatic memory management
|
|
44
|
+
|
|
45
|
+
**Use tool-based memory when:**
|
|
46
|
+
- You want the LLM to decide when to access memory
|
|
47
|
+
- Memory operations should be selective based on context
|
|
48
|
+
|
|
49
|
+
**Example:**
|
|
50
|
+
|
|
51
|
+
.. code-block:: yaml
|
|
52
|
+
|
|
53
|
+
functions:
|
|
54
|
+
my_react_agent:
|
|
55
|
+
_type: react_agent
|
|
56
|
+
llm_name: nim_llm
|
|
57
|
+
tool_names: [calculator, web_search]
|
|
58
|
+
|
|
59
|
+
memory:
|
|
60
|
+
zep_memory:
|
|
61
|
+
_type: nat.plugins.zep_cloud/zep_memory
|
|
62
|
+
|
|
63
|
+
workflow:
|
|
64
|
+
_type: auto_memory_agent
|
|
65
|
+
inner_agent_name: my_react_agent
|
|
66
|
+
memory_name: zep_memory
|
|
67
|
+
llm_name: nim_llm
|
|
68
|
+
verbose: true
|
|
69
|
+
|
|
70
|
+
**Multi-tenant User Isolation:**
|
|
71
|
+
|
|
72
|
+
User ID is automatically extracted from runtime context (user_manager.get_id()) for proper
|
|
73
|
+
multi-tenant memory isolation. Set user_manager via SessionManager.session() in production.
|
|
74
|
+
Defaults to "default_user" for testing/development. See README.md for deployment examples.
|
|
75
|
+
"""
|
|
76
|
+
|
|
77
|
+
# Memory configuration
|
|
78
|
+
memory_name: MemoryRef = Field(..., description="Name of the memory backend (from memory section of config)")
|
|
79
|
+
|
|
80
|
+
# Reference to inner agent by NAME (not inline config)
|
|
81
|
+
inner_agent_name: FunctionRef = Field(..., description="Name of the agent workflow to wrap with automatic memory")
|
|
82
|
+
|
|
83
|
+
# Feature flags
|
|
84
|
+
save_user_messages_to_memory: bool = Field(
|
|
85
|
+
default=True, description="Automatically save user messages to memory before agent processing")
|
|
86
|
+
retrieve_memory_for_every_response: bool = Field(
|
|
87
|
+
default=True,
|
|
88
|
+
description=("Automatically retrieve memory context before agent processing. "
|
|
89
|
+
"Set to false for save-only mode or when using tool-based retrieval."))
|
|
90
|
+
save_ai_messages_to_memory: bool = Field(
|
|
91
|
+
default=True, description="Automatically save AI agent responses to memory after generation")
|
|
92
|
+
|
|
93
|
+
# Memory retrieval configuration
|
|
94
|
+
search_params: dict[str, Any] = Field(
|
|
95
|
+
default_factory=dict,
|
|
96
|
+
description=(
|
|
97
|
+
"Backend-specific search parameters passed to memory_editor.search().\n"
|
|
98
|
+
"Common parameters:\n"
|
|
99
|
+
" - top_k (int): Maximum results to return (default: 5)\n"
|
|
100
|
+
" - mode (str): For Zep, 'basic' (fast) or 'summary' (comprehensive)\n\n"
|
|
101
|
+
"Additional parameters:\n"
|
|
102
|
+
" - Any additional parameters that the chosen memory backend supports in its search function\n\n"))
|
|
103
|
+
|
|
104
|
+
# Memory addition configuration
|
|
105
|
+
add_params: dict[str, Any] = Field(
|
|
106
|
+
default_factory=dict,
|
|
107
|
+
description=(
|
|
108
|
+
"Backend-specific parameters passed to memory_editor.add_items().\n"
|
|
109
|
+
"For Zep:\n"
|
|
110
|
+
" - ignore_roles (list[str]): Role types to exclude from graph memory (e.g., ['assistant'])\n"
|
|
111
|
+
" Available roles: norole, system, assistant, user, function, tool\n\n"
|
|
112
|
+
"Additional parameters:\n"
|
|
113
|
+
" - Any additional parameters that the chosen memory backend supports in its add_items function\n\n"))
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
@register_function(config_type=AutoMemoryAgentConfig, framework_wrappers=[LLMFrameworkEnum.LANGCHAIN])
|
|
117
|
+
async def auto_memory_agent(config: AutoMemoryAgentConfig, builder: Builder) -> AsyncGenerator[FunctionInfo, None]:
|
|
118
|
+
"""
|
|
119
|
+
Build the auto-memory agent that wraps another agent.
|
|
120
|
+
|
|
121
|
+
The inner agent is retrieved as a Function that receives a ChatRequest with
|
|
122
|
+
multiple messages (including system messages with memory context). It manages
|
|
123
|
+
its own internal state (ReActGraphState, etc.) and the wrapper never manipulates
|
|
124
|
+
that state.
|
|
125
|
+
"""
|
|
126
|
+
from langchain_core.messages.human import HumanMessage
|
|
127
|
+
from langgraph.graph.state import CompiledStateGraph
|
|
128
|
+
|
|
129
|
+
from nat.agent.auto_memory_wrapper.agent import AutoMemoryWrapperGraph
|
|
130
|
+
from nat.agent.auto_memory_wrapper.state import AutoMemoryWrapperState
|
|
131
|
+
from nat.agent.base import AGENT_LOG_PREFIX
|
|
132
|
+
|
|
133
|
+
# Get memory editor from builder
|
|
134
|
+
memory_editor = await builder.get_memory_client(config.memory_name)
|
|
135
|
+
|
|
136
|
+
# Get inner agent as a Function (not a dict config)
|
|
137
|
+
# This gives us a function that accepts ChatRequest with multiple messages
|
|
138
|
+
inner_agent_fn = await builder.get_function(config.inner_agent_name)
|
|
139
|
+
|
|
140
|
+
# Get inner agent config to calculate recursion limits
|
|
141
|
+
inner_agent_config = builder.get_function_config(config.inner_agent_name)
|
|
142
|
+
|
|
143
|
+
# Calculate recursion_limit based on inner agent's configuration
|
|
144
|
+
# This ensures the wrapper is transparent - users only configure the inner agent's limits
|
|
145
|
+
# and the wrapper automatically accounts for its own overhead
|
|
146
|
+
inner_max_calls = None
|
|
147
|
+
|
|
148
|
+
if hasattr(inner_agent_config, 'max_tool_calls'):
|
|
149
|
+
# ReAct agent and similar agents use max_tool_calls
|
|
150
|
+
value = inner_agent_config.max_tool_calls
|
|
151
|
+
if value is not None and isinstance(value, int | float):
|
|
152
|
+
inner_max_calls = value
|
|
153
|
+
|
|
154
|
+
if inner_max_calls is None and hasattr(inner_agent_config, 'max_iterations'):
|
|
155
|
+
# Some agents use max_iterations as an alias
|
|
156
|
+
value = inner_agent_config.max_iterations
|
|
157
|
+
if value is not None and isinstance(value, int | float):
|
|
158
|
+
inner_max_calls = value
|
|
159
|
+
|
|
160
|
+
if inner_max_calls is None and hasattr(inner_agent_config, 'tool_call_max_retries'):
|
|
161
|
+
# ReWOO agent uses tool_call_max_retries - needs more steps per retry
|
|
162
|
+
value = inner_agent_config.tool_call_max_retries
|
|
163
|
+
if value is not None and isinstance(value, int | float):
|
|
164
|
+
inner_max_calls = value * 3
|
|
165
|
+
|
|
166
|
+
if inner_max_calls is None:
|
|
167
|
+
# Safe default for agents without explicit limits
|
|
168
|
+
inner_max_calls = 15
|
|
169
|
+
|
|
170
|
+
# Use same calculation formula as react_agent for consistency
|
|
171
|
+
# Formula: (max_tool_calls + 1) * 2 allows proper tool calling cycles with retries
|
|
172
|
+
# See src/nat/agent/react_agent/register.py:145 for reference
|
|
173
|
+
inner_agent_recursion = (int(inner_max_calls) + 1) * 2
|
|
174
|
+
|
|
175
|
+
# Create wrapper
|
|
176
|
+
wrapper_graph = AutoMemoryWrapperGraph(inner_agent_fn=inner_agent_fn,
|
|
177
|
+
memory_editor=memory_editor,
|
|
178
|
+
save_user_messages=config.save_user_messages_to_memory,
|
|
179
|
+
retrieve_memory=config.retrieve_memory_for_every_response,
|
|
180
|
+
save_ai_responses=config.save_ai_messages_to_memory,
|
|
181
|
+
search_params=config.search_params,
|
|
182
|
+
add_params=config.add_params)
|
|
183
|
+
|
|
184
|
+
# Calculate total recursion limit: wrapper overhead + inner agent needs
|
|
185
|
+
wrapper_node_count = wrapper_graph.get_wrapper_node_count()
|
|
186
|
+
total_recursion_limit = wrapper_node_count + inner_agent_recursion
|
|
187
|
+
|
|
188
|
+
logger.debug(f"{AGENT_LOG_PREFIX} Auto-memory wrapper calculated recursion_limit={total_recursion_limit} "
|
|
189
|
+
f"(wrapper_overhead={wrapper_node_count} + inner_agent={inner_agent_recursion})")
|
|
190
|
+
|
|
191
|
+
# Build the graph
|
|
192
|
+
graph: CompiledStateGraph = wrapper_graph.build_graph()
|
|
193
|
+
|
|
194
|
+
async def _response_fn(input_message: str) -> str:
|
|
195
|
+
"""
|
|
196
|
+
Main workflow entry function for the auto-memory agent.
|
|
197
|
+
|
|
198
|
+
Args:
|
|
199
|
+
input_message (str): The input message to process
|
|
200
|
+
|
|
201
|
+
Returns:
|
|
202
|
+
str: The response from the wrapped agent
|
|
203
|
+
"""
|
|
204
|
+
try:
|
|
205
|
+
message = HumanMessage(content=input_message)
|
|
206
|
+
state = AutoMemoryWrapperState(messages=[message])
|
|
207
|
+
|
|
208
|
+
# Pass calculated recursion_limit to ensure wrapper + inner agent have enough steps
|
|
209
|
+
result_dict = await graph.ainvoke(state, config={'recursion_limit': total_recursion_limit})
|
|
210
|
+
result_state = AutoMemoryWrapperState(**result_dict)
|
|
211
|
+
|
|
212
|
+
output_message = result_state.messages[-1]
|
|
213
|
+
return str(output_message.content)
|
|
214
|
+
|
|
215
|
+
except Exception as ex:
|
|
216
|
+
logger.exception(f"{AGENT_LOG_PREFIX} Auto-memory agent failed with exception")
|
|
217
|
+
if config.verbose:
|
|
218
|
+
return str(ex)
|
|
219
|
+
return "Auto-memory agent failed"
|
|
220
|
+
|
|
221
|
+
try:
|
|
222
|
+
yield FunctionInfo.from_fn(_response_fn, description=config.description)
|
|
223
|
+
except GeneratorExit:
|
|
224
|
+
logger.debug("%s Workflow exited early!", AGENT_LOG_PREFIX)
|
|
225
|
+
raise
|
|
226
|
+
finally:
|
|
227
|
+
logger.debug("%s Cleaning up auto_memory_agent workflow.", AGENT_LOG_PREFIX)
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: Copyright (c) 2024-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
|
2
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
#
|
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
# you may not use this file except in compliance with the License.
|
|
6
|
+
# You may obtain a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
# See the License for the specific language governing permissions and
|
|
14
|
+
# limitations under the License.
|
|
15
|
+
|
|
16
|
+
from langchain_core.messages import BaseMessage
|
|
17
|
+
from pydantic import BaseModel
|
|
18
|
+
from pydantic import Field
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class AutoMemoryWrapperState(BaseModel):
|
|
22
|
+
"""
|
|
23
|
+
Simple wrapper state - only needs to track messages.
|
|
24
|
+
|
|
25
|
+
The inner agent manages its own complex state internally
|
|
26
|
+
(ReActGraphState, ReWOOGraphState, etc.). The wrapper
|
|
27
|
+
never sees or manipulates the inner agent's state.
|
|
28
|
+
"""
|
|
29
|
+
messages: list[BaseMessage] = Field(default_factory=list,
|
|
30
|
+
description="Conversation messages with context injection")
|
nat/agent/base.py
CHANGED
|
@@ -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");
|
nat/agent/dual_node.py
CHANGED
|
@@ -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) 2024-
|
|
1
|
+
# SPDX-FileCopyrightText: Copyright (c) 2024-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) 2021-
|
|
1
|
+
# SPDX-FileCopyrightText: Copyright (c) 2021-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");
|
nat/agent/react_agent/agent.py
CHANGED
|
@@ -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");
|
|
@@ -33,6 +33,7 @@ from langchain_core.prompts import MessagesPlaceholder
|
|
|
33
33
|
from langchain_core.runnables import Runnable
|
|
34
34
|
from langchain_core.runnables.config import RunnableConfig
|
|
35
35
|
from langchain_core.tools import BaseTool
|
|
36
|
+
from langgraph.runtime import DEFAULT_RUNTIME
|
|
36
37
|
from pydantic import BaseModel
|
|
37
38
|
from pydantic import Field
|
|
38
39
|
|
|
@@ -122,7 +123,7 @@ class ReActAgentGraph(DualNodeAgent):
|
|
|
122
123
|
"""
|
|
123
124
|
# models that don't need (or don't support)a stop sequence
|
|
124
125
|
smart_models = re.compile(r"gpt-?5", re.IGNORECASE)
|
|
125
|
-
if
|
|
126
|
+
if smart_models.search(str(getattr(self.llm, "model", ""))):
|
|
126
127
|
# no need to bind any additional parameters to the LLM
|
|
127
128
|
return self.llm
|
|
128
129
|
# add a stop sequence to the LLM
|
|
@@ -162,7 +163,8 @@ class ReActAgentGraph(DualNodeAgent):
|
|
|
162
163
|
{
|
|
163
164
|
"question": question, "chat_history": chat_history
|
|
164
165
|
},
|
|
165
|
-
RunnableConfig(callbacks=self.callbacks
|
|
166
|
+
RunnableConfig(callbacks=self.callbacks,
|
|
167
|
+
configurable={"__pregel_runtime": DEFAULT_RUNTIME}) # type: ignore
|
|
166
168
|
)
|
|
167
169
|
|
|
168
170
|
if self.detailed_logs:
|
|
@@ -184,10 +186,13 @@ class ReActAgentGraph(DualNodeAgent):
|
|
|
184
186
|
logger.debug("%s Querying agent, attempt: %s", AGENT_LOG_PREFIX, attempt)
|
|
185
187
|
|
|
186
188
|
output_message = await self._stream_llm(
|
|
187
|
-
self.agent,
|
|
189
|
+
self.agent,
|
|
190
|
+
{
|
|
188
191
|
"question": question, "agent_scratchpad": agent_scratchpad, "chat_history": chat_history
|
|
189
192
|
},
|
|
190
|
-
RunnableConfig(callbacks=self.callbacks
|
|
193
|
+
RunnableConfig(callbacks=self.callbacks,
|
|
194
|
+
configurable={"__pregel_runtime": DEFAULT_RUNTIME}) # type: ignore
|
|
195
|
+
)
|
|
191
196
|
|
|
192
197
|
if self.detailed_logs:
|
|
193
198
|
logger.info(AGENT_CALL_LOG_MESSAGE, question, output_message.content)
|
|
@@ -321,10 +326,12 @@ class ReActAgentGraph(DualNodeAgent):
|
|
|
321
326
|
tool_input = tool_input_str
|
|
322
327
|
|
|
323
328
|
# Call tool once with the determined input (either parsed dict or raw string)
|
|
324
|
-
tool_response = await self._call_tool(
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
329
|
+
tool_response = await self._call_tool(
|
|
330
|
+
requested_tool,
|
|
331
|
+
tool_input,
|
|
332
|
+
RunnableConfig(callbacks=self.callbacks,
|
|
333
|
+
configurable={"__pregel_runtime": DEFAULT_RUNTIME}), # type: ignore
|
|
334
|
+
max_retries=self.tool_call_max_retries)
|
|
328
335
|
|
|
329
336
|
if self.detailed_logs:
|
|
330
337
|
self._log_tool_response(requested_tool.name, tool_input, str(tool_response.content))
|
|
@@ -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");
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
|
|
16
16
|
import re
|
|
17
17
|
|
|
18
|
-
from
|
|
18
|
+
from langchain_classic.agents.agent import AgentOutputParser
|
|
19
19
|
from langchain_core.agents import AgentAction
|
|
20
20
|
from langchain_core.agents import AgentFinish
|
|
21
21
|
from langchain_core.exceptions import LangChainException
|