nvidia-nat 1.1.0a20251020__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 +66 -0
- nat/agent/__init__.py +0 -0
- nat/agent/base.py +265 -0
- nat/agent/dual_node.py +72 -0
- nat/agent/prompt_optimizer/__init__.py +0 -0
- nat/agent/prompt_optimizer/prompt.py +68 -0
- nat/agent/prompt_optimizer/register.py +149 -0
- nat/agent/react_agent/__init__.py +0 -0
- nat/agent/react_agent/agent.py +394 -0
- nat/agent/react_agent/output_parser.py +104 -0
- nat/agent/react_agent/prompt.py +44 -0
- nat/agent/react_agent/register.py +168 -0
- nat/agent/reasoning_agent/__init__.py +0 -0
- nat/agent/reasoning_agent/reasoning_agent.py +227 -0
- nat/agent/register.py +23 -0
- nat/agent/rewoo_agent/__init__.py +0 -0
- nat/agent/rewoo_agent/agent.py +593 -0
- nat/agent/rewoo_agent/prompt.py +107 -0
- nat/agent/rewoo_agent/register.py +175 -0
- nat/agent/tool_calling_agent/__init__.py +0 -0
- nat/agent/tool_calling_agent/agent.py +246 -0
- nat/agent/tool_calling_agent/register.py +129 -0
- nat/authentication/__init__.py +14 -0
- nat/authentication/api_key/__init__.py +14 -0
- nat/authentication/api_key/api_key_auth_provider.py +96 -0
- nat/authentication/api_key/api_key_auth_provider_config.py +124 -0
- nat/authentication/api_key/register.py +26 -0
- nat/authentication/credential_validator/__init__.py +14 -0
- nat/authentication/credential_validator/bearer_token_validator.py +557 -0
- nat/authentication/exceptions/__init__.py +14 -0
- nat/authentication/exceptions/api_key_exceptions.py +38 -0
- nat/authentication/http_basic_auth/__init__.py +0 -0
- nat/authentication/http_basic_auth/http_basic_auth_provider.py +81 -0
- nat/authentication/http_basic_auth/register.py +30 -0
- nat/authentication/interfaces.py +96 -0
- nat/authentication/oauth2/__init__.py +14 -0
- nat/authentication/oauth2/oauth2_auth_code_flow_provider.py +140 -0
- nat/authentication/oauth2/oauth2_auth_code_flow_provider_config.py +39 -0
- nat/authentication/oauth2/oauth2_resource_server_config.py +124 -0
- nat/authentication/oauth2/register.py +25 -0
- nat/authentication/register.py +20 -0
- nat/builder/__init__.py +0 -0
- nat/builder/builder.py +317 -0
- nat/builder/component_utils.py +320 -0
- nat/builder/context.py +321 -0
- nat/builder/embedder.py +24 -0
- nat/builder/eval_builder.py +166 -0
- nat/builder/evaluator.py +29 -0
- nat/builder/framework_enum.py +25 -0
- nat/builder/front_end.py +73 -0
- nat/builder/function.py +714 -0
- nat/builder/function_base.py +380 -0
- nat/builder/function_info.py +625 -0
- nat/builder/intermediate_step_manager.py +206 -0
- nat/builder/llm.py +25 -0
- nat/builder/retriever.py +25 -0
- nat/builder/user_interaction_manager.py +78 -0
- nat/builder/workflow.py +160 -0
- nat/builder/workflow_builder.py +1365 -0
- nat/cli/__init__.py +14 -0
- nat/cli/cli_utils/__init__.py +0 -0
- nat/cli/cli_utils/config_override.py +231 -0
- nat/cli/cli_utils/validation.py +37 -0
- nat/cli/commands/__init__.py +0 -0
- nat/cli/commands/configure/__init__.py +0 -0
- nat/cli/commands/configure/channel/__init__.py +0 -0
- nat/cli/commands/configure/channel/add.py +28 -0
- nat/cli/commands/configure/channel/channel.py +34 -0
- nat/cli/commands/configure/channel/remove.py +30 -0
- nat/cli/commands/configure/channel/update.py +30 -0
- nat/cli/commands/configure/configure.py +33 -0
- nat/cli/commands/evaluate.py +139 -0
- nat/cli/commands/info/__init__.py +14 -0
- nat/cli/commands/info/info.py +47 -0
- nat/cli/commands/info/list_channels.py +32 -0
- nat/cli/commands/info/list_components.py +128 -0
- nat/cli/commands/mcp/__init__.py +14 -0
- nat/cli/commands/mcp/mcp.py +986 -0
- nat/cli/commands/object_store/__init__.py +14 -0
- nat/cli/commands/object_store/object_store.py +227 -0
- nat/cli/commands/optimize.py +90 -0
- nat/cli/commands/registry/__init__.py +14 -0
- nat/cli/commands/registry/publish.py +88 -0
- nat/cli/commands/registry/pull.py +118 -0
- nat/cli/commands/registry/registry.py +36 -0
- nat/cli/commands/registry/remove.py +108 -0
- nat/cli/commands/registry/search.py +153 -0
- nat/cli/commands/sizing/__init__.py +14 -0
- nat/cli/commands/sizing/calc.py +297 -0
- nat/cli/commands/sizing/sizing.py +27 -0
- nat/cli/commands/start.py +257 -0
- nat/cli/commands/uninstall.py +81 -0
- nat/cli/commands/validate.py +47 -0
- nat/cli/commands/workflow/__init__.py +14 -0
- nat/cli/commands/workflow/templates/__init__.py.j2 +0 -0
- nat/cli/commands/workflow/templates/config.yml.j2 +17 -0
- nat/cli/commands/workflow/templates/pyproject.toml.j2 +25 -0
- nat/cli/commands/workflow/templates/register.py.j2 +4 -0
- nat/cli/commands/workflow/templates/workflow.py.j2 +50 -0
- nat/cli/commands/workflow/workflow.py +37 -0
- nat/cli/commands/workflow/workflow_commands.py +403 -0
- nat/cli/entrypoint.py +141 -0
- nat/cli/main.py +60 -0
- nat/cli/register_workflow.py +522 -0
- nat/cli/type_registry.py +1069 -0
- nat/control_flow/__init__.py +0 -0
- nat/control_flow/register.py +20 -0
- nat/control_flow/router_agent/__init__.py +0 -0
- nat/control_flow/router_agent/agent.py +329 -0
- nat/control_flow/router_agent/prompt.py +48 -0
- nat/control_flow/router_agent/register.py +91 -0
- nat/control_flow/sequential_executor.py +166 -0
- nat/data_models/__init__.py +14 -0
- nat/data_models/agent.py +34 -0
- nat/data_models/api_server.py +843 -0
- nat/data_models/authentication.py +245 -0
- nat/data_models/common.py +171 -0
- nat/data_models/component.py +60 -0
- nat/data_models/component_ref.py +179 -0
- nat/data_models/config.py +434 -0
- nat/data_models/dataset_handler.py +169 -0
- nat/data_models/discovery_metadata.py +305 -0
- nat/data_models/embedder.py +27 -0
- nat/data_models/evaluate.py +130 -0
- nat/data_models/evaluator.py +26 -0
- nat/data_models/front_end.py +26 -0
- nat/data_models/function.py +64 -0
- nat/data_models/function_dependencies.py +80 -0
- nat/data_models/gated_field_mixin.py +242 -0
- nat/data_models/interactive.py +246 -0
- nat/data_models/intermediate_step.py +302 -0
- nat/data_models/invocation_node.py +38 -0
- nat/data_models/llm.py +27 -0
- nat/data_models/logging.py +26 -0
- nat/data_models/memory.py +27 -0
- nat/data_models/object_store.py +44 -0
- nat/data_models/optimizable.py +119 -0
- nat/data_models/optimizer.py +149 -0
- nat/data_models/profiler.py +54 -0
- nat/data_models/registry_handler.py +26 -0
- nat/data_models/retriever.py +30 -0
- nat/data_models/retry_mixin.py +35 -0
- nat/data_models/span.py +228 -0
- nat/data_models/step_adaptor.py +64 -0
- nat/data_models/streaming.py +33 -0
- nat/data_models/swe_bench_model.py +54 -0
- nat/data_models/telemetry_exporter.py +26 -0
- nat/data_models/temperature_mixin.py +44 -0
- nat/data_models/thinking_mixin.py +86 -0
- nat/data_models/top_p_mixin.py +44 -0
- nat/data_models/ttc_strategy.py +30 -0
- nat/embedder/__init__.py +0 -0
- nat/embedder/azure_openai_embedder.py +46 -0
- nat/embedder/nim_embedder.py +59 -0
- nat/embedder/openai_embedder.py +42 -0
- nat/embedder/register.py +22 -0
- nat/eval/__init__.py +14 -0
- nat/eval/config.py +62 -0
- nat/eval/dataset_handler/__init__.py +0 -0
- nat/eval/dataset_handler/dataset_downloader.py +106 -0
- nat/eval/dataset_handler/dataset_filter.py +52 -0
- nat/eval/dataset_handler/dataset_handler.py +431 -0
- nat/eval/evaluate.py +565 -0
- nat/eval/evaluator/__init__.py +14 -0
- nat/eval/evaluator/base_evaluator.py +77 -0
- nat/eval/evaluator/evaluator_model.py +58 -0
- nat/eval/intermediate_step_adapter.py +99 -0
- nat/eval/rag_evaluator/__init__.py +0 -0
- nat/eval/rag_evaluator/evaluate.py +178 -0
- nat/eval/rag_evaluator/register.py +143 -0
- nat/eval/register.py +26 -0
- nat/eval/remote_workflow.py +133 -0
- nat/eval/runners/__init__.py +14 -0
- nat/eval/runners/config.py +39 -0
- nat/eval/runners/multi_eval_runner.py +54 -0
- nat/eval/runtime_evaluator/__init__.py +14 -0
- nat/eval/runtime_evaluator/evaluate.py +123 -0
- nat/eval/runtime_evaluator/register.py +100 -0
- nat/eval/runtime_event_subscriber.py +52 -0
- nat/eval/swe_bench_evaluator/__init__.py +0 -0
- nat/eval/swe_bench_evaluator/evaluate.py +215 -0
- nat/eval/swe_bench_evaluator/register.py +36 -0
- nat/eval/trajectory_evaluator/__init__.py +0 -0
- nat/eval/trajectory_evaluator/evaluate.py +75 -0
- nat/eval/trajectory_evaluator/register.py +40 -0
- nat/eval/tunable_rag_evaluator/__init__.py +0 -0
- nat/eval/tunable_rag_evaluator/evaluate.py +242 -0
- nat/eval/tunable_rag_evaluator/register.py +52 -0
- nat/eval/usage_stats.py +41 -0
- nat/eval/utils/__init__.py +0 -0
- nat/eval/utils/eval_trace_ctx.py +89 -0
- nat/eval/utils/output_uploader.py +140 -0
- nat/eval/utils/tqdm_position_registry.py +40 -0
- nat/eval/utils/weave_eval.py +193 -0
- nat/experimental/__init__.py +0 -0
- nat/experimental/decorators/__init__.py +0 -0
- nat/experimental/decorators/experimental_warning_decorator.py +154 -0
- nat/experimental/test_time_compute/__init__.py +0 -0
- nat/experimental/test_time_compute/editing/__init__.py +0 -0
- nat/experimental/test_time_compute/editing/iterative_plan_refinement_editor.py +147 -0
- nat/experimental/test_time_compute/editing/llm_as_a_judge_editor.py +204 -0
- nat/experimental/test_time_compute/editing/motivation_aware_summarization.py +107 -0
- nat/experimental/test_time_compute/functions/__init__.py +0 -0
- nat/experimental/test_time_compute/functions/execute_score_select_function.py +105 -0
- nat/experimental/test_time_compute/functions/plan_select_execute_function.py +228 -0
- nat/experimental/test_time_compute/functions/ttc_tool_orchestration_function.py +205 -0
- nat/experimental/test_time_compute/functions/ttc_tool_wrapper_function.py +146 -0
- nat/experimental/test_time_compute/models/__init__.py +0 -0
- nat/experimental/test_time_compute/models/editor_config.py +132 -0
- nat/experimental/test_time_compute/models/scoring_config.py +112 -0
- nat/experimental/test_time_compute/models/search_config.py +120 -0
- nat/experimental/test_time_compute/models/selection_config.py +154 -0
- nat/experimental/test_time_compute/models/stage_enums.py +43 -0
- nat/experimental/test_time_compute/models/strategy_base.py +67 -0
- nat/experimental/test_time_compute/models/tool_use_config.py +41 -0
- nat/experimental/test_time_compute/models/ttc_item.py +48 -0
- nat/experimental/test_time_compute/register.py +35 -0
- nat/experimental/test_time_compute/scoring/__init__.py +0 -0
- nat/experimental/test_time_compute/scoring/llm_based_agent_scorer.py +168 -0
- nat/experimental/test_time_compute/scoring/llm_based_plan_scorer.py +168 -0
- nat/experimental/test_time_compute/scoring/motivation_aware_scorer.py +111 -0
- nat/experimental/test_time_compute/search/__init__.py +0 -0
- nat/experimental/test_time_compute/search/multi_llm_planner.py +128 -0
- nat/experimental/test_time_compute/search/multi_query_retrieval_search.py +122 -0
- nat/experimental/test_time_compute/search/single_shot_multi_plan_planner.py +128 -0
- nat/experimental/test_time_compute/selection/__init__.py +0 -0
- nat/experimental/test_time_compute/selection/best_of_n_selector.py +63 -0
- nat/experimental/test_time_compute/selection/llm_based_agent_output_selector.py +131 -0
- nat/experimental/test_time_compute/selection/llm_based_output_merging_selector.py +157 -0
- nat/experimental/test_time_compute/selection/llm_based_plan_selector.py +128 -0
- nat/experimental/test_time_compute/selection/threshold_selector.py +58 -0
- nat/front_ends/__init__.py +14 -0
- nat/front_ends/console/__init__.py +14 -0
- nat/front_ends/console/authentication_flow_handler.py +285 -0
- nat/front_ends/console/console_front_end_config.py +32 -0
- nat/front_ends/console/console_front_end_plugin.py +108 -0
- nat/front_ends/console/register.py +25 -0
- nat/front_ends/cron/__init__.py +14 -0
- nat/front_ends/fastapi/__init__.py +14 -0
- nat/front_ends/fastapi/auth_flow_handlers/__init__.py +0 -0
- nat/front_ends/fastapi/auth_flow_handlers/http_flow_handler.py +27 -0
- nat/front_ends/fastapi/auth_flow_handlers/websocket_flow_handler.py +142 -0
- nat/front_ends/fastapi/dask_client_mixin.py +65 -0
- nat/front_ends/fastapi/fastapi_front_end_config.py +272 -0
- nat/front_ends/fastapi/fastapi_front_end_controller.py +68 -0
- nat/front_ends/fastapi/fastapi_front_end_plugin.py +247 -0
- nat/front_ends/fastapi/fastapi_front_end_plugin_worker.py +1257 -0
- nat/front_ends/fastapi/html_snippets/__init__.py +14 -0
- nat/front_ends/fastapi/html_snippets/auth_code_grant_success.py +35 -0
- nat/front_ends/fastapi/intermediate_steps_subscriber.py +80 -0
- nat/front_ends/fastapi/job_store.py +602 -0
- nat/front_ends/fastapi/main.py +64 -0
- nat/front_ends/fastapi/message_handler.py +344 -0
- nat/front_ends/fastapi/message_validator.py +351 -0
- nat/front_ends/fastapi/register.py +25 -0
- nat/front_ends/fastapi/response_helpers.py +195 -0
- nat/front_ends/fastapi/step_adaptor.py +319 -0
- nat/front_ends/fastapi/utils.py +57 -0
- nat/front_ends/mcp/__init__.py +14 -0
- nat/front_ends/mcp/introspection_token_verifier.py +73 -0
- nat/front_ends/mcp/mcp_front_end_config.py +90 -0
- nat/front_ends/mcp/mcp_front_end_plugin.py +113 -0
- nat/front_ends/mcp/mcp_front_end_plugin_worker.py +268 -0
- nat/front_ends/mcp/memory_profiler.py +320 -0
- nat/front_ends/mcp/register.py +27 -0
- nat/front_ends/mcp/tool_converter.py +290 -0
- nat/front_ends/register.py +21 -0
- nat/front_ends/simple_base/__init__.py +14 -0
- nat/front_ends/simple_base/simple_front_end_plugin_base.py +56 -0
- nat/llm/__init__.py +0 -0
- nat/llm/aws_bedrock_llm.py +69 -0
- nat/llm/azure_openai_llm.py +57 -0
- nat/llm/litellm_llm.py +69 -0
- nat/llm/nim_llm.py +58 -0
- nat/llm/openai_llm.py +54 -0
- nat/llm/register.py +27 -0
- nat/llm/utils/__init__.py +14 -0
- nat/llm/utils/env_config_value.py +93 -0
- nat/llm/utils/error.py +17 -0
- nat/llm/utils/thinking.py +215 -0
- nat/memory/__init__.py +20 -0
- nat/memory/interfaces.py +183 -0
- nat/memory/models.py +112 -0
- nat/meta/pypi.md +58 -0
- nat/object_store/__init__.py +20 -0
- nat/object_store/in_memory_object_store.py +76 -0
- nat/object_store/interfaces.py +84 -0
- nat/object_store/models.py +38 -0
- nat/object_store/register.py +19 -0
- nat/observability/__init__.py +14 -0
- nat/observability/exporter/__init__.py +14 -0
- nat/observability/exporter/base_exporter.py +449 -0
- nat/observability/exporter/exporter.py +78 -0
- nat/observability/exporter/file_exporter.py +33 -0
- nat/observability/exporter/processing_exporter.py +550 -0
- nat/observability/exporter/raw_exporter.py +52 -0
- nat/observability/exporter/span_exporter.py +308 -0
- nat/observability/exporter_manager.py +335 -0
- nat/observability/mixin/__init__.py +14 -0
- nat/observability/mixin/batch_config_mixin.py +26 -0
- nat/observability/mixin/collector_config_mixin.py +23 -0
- nat/observability/mixin/file_mixin.py +288 -0
- nat/observability/mixin/file_mode.py +23 -0
- nat/observability/mixin/redaction_config_mixin.py +42 -0
- nat/observability/mixin/resource_conflict_mixin.py +134 -0
- nat/observability/mixin/serialize_mixin.py +61 -0
- nat/observability/mixin/tagging_config_mixin.py +62 -0
- nat/observability/mixin/type_introspection_mixin.py +496 -0
- nat/observability/processor/__init__.py +14 -0
- nat/observability/processor/batching_processor.py +308 -0
- nat/observability/processor/callback_processor.py +42 -0
- nat/observability/processor/falsy_batch_filter_processor.py +55 -0
- nat/observability/processor/intermediate_step_serializer.py +28 -0
- nat/observability/processor/processor.py +74 -0
- nat/observability/processor/processor_factory.py +70 -0
- nat/observability/processor/redaction/__init__.py +24 -0
- nat/observability/processor/redaction/contextual_redaction_processor.py +125 -0
- nat/observability/processor/redaction/contextual_span_redaction_processor.py +66 -0
- nat/observability/processor/redaction/redaction_processor.py +177 -0
- nat/observability/processor/redaction/span_header_redaction_processor.py +92 -0
- nat/observability/processor/span_tagging_processor.py +68 -0
- nat/observability/register.py +114 -0
- nat/observability/utils/__init__.py +14 -0
- nat/observability/utils/dict_utils.py +236 -0
- nat/observability/utils/time_utils.py +31 -0
- nat/plugins/.namespace +1 -0
- nat/profiler/__init__.py +0 -0
- nat/profiler/calc/__init__.py +14 -0
- nat/profiler/calc/calc_runner.py +626 -0
- nat/profiler/calc/calculations.py +288 -0
- nat/profiler/calc/data_models.py +188 -0
- nat/profiler/calc/plot.py +345 -0
- nat/profiler/callbacks/__init__.py +0 -0
- nat/profiler/callbacks/agno_callback_handler.py +295 -0
- nat/profiler/callbacks/base_callback_class.py +20 -0
- nat/profiler/callbacks/langchain_callback_handler.py +297 -0
- nat/profiler/callbacks/llama_index_callback_handler.py +205 -0
- nat/profiler/callbacks/semantic_kernel_callback_handler.py +238 -0
- nat/profiler/callbacks/token_usage_base_model.py +27 -0
- nat/profiler/data_frame_row.py +51 -0
- nat/profiler/data_models.py +24 -0
- nat/profiler/decorators/__init__.py +0 -0
- nat/profiler/decorators/framework_wrapper.py +180 -0
- nat/profiler/decorators/function_tracking.py +411 -0
- nat/profiler/forecasting/__init__.py +0 -0
- nat/profiler/forecasting/config.py +18 -0
- nat/profiler/forecasting/model_trainer.py +75 -0
- nat/profiler/forecasting/models/__init__.py +22 -0
- nat/profiler/forecasting/models/forecasting_base_model.py +42 -0
- nat/profiler/forecasting/models/linear_model.py +197 -0
- nat/profiler/forecasting/models/random_forest_regressor.py +269 -0
- nat/profiler/inference_metrics_model.py +28 -0
- nat/profiler/inference_optimization/__init__.py +0 -0
- nat/profiler/inference_optimization/bottleneck_analysis/__init__.py +0 -0
- nat/profiler/inference_optimization/bottleneck_analysis/nested_stack_analysis.py +460 -0
- nat/profiler/inference_optimization/bottleneck_analysis/simple_stack_analysis.py +258 -0
- nat/profiler/inference_optimization/data_models.py +386 -0
- nat/profiler/inference_optimization/experimental/__init__.py +0 -0
- nat/profiler/inference_optimization/experimental/concurrency_spike_analysis.py +468 -0
- nat/profiler/inference_optimization/experimental/prefix_span_analysis.py +404 -0
- nat/profiler/inference_optimization/llm_metrics.py +212 -0
- nat/profiler/inference_optimization/prompt_caching.py +163 -0
- nat/profiler/inference_optimization/token_uniqueness.py +107 -0
- nat/profiler/inference_optimization/workflow_runtimes.py +72 -0
- nat/profiler/intermediate_property_adapter.py +102 -0
- nat/profiler/parameter_optimization/__init__.py +0 -0
- nat/profiler/parameter_optimization/optimizable_utils.py +93 -0
- nat/profiler/parameter_optimization/optimizer_runtime.py +67 -0
- nat/profiler/parameter_optimization/parameter_optimizer.py +153 -0
- nat/profiler/parameter_optimization/parameter_selection.py +107 -0
- nat/profiler/parameter_optimization/pareto_visualizer.py +380 -0
- nat/profiler/parameter_optimization/prompt_optimizer.py +384 -0
- nat/profiler/parameter_optimization/update_helpers.py +66 -0
- nat/profiler/profile_runner.py +478 -0
- nat/profiler/utils.py +186 -0
- nat/registry_handlers/__init__.py +0 -0
- nat/registry_handlers/local/__init__.py +0 -0
- nat/registry_handlers/local/local_handler.py +176 -0
- nat/registry_handlers/local/register_local.py +37 -0
- nat/registry_handlers/metadata_factory.py +60 -0
- nat/registry_handlers/package_utils.py +570 -0
- nat/registry_handlers/pypi/__init__.py +0 -0
- nat/registry_handlers/pypi/pypi_handler.py +248 -0
- nat/registry_handlers/pypi/register_pypi.py +40 -0
- nat/registry_handlers/register.py +20 -0
- nat/registry_handlers/registry_handler_base.py +157 -0
- nat/registry_handlers/rest/__init__.py +0 -0
- nat/registry_handlers/rest/register_rest.py +56 -0
- nat/registry_handlers/rest/rest_handler.py +236 -0
- nat/registry_handlers/schemas/__init__.py +0 -0
- nat/registry_handlers/schemas/headers.py +42 -0
- nat/registry_handlers/schemas/package.py +68 -0
- nat/registry_handlers/schemas/publish.py +68 -0
- nat/registry_handlers/schemas/pull.py +82 -0
- nat/registry_handlers/schemas/remove.py +36 -0
- nat/registry_handlers/schemas/search.py +91 -0
- nat/registry_handlers/schemas/status.py +47 -0
- nat/retriever/__init__.py +0 -0
- nat/retriever/interface.py +41 -0
- nat/retriever/milvus/__init__.py +14 -0
- nat/retriever/milvus/register.py +81 -0
- nat/retriever/milvus/retriever.py +228 -0
- nat/retriever/models.py +77 -0
- nat/retriever/nemo_retriever/__init__.py +14 -0
- nat/retriever/nemo_retriever/register.py +60 -0
- nat/retriever/nemo_retriever/retriever.py +190 -0
- nat/retriever/register.py +21 -0
- nat/runtime/__init__.py +14 -0
- nat/runtime/loader.py +220 -0
- nat/runtime/runner.py +292 -0
- nat/runtime/session.py +223 -0
- nat/runtime/user_metadata.py +130 -0
- nat/settings/__init__.py +0 -0
- nat/settings/global_settings.py +329 -0
- nat/test/.namespace +1 -0
- nat/tool/__init__.py +0 -0
- nat/tool/chat_completion.py +77 -0
- nat/tool/code_execution/README.md +151 -0
- nat/tool/code_execution/__init__.py +0 -0
- nat/tool/code_execution/code_sandbox.py +267 -0
- nat/tool/code_execution/local_sandbox/.gitignore +1 -0
- nat/tool/code_execution/local_sandbox/Dockerfile.sandbox +60 -0
- nat/tool/code_execution/local_sandbox/__init__.py +13 -0
- nat/tool/code_execution/local_sandbox/local_sandbox_server.py +198 -0
- nat/tool/code_execution/local_sandbox/sandbox.requirements.txt +6 -0
- nat/tool/code_execution/local_sandbox/start_local_sandbox.sh +50 -0
- nat/tool/code_execution/register.py +74 -0
- nat/tool/code_execution/test_code_execution_sandbox.py +414 -0
- nat/tool/code_execution/utils.py +100 -0
- nat/tool/datetime_tools.py +82 -0
- nat/tool/document_search.py +141 -0
- nat/tool/github_tools.py +450 -0
- nat/tool/memory_tools/__init__.py +0 -0
- nat/tool/memory_tools/add_memory_tool.py +79 -0
- nat/tool/memory_tools/delete_memory_tool.py +66 -0
- nat/tool/memory_tools/get_memory_tool.py +72 -0
- nat/tool/nvidia_rag.py +95 -0
- nat/tool/register.py +31 -0
- nat/tool/retriever.py +95 -0
- nat/tool/server_tools.py +66 -0
- nat/utils/__init__.py +0 -0
- nat/utils/callable_utils.py +70 -0
- nat/utils/data_models/__init__.py +0 -0
- nat/utils/data_models/schema_validator.py +58 -0
- nat/utils/debugging_utils.py +43 -0
- nat/utils/decorators.py +210 -0
- nat/utils/dump_distro_mapping.py +32 -0
- nat/utils/exception_handlers/__init__.py +0 -0
- nat/utils/exception_handlers/automatic_retries.py +342 -0
- nat/utils/exception_handlers/schemas.py +114 -0
- nat/utils/io/__init__.py +0 -0
- nat/utils/io/model_processing.py +28 -0
- nat/utils/io/yaml_tools.py +119 -0
- nat/utils/log_levels.py +25 -0
- nat/utils/log_utils.py +37 -0
- nat/utils/metadata_utils.py +74 -0
- nat/utils/optional_imports.py +142 -0
- nat/utils/producer_consumer_queue.py +178 -0
- nat/utils/reactive/__init__.py +0 -0
- nat/utils/reactive/base/__init__.py +0 -0
- nat/utils/reactive/base/observable_base.py +65 -0
- nat/utils/reactive/base/observer_base.py +55 -0
- nat/utils/reactive/base/subject_base.py +79 -0
- nat/utils/reactive/observable.py +59 -0
- nat/utils/reactive/observer.py +76 -0
- nat/utils/reactive/subject.py +131 -0
- nat/utils/reactive/subscription.py +49 -0
- nat/utils/settings/__init__.py +0 -0
- nat/utils/settings/global_settings.py +195 -0
- nat/utils/string_utils.py +38 -0
- nat/utils/type_converter.py +299 -0
- nat/utils/type_utils.py +488 -0
- nat/utils/url_utils.py +27 -0
- nvidia_nat-1.1.0a20251020.dist-info/METADATA +195 -0
- nvidia_nat-1.1.0a20251020.dist-info/RECORD +480 -0
- nvidia_nat-1.1.0a20251020.dist-info/WHEEL +5 -0
- nvidia_nat-1.1.0a20251020.dist-info/entry_points.txt +22 -0
- nvidia_nat-1.1.0a20251020.dist-info/licenses/LICENSE-3rd-party.txt +5478 -0
- nvidia_nat-1.1.0a20251020.dist-info/licenses/LICENSE.md +201 -0
- nvidia_nat-1.1.0a20251020.dist-info/top_level.txt +2 -0
nat/builder/function.py
ADDED
|
@@ -0,0 +1,714 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: Copyright (c) 2025, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
|
2
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
#
|
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
# you may not use this file except in compliance with the License.
|
|
6
|
+
# You may obtain a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
# See the License for the specific language governing permissions and
|
|
14
|
+
# limitations under the License.
|
|
15
|
+
|
|
16
|
+
import logging
|
|
17
|
+
import re
|
|
18
|
+
import typing
|
|
19
|
+
from abc import ABC
|
|
20
|
+
from abc import abstractmethod
|
|
21
|
+
from collections.abc import AsyncGenerator
|
|
22
|
+
from collections.abc import Awaitable
|
|
23
|
+
from collections.abc import Callable
|
|
24
|
+
from collections.abc import Sequence
|
|
25
|
+
|
|
26
|
+
from pydantic import BaseModel
|
|
27
|
+
|
|
28
|
+
from nat.builder.context import Context
|
|
29
|
+
from nat.builder.function_base import FunctionBase
|
|
30
|
+
from nat.builder.function_base import InputT
|
|
31
|
+
from nat.builder.function_base import SingleOutputT
|
|
32
|
+
from nat.builder.function_base import StreamingOutputT
|
|
33
|
+
from nat.builder.function_info import FunctionInfo
|
|
34
|
+
from nat.data_models.function import EmptyFunctionConfig
|
|
35
|
+
from nat.data_models.function import FunctionBaseConfig
|
|
36
|
+
from nat.data_models.function import FunctionGroupBaseConfig
|
|
37
|
+
|
|
38
|
+
_InvokeFnT = Callable[[InputT], Awaitable[SingleOutputT]]
|
|
39
|
+
_StreamFnT = Callable[[InputT], AsyncGenerator[StreamingOutputT]]
|
|
40
|
+
|
|
41
|
+
_T = typing.TypeVar("_T")
|
|
42
|
+
|
|
43
|
+
logger = logging.getLogger(__name__)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class Function(FunctionBase[InputT, StreamingOutputT, SingleOutputT], ABC):
|
|
47
|
+
|
|
48
|
+
def __init__(self,
|
|
49
|
+
*,
|
|
50
|
+
config: FunctionBaseConfig,
|
|
51
|
+
description: str | None,
|
|
52
|
+
input_schema: type[BaseModel] | None = None,
|
|
53
|
+
streaming_output_schema: type[BaseModel] | type[None] | None = None,
|
|
54
|
+
single_output_schema: type[BaseModel] | type[None] | None = None,
|
|
55
|
+
converters: list[Callable[[typing.Any], typing.Any]] | None = None,
|
|
56
|
+
instance_name: str | None = None):
|
|
57
|
+
|
|
58
|
+
super().__init__(input_schema=input_schema,
|
|
59
|
+
streaming_output_schema=streaming_output_schema,
|
|
60
|
+
single_output_schema=single_output_schema,
|
|
61
|
+
converters=converters)
|
|
62
|
+
|
|
63
|
+
self.config = config
|
|
64
|
+
self.description = description
|
|
65
|
+
self.instance_name = instance_name or config.type
|
|
66
|
+
self._context = Context.get()
|
|
67
|
+
|
|
68
|
+
def convert(self, value: typing.Any, to_type: type[_T]) -> _T:
|
|
69
|
+
"""
|
|
70
|
+
Converts the given value to the specified type using the function's converter.
|
|
71
|
+
|
|
72
|
+
Parameters
|
|
73
|
+
----------
|
|
74
|
+
value : typing.Any
|
|
75
|
+
The value to convert.
|
|
76
|
+
to_type : type
|
|
77
|
+
The type to convert the value to.
|
|
78
|
+
|
|
79
|
+
Returns
|
|
80
|
+
-------
|
|
81
|
+
_T
|
|
82
|
+
The converted value.
|
|
83
|
+
|
|
84
|
+
Raises
|
|
85
|
+
------
|
|
86
|
+
ValueError
|
|
87
|
+
If the value cannot be converted to the specified type (when `to_type` is specified).
|
|
88
|
+
"""
|
|
89
|
+
|
|
90
|
+
return self._converter.convert(value, to_type=to_type)
|
|
91
|
+
|
|
92
|
+
def try_convert(self, value: typing.Any, to_type: type[_T]) -> _T | typing.Any:
|
|
93
|
+
"""
|
|
94
|
+
Converts the given value to the specified type using graceful error handling.
|
|
95
|
+
If conversion fails, returns the original value and continues processing.
|
|
96
|
+
|
|
97
|
+
Parameters
|
|
98
|
+
----------
|
|
99
|
+
value : typing.Any
|
|
100
|
+
The value to convert.
|
|
101
|
+
to_type : type
|
|
102
|
+
The type to convert the value to.
|
|
103
|
+
|
|
104
|
+
Returns
|
|
105
|
+
-------
|
|
106
|
+
_T | typing.Any
|
|
107
|
+
The converted value, or original value if conversion fails.
|
|
108
|
+
"""
|
|
109
|
+
return self._converter.try_convert(value, to_type=to_type)
|
|
110
|
+
|
|
111
|
+
@abstractmethod
|
|
112
|
+
async def _ainvoke(self, value: InputT) -> SingleOutputT:
|
|
113
|
+
pass
|
|
114
|
+
|
|
115
|
+
@typing.overload
|
|
116
|
+
async def ainvoke(self, value: InputT | typing.Any) -> SingleOutputT:
|
|
117
|
+
...
|
|
118
|
+
|
|
119
|
+
@typing.overload
|
|
120
|
+
async def ainvoke(self, value: InputT | typing.Any, to_type: type[_T]) -> _T:
|
|
121
|
+
...
|
|
122
|
+
|
|
123
|
+
@typing.final
|
|
124
|
+
async def ainvoke(self, value: InputT | typing.Any, to_type: type | None = None):
|
|
125
|
+
"""
|
|
126
|
+
Runs the function with the given input and returns a single output from the function. This is the
|
|
127
|
+
main entry point for running a function.
|
|
128
|
+
|
|
129
|
+
Parameters
|
|
130
|
+
----------
|
|
131
|
+
value : InputT | typing.Any
|
|
132
|
+
The input to the function.
|
|
133
|
+
to_type : type | None, optional
|
|
134
|
+
The type to convert the output to using the function's converter. When not specified, the
|
|
135
|
+
output will match `single_output_type`.
|
|
136
|
+
|
|
137
|
+
Returns
|
|
138
|
+
-------
|
|
139
|
+
typing.Any
|
|
140
|
+
The output of the function optionally converted to the specified type.
|
|
141
|
+
|
|
142
|
+
Raises
|
|
143
|
+
------
|
|
144
|
+
ValueError
|
|
145
|
+
If the output of the function cannot be converted to the specified type.
|
|
146
|
+
"""
|
|
147
|
+
|
|
148
|
+
with self._context.push_active_function(self.instance_name,
|
|
149
|
+
input_data=value) as manager: # Set the current invocation context
|
|
150
|
+
try:
|
|
151
|
+
converted_input: InputT = self._convert_input(value)
|
|
152
|
+
|
|
153
|
+
result = await self._ainvoke(converted_input)
|
|
154
|
+
|
|
155
|
+
if to_type is not None and not isinstance(result, to_type):
|
|
156
|
+
result = self.convert(result, to_type)
|
|
157
|
+
|
|
158
|
+
manager.set_output(result)
|
|
159
|
+
|
|
160
|
+
return result
|
|
161
|
+
except Exception as e:
|
|
162
|
+
logger.error("Error with ainvoke in function with input: %s. Error: %s", value, e)
|
|
163
|
+
raise
|
|
164
|
+
|
|
165
|
+
@typing.final
|
|
166
|
+
async def acall_invoke(self, *args, **kwargs):
|
|
167
|
+
"""
|
|
168
|
+
A wrapper around `ainvoke` that allows for calling the function with arbitrary arguments and keyword arguments.
|
|
169
|
+
This is useful in scenarios where the function might be called by an LLM or other system which gives varying
|
|
170
|
+
inputs to the function. The function will attempt to convert the args and kwargs to the input schema of the
|
|
171
|
+
function.
|
|
172
|
+
|
|
173
|
+
Returns
|
|
174
|
+
-------
|
|
175
|
+
SingleOutputT
|
|
176
|
+
The output of the function.
|
|
177
|
+
"""
|
|
178
|
+
|
|
179
|
+
if (len(args) == 1 and not kwargs):
|
|
180
|
+
# If only one argument is passed, assume it is the input just like ainvoke
|
|
181
|
+
return await self.ainvoke(value=args[0])
|
|
182
|
+
|
|
183
|
+
if (not args and kwargs):
|
|
184
|
+
# If only kwargs are passed, assume we are calling a function with named arguments in a dict
|
|
185
|
+
# This will rely on the processing in ainvoke to convert from dict to the correct input type
|
|
186
|
+
return await self.ainvoke(value=kwargs)
|
|
187
|
+
|
|
188
|
+
# Possibly have both args and kwargs, final attempt is to use the input schema object constructor.
|
|
189
|
+
try:
|
|
190
|
+
input_obj = self.input_schema(*args, **kwargs)
|
|
191
|
+
|
|
192
|
+
return await self.ainvoke(value=input_obj)
|
|
193
|
+
except Exception:
|
|
194
|
+
logger.error(
|
|
195
|
+
"Error in acall_invoke() converting input to function schema. Both args and kwargs were "
|
|
196
|
+
"supplied which could not be converted to the input schema. args: %s\nkwargs: %s\nschema: %s",
|
|
197
|
+
args,
|
|
198
|
+
kwargs,
|
|
199
|
+
self.input_schema)
|
|
200
|
+
raise
|
|
201
|
+
|
|
202
|
+
@abstractmethod
|
|
203
|
+
async def _astream(self, value: InputT) -> AsyncGenerator[StreamingOutputT]:
|
|
204
|
+
yield # type: ignore
|
|
205
|
+
|
|
206
|
+
@typing.overload
|
|
207
|
+
async def astream(self, value: InputT | typing.Any) -> AsyncGenerator[SingleOutputT]:
|
|
208
|
+
...
|
|
209
|
+
|
|
210
|
+
@typing.overload
|
|
211
|
+
async def astream(self, value: InputT | typing.Any, to_type: type[_T]) -> AsyncGenerator[_T]:
|
|
212
|
+
...
|
|
213
|
+
|
|
214
|
+
@typing.final
|
|
215
|
+
async def astream(self, value: InputT | typing.Any, to_type: type | None = None):
|
|
216
|
+
"""
|
|
217
|
+
Runs the function with the given input and returns a stream of outputs from the function. This is the main entry
|
|
218
|
+
point for running a function with streaming output.
|
|
219
|
+
|
|
220
|
+
Parameters
|
|
221
|
+
----------
|
|
222
|
+
value : InputT | typing.Any
|
|
223
|
+
The input to the function.
|
|
224
|
+
to_type : type | None, optional
|
|
225
|
+
The type to convert the output to using the function's converter. When not specified, the
|
|
226
|
+
output will match `streaming_output_type`.
|
|
227
|
+
|
|
228
|
+
Yields
|
|
229
|
+
------
|
|
230
|
+
typing.Any
|
|
231
|
+
The output of the function optionally converted to the specified type.
|
|
232
|
+
|
|
233
|
+
Raises
|
|
234
|
+
------
|
|
235
|
+
ValueError
|
|
236
|
+
If the output of the function cannot be converted to the specified type (when `to_type` is specified).
|
|
237
|
+
"""
|
|
238
|
+
|
|
239
|
+
with self._context.push_active_function(self.instance_name, input_data=value) as manager:
|
|
240
|
+
try:
|
|
241
|
+
converted_input: InputT = self._convert_input(value)
|
|
242
|
+
|
|
243
|
+
# Collect streaming outputs to capture the final result
|
|
244
|
+
final_output: list[typing.Any] = []
|
|
245
|
+
|
|
246
|
+
async for data in self._astream(converted_input):
|
|
247
|
+
if to_type is not None and not isinstance(data, to_type):
|
|
248
|
+
converted_data = self.convert(data, to_type=to_type)
|
|
249
|
+
final_output.append(converted_data)
|
|
250
|
+
yield converted_data
|
|
251
|
+
else:
|
|
252
|
+
final_output.append(data)
|
|
253
|
+
yield data
|
|
254
|
+
|
|
255
|
+
# Set the final output for intermediate step tracking
|
|
256
|
+
manager.set_output(final_output)
|
|
257
|
+
|
|
258
|
+
except Exception as e:
|
|
259
|
+
logger.error("Error with astream in function with input: %s. Error: %s", value, e)
|
|
260
|
+
raise
|
|
261
|
+
|
|
262
|
+
@typing.final
|
|
263
|
+
async def acall_stream(self, *args, **kwargs):
|
|
264
|
+
"""
|
|
265
|
+
A wrapper around `astream` that allows for calling the function with arbitrary arguments and keyword arguments.
|
|
266
|
+
This is useful in scenarios where the function might be called by an LLM or other system which gives varying
|
|
267
|
+
inputs to the function. The function will attempt to convert the args and kwargs to the input schema of the
|
|
268
|
+
function.
|
|
269
|
+
|
|
270
|
+
Yields
|
|
271
|
+
------
|
|
272
|
+
StreamingOutputT
|
|
273
|
+
The output of the function.
|
|
274
|
+
"""
|
|
275
|
+
|
|
276
|
+
if (len(args) == 1 and not kwargs):
|
|
277
|
+
# If only one argument is passed, assume it is the input just like ainvoke
|
|
278
|
+
async for x in self.astream(value=args[0]):
|
|
279
|
+
yield x
|
|
280
|
+
|
|
281
|
+
elif (not args and kwargs):
|
|
282
|
+
# If only kwargs are passed, assume we are calling a function with named arguments in a dict
|
|
283
|
+
# This will rely on the processing in ainvoke to convert from dict to the correct input type
|
|
284
|
+
async for x in self.astream(value=kwargs):
|
|
285
|
+
yield x
|
|
286
|
+
|
|
287
|
+
# Possibly have both args and kwargs, final attempt is to use the input schema object constructor.
|
|
288
|
+
else:
|
|
289
|
+
try:
|
|
290
|
+
input_obj = self.input_schema(*args, **kwargs)
|
|
291
|
+
|
|
292
|
+
async for x in self.astream(value=input_obj):
|
|
293
|
+
yield x
|
|
294
|
+
except Exception:
|
|
295
|
+
logger.error(
|
|
296
|
+
"Error in acall_stream() converting input to function schema. Both args and kwargs were "
|
|
297
|
+
"supplied which could not be converted to the input schema. args: %s\nkwargs: %s\nschema: %s",
|
|
298
|
+
args,
|
|
299
|
+
kwargs,
|
|
300
|
+
self.input_schema)
|
|
301
|
+
raise
|
|
302
|
+
|
|
303
|
+
|
|
304
|
+
class LambdaFunction(Function[InputT, StreamingOutputT, SingleOutputT]):
|
|
305
|
+
|
|
306
|
+
def __init__(self, *, config: FunctionBaseConfig, info: FunctionInfo, instance_name: str | None = None):
|
|
307
|
+
|
|
308
|
+
super().__init__(config=config,
|
|
309
|
+
description=info.description,
|
|
310
|
+
input_schema=info.input_schema,
|
|
311
|
+
streaming_output_schema=info.stream_output_schema,
|
|
312
|
+
single_output_schema=info.single_output_schema,
|
|
313
|
+
converters=info.converters,
|
|
314
|
+
instance_name=instance_name)
|
|
315
|
+
|
|
316
|
+
self._info = info
|
|
317
|
+
self._ainvoke_fn: _InvokeFnT = info.single_fn
|
|
318
|
+
self._astream_fn: _StreamFnT = info.stream_fn
|
|
319
|
+
|
|
320
|
+
@property
|
|
321
|
+
def has_streaming_output(self) -> bool:
|
|
322
|
+
return self._astream_fn is not None
|
|
323
|
+
|
|
324
|
+
@property
|
|
325
|
+
def has_single_output(self) -> bool:
|
|
326
|
+
return self._ainvoke_fn is not None
|
|
327
|
+
|
|
328
|
+
async def _ainvoke(self, value: InputT) -> SingleOutputT:
|
|
329
|
+
return await self._ainvoke_fn(value)
|
|
330
|
+
|
|
331
|
+
async def _astream(self, value: InputT) -> AsyncGenerator[StreamingOutputT]:
|
|
332
|
+
async for x in self._astream_fn(value):
|
|
333
|
+
yield x
|
|
334
|
+
|
|
335
|
+
@staticmethod
|
|
336
|
+
def from_info(*,
|
|
337
|
+
config: FunctionBaseConfig,
|
|
338
|
+
info: FunctionInfo,
|
|
339
|
+
instance_name: str | None = None) -> 'LambdaFunction[InputT, StreamingOutputT, SingleOutputT]':
|
|
340
|
+
|
|
341
|
+
input_type: type = info.input_type
|
|
342
|
+
streaming_output_type = info.stream_output_type
|
|
343
|
+
single_output_type = info.single_output_type
|
|
344
|
+
|
|
345
|
+
class FunctionImpl(LambdaFunction[input_type, streaming_output_type, single_output_type]):
|
|
346
|
+
pass
|
|
347
|
+
|
|
348
|
+
return FunctionImpl(config=config, info=info, instance_name=instance_name)
|
|
349
|
+
|
|
350
|
+
|
|
351
|
+
class FunctionGroup:
|
|
352
|
+
"""
|
|
353
|
+
A group of functions that can be used together, sharing the same configuration, context, and resources.
|
|
354
|
+
"""
|
|
355
|
+
|
|
356
|
+
def __init__(self,
|
|
357
|
+
*,
|
|
358
|
+
config: FunctionGroupBaseConfig,
|
|
359
|
+
instance_name: str | None = None,
|
|
360
|
+
filter_fn: Callable[[Sequence[str]], Awaitable[Sequence[str]]] | None = None):
|
|
361
|
+
"""
|
|
362
|
+
Creates a new function group.
|
|
363
|
+
|
|
364
|
+
Parameters
|
|
365
|
+
----------
|
|
366
|
+
config : FunctionGroupBaseConfig
|
|
367
|
+
The configuration for the function group.
|
|
368
|
+
instance_name : str | None, optional
|
|
369
|
+
The name of the function group. If not provided, the type of the function group will be used.
|
|
370
|
+
filter_fn : Callable[[Sequence[str]], Awaitable[Sequence[str]]] | None, optional
|
|
371
|
+
A callback function to additionally filter the functions in the function group dynamically when
|
|
372
|
+
the functions are accessed via any accessor method.
|
|
373
|
+
"""
|
|
374
|
+
self._config = config
|
|
375
|
+
self._instance_name = instance_name or config.type
|
|
376
|
+
self._functions: dict[str, Function] = dict()
|
|
377
|
+
self._filter_fn = filter_fn
|
|
378
|
+
self._per_function_filter_fn: dict[str, Callable[[str], Awaitable[bool]]] = dict()
|
|
379
|
+
|
|
380
|
+
def add_function(self,
|
|
381
|
+
name: str,
|
|
382
|
+
fn: Callable,
|
|
383
|
+
*,
|
|
384
|
+
input_schema: type[BaseModel] | None = None,
|
|
385
|
+
description: str | None = None,
|
|
386
|
+
converters: list[Callable] | None = None,
|
|
387
|
+
filter_fn: Callable[[str], Awaitable[bool]] | None = None):
|
|
388
|
+
"""
|
|
389
|
+
Adds a function to the function group.
|
|
390
|
+
|
|
391
|
+
Parameters
|
|
392
|
+
----------
|
|
393
|
+
name : str
|
|
394
|
+
The name of the function.
|
|
395
|
+
fn : Callable
|
|
396
|
+
The function to add to the function group.
|
|
397
|
+
input_schema : type[BaseModel] | None, optional
|
|
398
|
+
The input schema for the function.
|
|
399
|
+
description : str | None, optional
|
|
400
|
+
The description of the function.
|
|
401
|
+
converters : list[Callable] | None, optional
|
|
402
|
+
The converters to use for the function.
|
|
403
|
+
filter_fn : Callable[[str], Awaitable[bool]] | None, optional
|
|
404
|
+
A callback to determine if the function should be included in the function group. The
|
|
405
|
+
callback will be called with the function name. The callback is invoked dynamically when
|
|
406
|
+
the functions are accessed via any accessor method such as `get_accessible_functions`,
|
|
407
|
+
`get_included_functions`, `get_excluded_functions`, `get_all_functions`.
|
|
408
|
+
|
|
409
|
+
Raises
|
|
410
|
+
------
|
|
411
|
+
ValueError
|
|
412
|
+
When the function name is empty or blank.
|
|
413
|
+
When the function name contains invalid characters.
|
|
414
|
+
When the function already exists in the function group.
|
|
415
|
+
"""
|
|
416
|
+
if not name.strip():
|
|
417
|
+
raise ValueError("Function name cannot be empty or blank")
|
|
418
|
+
if not re.match(r"^[a-zA-Z0-9_.-]+$", name):
|
|
419
|
+
raise ValueError(
|
|
420
|
+
f"Function name can only contain letters, numbers, underscores, periods, and hyphens: {name}")
|
|
421
|
+
if name in self._functions:
|
|
422
|
+
raise ValueError(f"Function {name} already exists in function group {self._instance_name}")
|
|
423
|
+
|
|
424
|
+
info = FunctionInfo.from_fn(fn, input_schema=input_schema, description=description, converters=converters)
|
|
425
|
+
full_name = self._get_fn_name(name)
|
|
426
|
+
lambda_fn = LambdaFunction.from_info(config=EmptyFunctionConfig(), info=info, instance_name=full_name)
|
|
427
|
+
self._functions[name] = lambda_fn
|
|
428
|
+
if filter_fn:
|
|
429
|
+
self._per_function_filter_fn[name] = filter_fn
|
|
430
|
+
|
|
431
|
+
def get_config(self) -> FunctionGroupBaseConfig:
|
|
432
|
+
"""
|
|
433
|
+
Returns the configuration for the function group.
|
|
434
|
+
|
|
435
|
+
Returns
|
|
436
|
+
-------
|
|
437
|
+
FunctionGroupBaseConfig
|
|
438
|
+
The configuration for the function group.
|
|
439
|
+
"""
|
|
440
|
+
return self._config
|
|
441
|
+
|
|
442
|
+
def _get_fn_name(self, name: str) -> str:
|
|
443
|
+
return f"{self._instance_name}.{name}"
|
|
444
|
+
|
|
445
|
+
async def _fn_should_be_included(self, name: str) -> bool:
|
|
446
|
+
if name not in self._per_function_filter_fn:
|
|
447
|
+
return True
|
|
448
|
+
return await self._per_function_filter_fn[name](name)
|
|
449
|
+
|
|
450
|
+
async def _get_all_but_excluded_functions(
|
|
451
|
+
self,
|
|
452
|
+
filter_fn: Callable[[Sequence[str]], Awaitable[Sequence[str]]] | None = None,
|
|
453
|
+
) -> dict[str, Function]:
|
|
454
|
+
"""
|
|
455
|
+
Returns a dictionary of all functions in the function group except the excluded functions.
|
|
456
|
+
"""
|
|
457
|
+
missing = set(self._config.exclude) - set(self._functions.keys())
|
|
458
|
+
if missing:
|
|
459
|
+
raise ValueError(f"Unknown excluded functions: {sorted(missing)}")
|
|
460
|
+
|
|
461
|
+
if filter_fn is None:
|
|
462
|
+
if self._filter_fn is None:
|
|
463
|
+
|
|
464
|
+
async def identity_filter(x: Sequence[str]) -> Sequence[str]:
|
|
465
|
+
return x
|
|
466
|
+
|
|
467
|
+
filter_fn = identity_filter
|
|
468
|
+
else:
|
|
469
|
+
filter_fn = self._filter_fn
|
|
470
|
+
|
|
471
|
+
excluded = set(self._config.exclude)
|
|
472
|
+
included = set(await filter_fn(list(self._functions.keys())))
|
|
473
|
+
|
|
474
|
+
result = {}
|
|
475
|
+
for name in self._functions:
|
|
476
|
+
if name in excluded:
|
|
477
|
+
continue
|
|
478
|
+
if not await self._fn_should_be_included(name):
|
|
479
|
+
continue
|
|
480
|
+
if name not in included:
|
|
481
|
+
continue
|
|
482
|
+
result[self._get_fn_name(name)] = self._functions[name]
|
|
483
|
+
|
|
484
|
+
return result
|
|
485
|
+
|
|
486
|
+
async def get_accessible_functions(
|
|
487
|
+
self,
|
|
488
|
+
filter_fn: Callable[[Sequence[str]], Awaitable[Sequence[str]]] | None = None,
|
|
489
|
+
) -> dict[str, Function]:
|
|
490
|
+
"""
|
|
491
|
+
Returns a dictionary of all accessible functions in the function group.
|
|
492
|
+
|
|
493
|
+
First, the functions are filtered by the function group's configuration.
|
|
494
|
+
If the function group is configured to:
|
|
495
|
+
- include some functions, this will return only the included functions.
|
|
496
|
+
- not include or exclude any function, this will return all functions in the group.
|
|
497
|
+
- exclude some functions, this will return all functions in the group except the excluded functions.
|
|
498
|
+
|
|
499
|
+
Then, the functions are filtered by filter function and per-function filter functions.
|
|
500
|
+
|
|
501
|
+
Parameters
|
|
502
|
+
----------
|
|
503
|
+
filter_fn : Callable[[Sequence[str]], Awaitable[Sequence[str]]] | None, optional
|
|
504
|
+
A callback function to additionally filter the functions in the function group dynamically. If not provided
|
|
505
|
+
then fall back to the function group's filter function. If no filter function is set for the function group
|
|
506
|
+
all functions will be returned.
|
|
507
|
+
|
|
508
|
+
Returns
|
|
509
|
+
-------
|
|
510
|
+
dict[str, Function]
|
|
511
|
+
A dictionary of all accessible functions in the function group.
|
|
512
|
+
|
|
513
|
+
Raises
|
|
514
|
+
------
|
|
515
|
+
ValueError
|
|
516
|
+
When the function group is configured to include functions that are not found in the group.
|
|
517
|
+
"""
|
|
518
|
+
if self._config.include:
|
|
519
|
+
return await self.get_included_functions(filter_fn=filter_fn)
|
|
520
|
+
if self._config.exclude:
|
|
521
|
+
return await self._get_all_but_excluded_functions(filter_fn=filter_fn)
|
|
522
|
+
return await self.get_all_functions(filter_fn=filter_fn)
|
|
523
|
+
|
|
524
|
+
async def get_excluded_functions(
|
|
525
|
+
self,
|
|
526
|
+
filter_fn: Callable[[Sequence[str]], Awaitable[Sequence[str]]] | None = None,
|
|
527
|
+
) -> dict[str, Function]:
|
|
528
|
+
"""
|
|
529
|
+
Returns a dictionary of all functions in the function group which are configured to be excluded or filtered
|
|
530
|
+
out by a filter function or per-function filter function.
|
|
531
|
+
|
|
532
|
+
Parameters
|
|
533
|
+
----------
|
|
534
|
+
filter_fn : Callable[[Sequence[str]], Awaitable[Sequence[str]]] | None, optional
|
|
535
|
+
A callback function to additionally filter the functions in the function group dynamically. If not provided
|
|
536
|
+
then fall back to the function group's filter function. If no filter function is set for the function group
|
|
537
|
+
then no functions will be added to the returned dictionary.
|
|
538
|
+
|
|
539
|
+
Returns
|
|
540
|
+
-------
|
|
541
|
+
dict[str, Function]
|
|
542
|
+
A dictionary of all excluded functions in the function group.
|
|
543
|
+
|
|
544
|
+
Raises
|
|
545
|
+
------
|
|
546
|
+
ValueError
|
|
547
|
+
When the function group is configured to exclude functions that are not found in the group.
|
|
548
|
+
"""
|
|
549
|
+
missing = set(self._config.exclude) - set(self._functions.keys())
|
|
550
|
+
if missing:
|
|
551
|
+
raise ValueError(f"Unknown excluded functions: {sorted(missing)}")
|
|
552
|
+
|
|
553
|
+
if filter_fn is None:
|
|
554
|
+
if self._filter_fn is None:
|
|
555
|
+
|
|
556
|
+
async def identity_filter(x: Sequence[str]) -> Sequence[str]:
|
|
557
|
+
return x
|
|
558
|
+
|
|
559
|
+
filter_fn = identity_filter
|
|
560
|
+
else:
|
|
561
|
+
filter_fn = self._filter_fn
|
|
562
|
+
|
|
563
|
+
excluded = set(self._config.exclude)
|
|
564
|
+
included = set(await filter_fn(list(self._functions.keys())))
|
|
565
|
+
|
|
566
|
+
result = {}
|
|
567
|
+
for name in self._functions:
|
|
568
|
+
is_excluded = False
|
|
569
|
+
if name in excluded:
|
|
570
|
+
is_excluded = True
|
|
571
|
+
elif not await self._fn_should_be_included(name):
|
|
572
|
+
is_excluded = True
|
|
573
|
+
elif name not in included:
|
|
574
|
+
is_excluded = True
|
|
575
|
+
|
|
576
|
+
if is_excluded:
|
|
577
|
+
result[self._get_fn_name(name)] = self._functions[name]
|
|
578
|
+
|
|
579
|
+
return result
|
|
580
|
+
|
|
581
|
+
async def get_included_functions(
|
|
582
|
+
self,
|
|
583
|
+
filter_fn: Callable[[Sequence[str]], Awaitable[Sequence[str]]] | None = None,
|
|
584
|
+
) -> dict[str, Function]:
|
|
585
|
+
"""
|
|
586
|
+
Returns a dictionary of all functions in the function group which are:
|
|
587
|
+
- configured to be included and added to the global function registry
|
|
588
|
+
- not configured to be excluded.
|
|
589
|
+
- not filtered out by a filter function.
|
|
590
|
+
|
|
591
|
+
Parameters
|
|
592
|
+
----------
|
|
593
|
+
filter_fn : Callable[[Sequence[str]], Awaitable[Sequence[str]]] | None, optional
|
|
594
|
+
A callback function to additionally filter the functions in the function group dynamically. If not provided
|
|
595
|
+
then fall back to the function group's filter function. If no filter function is set for the function group
|
|
596
|
+
all functions will be returned.
|
|
597
|
+
|
|
598
|
+
Returns
|
|
599
|
+
-------
|
|
600
|
+
dict[str, Function]
|
|
601
|
+
A dictionary of all included functions in the function group.
|
|
602
|
+
|
|
603
|
+
Raises
|
|
604
|
+
------
|
|
605
|
+
ValueError
|
|
606
|
+
When the function group is configured to include functions that are not found in the group.
|
|
607
|
+
"""
|
|
608
|
+
missing = set(self._config.include) - set(self._functions.keys())
|
|
609
|
+
if missing:
|
|
610
|
+
raise ValueError(f"Unknown included functions: {sorted(missing)}")
|
|
611
|
+
|
|
612
|
+
if filter_fn is None:
|
|
613
|
+
if self._filter_fn is None:
|
|
614
|
+
|
|
615
|
+
async def identity_filter(x: Sequence[str]) -> Sequence[str]:
|
|
616
|
+
return x
|
|
617
|
+
|
|
618
|
+
filter_fn = identity_filter
|
|
619
|
+
else:
|
|
620
|
+
filter_fn = self._filter_fn
|
|
621
|
+
|
|
622
|
+
included = set(await filter_fn(list(self._config.include)))
|
|
623
|
+
result = {}
|
|
624
|
+
for name in included:
|
|
625
|
+
if await self._fn_should_be_included(name):
|
|
626
|
+
result[self._get_fn_name(name)] = self._functions[name]
|
|
627
|
+
return result
|
|
628
|
+
|
|
629
|
+
async def get_all_functions(
|
|
630
|
+
self,
|
|
631
|
+
filter_fn: Callable[[Sequence[str]], Awaitable[Sequence[str]]] | None = None,
|
|
632
|
+
) -> dict[str, Function]:
|
|
633
|
+
"""
|
|
634
|
+
Returns a dictionary of all functions in the function group, regardless if they are included or excluded.
|
|
635
|
+
|
|
636
|
+
If a filter function has been set, the returned functions will additionally be filtered by the callback.
|
|
637
|
+
|
|
638
|
+
Parameters
|
|
639
|
+
----------
|
|
640
|
+
filter_fn : Callable[[Sequence[str]], Awaitable[Sequence[str]]] | None, optional
|
|
641
|
+
A callback function to additionally filter the functions in the function group dynamically. If not provided
|
|
642
|
+
then fall back to the function group's filter function. If no filter function is set for the function group
|
|
643
|
+
all functions will be returned.
|
|
644
|
+
|
|
645
|
+
Returns
|
|
646
|
+
-------
|
|
647
|
+
dict[str, Function]
|
|
648
|
+
A dictionary of all functions in the function group.
|
|
649
|
+
"""
|
|
650
|
+
if filter_fn is None:
|
|
651
|
+
if self._filter_fn is None:
|
|
652
|
+
|
|
653
|
+
async def identity_filter(x: Sequence[str]) -> Sequence[str]:
|
|
654
|
+
return x
|
|
655
|
+
|
|
656
|
+
filter_fn = identity_filter
|
|
657
|
+
else:
|
|
658
|
+
filter_fn = self._filter_fn
|
|
659
|
+
|
|
660
|
+
included = set(await filter_fn(list(self._functions.keys())))
|
|
661
|
+
result = {}
|
|
662
|
+
for name in included:
|
|
663
|
+
if await self._fn_should_be_included(name):
|
|
664
|
+
result[self._get_fn_name(name)] = self._functions[name]
|
|
665
|
+
return result
|
|
666
|
+
|
|
667
|
+
def set_filter_fn(self, filter_fn: Callable[[Sequence[str]], Awaitable[Sequence[str]]]):
|
|
668
|
+
"""
|
|
669
|
+
Sets the filter function for the function group.
|
|
670
|
+
|
|
671
|
+
Parameters
|
|
672
|
+
----------
|
|
673
|
+
filter_fn : Callable[[Sequence[str]], Awaitable[Sequence[str]]]
|
|
674
|
+
The filter function to set for the function group.
|
|
675
|
+
"""
|
|
676
|
+
self._filter_fn = filter_fn
|
|
677
|
+
|
|
678
|
+
def set_per_function_filter_fn(self, name: str, filter_fn: Callable[[str], Awaitable[bool]]):
|
|
679
|
+
"""
|
|
680
|
+
Sets the a per-function filter function for the a function within the function group.
|
|
681
|
+
|
|
682
|
+
Parameters
|
|
683
|
+
----------
|
|
684
|
+
name : str
|
|
685
|
+
The name of the function.
|
|
686
|
+
filter_fn : Callable[[str], Awaitable[bool]]
|
|
687
|
+
The per-function filter function to set for the function group.
|
|
688
|
+
|
|
689
|
+
Raises
|
|
690
|
+
------
|
|
691
|
+
ValueError
|
|
692
|
+
When the function is not found in the function group.
|
|
693
|
+
"""
|
|
694
|
+
if name not in self._functions:
|
|
695
|
+
raise ValueError(f"Function {name} not found in function group {self._instance_name}")
|
|
696
|
+
self._per_function_filter_fn[name] = filter_fn
|
|
697
|
+
|
|
698
|
+
def set_instance_name(self, instance_name: str):
|
|
699
|
+
"""
|
|
700
|
+
Sets the instance name for the function group.
|
|
701
|
+
|
|
702
|
+
Parameters
|
|
703
|
+
----------
|
|
704
|
+
instance_name : str
|
|
705
|
+
The instance name to set for the function group.
|
|
706
|
+
"""
|
|
707
|
+
self._instance_name = instance_name
|
|
708
|
+
|
|
709
|
+
@property
|
|
710
|
+
def instance_name(self) -> str:
|
|
711
|
+
"""
|
|
712
|
+
Returns the instance name for the function group.
|
|
713
|
+
"""
|
|
714
|
+
return self._instance_name
|