plugin docs: Stabilize the public plugin authoring API#1959
Conversation
Signed-off-by: Bryan Bednarski <bbednarski@nvidia.com>
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
WalkthroughAdds a pinned public plugin-authoring module ChangesPlugin API Surface & Contract
Documentation & Example Migration to Plugin API
Function Group Testing Support
Deprecation and Future Breaking Changes
🎯 4 (Complex) | ⏱️ ~75 minutes 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
Signed-off-by: Bryan Bednarski <bbednarski@nvidia.com>
Signed-off-by: Bryan Bednarski <bbednarski@nvidia.com>
…on differed items Signed-off-by: Bryan Bednarski <bbednarski@nvidia.com>
There was a problem hiding this comment.
Actionable comments posted: 5
🧹 Nitpick comments (4)
packages/nvidia_nat_eval/src/nat/plugins/eval/runtime/builder.py (1)
146-147: 💤 Low valueOptional: Simplify string formatting.
The warning message uses an f-string concatenated with another f-string. This can be simplified to a single f-string for better readability.
♻️ Proposed simplification
if (fn_name not in self._functions) and (new_fn_name in self._functions): logger.warning( - f"Function `{fn_name}` is deprecated and will be removed in a future release." + \ - f"Use `{new_fn_name}` instead." + f"Function `{fn_name}` is deprecated and will be removed in a future release. " + f"Use `{new_fn_name}` instead." )🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/nvidia_nat_eval/src/nat/plugins/eval/runtime/builder.py` around lines 146 - 147, The deprecation warning builds its message by concatenating two f-strings; replace the concatenation with a single f-string to improve readability. Update the code that constructs the message using fn_name and new_fn_name (the string currently written as f"...{fn_name}..." + f"...{new_fn_name}...") so it becomes one f-string that includes both placeholders in-line, e.g. a single f"...{fn_name}...{new_fn_name}..." expression.docs/source/improve-workflows/optimizer.md (1)
199-200: 💤 Low valueConsider clarifying mixed import sources in the example.
This code example mixes imports from the public API (
nat.plugin_api) with imports from internal modules (nat.data_models.optimizable). While optimizer-specific types may be intentionally out of scope for the public plugin API, the mixed import pattern could confuse plugin authors about which APIs are stable.Consider one of the following:
- Add a comment explaining that optimizer APIs are not part of the stable plugin surface and require internal imports
- If
OptimizableField,SearchSpace, andOptimizableMixinshould be public, migrate them tonat.plugin_api🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@docs/source/improve-workflows/optimizer.md` around lines 199 - 200, The example mixes public API imports (FunctionBaseConfig) with internal types (OptimizableField, SearchSpace, OptimizableMixin); clarify this by adding a short inline comment above the internal imports stating that OptimizableField, SearchSpace, and OptimizableMixin live in internal modules and are not part of the stable plugin API (or alternatively move those types into nat.plugin_api if they are intended to be public), so update the example to either add that explanatory comment referencing FunctionBaseConfig and the three optimizable symbols or migrate the three types to nat.plugin_api if public exposure is desired.docs/source/run-workflows/existing-agents/langgraph.md (1)
127-127: ⚡ Quick winComplete the migration to the public API for Builder import.
The example has partially migrated to
nat.plugin_api(line 126 forLLMFrameworkEnum) but still importsSyncBuilderfrom the internal modulenat.builder.sync_builder. According to the PR objectives and coding guidelines,Builderis explicitly part of the public plugin API facade and should be imported fromnat.plugin_api.Update the import to:
from nat.plugin_api import Builder # or SyncBuilder if exportedThis ensures consistency within the example and guides users toward the stable public API. As per coding guidelines, Builder imports from
nat.plugin_apiare the recommended pattern across provider documentation.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@docs/source/run-workflows/existing-agents/langgraph.md` at line 127, The example currently imports SyncBuilder from the internal module nat.builder.sync_builder; replace that import with the public API import from nat.plugin_api (import Builder or SyncBuilder as exported) so the example consistently uses the public facade (match the existing LLMFrameworkEnum import from nat.plugin_api), updating any references to SyncBuilder to use the public Builder symbol if necessary.packages/nvidia_nat_core/src/nat/plugin_api.py (1)
96-168: ⚡ Quick winSort
__all__to satisfy lint and reduce contract churn noise.
RUF022is already flagging this block. Keeping__all__sorted will avoid repeated lint noise and make export diffs easier to review.💡 Minimal fix approach
-__all__ = [ - "AuthProviderBaseConfig", - ... - "set_secret_from_env", -] +__all__ = sorted([ + "AuthProviderBaseConfig", + ... + "set_secret_from_env", +])🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/nvidia_nat_core/src/nat/plugin_api.py` around lines 96 - 168, The __all__ list in plugin_api.py is unsorted and triggers lint RUF022; reorder the entries in the __all__ list into a stable alphabetical order (e.g., ASCII/lexicographic) so names like "AuthProviderBaseConfig", "AuthenticationRef", "Builder", ... are sorted; preserve the original quoting, commas, and list formatting (one entry per line) and keep the existing items (no additions/removals) to minimize contract churn.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@docs/source/extend/custom-components/custom-functions/functions.md`:
- Line 71: Update the first public mention of the product name on this page:
replace "NeMo Agent Toolkit" with the full product name "NVIDIA NeMo Agent
Toolkit" in the paragraph that introduces registration (the sentence referencing
the nat.plugin_api.register_function decorator), leaving the rest of the text
unchanged.
- Line 197: Fix the grammar typo in the sentence that begins "Its required to
use an async context manager coroutine to register a function…" — change "Its
required" to "It's required" in the functions.md documentation where
nat.plugin_api.register_function is described so the user-facing text reads
"It's required to use an async context manager coroutine to register a
function…".
In `@docs/source/extend/plugin-api.md`:
- Around line 18-21: The page header and first public description use the short
name; update the top-level heading and opening sentence to use the full product
name "NVIDIA NeMo Agent Toolkit" (e.g., change "Public Plugin API" and the
opening line to start with "NVIDIA NeMo Agent Toolkit — Public Plugin API")
while preserving the note about importing from nat.plugin_api and the rest of
the content; ensure the heading and first sentence follow the documentation
naming convention and consistently use the full product name on first mention.
- Around line 74-95: The table block uses slash-form phrases and flagged terms
that break docs CI (Vale and referential path checks); edit the table rows in
the plugin-api section to replace slashes with explicit conjunctions (e.g., "LLM
and embedder" instead of "LLM/embedder"), avoid slash abbreviations (e.g.,
"Trainer and trainer adapter" instead of "Trainer/trainer adapter"), and
rephrase or parenthesize flagged terms like "trusted plugin" and "Deferred"
(e.g., "Stable public (trusted)" or "Deferred — requires review") so that no
path-like tokens or slash-forms remain and the descriptions still convey the
same meaning.
In `@packages/nvidia_nat_core/tests/nat/test_plugin_api.py`:
- Around line 290-303: The test currently uses the public_imports regex which
only matches single-line "from nat.plugin_api import ..." statements so
multiline or parenthesized imports bypass the check; replace the regex-based
approach (public_imports) with an AST-based scan: for each file in files parse
the file with ast.parse, iterate ast.ImportFrom nodes where node.module ==
"nat.plugin_api", collect all alias.name values (handling alias.asname) and then
validate each imported name against EXPECTED_PLUGIN_API_EXPORTS, appending
violations when a non-public symbol is imported; this will correctly handle
multiline and parenthesized imports.
---
Nitpick comments:
In `@docs/source/improve-workflows/optimizer.md`:
- Around line 199-200: The example mixes public API imports (FunctionBaseConfig)
with internal types (OptimizableField, SearchSpace, OptimizableMixin); clarify
this by adding a short inline comment above the internal imports stating that
OptimizableField, SearchSpace, and OptimizableMixin live in internal modules and
are not part of the stable plugin API (or alternatively move those types into
nat.plugin_api if they are intended to be public), so update the example to
either add that explanatory comment referencing FunctionBaseConfig and the three
optimizable symbols or migrate the three types to nat.plugin_api if public
exposure is desired.
In `@docs/source/run-workflows/existing-agents/langgraph.md`:
- Line 127: The example currently imports SyncBuilder from the internal module
nat.builder.sync_builder; replace that import with the public API import from
nat.plugin_api (import Builder or SyncBuilder as exported) so the example
consistently uses the public facade (match the existing LLMFrameworkEnum import
from nat.plugin_api), updating any references to SyncBuilder to use the public
Builder symbol if necessary.
In `@packages/nvidia_nat_core/src/nat/plugin_api.py`:
- Around line 96-168: The __all__ list in plugin_api.py is unsorted and triggers
lint RUF022; reorder the entries in the __all__ list into a stable alphabetical
order (e.g., ASCII/lexicographic) so names like "AuthProviderBaseConfig",
"AuthenticationRef", "Builder", ... are sorted; preserve the original quoting,
commas, and list formatting (one entry per line) and keep the existing items (no
additions/removals) to minimize contract churn.
In `@packages/nvidia_nat_eval/src/nat/plugins/eval/runtime/builder.py`:
- Around line 146-147: The deprecation warning builds its message by
concatenating two f-strings; replace the concatenation with a single f-string to
improve readability. Update the code that constructs the message using fn_name
and new_fn_name (the string currently written as f"...{fn_name}..." +
f"...{new_fn_name}...") so it becomes one f-string that includes both
placeholders in-line, e.g. a single f"...{fn_name}...{new_fn_name}..."
expression.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Enterprise
Run ID: 3b362a3f-fa75-4ac7-af7b-91152d1b9091
📒 Files selected for processing (42)
docs/source/build-workflows/advanced/middleware.mddocs/source/build-workflows/functions-and-function-groups/function-groups.mddocs/source/build-workflows/mcp-client.mddocs/source/build-workflows/retrievers.mddocs/source/components/sharing-components.mddocs/source/extend/custom-components/adding-a-retriever.mddocs/source/extend/custom-components/adding-an-authentication-provider.mddocs/source/extend/custom-components/adding-an-llm-provider.mddocs/source/extend/custom-components/custom-dataset-loader.mddocs/source/extend/custom-components/custom-evaluator.mddocs/source/extend/custom-components/custom-functions/function-groups.mddocs/source/extend/custom-components/custom-functions/functions.mddocs/source/extend/custom-components/custom-functions/per-user-functions.mddocs/source/extend/custom-components/finetuning.mddocs/source/extend/custom-components/memory.mddocs/source/extend/custom-components/object-store.mddocs/source/extend/custom-components/telemetry-exporters.mddocs/source/extend/plugin-api.mddocs/source/extend/plugins.mddocs/source/extend/testing/add-unit-tests-for-tools.mddocs/source/get-started/tutorials/add-tools-to-a-workflow.mddocs/source/improve-workflows/evaluate.mddocs/source/improve-workflows/optimizer.mddocs/source/index.mddocs/source/run-workflows/existing-agents/langgraph.mdexamples/A2A/math_assistant_a2a/README.mdexamples/A2A/math_assistant_a2a_protected/configs/config-client.ymlexamples/dynamo_integration/README.mdexamples/dynamo_integration/react_benchmark_agent/README.mdexamples/dynamo_integration/react_benchmark_agent/src/react_benchmark_agent/DEVELOPER_NOTES.mdexamples/dynamo_integration/react_benchmark_agent/src/react_benchmark_agent/evaluators/tsq_evaluator.pyexamples/dynamo_integration/react_benchmark_agent/tests/test_tsq_formula.pypackages/nvidia_nat_core/src/nat/builder/per_user_workflow_builder.pypackages/nvidia_nat_core/src/nat/builder/workflow_builder.pypackages/nvidia_nat_core/src/nat/cli/commands/workflow/templates/workflow.py.j2packages/nvidia_nat_core/src/nat/plugin_api.pypackages/nvidia_nat_core/tests/nat/test_plugin_api.pypackages/nvidia_nat_core/tests/nat/tools/test_tool_test_runner.pypackages/nvidia_nat_eval/src/nat/plugins/eval/runtime/builder.pypackages/nvidia_nat_langchain/src/nat/plugins/langchain/tools/exa_internet_search.pypackages/nvidia_nat_langchain/src/nat/plugins/langchain/tools/tavily_internet_search.pypackages/nvidia_nat_test/src/nat/test/tool_test_runner.py
|
I did a deeper pass on this. I agree with the direction: The scope mostly looks right to me, especially deferring front ends, logging, registry handlers, optimizer hooks, finetuning, and TTC. I left a few line comments on the places I think would make the public contract sharper before calling it stable: the |
|
Actionable comments posted: 0 |
Signed-off-by: Bryan Bednarski <bbednarski@nvidia.com>
…9/nemo-agent-toolkit into bbednarski/issue-1952
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (2)
packages/nvidia_nat_core/tests/nat/test_plugin_api.py (2)
389-406: 💤 Low valueConsider filtering to methods only or clarifying the attribute scope.
The test docstring and set names (
STABLE_BUILDER_METHODS,DEFERRED_BUILDER_METHODS) reference "method surface" (line 390), but line 393 checks all non-underscore attributes viavars(Builder), which includes properties, class variables, and other descriptors in addition to methods.Currently this works if
Builderhas only methods in its public surface, but ifBuilderlater adds a public property or class variable, the test will fail with a potentially confusing error message (since the sets are named*_METHODS).♻️ Options for clarity
Option 1: Filter to callables only
- actual = {name for name in vars(Builder) if not name.startswith("_")} + actual = {name for name in vars(Builder) if not name.startswith("_") and callable(getattr(Builder, name))}Option 2: Rename sets and clarify scope
If the intent is to track all public surface area (not just methods), rename the sets toSTABLE_BUILDER_SURFACE/DEFERRED_BUILDER_SURFACEand update the docstring to clarify "public surface" instead of "public method surface".🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/nvidia_nat_core/tests/nat/test_plugin_api.py` around lines 389 - 406, The test currently uses vars(Builder) to collect public names but the STABLE_BUILDER_METHODS/DEFERRED_BUILDER_METHODS sets are named for methods, so update the test to ensure the compared surface matches the intent: either (preferred) filter the collected names to methods/callables only (e.g., derive actual = {name for name, val in vars(Builder).items() if not name.startswith("_") and callable(val)}) so it only compares methods against STABLE_BUILDER_METHODS and DEFERRED_BUILDER_METHODS, or if you intend to track all public attributes, rename those sets to STABLE_BUILDER_SURFACE/DEFERRED_BUILDER_SURFACE and update the docstring to say “public surface” instead of “public method surface”; adjust references to Builder, vars(Builder), STABLE_BUILDER_METHODS, and DEFERRED_BUILDER_METHODS accordingly.
368-371: 💤 Low valueJinja template handling is fragile for complex templates.
The simple regex substitution
jinja_var.sub(r"\1", text)converts{{ var }}tovar, which works for the current simple.py.j2workflow template but will fail silently (via theSyntaxErrorcatch at line 376) for templates containing Jinja control structures ({% if %},{% for %}, filters, complex expressions).For the single targeted template this is acceptable, but if additional complex Jinja templates are added to the
pathslist in the future, violations may go undetected.♻️ Consider extracting Python code blocks from Jinja templates
A more robust approach would parse Jinja templates to extract only the Python code blocks (between
{%- ... %}or as plain Python outside Jinja directives) rather than attempting global text substitution. Alternatively, document that only simple variable-substitution templates are supported and should be added to thepathslist.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/nvidia_nat_core/tests/nat/test_plugin_api.py` around lines 368 - 371, The current jinja handling uses jinja_var.sub(r"\1", text) when file_path.name.endswith(".j2"), which will silently fail for complex templates (caught by the existing SyntaxError handler); replace this fragile regex approach by parsing the template with Jinja2 (e.g. use jinja2.Environment().parse(text) and jinja2.meta or walk the AST) to extract actual Python code blocks/variables to populate snippets, and keep the SyntaxError handler but rely on the parser to produce accurate snippets for `{% ... %}` and `{{ ... }}` constructs; alternatively, if you prefer the simpler route, document in tests that only simple variable-substitution `.j2` templates are supported and restrict paths accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@packages/nvidia_nat_core/tests/nat/test_plugin_api.py`:
- Around line 389-406: The test currently uses vars(Builder) to collect public
names but the STABLE_BUILDER_METHODS/DEFERRED_BUILDER_METHODS sets are named for
methods, so update the test to ensure the compared surface matches the intent:
either (preferred) filter the collected names to methods/callables only (e.g.,
derive actual = {name for name, val in vars(Builder).items() if not
name.startswith("_") and callable(val)}) so it only compares methods against
STABLE_BUILDER_METHODS and DEFERRED_BUILDER_METHODS, or if you intend to track
all public attributes, rename those sets to
STABLE_BUILDER_SURFACE/DEFERRED_BUILDER_SURFACE and update the docstring to say
“public surface” instead of “public method surface”; adjust references to
Builder, vars(Builder), STABLE_BUILDER_METHODS, and DEFERRED_BUILDER_METHODS
accordingly.
- Around line 368-371: The current jinja handling uses jinja_var.sub(r"\1",
text) when file_path.name.endswith(".j2"), which will silently fail for complex
templates (caught by the existing SyntaxError handler); replace this fragile
regex approach by parsing the template with Jinja2 (e.g. use
jinja2.Environment().parse(text) and jinja2.meta or walk the AST) to extract
actual Python code blocks/variables to populate snippets, and keep the
SyntaxError handler but rely on the parser to produce accurate snippets for `{%
... %}` and `{{ ... }}` constructs; alternatively, if you prefer the simpler
route, document in tests that only simple variable-substitution `.j2` templates
are supported and restrict paths accordingly.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Enterprise
Run ID: dc37832b-6431-40d1-9fcc-d5b6c64450f5
📒 Files selected for processing (5)
docs/source/extend/custom-components/custom-functions/functions.mddocs/source/extend/plugin-api.mddocs/source/extend/plugins.mdpackages/nvidia_nat_core/src/nat/plugin_api.pypackages/nvidia_nat_core/tests/nat/test_plugin_api.py
✅ Files skipped from review due to trivial changes (2)
- docs/source/extend/plugins.md
- docs/source/extend/custom-components/custom-functions/functions.md
🚧 Files skipped from review as they are similar to previous changes (2)
- packages/nvidia_nat_core/src/nat/plugin_api.py
- docs/source/extend/plugin-api.md
Signed-off-by: Bryan Bednarski <bbednarski@nvidia.com>
|
Actionable comments posted: 0 |
Signed-off-by: Bryan Bednarski <bbednarski@nvidia.com>
|
Actionable comments posted: 0 |
Signed-off-by: Bryan Bednarski <bbednarski@nvidia.com>
Signed-off-by: Bryan Bednarski <bbednarski@nvidia.com>
mnajafian-nv
left a comment
There was a problem hiding this comment.
Thanks Bryan, this is much closer now. The Builder concern and consumer-style tests look addressed to me.
I left a few remaining comments focused on public API contract consistency across the stability table, subsystem guides, and the actual nat.plugin_api facade. I do not think these need to block approval, but I would like them cleaned up before merge so third-party plugin authors get one coherent contract.
Approved from my side assuming those contract-alignment comments are addressed.
… Add retriever, retoutput and document ro the plugin api Signed-off-by: Bryan Bednarski <bbednarski@nvidia.com>
- Split middleware into stable basic/function middleware vs provisional dynamic/runtime introspection. - Narrowed the builder row to the tested stable method subset. - Added evaluator-guide note that only registration/config/EvaluatorInfo are stable facade APIs. - Updated nat.plugin_api docstring to include deferred auth builder methods. Signed-off-by: Bryan Bednarski <bbednarski@nvidia.com>
Signed-off-by: Bryan Bednarski <bbednarski@nvidia.com>
Signed-off-by: Bryan Bednarski <bbednarski@nvidia.com>
|
/merge |
Stabilize the public plugin authoring API
Closes #1952.
Summary
This PR defines
nat.plugin_apias the stable public import surface for third-party plugin authors and updates the author-facing docs/examples to use that surface instead of deeper implementation modules.It also adds a third-party plugin package guide for partner-owned repositories, including package naming, project layout,
nat.pluginsentry points, compatibility expectations, listing requirements, and testing guidance.The intent is to make the common external plugin contract explicit without redesigning provider-specific capabilities such as web search results, embeddings, or retrieval payloads, and without prematurely promoting every runtime extension point into the stable facade.
What Changed
nat.plugin_apias the public facade for plugin authoring APIs:nat.plugin_api.__all__export map so public API drift is intentional.nat.pluginsentry-point group, whilenat.componentsremains supported for backward compatibility.nat.plugin_api.nat.plugin_apiexports.ToolTestRunnerwith function-group helpers so external packages can test registered function groups and assertgroup__functionnames without constructing a full workflow.Scope Boundaries
In scope:
group__functionconvention.Out of scope:
nat.componentsentry points.Web search result fields remain provider-specific in this PR. Third-party packages should use the public plugin authoring API, but their result payloads should stay unconstrained unless a separate capability contract is designed later.
Motivation
External packages such as
nemo-agent-toolkit-tavilyneed a clearer contract for which NeMo Agent Toolkit APIs are public and stable. Today, plugin examples and downstream packages can end up importing from implementation modules such asnat.builder.*,nat.cli.register_workflow, andnat.data_models.*.This PR creates a conservative facade that external packages can rely on across minor and patch releases, while leaving private implementation modules free to evolve as long as the public contract remains intact.
Installed plugins still execute as trusted Python code in the application environment. This PR stabilizes import paths and authoring contracts; it does not make untrusted plugins safe to install or run.
Testing
uv run ruff check packages/nvidia_nat_core/src/nat/plugin_api.py packages/nvidia_nat_core/tests/nat/test_plugin_api.py packages/nvidia_nat_test/src/nat/test/tool_test_runner.py packages/nvidia_nat_core/tests/nat/tools/test_tool_test_runner.py packages/nvidia_nat_langchain/src/nat/plugins/langchain/tools/tavily_internet_search.py packages/nvidia_nat_langchain/src/nat/plugins/langchain/tools/exa_internet_search.pyuv run --project packages/nvidia_nat_core --extra test pytest packages/nvidia_nat_core/tests/nat/test_plugin_api.py packages/nvidia_nat_core/tests/nat/tools/test_tool_test_runner.py -q11 passeduv run ruff check packages/nvidia_nat_core/src/nat/plugin_api.py packages/nvidia_nat_core/tests/nat/test_plugin_api.py docs/source/extend/third-party-plugins.mduv run --project packages/nvidia_nat_core --extra test pytest packages/nvidia_nat_core/tests/nat/test_plugin_api.py packages/nvidia_nat_core/tests/nat/tools/test_tool_test_runner.py -q14 passedgit diff --checkpython3 ci/scripts/license_diff.py develop > license_diff_output.txtpython3 ci/scripts/path_checks.py --check-paths-in-filesexternal/lc-deepagents-quickstartsexample paths from the checkoutFollow-Ups
nemo-agent-toolkit-tavily, to import fromnat.plugin_api.nat.plugin_api.By Submitting this PR I confirm:
Summary by CodeRabbit
Documentation
New Features
Tests