DEV Community

Cover image for GTC Berlin side quest: one import hid 7 NVIDIA agent tools, so I made it lazy
Shreya Boyane
Shreya Boyane

Posted on

GTC Berlin side quest: one import hid 7 NVIDIA agent tools, so I made it lazy

At GTC Berlin on October 21, NVIDIA expanded its Agent Toolkit: a new Agent Knowledge Foundation for grounding agents in company data, the new Kumo models, the OpenShell secure runtime, and tools like NeMo Relay. Two days later, NeMo Relay turned up somewhere else. The README of NVIDIA's open-source agent library, NeMo Agent Toolkit, gained a deprecation notice that points users to NeMo Relay, NeMo Helix and NeMo Fabric, with end of life set for the end of 2026.

That made me curious about the piece people still install today. So I built a fresh environment and looked at what a user actually gets. Seven of the library's 12 built-in tools never registered, and the error message pointed somewhere else entirely.

The side quest became PR #2474: +10/-3 lines in one source file plus a regression test, approved by an NVIDIA maintainer and merged about 19 hours after I opened it.

The short version

The toolkit registers its built-in tools by importing a list of modules, one after another. One of those modules asked for a LangChain class the moment it was imported. LangChain is not part of the core install, so on a plain install that import failed, the list stopped there, and the seven tools after it were never registered. The only trace was one warning in the log. The fix moves that import to the one method that actually uses it.

The concept, animated

Animated figure. nat/tool/register.py drawn as a rack of twelve labelled tool cards in import order, with an "import" pointer walking along it and lighting each card's lamp as that tool registers. The nvidia_rag card has a socket for langchain_core at its top; the langchain_core block at the front reads "not installed" on a plain install, and the pointer stops at nvidia_rag with ModuleNotFoundError, leaving seven lamps dark. After the fix the socket sits inside to_document() and all twelve lamps light.

Figure 1. The rack is nat/tool/register.py, one card per built-in tool, named as in the registry. The pointer is the import pass the nat_tools entry point runs top to bottom; a lit lamp is a registered tool. The socket on nvidia_rag.py marks where it needs langchain_core: at import time before the fix, inside to_document() after. The three states are a dev install, a plain install before #2474, and a plain install after it.

Plugins reach nat, the toolkit's package, through Python entry points. The nat_tools entry point loads one file, nat/tool/register.py, which is a list of imports, and every import registers the tool it names. That list is the rack in figure 1, and the import pass is the pointer.

Line 21 of nvidia_rag.py imported LangChain's Document class at module level, which means it needed langchain-core just to be imported, before anyone used the tool. That is the socket at the top of the nvidia_rag card, and the block at the front is the package it asks for.

On every contributor's machine that block reads "installed", because the test extras pull in langchain-core through langchain-community. On a plain install, a virtual environment holding only nvidia-nat-core and nvidia-nat-atif and their declared dependencies, it reads "not installed". The import raises ModuleNotFoundError, the loader catches it for that entry point, writes one warning, and carries on with nothing. Five lamps lit, seven dark: nvidia_rag, nat_retriever, current_request_attributes, code_execution, add_memory, delete_memory and get_memory.

What a fresh install actually gives you

I wrote a minimal workflow whose only setting was _type: code_execution, one of the built-in tools, and ran nat validate on it. It failed with this:

Input tag 'code_execution' found using discriminator() does not match any of the expected tags

So the validator claimed a built-in tool did not exist, and said nothing about imports or missing packages. If the registry did not know code_execution, I wanted to see what it did know, so I listed every registered function after plugin discovery. Five of twelve. The log held the only real clue, a warning that is easy to scroll past: Failed to import plugin 'nat_tools', followed by ModuleNotFoundError: No module named 'langchain_core'.

The same masking had hidden an earlier bug, #2386, where packaging was missing on a plain install (#2392 fixed it). The import was also in the released 1.9.0.

The fix, in one idea

Still from the third state: the socket on the nvidia_rag card now sits inside to_document(), the langchain_core block still reads "not installed", and all twelve lamps are lit.

Figure 2. After the fix the socket sits inside to_document(): the package is needed when the RAG tool runs, not when its module is imported. A plain install registers all twelve tools with langchain_core still absent.

Move the import to the moment it is needed. Document is only used inside one method, the one that turns a RAG result into a LangChain document, so the import now lives inside that method:

def to_document(self) -> "Document":
    from langchain_core.documents import Document
    return Document(page_content=self.content, ...)
Enter fullscreen mode Exit fullscreen mode

The type hints stay under TYPE_CHECKING, so editors and type checkers see the same types as before. The tool's build function already imported langchain_core.prompts this way. Using the nvidia_rag tool still needs langchain-core, exactly as before. Importing the module no longer does.

I weighed two other fixes. Declaring langchain-core a core dependency would pull LangChain into the core package for everyone. Wrapping each import in register.py in try/except would hide real errors.

The regression test plays the plain install on any machine: it blocks every langchain_core entry in sys.modules, imports nat.tool.nvidia_rag fresh against a mocked registry, and checks that the tool registers. On the old code it fails with the same ModuleNotFoundError. A second test checks that both RAG response shapes, results and chunks, still produce the same LangChain Document objects. Before the fix, 1 test failed and 2 passed. After it, all 3 pass. Across the core suite, 2,981 tests passed, 310 were skipped and 8 failed; none of the 8 import nat.tool, and the five I reran on develop fail there the same way. I ran everything on Windows 11 with Python 3.11.9, not on Linux.

What changed for users

Built-in tool on a plain install Before After
chat_completion, current_datetime, current_timezone, milvus_document_search, github_files_tool registered registered
nvidia_rag, nat_retriever, current_request_attributes, code_execution, add_memory, delete_memory, get_memory missing registered
  • nat validate on the code_execution workflow went from exit code 1 and the misleading tag error to Configuration file is valid!
  • nat info components -t function printed the Failed to import plugin 'nat_tools' warning twice before the fix and zero times after.
  • A workflow on a plain install can now configure code execution, the retriever, request attributes and the three memory tools without LangChain installed.

Why fix a library that is being deprecated?

The deprecation notice gives users until the end of 2026 to migrate. Until then, anyone who installs only the core packages, in CI, in a container or on a new laptop, gets the environment I tested. The maintainers merged this fix three days after the deprecation notice landed.

Thank you, willkill07

Thank you to willkill07 (Will Killian) at NVIDIA. He started CI on NVIDIA's runners with /ok to test, approved the PR about 12 hours after I opened it, and sent it to merge with /merge about seven hours after that.

Thanks as well to the NeMo Agent Toolkit maintainers, who keep this repo open to outside contributors. When I checked on October 26, 39 of the last 40 merged PRs came from people outside the NVIDIA GitHub organization, with a median of 13.9 hours from open to merge.

The PR template asks every PR to close an issue, so I filed #2473 first. DCO and branch checks passed, CodeRabbit left one minor note on test cleanup, and a maintainer added the bug and non-breaking labels.

What I took away

Your dev environment is a superset of every user's environment, which makes it the one place a missing dependency can never show up.

A plugin system that imports a list of modules stops at the first missing optional dependency. Here that cost seven tools and produced one log warning. Unit tests could not catch it, because they run where every extra is installed.

Before my MS in AI at WPI, I was a Lead DevOps Engineer, and this bug sits between packaging and code, where neither side's tests look. I now build the exact install a user gets and import every plugin before I trust a green test run. I want to propose a CI job that does the same for this repo. The bug I'm looking at now is the same class: on a plain install, nat serve fails with No module named 'sqlalchemy'.

I'm open to ML engineering and agent infrastructure roles. If your team builds AI agents or the tooling under them, I'd be glad to talk. You can find my work at shreyaboyane.dev, my code on GitHub as Sonica-B, and me on LinkedIn.

Top comments (0)