nvidia-nat 1.4.0a20251015__py3-none-any.whl → 1.4.0a20251022__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.
- nat/agent/base.py +3 -3
- nat/agent/reasoning_agent/reasoning_agent.py +6 -6
- nat/agent/register.py +1 -0
- nat/agent/responses_api_agent/__init__.py +14 -0
- nat/agent/responses_api_agent/register.py +126 -0
- nat/agent/tool_calling_agent/agent.py +6 -10
- nat/builder/context.py +2 -1
- nat/builder/intermediate_step_manager.py +6 -2
- nat/data_models/api_server.py +83 -33
- nat/data_models/intermediate_step.py +9 -1
- nat/data_models/llm.py +15 -1
- nat/data_models/openai_mcp.py +46 -0
- nat/data_models/optimizable.py +2 -1
- nat/data_models/thinking_mixin.py +2 -2
- nat/eval/evaluate.py +2 -0
- nat/eval/usage_stats.py +2 -0
- nat/front_ends/fastapi/fastapi_front_end_plugin_worker.py +3 -0
- nat/front_ends/fastapi/message_handler.py +65 -40
- nat/front_ends/fastapi/message_validator.py +1 -2
- nat/front_ends/mcp/mcp_front_end_config.py +32 -0
- nat/front_ends/mcp/mcp_front_end_plugin.py +9 -6
- nat/llm/aws_bedrock_llm.py +3 -3
- nat/llm/litellm_llm.py +6 -3
- nat/llm/nim_llm.py +3 -3
- nat/llm/openai_llm.py +4 -3
- nat/profiler/callbacks/langchain_callback_handler.py +32 -7
- nat/profiler/callbacks/llama_index_callback_handler.py +36 -2
- nat/profiler/callbacks/token_usage_base_model.py +2 -0
- nat/runtime/runner.py +11 -3
- nat/utils/exception_handlers/automatic_retries.py +205 -54
- nat/utils/responses_api.py +26 -0
- nat/utils/string_utils.py +16 -0
- {nvidia_nat-1.4.0a20251015.dist-info → nvidia_nat-1.4.0a20251022.dist-info}/METADATA +4 -4
- {nvidia_nat-1.4.0a20251015.dist-info → nvidia_nat-1.4.0a20251022.dist-info}/RECORD +39 -35
- {nvidia_nat-1.4.0a20251015.dist-info → nvidia_nat-1.4.0a20251022.dist-info}/WHEEL +0 -0
- {nvidia_nat-1.4.0a20251015.dist-info → nvidia_nat-1.4.0a20251022.dist-info}/entry_points.txt +0 -0
- {nvidia_nat-1.4.0a20251015.dist-info → nvidia_nat-1.4.0a20251022.dist-info}/licenses/LICENSE-3rd-party.txt +0 -0
- {nvidia_nat-1.4.0a20251015.dist-info → nvidia_nat-1.4.0a20251022.dist-info}/licenses/LICENSE.md +0 -0
- {nvidia_nat-1.4.0a20251015.dist-info → nvidia_nat-1.4.0a20251022.dist-info}/top_level.txt +0 -0
|
@@ -15,11 +15,13 @@
|
|
|
15
15
|
import asyncio
|
|
16
16
|
import copy
|
|
17
17
|
import functools
|
|
18
|
+
import gc
|
|
18
19
|
import inspect
|
|
19
20
|
import logging
|
|
20
21
|
import re
|
|
21
22
|
import time
|
|
22
23
|
import types
|
|
24
|
+
import weakref
|
|
23
25
|
from collections.abc import Callable
|
|
24
26
|
from collections.abc import Iterable
|
|
25
27
|
from collections.abc import Sequence
|
|
@@ -31,9 +33,62 @@ Exc = tuple[type[BaseException], ...] # exception classes
|
|
|
31
33
|
CodePattern = int | str | range # for retry_codes argument
|
|
32
34
|
logger = logging.getLogger(__name__)
|
|
33
35
|
|
|
34
|
-
#
|
|
36
|
+
# ─────────────────────────────────────────────────────────────
|
|
37
|
+
# Memory-optimized helpers
|
|
38
|
+
# ─────────────────────────────────────────────────────────────
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _shallow_copy_args(args: tuple, kwargs: dict) -> tuple[tuple, dict]:
|
|
42
|
+
"""Create shallow copies of args and kwargs to avoid deep copy overhead."""
|
|
43
|
+
# For most use cases, shallow copy is sufficient and much faster
|
|
44
|
+
return tuple(args), dict(kwargs)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def _deep_copy_args(args: tuple, kwargs: dict, skip_first: bool = False) -> tuple[tuple, dict]:
|
|
48
|
+
"""Create deep copies of args and kwargs to prevent mutation issues.
|
|
49
|
+
|
|
50
|
+
Args:
|
|
51
|
+
args: Positional arguments to copy
|
|
52
|
+
kwargs: Keyword arguments to copy
|
|
53
|
+
skip_first: If True, skip copying the first arg (typically 'self')
|
|
54
|
+
"""
|
|
55
|
+
if skip_first and args:
|
|
56
|
+
# Don't deep copy self, only the remaining arguments
|
|
57
|
+
return (args[0], ) + copy.deepcopy(args[1:]), copy.deepcopy(kwargs)
|
|
58
|
+
return copy.deepcopy(args), copy.deepcopy(kwargs)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def _clear_exception_context(exc: BaseException) -> None:
|
|
62
|
+
"""Clear exception traceback to free memory."""
|
|
63
|
+
if exc is None:
|
|
64
|
+
return
|
|
65
|
+
|
|
66
|
+
# Clear the exception's traceback to break reference cycles
|
|
67
|
+
# This is the main memory optimization
|
|
68
|
+
try:
|
|
69
|
+
exc.__traceback__ = None
|
|
70
|
+
except AttributeError:
|
|
71
|
+
pass
|
|
72
|
+
|
|
73
|
+
# Also try to clear any chained exceptions
|
|
74
|
+
try:
|
|
75
|
+
if hasattr(exc, '__cause__') and exc.__cause__ is not None:
|
|
76
|
+
_clear_exception_context(exc.__cause__)
|
|
77
|
+
if hasattr(exc, '__context__') and exc.__context__ is not None:
|
|
78
|
+
_clear_exception_context(exc.__context__)
|
|
79
|
+
except AttributeError:
|
|
80
|
+
pass
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def _run_gc_if_needed(attempt: int, gc_frequency: int = 3) -> None:
|
|
84
|
+
"""Run garbage collection periodically to free memory."""
|
|
85
|
+
if attempt > 0 and attempt % gc_frequency == 0:
|
|
86
|
+
gc.collect()
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
# ─────────────────────────────────────────────────────────────
|
|
35
90
|
# Helpers: status-code extraction & pattern matching
|
|
36
|
-
#
|
|
91
|
+
# ─────────────────────────────────────────────────────────────
|
|
37
92
|
_CODE_ATTRS = ("code", "status", "status_code", "http_status")
|
|
38
93
|
|
|
39
94
|
|
|
@@ -55,11 +110,12 @@ def _extract_status_code(exc: BaseException) -> int | None:
|
|
|
55
110
|
|
|
56
111
|
def _pattern_to_regex(pat: str) -> re.Pattern[str]:
|
|
57
112
|
"""
|
|
58
|
-
Convert simple wildcard pattern (
|
|
59
|
-
Rule:
|
|
113
|
+
Convert simple wildcard pattern ("4xx", "5*", "40x") to a ^regex$.
|
|
114
|
+
Rule: 'x' or '*' ⇒ any digit.
|
|
60
115
|
"""
|
|
61
116
|
escaped = re.escape(pat)
|
|
62
|
-
|
|
117
|
+
regex_pattern = escaped.replace(r"\*", r"\d").replace("x", r"\d")
|
|
118
|
+
return re.compile("^" + regex_pattern + "$")
|
|
63
119
|
|
|
64
120
|
|
|
65
121
|
def _code_matches(code: int, pat: CodePattern) -> bool:
|
|
@@ -70,9 +126,9 @@ def _code_matches(code: int, pat: CodePattern) -> bool:
|
|
|
70
126
|
return bool(_pattern_to_regex(pat).match(str(code)))
|
|
71
127
|
|
|
72
128
|
|
|
73
|
-
#
|
|
74
|
-
# Unified retry-decision helper
|
|
75
|
-
#
|
|
129
|
+
# ─────────────────────────────────────────────────────────────
|
|
130
|
+
# Unified retry-decision helper (unchanged)
|
|
131
|
+
# ─────────────────────────────────────────────────────────────
|
|
76
132
|
def _want_retry(
|
|
77
133
|
exc: BaseException,
|
|
78
134
|
*,
|
|
@@ -106,9 +162,9 @@ def _want_retry(
|
|
|
106
162
|
return False
|
|
107
163
|
|
|
108
164
|
|
|
109
|
-
#
|
|
110
|
-
#
|
|
111
|
-
#
|
|
165
|
+
# ─────────────────────────────────────────────────────────────
|
|
166
|
+
# Memory-optimized decorator factory
|
|
167
|
+
# ─────────────────────────────────────────────────────────────
|
|
112
168
|
def _retry_decorator(
|
|
113
169
|
*,
|
|
114
170
|
retries: int = 3,
|
|
@@ -117,10 +173,12 @@ def _retry_decorator(
|
|
|
117
173
|
retry_on: Exc = (Exception, ),
|
|
118
174
|
retry_codes: Sequence[CodePattern] | None = None,
|
|
119
175
|
retry_on_messages: Sequence[str] | None = None,
|
|
120
|
-
|
|
176
|
+
shallow_copy: bool = True, # Changed default to shallow copy
|
|
177
|
+
gc_frequency: int = 3, # Run GC every N retries
|
|
178
|
+
clear_tracebacks: bool = True, # Clear exception tracebacks
|
|
121
179
|
instance_context_aware: bool = False,
|
|
122
180
|
) -> Callable[[Callable[..., T]], Callable[..., T]]:
|
|
123
|
-
"""
|
|
181
|
+
""""
|
|
124
182
|
Build a decorator that retries with exponential back-off *iff*:
|
|
125
183
|
|
|
126
184
|
• the raised exception is an instance of one of `retry_on`
|
|
@@ -128,10 +186,6 @@ def _retry_decorator(
|
|
|
128
186
|
|
|
129
187
|
If both `retry_codes` and `retry_on_messages` are None, all exceptions are retried.
|
|
130
188
|
|
|
131
|
-
deepcopy:
|
|
132
|
-
If True, each retry receives deep‑copied *args and **kwargs* to avoid
|
|
133
|
-
mutating shared state between attempts.
|
|
134
|
-
|
|
135
189
|
instance_context_aware:
|
|
136
190
|
If True, the decorator will check for a retry context flag on the first
|
|
137
191
|
argument (assumed to be 'self'). If the flag is set, retries are skipped
|
|
@@ -139,115 +193,207 @@ def _retry_decorator(
|
|
|
139
193
|
"""
|
|
140
194
|
|
|
141
195
|
def decorate(fn: Callable[..., T]) -> Callable[..., T]:
|
|
142
|
-
|
|
196
|
+
use_shallow_copy = shallow_copy
|
|
143
197
|
use_context_aware = instance_context_aware
|
|
198
|
+
skip_self_in_deepcopy = instance_context_aware
|
|
144
199
|
|
|
145
200
|
class _RetryContext:
|
|
146
201
|
"""Context manager for instance-level retry gating."""
|
|
147
202
|
|
|
148
|
-
__slots__ = ("
|
|
203
|
+
__slots__ = ("_obj_ref", "_enabled", "_active")
|
|
149
204
|
|
|
150
205
|
def __init__(self, args: tuple[Any, ...]):
|
|
151
|
-
|
|
152
|
-
|
|
206
|
+
if use_context_aware and args:
|
|
207
|
+
try:
|
|
208
|
+
# Use weak reference to avoid keeping objects alive
|
|
209
|
+
self._obj_ref = weakref.ref(args[0])
|
|
210
|
+
self._enabled = True
|
|
211
|
+
except TypeError:
|
|
212
|
+
# Object doesn't support weak references
|
|
213
|
+
self._obj_ref = None
|
|
214
|
+
self._enabled = False
|
|
215
|
+
else:
|
|
216
|
+
self._obj_ref = None
|
|
217
|
+
self._enabled = False
|
|
153
218
|
self._active = False
|
|
154
219
|
|
|
155
220
|
def __enter__(self):
|
|
156
|
-
if not self._enabled:
|
|
221
|
+
if not self._enabled or self._obj_ref is None:
|
|
222
|
+
return False
|
|
223
|
+
|
|
224
|
+
obj = self._obj_ref()
|
|
225
|
+
if obj is None:
|
|
157
226
|
return False
|
|
227
|
+
|
|
158
228
|
try:
|
|
159
|
-
# If already in retry context,
|
|
160
|
-
if getattr(
|
|
229
|
+
# If already in retry context, skip retries
|
|
230
|
+
if getattr(obj, "_in_retry_context", False):
|
|
161
231
|
return True
|
|
162
|
-
object.__setattr__(
|
|
232
|
+
object.__setattr__(obj, "_in_retry_context", True)
|
|
163
233
|
self._active = True
|
|
164
234
|
return False
|
|
165
235
|
except Exception:
|
|
166
|
-
#
|
|
236
|
+
# Cannot set attribute, disable context
|
|
167
237
|
self._enabled = False
|
|
168
238
|
return False
|
|
169
239
|
|
|
170
240
|
def __exit__(self, _exc_type, _exc, _tb):
|
|
171
|
-
if self._enabled and self._active:
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
241
|
+
if (self._enabled and self._active and self._obj_ref is not None):
|
|
242
|
+
obj = self._obj_ref()
|
|
243
|
+
if obj is not None:
|
|
244
|
+
try:
|
|
245
|
+
object.__setattr__(obj, "_in_retry_context", False)
|
|
246
|
+
except Exception:
|
|
247
|
+
pass
|
|
176
248
|
|
|
177
249
|
async def _call_with_retry_async(*args, **kw) -> T:
|
|
178
250
|
with _RetryContext(args) as already_in_context:
|
|
179
251
|
if already_in_context:
|
|
180
252
|
return await fn(*args, **kw)
|
|
253
|
+
|
|
181
254
|
delay = base_delay
|
|
255
|
+
last_exception = None
|
|
256
|
+
|
|
182
257
|
for attempt in range(retries):
|
|
183
|
-
|
|
184
|
-
|
|
258
|
+
# Copy args based on configuration
|
|
259
|
+
if use_shallow_copy:
|
|
260
|
+
call_args, call_kwargs = _shallow_copy_args(args, kw)
|
|
261
|
+
else:
|
|
262
|
+
call_args, call_kwargs = _deep_copy_args(args, kw, skip_first=skip_self_in_deepcopy)
|
|
263
|
+
|
|
185
264
|
try:
|
|
186
265
|
return await fn(*call_args, **call_kwargs)
|
|
187
266
|
except retry_on as exc:
|
|
188
|
-
|
|
189
|
-
|
|
267
|
+
last_exception = exc
|
|
268
|
+
|
|
269
|
+
# Clear traceback to free memory
|
|
270
|
+
if clear_tracebacks:
|
|
271
|
+
_clear_exception_context(exc)
|
|
272
|
+
|
|
273
|
+
# Run GC periodically
|
|
274
|
+
_run_gc_if_needed(attempt, gc_frequency)
|
|
275
|
+
|
|
276
|
+
if not _want_retry(exc, code_patterns=retry_codes,
|
|
277
|
+
msg_substrings=retry_on_messages) or attempt == retries - 1:
|
|
190
278
|
raise
|
|
279
|
+
|
|
191
280
|
await asyncio.sleep(delay)
|
|
192
281
|
delay *= backoff
|
|
193
282
|
|
|
283
|
+
if last_exception:
|
|
284
|
+
raise last_exception
|
|
285
|
+
|
|
194
286
|
async def _agen_with_retry(*args, **kw):
|
|
195
287
|
with _RetryContext(args) as already_in_context:
|
|
196
288
|
if already_in_context:
|
|
197
289
|
async for item in fn(*args, **kw):
|
|
198
290
|
yield item
|
|
199
291
|
return
|
|
292
|
+
|
|
200
293
|
delay = base_delay
|
|
294
|
+
last_exception = None
|
|
295
|
+
|
|
201
296
|
for attempt in range(retries):
|
|
202
|
-
|
|
203
|
-
|
|
297
|
+
if use_shallow_copy:
|
|
298
|
+
call_args, call_kwargs = _shallow_copy_args(args, kw)
|
|
299
|
+
else:
|
|
300
|
+
call_args, call_kwargs = _deep_copy_args(args, kw, skip_first=skip_self_in_deepcopy)
|
|
301
|
+
|
|
204
302
|
try:
|
|
205
303
|
async for item in fn(*call_args, **call_kwargs):
|
|
206
304
|
yield item
|
|
207
305
|
return
|
|
208
306
|
except retry_on as exc:
|
|
209
|
-
|
|
210
|
-
|
|
307
|
+
last_exception = exc
|
|
308
|
+
|
|
309
|
+
# Memory cleanup
|
|
310
|
+
if clear_tracebacks:
|
|
311
|
+
_clear_exception_context(exc)
|
|
312
|
+
|
|
313
|
+
_run_gc_if_needed(attempt, gc_frequency)
|
|
314
|
+
|
|
315
|
+
if not _want_retry(exc, code_patterns=retry_codes,
|
|
316
|
+
msg_substrings=retry_on_messages) or attempt == retries - 1:
|
|
211
317
|
raise
|
|
318
|
+
|
|
212
319
|
await asyncio.sleep(delay)
|
|
213
320
|
delay *= backoff
|
|
214
321
|
|
|
322
|
+
if last_exception:
|
|
323
|
+
raise last_exception
|
|
324
|
+
|
|
215
325
|
def _gen_with_retry(*args, **kw) -> Iterable[Any]:
|
|
216
326
|
with _RetryContext(args) as already_in_context:
|
|
217
327
|
if already_in_context:
|
|
218
328
|
yield from fn(*args, **kw)
|
|
219
329
|
return
|
|
330
|
+
|
|
220
331
|
delay = base_delay
|
|
332
|
+
last_exception = None
|
|
333
|
+
|
|
221
334
|
for attempt in range(retries):
|
|
222
|
-
|
|
223
|
-
|
|
335
|
+
if use_shallow_copy:
|
|
336
|
+
call_args, call_kwargs = _shallow_copy_args(args, kw)
|
|
337
|
+
else:
|
|
338
|
+
call_args, call_kwargs = _deep_copy_args(args, kw, skip_first=skip_self_in_deepcopy)
|
|
339
|
+
|
|
224
340
|
try:
|
|
225
341
|
yield from fn(*call_args, **call_kwargs)
|
|
226
342
|
return
|
|
227
343
|
except retry_on as exc:
|
|
228
|
-
|
|
229
|
-
|
|
344
|
+
last_exception = exc
|
|
345
|
+
|
|
346
|
+
# Memory cleanup
|
|
347
|
+
if clear_tracebacks:
|
|
348
|
+
_clear_exception_context(exc)
|
|
349
|
+
|
|
350
|
+
_run_gc_if_needed(attempt, gc_frequency)
|
|
351
|
+
|
|
352
|
+
if not _want_retry(exc, code_patterns=retry_codes,
|
|
353
|
+
msg_substrings=retry_on_messages) or attempt == retries - 1:
|
|
230
354
|
raise
|
|
355
|
+
|
|
231
356
|
time.sleep(delay)
|
|
232
357
|
delay *= backoff
|
|
233
358
|
|
|
359
|
+
if last_exception:
|
|
360
|
+
raise last_exception
|
|
361
|
+
|
|
234
362
|
def _sync_with_retry(*args, **kw) -> T:
|
|
235
363
|
with _RetryContext(args) as already_in_context:
|
|
236
364
|
if already_in_context:
|
|
237
365
|
return fn(*args, **kw)
|
|
366
|
+
|
|
238
367
|
delay = base_delay
|
|
368
|
+
last_exception = None
|
|
369
|
+
|
|
239
370
|
for attempt in range(retries):
|
|
240
|
-
|
|
241
|
-
|
|
371
|
+
if use_shallow_copy:
|
|
372
|
+
call_args, call_kwargs = _shallow_copy_args(args, kw)
|
|
373
|
+
else:
|
|
374
|
+
call_args, call_kwargs = _deep_copy_args(args, kw, skip_first=skip_self_in_deepcopy)
|
|
375
|
+
|
|
242
376
|
try:
|
|
243
377
|
return fn(*call_args, **call_kwargs)
|
|
244
378
|
except retry_on as exc:
|
|
245
|
-
|
|
246
|
-
|
|
379
|
+
last_exception = exc
|
|
380
|
+
|
|
381
|
+
# Memory cleanup
|
|
382
|
+
if clear_tracebacks:
|
|
383
|
+
_clear_exception_context(exc)
|
|
384
|
+
|
|
385
|
+
_run_gc_if_needed(attempt, gc_frequency)
|
|
386
|
+
|
|
387
|
+
if not _want_retry(exc, code_patterns=retry_codes,
|
|
388
|
+
msg_substrings=retry_on_messages) or attempt == retries - 1:
|
|
247
389
|
raise
|
|
390
|
+
|
|
248
391
|
time.sleep(delay)
|
|
249
392
|
delay *= backoff
|
|
250
393
|
|
|
394
|
+
if last_exception:
|
|
395
|
+
raise last_exception
|
|
396
|
+
|
|
251
397
|
# Decide which wrapper to return
|
|
252
398
|
if inspect.iscoroutinefunction(fn):
|
|
253
399
|
wrapper = _call_with_retry_async
|
|
@@ -263,9 +409,6 @@ def _retry_decorator(
|
|
|
263
409
|
return decorate
|
|
264
410
|
|
|
265
411
|
|
|
266
|
-
# ──────────────────────────────────────────────────────────────────────────────
|
|
267
|
-
# Public helper : patch_with_retry
|
|
268
|
-
# ──────────────────────────────────────────────────────────────────────────────
|
|
269
412
|
def patch_with_retry(
|
|
270
413
|
obj: Any,
|
|
271
414
|
*,
|
|
@@ -275,7 +418,9 @@ def patch_with_retry(
|
|
|
275
418
|
retry_on: Exc = (Exception, ),
|
|
276
419
|
retry_codes: Sequence[CodePattern] | None = None,
|
|
277
420
|
retry_on_messages: Sequence[str] | None = None,
|
|
278
|
-
|
|
421
|
+
deep_copy: bool = False,
|
|
422
|
+
gc_frequency: int = 3,
|
|
423
|
+
clear_tracebacks: bool = True,
|
|
279
424
|
) -> Any:
|
|
280
425
|
"""
|
|
281
426
|
Patch *obj* instance-locally so **every public method** retries on failure.
|
|
@@ -291,6 +436,10 @@ def patch_with_retry(
|
|
|
291
436
|
If True, each retry receives deep‑copied *args and **kwargs* to avoid
|
|
292
437
|
mutating shared state between attempts.
|
|
293
438
|
"""
|
|
439
|
+
|
|
440
|
+
# Invert deep copy to keep function signature the same
|
|
441
|
+
shallow_copy = not deep_copy
|
|
442
|
+
|
|
294
443
|
deco = _retry_decorator(
|
|
295
444
|
retries=retries,
|
|
296
445
|
base_delay=base_delay,
|
|
@@ -298,11 +447,13 @@ def patch_with_retry(
|
|
|
298
447
|
retry_on=retry_on,
|
|
299
448
|
retry_codes=retry_codes,
|
|
300
449
|
retry_on_messages=retry_on_messages,
|
|
301
|
-
|
|
450
|
+
shallow_copy=shallow_copy,
|
|
451
|
+
gc_frequency=gc_frequency,
|
|
452
|
+
clear_tracebacks=clear_tracebacks,
|
|
302
453
|
instance_context_aware=True, # Prevent retry storms
|
|
303
454
|
)
|
|
304
455
|
|
|
305
|
-
# Choose attribute source: the *class* to avoid
|
|
456
|
+
# Choose attribute source: the *class* to avoid __getattr__
|
|
306
457
|
cls = obj if inspect.isclass(obj) else type(obj)
|
|
307
458
|
cls_name = getattr(cls, "__name__", str(cls))
|
|
308
459
|
|
|
@@ -310,7 +461,7 @@ def patch_with_retry(
|
|
|
310
461
|
descriptor = inspect.getattr_static(cls, name)
|
|
311
462
|
|
|
312
463
|
# Skip dunders, privates and all descriptors we must not wrap
|
|
313
|
-
if
|
|
464
|
+
if name.startswith("_") or isinstance(descriptor, property | staticmethod | classmethod):
|
|
314
465
|
continue
|
|
315
466
|
|
|
316
467
|
original = descriptor.__func__ if isinstance(descriptor, types.MethodType) else descriptor
|
|
@@ -0,0 +1,26 @@
|
|
|
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
|
+
# pylint: disable=raising-format-tuple
|
|
16
|
+
|
|
17
|
+
from nat.builder.framework_enum import LLMFrameworkEnum
|
|
18
|
+
from nat.data_models.llm import APITypeEnum
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def validate_no_responses_api(llm_config, framework: LLMFrameworkEnum):
|
|
22
|
+
"""Validate that the LLM config does not use the Responses API."""
|
|
23
|
+
|
|
24
|
+
if llm_config.api_type == APITypeEnum.RESPONSES:
|
|
25
|
+
raise ValueError(f"Responses API is not supported for config {str(type(llm_config))} in framework {framework}. "
|
|
26
|
+
f"Please use a different API type.")
|
nat/utils/string_utils.py
CHANGED
|
@@ -36,3 +36,19 @@ def convert_to_str(value: Any) -> str:
|
|
|
36
36
|
return str(value)
|
|
37
37
|
else:
|
|
38
38
|
raise ValueError(f"Unsupported type for conversion to string: {type(value)}")
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def truncate_string(text: str | None, max_length: int = 100) -> str | None:
|
|
42
|
+
"""
|
|
43
|
+
Truncate a string to a maximum length, adding ellipsis if truncated.
|
|
44
|
+
|
|
45
|
+
Args:
|
|
46
|
+
text: The text to truncate (can be None)
|
|
47
|
+
max_length: Maximum allowed length (default: 100)
|
|
48
|
+
|
|
49
|
+
Returns:
|
|
50
|
+
The truncated text with ellipsis if needed, or None if input was None
|
|
51
|
+
"""
|
|
52
|
+
if not text or len(text) <= max_length:
|
|
53
|
+
return text
|
|
54
|
+
return text[:max_length - 3] + "..."
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: nvidia-nat
|
|
3
|
-
Version: 1.4.
|
|
3
|
+
Version: 1.4.0a20251022
|
|
4
4
|
Summary: NVIDIA NeMo Agent toolkit
|
|
5
5
|
Author: NVIDIA Corporation
|
|
6
6
|
Maintainer: NVIDIA Corporation
|
|
@@ -17,7 +17,7 @@ Description-Content-Type: text/markdown
|
|
|
17
17
|
License-File: LICENSE-3rd-party.txt
|
|
18
18
|
License-File: LICENSE.md
|
|
19
19
|
Requires-Dist: aioboto3>=11.0.0
|
|
20
|
-
Requires-Dist: authlib
|
|
20
|
+
Requires-Dist: authlib<2.0.0,>=1.6.5
|
|
21
21
|
Requires-Dist: click~=8.1
|
|
22
22
|
Requires-Dist: colorama~=0.4.6
|
|
23
23
|
Requires-Dist: datasets~=4.0
|
|
@@ -84,10 +84,11 @@ Requires-Dist: nvidia-nat-s3; extra == "s3"
|
|
|
84
84
|
Provides-Extra: semantic-kernel
|
|
85
85
|
Requires-Dist: nvidia-nat-semantic-kernel; extra == "semantic-kernel"
|
|
86
86
|
Provides-Extra: telemetry
|
|
87
|
+
Requires-Dist: nvidia-nat-data-flywheel; extra == "telemetry"
|
|
87
88
|
Requires-Dist: nvidia-nat-opentelemetry; extra == "telemetry"
|
|
88
89
|
Requires-Dist: nvidia-nat-phoenix; extra == "telemetry"
|
|
89
|
-
Requires-Dist: nvidia-nat-weave; extra == "telemetry"
|
|
90
90
|
Requires-Dist: nvidia-nat-ragaai; extra == "telemetry"
|
|
91
|
+
Requires-Dist: nvidia-nat-weave; extra == "telemetry"
|
|
91
92
|
Provides-Extra: weave
|
|
92
93
|
Requires-Dist: nvidia-nat-weave; extra == "weave"
|
|
93
94
|
Provides-Extra: zep-cloud
|
|
@@ -103,7 +104,6 @@ Requires-Dist: nat_multi_frameworks; extra == "examples"
|
|
|
103
104
|
Requires-Dist: nat_plot_charts; extra == "examples"
|
|
104
105
|
Requires-Dist: nat_por_to_jiratickets; extra == "examples"
|
|
105
106
|
Requires-Dist: nat_profiler_agent; extra == "examples"
|
|
106
|
-
Requires-Dist: nat_redact_pii; extra == "examples"
|
|
107
107
|
Requires-Dist: nat_router_agent; extra == "examples"
|
|
108
108
|
Requires-Dist: nat_semantic_kernel_demo; extra == "examples"
|
|
109
109
|
Requires-Dist: nat_sequential_executor; extra == "examples"
|