nvidia-nat 1.3.0a20250910__py3-none-any.whl → 1.3.0a20250922__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 (114) hide show
  1. nat/agent/base.py +9 -4
  2. nat/agent/prompt_optimizer/prompt.py +68 -0
  3. nat/agent/prompt_optimizer/register.py +149 -0
  4. nat/agent/react_agent/agent.py +1 -1
  5. nat/agent/react_agent/register.py +17 -14
  6. nat/agent/reasoning_agent/reasoning_agent.py +9 -7
  7. nat/agent/register.py +1 -0
  8. nat/agent/rewoo_agent/agent.py +9 -2
  9. nat/agent/rewoo_agent/register.py +16 -12
  10. nat/agent/tool_calling_agent/agent.py +69 -7
  11. nat/agent/tool_calling_agent/register.py +14 -13
  12. nat/authentication/credential_validator/__init__.py +14 -0
  13. nat/authentication/credential_validator/bearer_token_validator.py +557 -0
  14. nat/authentication/oauth2/oauth2_resource_server_config.py +124 -0
  15. nat/builder/builder.py +27 -4
  16. nat/builder/component_utils.py +7 -3
  17. nat/builder/context.py +28 -6
  18. nat/builder/function.py +313 -0
  19. nat/builder/function_info.py +1 -1
  20. nat/builder/workflow.py +5 -0
  21. nat/builder/workflow_builder.py +215 -16
  22. nat/cli/commands/optimize.py +90 -0
  23. nat/cli/commands/workflow/templates/config.yml.j2 +0 -1
  24. nat/cli/commands/workflow/workflow_commands.py +4 -7
  25. nat/cli/entrypoint.py +4 -9
  26. nat/cli/register_workflow.py +38 -4
  27. nat/cli/type_registry.py +71 -0
  28. nat/control_flow/__init__.py +0 -0
  29. nat/control_flow/register.py +20 -0
  30. nat/control_flow/router_agent/__init__.py +0 -0
  31. nat/control_flow/router_agent/agent.py +329 -0
  32. nat/control_flow/router_agent/prompt.py +48 -0
  33. nat/control_flow/router_agent/register.py +91 -0
  34. nat/control_flow/sequential_executor.py +167 -0
  35. nat/data_models/agent.py +34 -0
  36. nat/data_models/authentication.py +38 -0
  37. nat/data_models/component.py +2 -0
  38. nat/data_models/component_ref.py +11 -0
  39. nat/data_models/config.py +40 -16
  40. nat/data_models/function.py +34 -0
  41. nat/data_models/function_dependencies.py +8 -0
  42. nat/data_models/optimizable.py +119 -0
  43. nat/data_models/optimizer.py +149 -0
  44. nat/data_models/temperature_mixin.py +4 -3
  45. nat/data_models/top_p_mixin.py +4 -3
  46. nat/embedder/nim_embedder.py +1 -1
  47. nat/embedder/openai_embedder.py +1 -1
  48. nat/eval/config.py +1 -1
  49. nat/eval/evaluate.py +5 -1
  50. nat/eval/register.py +4 -0
  51. nat/eval/runtime_evaluator/__init__.py +14 -0
  52. nat/eval/runtime_evaluator/evaluate.py +123 -0
  53. nat/eval/runtime_evaluator/register.py +100 -0
  54. nat/experimental/test_time_compute/functions/plan_select_execute_function.py +5 -1
  55. nat/front_ends/fastapi/dask_client_mixin.py +65 -0
  56. nat/front_ends/fastapi/fastapi_front_end_config.py +18 -3
  57. nat/front_ends/fastapi/fastapi_front_end_plugin.py +134 -3
  58. nat/front_ends/fastapi/fastapi_front_end_plugin_worker.py +243 -228
  59. nat/front_ends/fastapi/job_store.py +518 -99
  60. nat/front_ends/fastapi/main.py +11 -19
  61. nat/front_ends/fastapi/utils.py +57 -0
  62. nat/front_ends/mcp/introspection_token_verifier.py +73 -0
  63. nat/front_ends/mcp/mcp_front_end_config.py +5 -1
  64. nat/front_ends/mcp/mcp_front_end_plugin.py +37 -11
  65. nat/front_ends/mcp/mcp_front_end_plugin_worker.py +111 -3
  66. nat/front_ends/mcp/tool_converter.py +3 -0
  67. nat/llm/aws_bedrock_llm.py +14 -3
  68. nat/llm/nim_llm.py +14 -3
  69. nat/llm/openai_llm.py +8 -1
  70. nat/observability/exporter/processing_exporter.py +29 -55
  71. nat/observability/mixin/redaction_config_mixin.py +5 -4
  72. nat/observability/mixin/tagging_config_mixin.py +26 -14
  73. nat/observability/mixin/type_introspection_mixin.py +420 -107
  74. nat/observability/processor/processor.py +3 -0
  75. nat/observability/processor/redaction/__init__.py +24 -0
  76. nat/observability/processor/redaction/contextual_redaction_processor.py +125 -0
  77. nat/observability/processor/redaction/contextual_span_redaction_processor.py +66 -0
  78. nat/observability/processor/redaction/redaction_processor.py +177 -0
  79. nat/observability/processor/redaction/span_header_redaction_processor.py +92 -0
  80. nat/observability/processor/span_tagging_processor.py +21 -14
  81. nat/profiler/decorators/framework_wrapper.py +9 -6
  82. nat/profiler/parameter_optimization/__init__.py +0 -0
  83. nat/profiler/parameter_optimization/optimizable_utils.py +93 -0
  84. nat/profiler/parameter_optimization/optimizer_runtime.py +67 -0
  85. nat/profiler/parameter_optimization/parameter_optimizer.py +153 -0
  86. nat/profiler/parameter_optimization/parameter_selection.py +108 -0
  87. nat/profiler/parameter_optimization/pareto_visualizer.py +380 -0
  88. nat/profiler/parameter_optimization/prompt_optimizer.py +384 -0
  89. nat/profiler/parameter_optimization/update_helpers.py +66 -0
  90. nat/profiler/utils.py +3 -1
  91. nat/tool/chat_completion.py +4 -1
  92. nat/tool/github_tools.py +450 -0
  93. nat/tool/register.py +2 -7
  94. nat/utils/callable_utils.py +70 -0
  95. nat/utils/exception_handlers/automatic_retries.py +103 -48
  96. nat/utils/log_levels.py +25 -0
  97. nat/utils/type_utils.py +4 -0
  98. {nvidia_nat-1.3.0a20250910.dist-info → nvidia_nat-1.3.0a20250922.dist-info}/METADATA +10 -1
  99. {nvidia_nat-1.3.0a20250910.dist-info → nvidia_nat-1.3.0a20250922.dist-info}/RECORD +105 -76
  100. {nvidia_nat-1.3.0a20250910.dist-info → nvidia_nat-1.3.0a20250922.dist-info}/entry_points.txt +1 -0
  101. nat/observability/processor/header_redaction_processor.py +0 -123
  102. nat/observability/processor/redaction_processor.py +0 -77
  103. nat/tool/github_tools/create_github_commit.py +0 -133
  104. nat/tool/github_tools/create_github_issue.py +0 -87
  105. nat/tool/github_tools/create_github_pr.py +0 -106
  106. nat/tool/github_tools/get_github_file.py +0 -106
  107. nat/tool/github_tools/get_github_issue.py +0 -166
  108. nat/tool/github_tools/get_github_pr.py +0 -256
  109. nat/tool/github_tools/update_github_issue.py +0 -100
  110. /nat/{tool/github_tools → agent/prompt_optimizer}/__init__.py +0 -0
  111. {nvidia_nat-1.3.0a20250910.dist-info → nvidia_nat-1.3.0a20250922.dist-info}/WHEEL +0 -0
  112. {nvidia_nat-1.3.0a20250910.dist-info → nvidia_nat-1.3.0a20250922.dist-info}/licenses/LICENSE-3rd-party.txt +0 -0
  113. {nvidia_nat-1.3.0a20250910.dist-info → nvidia_nat-1.3.0a20250922.dist-info}/licenses/LICENSE.md +0 -0
  114. {nvidia_nat-1.3.0a20250910.dist-info → nvidia_nat-1.3.0a20250922.dist-info}/top_level.txt +0 -0
@@ -118,6 +118,7 @@ def _retry_decorator(
118
118
  retry_codes: Sequence[CodePattern] | None = None,
119
119
  retry_on_messages: Sequence[str] | None = None,
120
120
  deepcopy: bool = False,
121
+ instance_context_aware: bool = False,
121
122
  ) -> Callable[[Callable[..., T]], Callable[..., T]]:
122
123
  """
123
124
  Build a decorator that retries with exponential back-off *iff*:
@@ -130,69 +131,122 @@ def _retry_decorator(
130
131
  deepcopy:
131
132
  If True, each retry receives deep‑copied *args and **kwargs* to avoid
132
133
  mutating shared state between attempts.
134
+
135
+ instance_context_aware:
136
+ If True, the decorator will check for a retry context flag on the first
137
+ argument (assumed to be 'self'). If the flag is set, retries are skipped
138
+ to prevent retry storms in nested method calls.
133
139
  """
134
140
 
135
141
  def decorate(fn: Callable[..., T]) -> Callable[..., T]:
136
142
  use_deepcopy = deepcopy
143
+ use_context_aware = instance_context_aware
137
144
 
138
- async def _call_with_retry_async(*args, **kw) -> T:
139
- delay = base_delay
140
- for attempt in range(retries):
141
- call_args = copy.deepcopy(args) if use_deepcopy else args
142
- call_kwargs = copy.deepcopy(kw) if use_deepcopy else kw
145
+ class _RetryContext:
146
+ """Context manager for instance-level retry gating."""
147
+
148
+ __slots__ = ("_obj", "_enabled", "_active")
149
+
150
+ def __init__(self, args: tuple[Any, ...]):
151
+ self._obj = args[0] if (use_context_aware and args) else None
152
+ self._enabled = bool(self._obj)
153
+ self._active = False
154
+
155
+ def __enter__(self):
156
+ if not self._enabled:
157
+ return False
143
158
  try:
144
- return await fn(*call_args, **call_kwargs)
145
- except retry_on as exc:
146
- if (not _want_retry(exc, code_patterns=retry_codes, msg_substrings=retry_on_messages)
147
- or attempt == retries - 1):
148
- raise
149
- await asyncio.sleep(delay)
150
- delay *= backoff
159
+ # If already in retry context, signal caller to skip retries
160
+ if getattr(self._obj, "_in_retry_context", False):
161
+ return True
162
+ object.__setattr__(self._obj, "_in_retry_context", True)
163
+ self._active = True
164
+ return False
165
+ except Exception:
166
+ # If we cannot set the attribute, behave as if context isn't enabled
167
+ self._enabled = False
168
+ return False
169
+
170
+ def __exit__(self, _exc_type, _exc, _tb):
171
+ if self._enabled and self._active:
172
+ try:
173
+ object.__setattr__(self._obj, "_in_retry_context", False)
174
+ except Exception:
175
+ pass
176
+
177
+ async def _call_with_retry_async(*args, **kw) -> T:
178
+ with _RetryContext(args) as already_in_context:
179
+ if already_in_context:
180
+ return await fn(*args, **kw)
181
+ delay = base_delay
182
+ for attempt in range(retries):
183
+ call_args = copy.deepcopy(args) if use_deepcopy else args
184
+ call_kwargs = copy.deepcopy(kw) if use_deepcopy else kw
185
+ try:
186
+ return await fn(*call_args, **call_kwargs)
187
+ except retry_on as exc:
188
+ if (not _want_retry(exc, code_patterns=retry_codes, msg_substrings=retry_on_messages)
189
+ or attempt == retries - 1):
190
+ raise
191
+ await asyncio.sleep(delay)
192
+ delay *= backoff
151
193
 
152
194
  async def _agen_with_retry(*args, **kw):
153
- delay = base_delay
154
- for attempt in range(retries):
155
- call_args = copy.deepcopy(args) if use_deepcopy else args
156
- call_kwargs = copy.deepcopy(kw) if use_deepcopy else kw
157
- try:
158
- async for item in fn(*call_args, **call_kwargs):
195
+ with _RetryContext(args) as already_in_context:
196
+ if already_in_context:
197
+ async for item in fn(*args, **kw):
159
198
  yield item
160
199
  return
161
- except retry_on as exc:
162
- if (not _want_retry(exc, code_patterns=retry_codes, msg_substrings=retry_on_messages)
163
- or attempt == retries - 1):
164
- raise
165
- await asyncio.sleep(delay)
166
- delay *= backoff
200
+ delay = base_delay
201
+ for attempt in range(retries):
202
+ call_args = copy.deepcopy(args) if use_deepcopy else args
203
+ call_kwargs = copy.deepcopy(kw) if use_deepcopy else kw
204
+ try:
205
+ async for item in fn(*call_args, **call_kwargs):
206
+ yield item
207
+ return
208
+ except retry_on as exc:
209
+ if (not _want_retry(exc, code_patterns=retry_codes, msg_substrings=retry_on_messages)
210
+ or attempt == retries - 1):
211
+ raise
212
+ await asyncio.sleep(delay)
213
+ delay *= backoff
167
214
 
168
215
  def _gen_with_retry(*args, **kw) -> Iterable[Any]:
169
- delay = base_delay
170
- for attempt in range(retries):
171
- call_args = copy.deepcopy(args) if use_deepcopy else args
172
- call_kwargs = copy.deepcopy(kw) if use_deepcopy else kw
173
- try:
174
- yield from fn(*call_args, **call_kwargs)
216
+ with _RetryContext(args) as already_in_context:
217
+ if already_in_context:
218
+ yield from fn(*args, **kw)
175
219
  return
176
- except retry_on as exc:
177
- if (not _want_retry(exc, code_patterns=retry_codes, msg_substrings=retry_on_messages)
178
- or attempt == retries - 1):
179
- raise
180
- time.sleep(delay)
181
- delay *= backoff
220
+ delay = base_delay
221
+ for attempt in range(retries):
222
+ call_args = copy.deepcopy(args) if use_deepcopy else args
223
+ call_kwargs = copy.deepcopy(kw) if use_deepcopy else kw
224
+ try:
225
+ yield from fn(*call_args, **call_kwargs)
226
+ return
227
+ except retry_on as exc:
228
+ if (not _want_retry(exc, code_patterns=retry_codes, msg_substrings=retry_on_messages)
229
+ or attempt == retries - 1):
230
+ raise
231
+ time.sleep(delay)
232
+ delay *= backoff
182
233
 
183
234
  def _sync_with_retry(*args, **kw) -> T:
184
- delay = base_delay
185
- for attempt in range(retries):
186
- call_args = copy.deepcopy(args) if use_deepcopy else args
187
- call_kwargs = copy.deepcopy(kw) if use_deepcopy else kw
188
- try:
189
- return fn(*call_args, **call_kwargs)
190
- except retry_on as exc:
191
- if (not _want_retry(exc, code_patterns=retry_codes, msg_substrings=retry_on_messages)
192
- or attempt == retries - 1):
193
- raise
194
- time.sleep(delay)
195
- delay *= backoff
235
+ with _RetryContext(args) as already_in_context:
236
+ if already_in_context:
237
+ return fn(*args, **kw)
238
+ delay = base_delay
239
+ for attempt in range(retries):
240
+ call_args = copy.deepcopy(args) if use_deepcopy else args
241
+ call_kwargs = copy.deepcopy(kw) if use_deepcopy else kw
242
+ try:
243
+ return fn(*call_args, **call_kwargs)
244
+ except retry_on as exc:
245
+ if (not _want_retry(exc, code_patterns=retry_codes, msg_substrings=retry_on_messages)
246
+ or attempt == retries - 1):
247
+ raise
248
+ time.sleep(delay)
249
+ delay *= backoff
196
250
 
197
251
  # Decide which wrapper to return
198
252
  if inspect.iscoroutinefunction(fn):
@@ -245,6 +299,7 @@ def patch_with_retry(
245
299
  retry_codes=retry_codes,
246
300
  retry_on_messages=retry_on_messages,
247
301
  deepcopy=deepcopy,
302
+ instance_context_aware=True, # Prevent retry storms
248
303
  )
249
304
 
250
305
  # Choose attribute source: the *class* to avoid triggering __getattr__
@@ -0,0 +1,25 @@
1
+ # SPDX-FileCopyrightText: Copyright (c) 2025, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2
+ # SPDX-License-Identifier: Apache-2.0
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ import logging
17
+
18
+ # Define log level choices
19
+ LOG_LEVELS = {
20
+ 'DEBUG': logging.DEBUG,
21
+ 'INFO': logging.INFO,
22
+ 'WARNING': logging.WARNING,
23
+ 'ERROR': logging.ERROR,
24
+ 'CRITICAL': logging.CRITICAL
25
+ }
nat/utils/type_utils.py CHANGED
@@ -469,6 +469,10 @@ class DecomposedType:
469
469
  # Handle generic types that can't use issubclass
470
470
  pass
471
471
 
472
+ # Check direct equality (works for both regular and generic types)
473
+ if source_type == target_type:
474
+ return True
475
+
472
476
  # Check if source outputs list[T] and target expects T
473
477
  source_decomposed = DecomposedType(source_type)
474
478
  if source_decomposed.origin is list and source_decomposed.args:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nvidia-nat
3
- Version: 1.3.0a20250910
3
+ Version: 1.3.0a20250922
4
4
  Summary: NVIDIA NeMo Agent toolkit
5
5
  Author: NVIDIA Corporation
6
6
  Maintainer: NVIDIA Corporation
@@ -225,11 +225,13 @@ Requires-Dist: httpx~=0.27
225
225
  Requires-Dist: jinja2~=3.1
226
226
  Requires-Dist: jsonpath-ng~=1.7
227
227
  Requires-Dist: mcp~=1.13
228
+ Requires-Dist: nest-asyncio~=1.6
228
229
  Requires-Dist: networkx~=3.4
229
230
  Requires-Dist: numpy~=1.26; python_version < "3.12"
230
231
  Requires-Dist: numpy~=2.3; python_version >= "3.12"
231
232
  Requires-Dist: openinference-semantic-conventions~=0.1.14
232
233
  Requires-Dist: openpyxl~=3.1
234
+ Requires-Dist: optuna~=4.4.0
233
235
  Requires-Dist: pkce==1.0.3
234
236
  Requires-Dist: pkginfo~=1.12
235
237
  Requires-Dist: platformdirs~=4.3
@@ -296,7 +298,9 @@ Requires-Dist: nat_por_to_jiratickets; extra == "examples"
296
298
  Requires-Dist: nat_profiler_agent; extra == "examples"
297
299
  Requires-Dist: nat_redact_pii; extra == "examples"
298
300
  Requires-Dist: nat_retail_sales_agent; extra == "examples"
301
+ Requires-Dist: nat_router_agent; extra == "examples"
299
302
  Requires-Dist: nat_semantic_kernel_demo; extra == "examples"
303
+ Requires-Dist: nat_sequential_executor; extra == "examples"
300
304
  Requires-Dist: nat_simple_auth; extra == "examples"
301
305
  Requires-Dist: nat_simple_web_query; extra == "examples"
302
306
  Requires-Dist: nat_simple_web_query_eval; extra == "examples"
@@ -311,6 +315,11 @@ Requires-Dist: nat_swe_bench; extra == "examples"
311
315
  Requires-Dist: nat_user_report; extra == "examples"
312
316
  Provides-Extra: gunicorn
313
317
  Requires-Dist: gunicorn~=23.0; extra == "gunicorn"
318
+ Provides-Extra: async-endpoints
319
+ Requires-Dist: aiosqlite~=0.21; extra == "async-endpoints"
320
+ Requires-Dist: dask==2023.6; extra == "async-endpoints"
321
+ Requires-Dist: distributed==2023.6; extra == "async-endpoints"
322
+ Requires-Dist: sqlalchemy[asyncio]~=2.0; extra == "async-endpoints"
314
323
  Dynamic: license-file
315
324
 
316
325
  <!--