nvidia-nat 1.2.0__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.
Files changed (435) hide show
  1. aiq/__init__.py +66 -0
  2. nat/agent/__init__.py +0 -0
  3. nat/agent/base.py +256 -0
  4. nat/agent/dual_node.py +67 -0
  5. nat/agent/react_agent/__init__.py +0 -0
  6. nat/agent/react_agent/agent.py +363 -0
  7. nat/agent/react_agent/output_parser.py +104 -0
  8. nat/agent/react_agent/prompt.py +44 -0
  9. nat/agent/react_agent/register.py +149 -0
  10. nat/agent/reasoning_agent/__init__.py +0 -0
  11. nat/agent/reasoning_agent/reasoning_agent.py +225 -0
  12. nat/agent/register.py +23 -0
  13. nat/agent/rewoo_agent/__init__.py +0 -0
  14. nat/agent/rewoo_agent/agent.py +415 -0
  15. nat/agent/rewoo_agent/prompt.py +110 -0
  16. nat/agent/rewoo_agent/register.py +157 -0
  17. nat/agent/tool_calling_agent/__init__.py +0 -0
  18. nat/agent/tool_calling_agent/agent.py +119 -0
  19. nat/agent/tool_calling_agent/register.py +106 -0
  20. nat/authentication/__init__.py +14 -0
  21. nat/authentication/api_key/__init__.py +14 -0
  22. nat/authentication/api_key/api_key_auth_provider.py +96 -0
  23. nat/authentication/api_key/api_key_auth_provider_config.py +124 -0
  24. nat/authentication/api_key/register.py +26 -0
  25. nat/authentication/exceptions/__init__.py +14 -0
  26. nat/authentication/exceptions/api_key_exceptions.py +38 -0
  27. nat/authentication/http_basic_auth/__init__.py +0 -0
  28. nat/authentication/http_basic_auth/http_basic_auth_provider.py +81 -0
  29. nat/authentication/http_basic_auth/register.py +30 -0
  30. nat/authentication/interfaces.py +93 -0
  31. nat/authentication/oauth2/__init__.py +14 -0
  32. nat/authentication/oauth2/oauth2_auth_code_flow_provider.py +107 -0
  33. nat/authentication/oauth2/oauth2_auth_code_flow_provider_config.py +39 -0
  34. nat/authentication/oauth2/register.py +25 -0
  35. nat/authentication/register.py +21 -0
  36. nat/builder/__init__.py +0 -0
  37. nat/builder/builder.py +285 -0
  38. nat/builder/component_utils.py +316 -0
  39. nat/builder/context.py +270 -0
  40. nat/builder/embedder.py +24 -0
  41. nat/builder/eval_builder.py +161 -0
  42. nat/builder/evaluator.py +29 -0
  43. nat/builder/framework_enum.py +24 -0
  44. nat/builder/front_end.py +73 -0
  45. nat/builder/function.py +344 -0
  46. nat/builder/function_base.py +380 -0
  47. nat/builder/function_info.py +627 -0
  48. nat/builder/intermediate_step_manager.py +174 -0
  49. nat/builder/llm.py +25 -0
  50. nat/builder/retriever.py +25 -0
  51. nat/builder/user_interaction_manager.py +78 -0
  52. nat/builder/workflow.py +148 -0
  53. nat/builder/workflow_builder.py +1117 -0
  54. nat/cli/__init__.py +14 -0
  55. nat/cli/cli_utils/__init__.py +0 -0
  56. nat/cli/cli_utils/config_override.py +231 -0
  57. nat/cli/cli_utils/validation.py +37 -0
  58. nat/cli/commands/__init__.py +0 -0
  59. nat/cli/commands/configure/__init__.py +0 -0
  60. nat/cli/commands/configure/channel/__init__.py +0 -0
  61. nat/cli/commands/configure/channel/add.py +28 -0
  62. nat/cli/commands/configure/channel/channel.py +34 -0
  63. nat/cli/commands/configure/channel/remove.py +30 -0
  64. nat/cli/commands/configure/channel/update.py +30 -0
  65. nat/cli/commands/configure/configure.py +33 -0
  66. nat/cli/commands/evaluate.py +139 -0
  67. nat/cli/commands/info/__init__.py +14 -0
  68. nat/cli/commands/info/info.py +37 -0
  69. nat/cli/commands/info/list_channels.py +32 -0
  70. nat/cli/commands/info/list_components.py +129 -0
  71. nat/cli/commands/info/list_mcp.py +304 -0
  72. nat/cli/commands/registry/__init__.py +14 -0
  73. nat/cli/commands/registry/publish.py +88 -0
  74. nat/cli/commands/registry/pull.py +118 -0
  75. nat/cli/commands/registry/registry.py +36 -0
  76. nat/cli/commands/registry/remove.py +108 -0
  77. nat/cli/commands/registry/search.py +155 -0
  78. nat/cli/commands/sizing/__init__.py +14 -0
  79. nat/cli/commands/sizing/calc.py +297 -0
  80. nat/cli/commands/sizing/sizing.py +27 -0
  81. nat/cli/commands/start.py +246 -0
  82. nat/cli/commands/uninstall.py +81 -0
  83. nat/cli/commands/validate.py +47 -0
  84. nat/cli/commands/workflow/__init__.py +14 -0
  85. nat/cli/commands/workflow/templates/__init__.py.j2 +0 -0
  86. nat/cli/commands/workflow/templates/config.yml.j2 +16 -0
  87. nat/cli/commands/workflow/templates/pyproject.toml.j2 +22 -0
  88. nat/cli/commands/workflow/templates/register.py.j2 +5 -0
  89. nat/cli/commands/workflow/templates/workflow.py.j2 +36 -0
  90. nat/cli/commands/workflow/workflow.py +37 -0
  91. nat/cli/commands/workflow/workflow_commands.py +317 -0
  92. nat/cli/entrypoint.py +135 -0
  93. nat/cli/main.py +57 -0
  94. nat/cli/register_workflow.py +488 -0
  95. nat/cli/type_registry.py +1000 -0
  96. nat/data_models/__init__.py +14 -0
  97. nat/data_models/api_server.py +716 -0
  98. nat/data_models/authentication.py +231 -0
  99. nat/data_models/common.py +171 -0
  100. nat/data_models/component.py +58 -0
  101. nat/data_models/component_ref.py +168 -0
  102. nat/data_models/config.py +410 -0
  103. nat/data_models/dataset_handler.py +169 -0
  104. nat/data_models/discovery_metadata.py +305 -0
  105. nat/data_models/embedder.py +27 -0
  106. nat/data_models/evaluate.py +127 -0
  107. nat/data_models/evaluator.py +26 -0
  108. nat/data_models/front_end.py +26 -0
  109. nat/data_models/function.py +30 -0
  110. nat/data_models/function_dependencies.py +72 -0
  111. nat/data_models/interactive.py +246 -0
  112. nat/data_models/intermediate_step.py +302 -0
  113. nat/data_models/invocation_node.py +38 -0
  114. nat/data_models/llm.py +27 -0
  115. nat/data_models/logging.py +26 -0
  116. nat/data_models/memory.py +27 -0
  117. nat/data_models/object_store.py +44 -0
  118. nat/data_models/profiler.py +54 -0
  119. nat/data_models/registry_handler.py +26 -0
  120. nat/data_models/retriever.py +30 -0
  121. nat/data_models/retry_mixin.py +35 -0
  122. nat/data_models/span.py +190 -0
  123. nat/data_models/step_adaptor.py +64 -0
  124. nat/data_models/streaming.py +33 -0
  125. nat/data_models/swe_bench_model.py +54 -0
  126. nat/data_models/telemetry_exporter.py +26 -0
  127. nat/data_models/ttc_strategy.py +30 -0
  128. nat/embedder/__init__.py +0 -0
  129. nat/embedder/nim_embedder.py +59 -0
  130. nat/embedder/openai_embedder.py +43 -0
  131. nat/embedder/register.py +22 -0
  132. nat/eval/__init__.py +14 -0
  133. nat/eval/config.py +60 -0
  134. nat/eval/dataset_handler/__init__.py +0 -0
  135. nat/eval/dataset_handler/dataset_downloader.py +106 -0
  136. nat/eval/dataset_handler/dataset_filter.py +52 -0
  137. nat/eval/dataset_handler/dataset_handler.py +367 -0
  138. nat/eval/evaluate.py +510 -0
  139. nat/eval/evaluator/__init__.py +14 -0
  140. nat/eval/evaluator/base_evaluator.py +77 -0
  141. nat/eval/evaluator/evaluator_model.py +45 -0
  142. nat/eval/intermediate_step_adapter.py +99 -0
  143. nat/eval/rag_evaluator/__init__.py +0 -0
  144. nat/eval/rag_evaluator/evaluate.py +178 -0
  145. nat/eval/rag_evaluator/register.py +143 -0
  146. nat/eval/register.py +23 -0
  147. nat/eval/remote_workflow.py +133 -0
  148. nat/eval/runners/__init__.py +14 -0
  149. nat/eval/runners/config.py +39 -0
  150. nat/eval/runners/multi_eval_runner.py +54 -0
  151. nat/eval/runtime_event_subscriber.py +52 -0
  152. nat/eval/swe_bench_evaluator/__init__.py +0 -0
  153. nat/eval/swe_bench_evaluator/evaluate.py +215 -0
  154. nat/eval/swe_bench_evaluator/register.py +36 -0
  155. nat/eval/trajectory_evaluator/__init__.py +0 -0
  156. nat/eval/trajectory_evaluator/evaluate.py +75 -0
  157. nat/eval/trajectory_evaluator/register.py +40 -0
  158. nat/eval/tunable_rag_evaluator/__init__.py +0 -0
  159. nat/eval/tunable_rag_evaluator/evaluate.py +245 -0
  160. nat/eval/tunable_rag_evaluator/register.py +52 -0
  161. nat/eval/usage_stats.py +41 -0
  162. nat/eval/utils/__init__.py +0 -0
  163. nat/eval/utils/output_uploader.py +140 -0
  164. nat/eval/utils/tqdm_position_registry.py +40 -0
  165. nat/eval/utils/weave_eval.py +184 -0
  166. nat/experimental/__init__.py +0 -0
  167. nat/experimental/decorators/__init__.py +0 -0
  168. nat/experimental/decorators/experimental_warning_decorator.py +134 -0
  169. nat/experimental/test_time_compute/__init__.py +0 -0
  170. nat/experimental/test_time_compute/editing/__init__.py +0 -0
  171. nat/experimental/test_time_compute/editing/iterative_plan_refinement_editor.py +147 -0
  172. nat/experimental/test_time_compute/editing/llm_as_a_judge_editor.py +204 -0
  173. nat/experimental/test_time_compute/editing/motivation_aware_summarization.py +107 -0
  174. nat/experimental/test_time_compute/functions/__init__.py +0 -0
  175. nat/experimental/test_time_compute/functions/execute_score_select_function.py +105 -0
  176. nat/experimental/test_time_compute/functions/plan_select_execute_function.py +224 -0
  177. nat/experimental/test_time_compute/functions/ttc_tool_orchestration_function.py +205 -0
  178. nat/experimental/test_time_compute/functions/ttc_tool_wrapper_function.py +146 -0
  179. nat/experimental/test_time_compute/models/__init__.py +0 -0
  180. nat/experimental/test_time_compute/models/editor_config.py +132 -0
  181. nat/experimental/test_time_compute/models/scoring_config.py +112 -0
  182. nat/experimental/test_time_compute/models/search_config.py +120 -0
  183. nat/experimental/test_time_compute/models/selection_config.py +154 -0
  184. nat/experimental/test_time_compute/models/stage_enums.py +43 -0
  185. nat/experimental/test_time_compute/models/strategy_base.py +66 -0
  186. nat/experimental/test_time_compute/models/tool_use_config.py +41 -0
  187. nat/experimental/test_time_compute/models/ttc_item.py +48 -0
  188. nat/experimental/test_time_compute/register.py +36 -0
  189. nat/experimental/test_time_compute/scoring/__init__.py +0 -0
  190. nat/experimental/test_time_compute/scoring/llm_based_agent_scorer.py +168 -0
  191. nat/experimental/test_time_compute/scoring/llm_based_plan_scorer.py +168 -0
  192. nat/experimental/test_time_compute/scoring/motivation_aware_scorer.py +111 -0
  193. nat/experimental/test_time_compute/search/__init__.py +0 -0
  194. nat/experimental/test_time_compute/search/multi_llm_planner.py +128 -0
  195. nat/experimental/test_time_compute/search/multi_query_retrieval_search.py +122 -0
  196. nat/experimental/test_time_compute/search/single_shot_multi_plan_planner.py +128 -0
  197. nat/experimental/test_time_compute/selection/__init__.py +0 -0
  198. nat/experimental/test_time_compute/selection/best_of_n_selector.py +63 -0
  199. nat/experimental/test_time_compute/selection/llm_based_agent_output_selector.py +131 -0
  200. nat/experimental/test_time_compute/selection/llm_based_output_merging_selector.py +159 -0
  201. nat/experimental/test_time_compute/selection/llm_based_plan_selector.py +128 -0
  202. nat/experimental/test_time_compute/selection/threshold_selector.py +58 -0
  203. nat/front_ends/__init__.py +14 -0
  204. nat/front_ends/console/__init__.py +14 -0
  205. nat/front_ends/console/authentication_flow_handler.py +233 -0
  206. nat/front_ends/console/console_front_end_config.py +32 -0
  207. nat/front_ends/console/console_front_end_plugin.py +96 -0
  208. nat/front_ends/console/register.py +25 -0
  209. nat/front_ends/cron/__init__.py +14 -0
  210. nat/front_ends/fastapi/__init__.py +14 -0
  211. nat/front_ends/fastapi/auth_flow_handlers/__init__.py +0 -0
  212. nat/front_ends/fastapi/auth_flow_handlers/http_flow_handler.py +27 -0
  213. nat/front_ends/fastapi/auth_flow_handlers/websocket_flow_handler.py +107 -0
  214. nat/front_ends/fastapi/fastapi_front_end_config.py +241 -0
  215. nat/front_ends/fastapi/fastapi_front_end_controller.py +68 -0
  216. nat/front_ends/fastapi/fastapi_front_end_plugin.py +116 -0
  217. nat/front_ends/fastapi/fastapi_front_end_plugin_worker.py +1087 -0
  218. nat/front_ends/fastapi/html_snippets/__init__.py +14 -0
  219. nat/front_ends/fastapi/html_snippets/auth_code_grant_success.py +35 -0
  220. nat/front_ends/fastapi/intermediate_steps_subscriber.py +80 -0
  221. nat/front_ends/fastapi/job_store.py +183 -0
  222. nat/front_ends/fastapi/main.py +72 -0
  223. nat/front_ends/fastapi/message_handler.py +320 -0
  224. nat/front_ends/fastapi/message_validator.py +352 -0
  225. nat/front_ends/fastapi/register.py +25 -0
  226. nat/front_ends/fastapi/response_helpers.py +195 -0
  227. nat/front_ends/fastapi/step_adaptor.py +319 -0
  228. nat/front_ends/mcp/__init__.py +14 -0
  229. nat/front_ends/mcp/mcp_front_end_config.py +36 -0
  230. nat/front_ends/mcp/mcp_front_end_plugin.py +81 -0
  231. nat/front_ends/mcp/mcp_front_end_plugin_worker.py +143 -0
  232. nat/front_ends/mcp/register.py +27 -0
  233. nat/front_ends/mcp/tool_converter.py +241 -0
  234. nat/front_ends/register.py +22 -0
  235. nat/front_ends/simple_base/__init__.py +14 -0
  236. nat/front_ends/simple_base/simple_front_end_plugin_base.py +54 -0
  237. nat/llm/__init__.py +0 -0
  238. nat/llm/aws_bedrock_llm.py +57 -0
  239. nat/llm/nim_llm.py +46 -0
  240. nat/llm/openai_llm.py +46 -0
  241. nat/llm/register.py +23 -0
  242. nat/llm/utils/__init__.py +14 -0
  243. nat/llm/utils/env_config_value.py +94 -0
  244. nat/llm/utils/error.py +17 -0
  245. nat/memory/__init__.py +20 -0
  246. nat/memory/interfaces.py +183 -0
  247. nat/memory/models.py +112 -0
  248. nat/meta/pypi.md +58 -0
  249. nat/object_store/__init__.py +20 -0
  250. nat/object_store/in_memory_object_store.py +76 -0
  251. nat/object_store/interfaces.py +84 -0
  252. nat/object_store/models.py +38 -0
  253. nat/object_store/register.py +20 -0
  254. nat/observability/__init__.py +14 -0
  255. nat/observability/exporter/__init__.py +14 -0
  256. nat/observability/exporter/base_exporter.py +449 -0
  257. nat/observability/exporter/exporter.py +78 -0
  258. nat/observability/exporter/file_exporter.py +33 -0
  259. nat/observability/exporter/processing_exporter.py +322 -0
  260. nat/observability/exporter/raw_exporter.py +52 -0
  261. nat/observability/exporter/span_exporter.py +288 -0
  262. nat/observability/exporter_manager.py +335 -0
  263. nat/observability/mixin/__init__.py +14 -0
  264. nat/observability/mixin/batch_config_mixin.py +26 -0
  265. nat/observability/mixin/collector_config_mixin.py +23 -0
  266. nat/observability/mixin/file_mixin.py +288 -0
  267. nat/observability/mixin/file_mode.py +23 -0
  268. nat/observability/mixin/resource_conflict_mixin.py +134 -0
  269. nat/observability/mixin/serialize_mixin.py +61 -0
  270. nat/observability/mixin/type_introspection_mixin.py +183 -0
  271. nat/observability/processor/__init__.py +14 -0
  272. nat/observability/processor/batching_processor.py +310 -0
  273. nat/observability/processor/callback_processor.py +42 -0
  274. nat/observability/processor/intermediate_step_serializer.py +28 -0
  275. nat/observability/processor/processor.py +71 -0
  276. nat/observability/register.py +96 -0
  277. nat/observability/utils/__init__.py +14 -0
  278. nat/observability/utils/dict_utils.py +236 -0
  279. nat/observability/utils/time_utils.py +31 -0
  280. nat/plugins/.namespace +1 -0
  281. nat/profiler/__init__.py +0 -0
  282. nat/profiler/calc/__init__.py +14 -0
  283. nat/profiler/calc/calc_runner.py +627 -0
  284. nat/profiler/calc/calculations.py +288 -0
  285. nat/profiler/calc/data_models.py +188 -0
  286. nat/profiler/calc/plot.py +345 -0
  287. nat/profiler/callbacks/__init__.py +0 -0
  288. nat/profiler/callbacks/agno_callback_handler.py +295 -0
  289. nat/profiler/callbacks/base_callback_class.py +20 -0
  290. nat/profiler/callbacks/langchain_callback_handler.py +290 -0
  291. nat/profiler/callbacks/llama_index_callback_handler.py +205 -0
  292. nat/profiler/callbacks/semantic_kernel_callback_handler.py +238 -0
  293. nat/profiler/callbacks/token_usage_base_model.py +27 -0
  294. nat/profiler/data_frame_row.py +51 -0
  295. nat/profiler/data_models.py +24 -0
  296. nat/profiler/decorators/__init__.py +0 -0
  297. nat/profiler/decorators/framework_wrapper.py +131 -0
  298. nat/profiler/decorators/function_tracking.py +254 -0
  299. nat/profiler/forecasting/__init__.py +0 -0
  300. nat/profiler/forecasting/config.py +18 -0
  301. nat/profiler/forecasting/model_trainer.py +75 -0
  302. nat/profiler/forecasting/models/__init__.py +22 -0
  303. nat/profiler/forecasting/models/forecasting_base_model.py +40 -0
  304. nat/profiler/forecasting/models/linear_model.py +197 -0
  305. nat/profiler/forecasting/models/random_forest_regressor.py +269 -0
  306. nat/profiler/inference_metrics_model.py +28 -0
  307. nat/profiler/inference_optimization/__init__.py +0 -0
  308. nat/profiler/inference_optimization/bottleneck_analysis/__init__.py +0 -0
  309. nat/profiler/inference_optimization/bottleneck_analysis/nested_stack_analysis.py +460 -0
  310. nat/profiler/inference_optimization/bottleneck_analysis/simple_stack_analysis.py +258 -0
  311. nat/profiler/inference_optimization/data_models.py +386 -0
  312. nat/profiler/inference_optimization/experimental/__init__.py +0 -0
  313. nat/profiler/inference_optimization/experimental/concurrency_spike_analysis.py +468 -0
  314. nat/profiler/inference_optimization/experimental/prefix_span_analysis.py +405 -0
  315. nat/profiler/inference_optimization/llm_metrics.py +212 -0
  316. nat/profiler/inference_optimization/prompt_caching.py +163 -0
  317. nat/profiler/inference_optimization/token_uniqueness.py +107 -0
  318. nat/profiler/inference_optimization/workflow_runtimes.py +72 -0
  319. nat/profiler/intermediate_property_adapter.py +102 -0
  320. nat/profiler/profile_runner.py +473 -0
  321. nat/profiler/utils.py +184 -0
  322. nat/registry_handlers/__init__.py +0 -0
  323. nat/registry_handlers/local/__init__.py +0 -0
  324. nat/registry_handlers/local/local_handler.py +176 -0
  325. nat/registry_handlers/local/register_local.py +37 -0
  326. nat/registry_handlers/metadata_factory.py +60 -0
  327. nat/registry_handlers/package_utils.py +571 -0
  328. nat/registry_handlers/pypi/__init__.py +0 -0
  329. nat/registry_handlers/pypi/pypi_handler.py +251 -0
  330. nat/registry_handlers/pypi/register_pypi.py +40 -0
  331. nat/registry_handlers/register.py +21 -0
  332. nat/registry_handlers/registry_handler_base.py +157 -0
  333. nat/registry_handlers/rest/__init__.py +0 -0
  334. nat/registry_handlers/rest/register_rest.py +56 -0
  335. nat/registry_handlers/rest/rest_handler.py +237 -0
  336. nat/registry_handlers/schemas/__init__.py +0 -0
  337. nat/registry_handlers/schemas/headers.py +42 -0
  338. nat/registry_handlers/schemas/package.py +68 -0
  339. nat/registry_handlers/schemas/publish.py +68 -0
  340. nat/registry_handlers/schemas/pull.py +82 -0
  341. nat/registry_handlers/schemas/remove.py +36 -0
  342. nat/registry_handlers/schemas/search.py +91 -0
  343. nat/registry_handlers/schemas/status.py +47 -0
  344. nat/retriever/__init__.py +0 -0
  345. nat/retriever/interface.py +41 -0
  346. nat/retriever/milvus/__init__.py +14 -0
  347. nat/retriever/milvus/register.py +81 -0
  348. nat/retriever/milvus/retriever.py +228 -0
  349. nat/retriever/models.py +77 -0
  350. nat/retriever/nemo_retriever/__init__.py +14 -0
  351. nat/retriever/nemo_retriever/register.py +60 -0
  352. nat/retriever/nemo_retriever/retriever.py +190 -0
  353. nat/retriever/register.py +22 -0
  354. nat/runtime/__init__.py +14 -0
  355. nat/runtime/loader.py +220 -0
  356. nat/runtime/runner.py +195 -0
  357. nat/runtime/session.py +162 -0
  358. nat/runtime/user_metadata.py +130 -0
  359. nat/settings/__init__.py +0 -0
  360. nat/settings/global_settings.py +318 -0
  361. nat/test/.namespace +1 -0
  362. nat/tool/__init__.py +0 -0
  363. nat/tool/chat_completion.py +74 -0
  364. nat/tool/code_execution/README.md +151 -0
  365. nat/tool/code_execution/__init__.py +0 -0
  366. nat/tool/code_execution/code_sandbox.py +267 -0
  367. nat/tool/code_execution/local_sandbox/.gitignore +1 -0
  368. nat/tool/code_execution/local_sandbox/Dockerfile.sandbox +60 -0
  369. nat/tool/code_execution/local_sandbox/__init__.py +13 -0
  370. nat/tool/code_execution/local_sandbox/local_sandbox_server.py +198 -0
  371. nat/tool/code_execution/local_sandbox/sandbox.requirements.txt +6 -0
  372. nat/tool/code_execution/local_sandbox/start_local_sandbox.sh +50 -0
  373. nat/tool/code_execution/register.py +74 -0
  374. nat/tool/code_execution/test_code_execution_sandbox.py +414 -0
  375. nat/tool/code_execution/utils.py +100 -0
  376. nat/tool/datetime_tools.py +42 -0
  377. nat/tool/document_search.py +141 -0
  378. nat/tool/github_tools/__init__.py +0 -0
  379. nat/tool/github_tools/create_github_commit.py +133 -0
  380. nat/tool/github_tools/create_github_issue.py +87 -0
  381. nat/tool/github_tools/create_github_pr.py +106 -0
  382. nat/tool/github_tools/get_github_file.py +106 -0
  383. nat/tool/github_tools/get_github_issue.py +166 -0
  384. nat/tool/github_tools/get_github_pr.py +256 -0
  385. nat/tool/github_tools/update_github_issue.py +100 -0
  386. nat/tool/mcp/__init__.py +14 -0
  387. nat/tool/mcp/exceptions.py +142 -0
  388. nat/tool/mcp/mcp_client.py +255 -0
  389. nat/tool/mcp/mcp_tool.py +96 -0
  390. nat/tool/memory_tools/__init__.py +0 -0
  391. nat/tool/memory_tools/add_memory_tool.py +79 -0
  392. nat/tool/memory_tools/delete_memory_tool.py +67 -0
  393. nat/tool/memory_tools/get_memory_tool.py +72 -0
  394. nat/tool/nvidia_rag.py +95 -0
  395. nat/tool/register.py +38 -0
  396. nat/tool/retriever.py +94 -0
  397. nat/tool/server_tools.py +66 -0
  398. nat/utils/__init__.py +0 -0
  399. nat/utils/data_models/__init__.py +0 -0
  400. nat/utils/data_models/schema_validator.py +58 -0
  401. nat/utils/debugging_utils.py +43 -0
  402. nat/utils/dump_distro_mapping.py +32 -0
  403. nat/utils/exception_handlers/__init__.py +0 -0
  404. nat/utils/exception_handlers/automatic_retries.py +289 -0
  405. nat/utils/exception_handlers/mcp.py +211 -0
  406. nat/utils/exception_handlers/schemas.py +114 -0
  407. nat/utils/io/__init__.py +0 -0
  408. nat/utils/io/model_processing.py +28 -0
  409. nat/utils/io/yaml_tools.py +119 -0
  410. nat/utils/log_utils.py +37 -0
  411. nat/utils/metadata_utils.py +74 -0
  412. nat/utils/optional_imports.py +142 -0
  413. nat/utils/producer_consumer_queue.py +178 -0
  414. nat/utils/reactive/__init__.py +0 -0
  415. nat/utils/reactive/base/__init__.py +0 -0
  416. nat/utils/reactive/base/observable_base.py +65 -0
  417. nat/utils/reactive/base/observer_base.py +55 -0
  418. nat/utils/reactive/base/subject_base.py +79 -0
  419. nat/utils/reactive/observable.py +59 -0
  420. nat/utils/reactive/observer.py +76 -0
  421. nat/utils/reactive/subject.py +131 -0
  422. nat/utils/reactive/subscription.py +49 -0
  423. nat/utils/settings/__init__.py +0 -0
  424. nat/utils/settings/global_settings.py +197 -0
  425. nat/utils/string_utils.py +38 -0
  426. nat/utils/type_converter.py +290 -0
  427. nat/utils/type_utils.py +484 -0
  428. nat/utils/url_utils.py +27 -0
  429. nvidia_nat-1.2.0.dist-info/METADATA +365 -0
  430. nvidia_nat-1.2.0.dist-info/RECORD +435 -0
  431. nvidia_nat-1.2.0.dist-info/WHEEL +5 -0
  432. nvidia_nat-1.2.0.dist-info/entry_points.txt +21 -0
  433. nvidia_nat-1.2.0.dist-info/licenses/LICENSE-3rd-party.txt +5478 -0
  434. nvidia_nat-1.2.0.dist-info/licenses/LICENSE.md +201 -0
  435. nvidia_nat-1.2.0.dist-info/top_level.txt +2 -0
@@ -0,0 +1,317 @@
1
+ # SPDX-FileCopyrightText: Copyright (c) 2024-2025, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2
+ # SPDX-License-Identifier: Apache-2.0
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ import logging
17
+ import os.path
18
+ import shutil
19
+ import subprocess
20
+ from pathlib import Path
21
+ from urllib.parse import urlparse
22
+
23
+ import click
24
+ from jinja2 import Environment
25
+ from jinja2 import FileSystemLoader
26
+
27
+ logger = logging.getLogger(__name__)
28
+
29
+
30
+ class PackageError(Exception):
31
+ pass
32
+
33
+
34
+ def get_repo_root():
35
+ return find_package_root("nvidia-nat")
36
+
37
+
38
+ def _get_module_name(workflow_name: str):
39
+ return workflow_name.replace("-", "_")
40
+
41
+
42
+ def _generate_valid_classname(class_name: str):
43
+ return class_name.replace('_', ' ').replace('-', ' ').title().replace(' ', '')
44
+
45
+
46
+ def find_package_root(package_name: str) -> Path | None:
47
+ """
48
+ Find the root directory for a python package installed with the "editable" option.
49
+
50
+ Args:
51
+ package_name: The python package name as it appears when importing it into a python script
52
+
53
+ Returns:
54
+ Posix path pointing to the package root
55
+ """
56
+ import json
57
+ from importlib.metadata import Distribution
58
+ from importlib.metadata import PackageNotFoundError
59
+
60
+ try:
61
+ dist_info = Distribution.from_name(package_name)
62
+ direct_url = dist_info.read_text("direct_url.json")
63
+ if not direct_url:
64
+ return None
65
+
66
+ try:
67
+ info = json.loads(direct_url)
68
+ except json.JSONDecodeError:
69
+ logger.error("Malformed direct_url.json for package: %s", package_name)
70
+ return None
71
+
72
+ if not info.get("dir_info", {}).get("editable"):
73
+ return None
74
+
75
+ # Parse URL
76
+ url = info.get("url", "")
77
+ parsed_url = urlparse(url)
78
+
79
+ if parsed_url.scheme != "file":
80
+ logger.error("Invalid URL scheme in direct_url.json: %s", url)
81
+ return None
82
+
83
+ package_root = Path(parsed_url.path).resolve()
84
+
85
+ # Ensure the path exists and is within an allowed base directory
86
+ if not package_root.exists() or not package_root.is_dir():
87
+ logger.error("Package root does not exist: %s", package_root)
88
+ return None
89
+
90
+ return package_root
91
+
92
+ except TypeError:
93
+ return None
94
+
95
+ except PackageNotFoundError as e:
96
+ raise PackageError(f"Package {package_name} is not installed") from e
97
+
98
+
99
+ def get_workflow_path_from_name(workflow_name: str):
100
+ """
101
+ Look up the location of an installed NAT workflow and retrieve the root directory of the installed workflow.
102
+
103
+ Args:
104
+ workflow_name: The name of the workflow.
105
+
106
+ Returns:
107
+ Path object for the workflow's root directory.
108
+ """
109
+ # Get the module name as a valid package name.
110
+ try:
111
+ module_name = _get_module_name(workflow_name)
112
+ package_root = find_package_root(module_name)
113
+ return package_root
114
+
115
+ except PackageError as e:
116
+ logger.info("Unable to get the directory path for %s: %s", workflow_name, e)
117
+ return None
118
+
119
+
120
+ @click.command()
121
+ @click.argument('workflow_name')
122
+ @click.option('--install/--no-install', default=True, help="Whether to install the workflow package immediately.")
123
+ @click.option(
124
+ "--workflow-dir",
125
+ default=".",
126
+ help="Output directory for saving the created workflow. A new folder with the workflow name will be created "
127
+ "within. Defaults to the present working directory.")
128
+ @click.option(
129
+ "--description",
130
+ default="NAT function template. Please update the description.",
131
+ help="""A description of the component being created. Will be used to populate the docstring and will describe the
132
+ component when inspecting installed components using 'nat info component'""")
133
+ # pylint: disable=missing-param-doc
134
+ def create_command(workflow_name: str, install: bool, workflow_dir: str, description: str):
135
+ """
136
+ Create a new NAT workflow using templates.
137
+
138
+ Args:
139
+ workflow_name (str): The name of the new workflow.
140
+ install (bool): Whether to install the workflow package immediately.
141
+ workflow_dir (str): The directory to create the workflow package.
142
+ description (str): Description to pre-popluate the workflow docstring.
143
+ """
144
+ try:
145
+ # Get the repository root
146
+ try:
147
+ repo_root = get_repo_root()
148
+ except PackageError:
149
+ repo_root = None
150
+
151
+ # Get the absolute path for the output directory
152
+ if not os.path.isabs(workflow_dir):
153
+ workflow_dir = os.path.abspath(workflow_dir)
154
+
155
+ if not os.path.exists(workflow_dir):
156
+ raise ValueError(f"Invalid workflow directory specified. {workflow_dir} does not exist.")
157
+
158
+ # Define paths
159
+ template_dir = Path(__file__).parent / 'templates'
160
+ new_workflow_dir = Path(workflow_dir) / workflow_name
161
+ package_name = _get_module_name(workflow_name)
162
+ rel_path_to_repo_root = "" if not repo_root else os.path.relpath(repo_root, new_workflow_dir)
163
+
164
+ # Check if the workflow already exists
165
+ if new_workflow_dir.exists():
166
+ click.echo(f"Workflow '{workflow_name}' already exists.")
167
+ return
168
+
169
+ # Create directory structure
170
+ (new_workflow_dir / 'src' / package_name).mkdir(parents=True)
171
+ # Create config directory
172
+ (new_workflow_dir / 'src' / package_name / 'configs').mkdir(parents=True)
173
+ # Create package level configs directory
174
+ (new_workflow_dir / 'configs').mkdir(parents=True)
175
+
176
+ # Initialize Jinja2 environment
177
+ env = Environment(loader=FileSystemLoader(str(template_dir)))
178
+ editable = get_repo_root() is not None
179
+
180
+ if editable:
181
+ install_cmd = ['uv', 'pip', 'install', '-e', str(new_workflow_dir)]
182
+ else:
183
+ install_cmd = ['pip', 'install', '-e', str(new_workflow_dir)]
184
+
185
+ # List of templates and their destinations
186
+ files_to_render = {
187
+ 'pyproject.toml.j2': new_workflow_dir / 'pyproject.toml',
188
+ 'register.py.j2': new_workflow_dir / 'src' / package_name / 'register.py',
189
+ 'workflow.py.j2': new_workflow_dir / 'src' / package_name / f'{workflow_name}_function.py',
190
+ '__init__.py.j2': new_workflow_dir / 'src' / package_name / '__init__.py',
191
+ 'config.yml.j2': new_workflow_dir / 'src' / package_name / 'configs' / 'config.yml',
192
+ }
193
+
194
+ # Render templates
195
+ context = {
196
+ 'editable': editable,
197
+ 'workflow_name': workflow_name,
198
+ 'python_safe_workflow_name': workflow_name.replace("-", "_"),
199
+ 'package_name': package_name,
200
+ 'rel_path_to_repo_root': rel_path_to_repo_root,
201
+ 'workflow_class_name': f"{_generate_valid_classname(workflow_name)}FunctionConfig",
202
+ 'workflow_description': description
203
+ }
204
+
205
+ for template_name, output_path in files_to_render.items():
206
+ template = env.get_template(template_name)
207
+ content = template.render(context)
208
+ with open(output_path, 'w', encoding="utf-8") as f:
209
+ f.write(content)
210
+
211
+ # Create symlink for config.yml
212
+ config_source = new_workflow_dir / 'src' / package_name / 'configs' / 'config.yml'
213
+ config_link = new_workflow_dir / 'configs' / 'config.yml'
214
+ os.symlink(config_source, config_link)
215
+
216
+ if install:
217
+ # Install the new package without changing directories
218
+ click.echo(f"Installing workflow '{workflow_name}'...")
219
+ result = subprocess.run(install_cmd, capture_output=True, text=True, check=True)
220
+
221
+ if result.returncode != 0:
222
+ click.echo(f"An error occurred during installation:\n{result.stderr}")
223
+ return
224
+
225
+ click.echo(f"Workflow '{workflow_name}' installed successfully.")
226
+
227
+ click.echo(f"Workflow '{workflow_name}' created successfully in '{new_workflow_dir}'.")
228
+ except Exception as e:
229
+ logger.exception("An error occurred while creating the workflow: %s", e, exc_info=True)
230
+ click.echo(f"An error occurred while creating the workflow: {e}")
231
+
232
+
233
+ @click.command()
234
+ @click.argument('workflow_name')
235
+ def reinstall_command(workflow_name):
236
+ """
237
+ Reinstall a NAT workflow to update dependencies and code changes.
238
+
239
+ Args:
240
+ workflow_name (str): The name of the workflow to reinstall.
241
+ """
242
+ try:
243
+ editable = get_repo_root() is not None
244
+
245
+ workflow_dir = get_workflow_path_from_name(workflow_name)
246
+ if not workflow_dir or not workflow_dir.exists():
247
+ click.echo(f"Workflow '{workflow_name}' does not exist.")
248
+ return
249
+
250
+ # Reinstall the package without changing directories
251
+ click.echo(f"Reinstalling workflow '{workflow_name}'...")
252
+ if editable:
253
+ reinstall_cmd = ['uv', 'pip', 'install', '-e', str(workflow_dir)]
254
+ else:
255
+ reinstall_cmd = ['pip', 'install', '-e', str(workflow_dir)]
256
+
257
+ result = subprocess.run(reinstall_cmd, capture_output=True, text=True, check=True)
258
+
259
+ if result.returncode != 0:
260
+ click.echo(f"An error occurred during installation:\n{result.stderr}")
261
+ return
262
+
263
+ click.echo(f"Workflow '{workflow_name}' reinstalled successfully.")
264
+ except Exception as e:
265
+ logger.exception("An error occurred while reinstalling the workflow: %s", e, exc_info=True)
266
+ click.echo(f"An error occurred while reinstalling the workflow: {e}")
267
+
268
+
269
+ @click.command()
270
+ @click.argument('workflow_name')
271
+ def delete_command(workflow_name: str):
272
+ """
273
+ Delete a NAT workflow and uninstall its package.
274
+
275
+ Args:
276
+ workflow_name (str): The name of the workflow to delete.
277
+ """
278
+ try:
279
+ if not click.confirm(f"Are you sure you want to delete the workflow '{workflow_name}'?"):
280
+ click.echo("Workflow deletion cancelled.")
281
+ return
282
+ editable = get_repo_root() is not None
283
+
284
+ workflow_dir = get_workflow_path_from_name(workflow_name)
285
+ package_name = _get_module_name(workflow_name)
286
+
287
+ if editable:
288
+ uninstall_cmd = ['uv', 'pip', 'uninstall', package_name]
289
+ else:
290
+ uninstall_cmd = ['pip', 'uninstall', '-y', package_name]
291
+
292
+ # Uninstall the package
293
+ click.echo(f"Uninstalling workflow '{workflow_name}' package...")
294
+ result = subprocess.run(uninstall_cmd, capture_output=True, text=True, check=True)
295
+
296
+ if result.returncode != 0:
297
+ click.echo(f"An error occurred during uninstallation:\n{result.stderr}")
298
+ return
299
+ click.echo(
300
+ f"Workflow '{workflow_name}' (package '{package_name}') successfully uninstalled from python environment")
301
+
302
+ if not workflow_dir or not workflow_dir.exists():
303
+ click.echo(f"Unable to locate local files for {workflow_name}. Nothing will be deleted.")
304
+ return
305
+
306
+ # Remove the workflow directory
307
+ click.echo(f"Deleting workflow directory '{workflow_dir}'...")
308
+ shutil.rmtree(workflow_dir)
309
+
310
+ click.echo(f"Workflow '{workflow_name}' deleted successfully.")
311
+ except Exception as e:
312
+ logger.exception("An error occurred while deleting the workflow: %s", e, exc_info=True)
313
+ click.echo(f"An error occurred while deleting the workflow: {e}")
314
+
315
+
316
+ # Compatibility aliases with previous releases
317
+ AIQPackageError = PackageError
nat/cli/entrypoint.py ADDED
@@ -0,0 +1,135 @@
1
+ # SPDX-FileCopyrightText: Copyright (c) 2024-2025, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2
+ # SPDX-License-Identifier: Apache-2.0
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ # SPDX-FileCopyrightText: Copyright (c) 2024-2025, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
17
+ # SPDX-License-Identifier: LicenseRef-NvidiaProprietary
18
+ #
19
+ # NVIDIA CORPORATION, its affiliates and licensors retain all intellectual
20
+ # property and proprietary rights in and to this material, related
21
+ # documentation and any modifications thereto. Any use, reproduction,
22
+ # disclosure or distribution of this material and related documentation
23
+ # without an express license agreement from NVIDIA CORPORATION or
24
+ # its affiliates is strictly prohibited.
25
+
26
+ import logging
27
+ import sys
28
+ import time
29
+
30
+ import click
31
+ import nest_asyncio
32
+
33
+ from .commands.configure.configure import configure_command
34
+ from .commands.evaluate import eval_command
35
+ from .commands.info.info import info_command
36
+ from .commands.registry.registry import registry_command
37
+ from .commands.sizing.sizing import sizing
38
+ from .commands.start import start_command
39
+ from .commands.uninstall import uninstall_command
40
+ from .commands.validate import validate_command
41
+ from .commands.workflow.workflow import workflow_command
42
+
43
+ # Apply at the beginning of the file to avoid issues with asyncio
44
+ nest_asyncio.apply()
45
+
46
+ # Define log level choices
47
+ LOG_LEVELS = {
48
+ 'DEBUG': logging.DEBUG,
49
+ 'INFO': logging.INFO,
50
+ 'WARNING': logging.WARNING,
51
+ 'ERROR': logging.ERROR,
52
+ 'CRITICAL': logging.CRITICAL
53
+ }
54
+
55
+
56
+ def setup_logging(log_level: str):
57
+ """Configure logging with the specified level"""
58
+ numeric_level = LOG_LEVELS.get(log_level.upper(), logging.INFO)
59
+ logging.basicConfig(level=numeric_level, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
60
+ return numeric_level
61
+
62
+
63
+ def get_version():
64
+ from importlib.metadata import PackageNotFoundError
65
+ from importlib.metadata import version
66
+ try:
67
+ # Use the distro name to get the version
68
+ return version("nvidia-nat")
69
+ except PackageNotFoundError:
70
+ return "unknown"
71
+
72
+
73
+ @click.group(name="nat", chain=False, invoke_without_command=True, no_args_is_help=True)
74
+ @click.version_option(version=get_version())
75
+ @click.option('--log-level',
76
+ type=click.Choice(LOG_LEVELS.keys(), case_sensitive=False),
77
+ default='INFO',
78
+ help='Set the logging level')
79
+ @click.pass_context
80
+ def cli(ctx: click.Context, log_level: str):
81
+ """Main entrypoint for the NAT CLI"""
82
+
83
+ ctx_dict = ctx.ensure_object(dict)
84
+
85
+ # Setup logging
86
+ numeric_level = setup_logging(log_level)
87
+
88
+ nat_logger = logging.getLogger("nat")
89
+ nat_logger.setLevel(numeric_level)
90
+
91
+ logger = logging.getLogger(__package__)
92
+
93
+ # Set the parent logger for all of the llm examples to use morpheus so we can take advantage of configure_logging
94
+ logger.parent = nat_logger
95
+ logger.setLevel(numeric_level)
96
+
97
+ ctx_dict["start_time"] = time.time()
98
+ ctx_dict["log_level"] = log_level
99
+
100
+
101
+ cli.add_command(configure_command, name="configure")
102
+ cli.add_command(eval_command, name="eval")
103
+ cli.add_command(info_command, name="info")
104
+ cli.add_command(registry_command, name="registry")
105
+ cli.add_command(start_command, name="start")
106
+ cli.add_command(uninstall_command, name="uninstall")
107
+ cli.add_command(validate_command, name="validate")
108
+ cli.add_command(workflow_command, name="workflow")
109
+ cli.add_command(sizing, name="sizing")
110
+
111
+ # Aliases
112
+ cli.add_command(start_command.get_command(None, "console"), name="run") # type: ignore
113
+ cli.add_command(start_command.get_command(None, "fastapi"), name="serve") # type: ignore
114
+ cli.add_command(start_command.get_command(None, "mcp"), name="mcp")
115
+
116
+
117
+ @cli.result_callback()
118
+ @click.pass_context
119
+ def after_pipeline(ctx: click.Context, pipeline_start_time: float, *_, **__):
120
+ logger = logging.getLogger(__name__)
121
+
122
+ end_time = time.time()
123
+
124
+ ctx_dict = ctx.ensure_object(dict)
125
+
126
+ start_time = ctx_dict["start_time"]
127
+
128
+ # Reset the terminal colors, not using print to avoid an additional newline
129
+ for stream in (sys.stdout, sys.stderr):
130
+ stream.write("\x1b[0m")
131
+
132
+ logger.debug("Total time: %.2f sec", end_time - start_time)
133
+
134
+ if (pipeline_start_time is not None):
135
+ logger.debug("Pipeline runtime: %.2f sec", end_time - pipeline_start_time)
nat/cli/main.py ADDED
@@ -0,0 +1,57 @@
1
+ # SPDX-FileCopyrightText: Copyright (c) 2024-2025, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2
+ # SPDX-License-Identifier: Apache-2.0
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ # SPDX-FileCopyrightText: Copyright (c) 2024-2025, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
17
+ # SPDX-License-Identifier: LicenseRef-NvidiaProprietary
18
+ #
19
+ # NVIDIA CORPORATION, its affiliates and licensors retain all intellectual
20
+ # property and proprietary rights in and to this material, related
21
+ # documentation and any modifications thereto. Any use, reproduction,
22
+ # disclosure or distribution of this material and related documentation
23
+ # without an express license agreement from NVIDIA CORPORATION or
24
+ # its affiliates is strictly prohibited.
25
+
26
+
27
+ # The purpose of this function is to allow loading the current directory as a module. This allows relative imports and
28
+ # more specifically `..common` to function correctly
29
+ def run_cli():
30
+ import os
31
+ import sys
32
+
33
+ parent_dir = os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
34
+
35
+ if (parent_dir not in sys.path):
36
+ sys.path.append(parent_dir)
37
+
38
+ from nat.cli.entrypoint import cli
39
+
40
+ cli(obj={}, auto_envvar_prefix='NAT', show_default=True, prog_name="nat")
41
+
42
+
43
+ def run_cli_aiq_compat():
44
+ "Entrypoint for the `aiq` compatibility command"
45
+ import warnings
46
+
47
+ # Warn with a UserWarning since DeprecationWarnings are not shown by default
48
+ warnings.warn(
49
+ "The 'aiq' command is deprecated and will be removed in a future release. "
50
+ "Please use the 'nat' command instead.",
51
+ UserWarning,
52
+ stacklevel=2)
53
+ run_cli()
54
+
55
+
56
+ if __name__ == '__main__':
57
+ run_cli()