NVIDIA / NVIDIA/NeMo-Agent-Toolkit

fix: LLM, embedder, and memory framework adapters ignore do_auto_retry=False

Open
#2,212 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Python
Stars
2.6k
Forks
762
Avg merge
21h 28m
Merged PRs (30d)
27

Description

Version

develop (and v1.9.0-rc3)

Which installation method(s) does this occur on?

Source

Describe the bug.

RetryMixin provides do_auto_retry: bool = Field(default=True, description="Whether to automatically retry method calls that fail with a retryable error.", exclude=True) and num_retries: int = Field(default=5, gt=0, ...).

Because num_retries validates gt=0, users cannot disable retries by specifying num_retries: 0. Setting do_auto_retry: false in workflow configurations is the documented and tested mechanism to disable retries (as tested in test_retry_mixin.py: test_disabling_retries_uses_do_auto_retry).

While evaluator integrations (langsmith_judge.py, trajectory_evaluator.py, ragas, remote_workflow.py) properly check if config.do_auto_retry:, all runtime framework adapters for LLMs, embedders, and memory editors only check:

if isinstance(llm_config, RetryMixin):
    client = patch_with_retry(...)

(or in nvidia_nat_memmachine, call patch_with_retry unconditionally without any check).

Because all provider configs (OpenAIModelConfig, NIMModelConfig, AzureOpenAIModelConfig, AWSBedrockModelConfig, etc.) inherit from RetryMixin, isinstance(..., RetryMixin) is always True. As a result, setting do_auto_retry: false in YAML or configuration is completely ignored across:

  • nvidia_nat_langchain (LLMs & embedders)
  • nvidia_nat_llama_index (LLMs & embedders)
  • nvidia_nat_agno (LLMs)
  • nvidia_nat_autogen (LLMs)
  • nvidia_nat_crewai (LLMs)
  • nvidia_nat_semantic_kernel (LLMs)
  • nvidia_nat_strands (LLMs)
  • nvidia_nat_mem0ai (memory)
  • nvidia_nat_memmachine (memory)
  • nvidia_nat_zep_cloud (memory)

When a retryable error occurs (e.g., HTTP 429, 500, 503), the client retries 5 times with exponential backoff instead of failing immediately as requested by the user.

Expected Behavior

When do_auto_retry: false is configured, client wrappers should not wrap the instance with patch_with_retry, allowing immediate failure and honoring user configuration.

Minimum reproducible example
import asyncio
from unittest.mock import MagicMock, patch
from nat.llm.openai_llm import OpenAIModelConfig
from nat.plugins.langchain.llm import openai_langchain

class DummyChat:
    def __init__(self):
        self.attempts = 0
        self.model_kwargs = {}
    async def ainvoke(self, *args, **kwargs):
        self.attempts += 1
        print(f"Attempt {self.attempts}")
        raise RuntimeError("429 Too Many Requests")

async def main():
    cfg = OpenAIModelConfig(model_name="gpt-4o-mini", do_auto_retry=False)
    mock_builder = MagicMock()
    dummy = DummyChat()

    with patch("langchain_openai.ChatOpenAI", return_value=dummy):
        async with openai_langchain(cfg, mock_builder) as client:
            try:
                await client.ainvoke("hello")
            except Exception:
                print(f"Total attempts made: {dummy.attempts}")

asyncio.run(main())
Relevant log output
Attempt 1
Attempt 2
Attempt 3
Attempt 4
Attempt 5
Total attempts made: 5

(Expected: 1 attempt, but 5 attempts were executed because patch_with_retry was applied despite do_auto_retry=False.)

Other/Misc.

I have verified the fix and will submit a PR linking to this issue.

Code of Conduct
  • I agree to follow the NeMo Agent Toolkit Code of Conduct
  • I have searched the open bugs and have found no duplicates for this bug report

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with test_retry_mixin.py and trace patch_with_retry through the runtime adapters named in the issue, including the LLM, embedder, and memory integrations. Compare them with the evaluator integrations that already inspect do_auto_retry. Done means each listed adapter honors do_auto_retry: false and retry behavior is covered by tests.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
ai, backend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
38/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.