nvidia-nat 1.4.0a20251015__py3-none-any.whl → 1.4.0a20251021__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 (37) hide show
  1. nat/agent/base.py +3 -3
  2. nat/agent/reasoning_agent/reasoning_agent.py +6 -6
  3. nat/agent/register.py +1 -0
  4. nat/agent/responses_api_agent/__init__.py +14 -0
  5. nat/agent/responses_api_agent/register.py +126 -0
  6. nat/agent/tool_calling_agent/agent.py +6 -10
  7. nat/builder/context.py +2 -1
  8. nat/builder/intermediate_step_manager.py +6 -2
  9. nat/data_models/api_server.py +83 -33
  10. nat/data_models/intermediate_step.py +9 -1
  11. nat/data_models/llm.py +15 -1
  12. nat/data_models/openai_mcp.py +46 -0
  13. nat/data_models/optimizable.py +2 -1
  14. nat/data_models/thinking_mixin.py +2 -2
  15. nat/eval/evaluate.py +2 -0
  16. nat/eval/usage_stats.py +2 -0
  17. nat/front_ends/fastapi/fastapi_front_end_plugin_worker.py +3 -0
  18. nat/front_ends/fastapi/message_handler.py +65 -40
  19. nat/front_ends/fastapi/message_validator.py +1 -2
  20. nat/front_ends/mcp/mcp_front_end_config.py +32 -0
  21. nat/front_ends/mcp/mcp_front_end_plugin.py +9 -6
  22. nat/llm/aws_bedrock_llm.py +3 -3
  23. nat/llm/litellm_llm.py +6 -3
  24. nat/llm/nim_llm.py +3 -3
  25. nat/llm/openai_llm.py +4 -3
  26. nat/profiler/callbacks/langchain_callback_handler.py +32 -7
  27. nat/profiler/callbacks/llama_index_callback_handler.py +36 -2
  28. nat/profiler/callbacks/token_usage_base_model.py +2 -0
  29. nat/utils/exception_handlers/automatic_retries.py +205 -54
  30. nat/utils/responses_api.py +26 -0
  31. {nvidia_nat-1.4.0a20251015.dist-info → nvidia_nat-1.4.0a20251021.dist-info}/METADATA +4 -4
  32. {nvidia_nat-1.4.0a20251015.dist-info → nvidia_nat-1.4.0a20251021.dist-info}/RECORD +37 -33
  33. {nvidia_nat-1.4.0a20251015.dist-info → nvidia_nat-1.4.0a20251021.dist-info}/WHEEL +0 -0
  34. {nvidia_nat-1.4.0a20251015.dist-info → nvidia_nat-1.4.0a20251021.dist-info}/entry_points.txt +0 -0
  35. {nvidia_nat-1.4.0a20251015.dist-info → nvidia_nat-1.4.0a20251021.dist-info}/licenses/LICENSE-3rd-party.txt +0 -0
  36. {nvidia_nat-1.4.0a20251015.dist-info → nvidia_nat-1.4.0a20251021.dist-info}/licenses/LICENSE.md +0 -0
  37. {nvidia_nat-1.4.0a20251015.dist-info → nvidia_nat-1.4.0a20251021.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 (4xx”, 5*”, 40x) to a ^regex$.
59
- Rule: x or ‘*’ ⇒ any digit.
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
- return re.compile("^" + escaped.replace(r"\*", r"\d").replace("x", r"\d") + "$")
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
- # Core decorator factory (sync / async / (a)gen)
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
- deepcopy: bool = False,
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
- use_deepcopy = deepcopy
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__ = ("_obj", "_enabled", "_active")
203
+ __slots__ = ("_obj_ref", "_enabled", "_active")
149
204
 
150
205
  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)
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, signal caller to skip retries
160
- if getattr(self._obj, "_in_retry_context", False):
229
+ # If already in retry context, skip retries
230
+ if getattr(obj, "_in_retry_context", False):
161
231
  return True
162
- object.__setattr__(self._obj, "_in_retry_context", True)
232
+ object.__setattr__(obj, "_in_retry_context", True)
163
233
  self._active = True
164
234
  return False
165
235
  except Exception:
166
- # If we cannot set the attribute, behave as if context isn't enabled
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
- try:
173
- object.__setattr__(self._obj, "_in_retry_context", False)
174
- except Exception:
175
- pass
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
- call_args = copy.deepcopy(args) if use_deepcopy else args
184
- call_kwargs = copy.deepcopy(kw) if use_deepcopy else kw
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
- if (not _want_retry(exc, code_patterns=retry_codes, msg_substrings=retry_on_messages)
189
- or attempt == retries - 1):
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
- call_args = copy.deepcopy(args) if use_deepcopy else args
203
- call_kwargs = copy.deepcopy(kw) if use_deepcopy else kw
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
- if (not _want_retry(exc, code_patterns=retry_codes, msg_substrings=retry_on_messages)
210
- or attempt == retries - 1):
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
- call_args = copy.deepcopy(args) if use_deepcopy else args
223
- call_kwargs = copy.deepcopy(kw) if use_deepcopy else kw
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
- if (not _want_retry(exc, code_patterns=retry_codes, msg_substrings=retry_on_messages)
229
- or attempt == retries - 1):
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
- call_args = copy.deepcopy(args) if use_deepcopy else args
241
- call_kwargs = copy.deepcopy(kw) if use_deepcopy else kw
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
- if (not _want_retry(exc, code_patterns=retry_codes, msg_substrings=retry_on_messages)
246
- or attempt == retries - 1):
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
- deepcopy: bool = False,
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
- deepcopy=deepcopy,
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 triggering __getattr__
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 (name.startswith("_") or isinstance(descriptor, property | staticmethod | classmethod)):
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.")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nvidia-nat
3
- Version: 1.4.0a20251015
3
+ Version: 1.4.0a20251021
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~=1.5
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"