Skip to content

Commit 7c10f0b

Browse files
authored
Merge branch 'develop' into vasiliyr/03152026
2 parents 6c0a4c7 + cff3925 commit 7c10f0b

571 files changed

Lines changed: 50001 additions & 10260 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.coderabbit.yaml

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,13 @@ reviews:
131131
instructions: >-
132132
This directory contains the core functionality of the toolkit. Changes should prioritize backward compatibility.
133133
134+
- path: "packages/nvidia_nat_core/src/nat/eval/**/*"
135+
instructions: >-
136+
- This is a deprecated compatibility shim area and should not grow.
137+
- Flag any PR that adds new files under this path as a blocking issue.
138+
- New evaluation code should be added under `packages/nvidia_nat_eval/src/nat/plugins/eval/` instead.
139+
- Changes in this path should be limited to compatibility-only fixes that are explicitly justified in PR notes.
140+
134141
- path: "packages/**/*"
135142
instructions: >-
136143
- This directory contains packages for the toolkit, each should contain a `pyproject.toml` file.
@@ -145,17 +152,31 @@ reviews:
145152
- `nvidia-nat-test` should likely be listed as an optional dependency in the `test` extra
146153
- A single dependency should be listed on each line and should always have a version specifier.
147154
- All dependencies should be listed under the `[tool.setuptools_dynamic_dependencies]` section
148-
- Any dependency that is an NVIDIA NeMo Agent Toolkit package should be declared with a version constraint of `== {version}`
155+
- Any dependency that is an NVIDIA NeMo Agent Toolkit package should be declared with a version constraint of `== {version}`
156+
157+
- path: "packages/nvidia_nat_core/pyproject.toml"
158+
instructions: >-
159+
- This package is part of the thin-core strategy; default to minimizing direct dependencies.
160+
- Treat any new dependency addition as high-risk and require explicit justification in PR review notes.
161+
- Prefer moving framework-specific or optional capabilities into non-core plugin packages instead of adding dependencies here.
162+
- If a new dependency is unavoidable, confirm it is required by core contracts/runtime and not by optional evaluators, exporters, profiling, or framework integrations.
163+
164+
- path: "packages/nvidia_nat_eval/pyproject.toml"
165+
instructions: >-
166+
- This package follows a thin-core eval strategy; prioritize keeping dependencies minimal.
167+
- Treat any new dependency addition as high-risk and require explicit justification in PR review notes.
168+
- Prefer package-affinity placement (framework/profiler/security/exporter packages) instead of adding dependencies here.
169+
- If a new dependency is unavoidable, confirm it supports core harness/contracts only and is not better hosted in optional packages.
149170
150171
- path: "**/tests/**/*.py"
151172
instructions: >-
152173
- Ensure that tests are comprehensive, cover edge cases, and validate the functionality of the code.
153174
- Test functions should be named using the `test_` prefix, using snake_case.
154175
- Any frequently repeated code should be extracted into pytest fixtures.
155176
- Pytest fixtures should define the name argument when applying the pytest.fixture decorator. The fixture
156-
function being decorated should be named using the `fixture_` prefix, using snake_case. Example:
157-
@pytest.fixture(name="my_fixture")
158-
def fixture_my_fixture():
177+
function being decorated should be named using either a `fixture_` prefix or `_fixture` suffix, using snake_case. Example:
178+
@pytest.fixture(name="my_custom_config")
179+
def my_custom_config_fixture():
159180
pass
160181
- Do NOT add `@pytest.mark.asyncio` to any test. Async tests are automatically detected and run by the
161182
async runner - the decorator is unnecessary clutter.

.cursor/rules/general.mdc

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -113,11 +113,11 @@ These are the overarching standards that every **source, test, documentation and
113113
- Test functions should be named using the `test_` prefix, using snake_case.
114114
- Any frequently repeated code should be extracted into pytest fixtures.
115115
- Pytest fixtures should define the name argument when applying the pytest.fixture decorator.
116-
- The fixture function being decorated should be named using the `fixture_` prefix, using snake_case.
116+
- The fixture function being decorated should be named using the `fixture_` prefix or `_fixture` suffix, using snake_case.
117117
- Example:
118118
```python
119-
@pytest.fixture(name="my_fixture")
120-
def fixture_my_fixture():
119+
@pytest.fixture(name="my_custom_config")
120+
def my_custom_config_fixture():
121121
pass
122122
```
123123
- Maintain **≥ 80 %** coverage; add or update tests when introducing changes.

.cursor/rules/nat-tests/general.mdc

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,26 @@ All tests in NeMo Agent Toolkit use pytest. See the general coding guidelines fo
2323

2424
- Use `pytest` for all unit tests
2525
- Name test files `test_*.py`
26-
- Use `@pytest.fixture(name="fixture_name")` decorator pattern
2726
- Mock external services with `pytest_httpserver` or `unittest.mock`
2827
- Maintain ≥ 80% code coverage
2928
- Do NOT add `@pytest.mark.asyncio` to any test - async tests are automatically detected and run by the async runner
3029

30+
### Fixtures
31+
- Use `@pytest.fixture(name="fixture_name")` decorator pattern
32+
- Fixtures that are used in multiple tests should be defined in the `packages/nvidia_nat_test/src/nat/test/plugin.py` file, fixtures specific to a single package should be defined in a `conftest.py` file in the `tests` directory of the package, and fixtures that are specific to a single test can be defined in the test file itself.
33+
34+
#### Available Fixtures
35+
36+
**API Keys**: `nvidia_api_key`, `openai_api_key`, `tavily_api_key`, `mem0_api_key`
37+
38+
**Services**: `milvus_uri`, `redis_url`, `mysql_connection_info`, `phoenix_url`
39+
40+
**Directories**: `root_repo_dir`, `examples_dir` (NAT repo only)
41+
42+
**Mocked Objects**: `mock_httpx_async_client`, `mock_httpx_sync_client`, `mock_builder`
43+
44+
There are many more fixtures available, refer to the [plugin.py](mdc:packages/nvidia_nat_test/src/nat/test/plugin.py) file and any `conftest.py` files defined in the file hierarchy of the current test file for the complete list.
45+
3146
### Integration Tests
3247

3348
For workflows that require actual LLM services or external services, follow the integration testing guidelines:
@@ -94,14 +109,6 @@ pytest --run_slow --run_integration packages/nvidia_nat_langchain
94109
- `run_workflow(config_file, question, expected_answer)` - Run and validate workflows
95110
- `load_config(config_file)` - Load configuration objects
96111

97-
### Available Fixtures
98-
99-
**API Keys**: `nvidia_api_key`, `openai_api_key`, `tavily_api_key`, `mem0_api_key`
100-
101-
**Services**: `milvus_uri`, `redis_url`, `mysql_connection_info`, `phoenix_url`
102-
103-
**Directories**: `root_repo_dir`, `examples_dir` (NAT repo only)
104-
105112
### Test LLM
106113

107114
- `_type: nat_test_llm` - Use in YAML configs to stub LLM responses

.github/workflows/ci_pipe.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,15 @@ jobs:
209209
shell: bash
210210
run: ./nat/ci/scripts/github/build_wheel.sh
211211

212+
- name: Upload Package Reports
213+
uses: actions/upload-artifact@v6
214+
if: ${{ always() }}
215+
with:
216+
name: "package_listings"
217+
path: "${{ github.workspace }}/tmp/package_listings.tar.bz2"
218+
if-no-files-found: error
219+
compression-level: 0
220+
212221
- name: Upload Wheels
213222
uses: actions/upload-artifact@v6
214223
with:

.pre-commit-config.yaml

Lines changed: 19 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -26,39 +26,25 @@ repos:
2626
# Run the linter.
2727
- id: ruff-check
2828
args: [ --fix ]
29-
30-
- repo: https://github.com/astral-sh/uv-pre-commit
31-
rev: 0.9.28
29+
- repo: local
3230
hooks:
33-
- { id: uv-lock, name: "uv-lock", files: "pyproject.toml" }
34-
- { id: uv-lock, name: "uv-lock-a2a", args: [--project, packages/nvidia_nat_a2a], files: "packages/nvidia_nat_a2a/pyproject.toml" }
35-
- { id: uv-lock, name: "uv-lock-adk", args: [--project, packages/nvidia_nat_adk], files: "packages/nvidia_nat_adk/pyproject.toml" }
36-
- { id: uv-lock, name: "uv-lock-agno", args: [--project, packages/nvidia_nat_agno], files: "packages/nvidia_nat_agno/pyproject.toml" }
37-
- { id: uv-lock, name: "uv-lock-autogen", args: [--project, packages/nvidia_nat_autogen], files: "packages/nvidia_nat_autogen/pyproject.toml" }
38-
- { id: uv-lock, name: "uv-lock-core", args: [--project, packages/nvidia_nat_core], files: "packages/nvidia_nat_core/pyproject.toml" }
39-
- { id: uv-lock, name: "uv-lock-crewai", args: [--project, packages/nvidia_nat_crewai], files: "packages/nvidia_nat_crewai/pyproject.toml" }
40-
- { id: uv-lock, name: "uv-lock-data_flywheel", args: [--project, packages/nvidia_nat_data_flywheel], files: "packages/nvidia_nat_data_flywheel/pyproject.toml" }
41-
- { id: uv-lock, name: "uv-lock-eval", args: [--project, packages/nvidia_nat_eval], files: "packages/nvidia_nat_eval/pyproject.toml" }
42-
- { id: uv-lock, name: "uv-lock-fastmcp", args: [--project, packages/nvidia_nat_fastmcp], files: "packages/nvidia_nat_fastmcp/pyproject.toml" }
43-
- { id: uv-lock, name: "uv-lock-langchain", args: [--project, packages/nvidia_nat_langchain], files: "packages/nvidia_nat_langchain/pyproject.toml" }
44-
- { id: uv-lock, name: "uv-lock-llama_index", args: [--project, packages/nvidia_nat_llama_index], files: "packages/nvidia_nat_llama_index/pyproject.toml" }
45-
- { id: uv-lock, name: "uv-lock-mcp", args: [--project, packages/nvidia_nat_mcp], files: "packages/nvidia_nat_mcp/pyproject.toml" }
46-
- { id: uv-lock, name: "uv-lock-mem0ai", args: [--project, packages/nvidia_nat_mem0ai], files: "packages/nvidia_nat_mem0ai/pyproject.toml" }
47-
- { id: uv-lock, name: "uv-lock-mysql", args: [--project, packages/nvidia_nat_mysql], files: "packages/nvidia_nat_mysql/pyproject.toml" }
48-
- { id: uv-lock, name: "uv-lock-nemo_customizer", args: [--project, packages/nvidia_nat_nemo_customizer], files: "packages/nvidia_nat_nemo_customizer/pyproject.toml" }
49-
- { id: uv-lock, name: "uv-lock-openpipe_art", args: [--project, packages/nvidia_nat_openpipe_art], files: "packages/nvidia_nat_openpipe_art/pyproject.toml" }
50-
- { id: uv-lock, name: "uv-lock-opentelemetry", args: [--project, packages/nvidia_nat_opentelemetry], files: "packages/nvidia_nat_opentelemetry/pyproject.toml" }
51-
- { id: uv-lock, name: "uv-lock-phoenix", args: [--project, packages/nvidia_nat_phoenix], files: "packages/nvidia_nat_phoenix/pyproject.toml" }
52-
- { id: uv-lock, name: "uv-lock-rag", args: [--project, packages/nvidia_nat_rag], files: "packages/nvidia_nat_rag/pyproject.toml" }
53-
- { id: uv-lock, name: "uv-lock-ragaai", args: [--project, packages/nvidia_nat_ragaai], files: "packages/nvidia_nat_ragaai/pyproject.toml" }
54-
- { id: uv-lock, name: "uv-lock-redis", args: [--project, packages/nvidia_nat_redis], files: "packages/nvidia_nat_redis/pyproject.toml" }
55-
- { id: uv-lock, name: "uv-lock-s3", args: [--project, packages/nvidia_nat_s3], files: "packages/nvidia_nat_s3/pyproject.toml" }
56-
- { id: uv-lock, name: "uv-lock-semantic_kernel", args: [--project, packages/nvidia_nat_semantic_kernel], files: "packages/nvidia_nat_semantic_kernel/pyproject.toml" }
57-
- { id: uv-lock, name: "uv-lock-strands", args: [--project, packages/nvidia_nat_strands], files: "packages/nvidia_nat_strands/pyproject.toml" }
58-
- { id: uv-lock, name: "uv-lock-test", args: [--project, packages/nvidia_nat_test], files: "packages/nvidia_nat_test/pyproject.toml" }
59-
- { id: uv-lock, name: "uv-lock-vanna", args: [--project, packages/nvidia_nat_vanna], files: "packages/nvidia_nat_vanna/pyproject.toml" }
60-
- { id: uv-lock, name: "uv-lock-weave", args: [--project, packages/nvidia_nat_weave], files: "packages/nvidia_nat_weave/pyproject.toml" }
61-
- { id: uv-lock, name: "uv-lock-zep_cloud", args: [--project, packages/nvidia_nat_zep_cloud], files: "packages/nvidia_nat_zep_cloud/pyproject.toml" }
31+
- id: uv-lock-all-pyprojects
32+
name: Ensure `uv lock` is run for all pyproject.toml files
33+
entry: >-
34+
bash -ec '
35+
status=0
36+
while IFS= read -r -d "" pyproject; do
37+
(
38+
echo "Locking $(dirname "$pyproject")" &&
39+
cd "$(dirname "$pyproject")" &&
40+
uv lock
41+
) || status=$?
42+
done < <(find . -name pyproject.toml -not -path "*/.*/*" -print0)
43+
exit "$status"
44+
'
45+
language: system
46+
files: "pyproject\\.toml$"
47+
pass_filenames: false
6248
- repo: local
6349
hooks:
6450
- id: clear-notebook-output-cells
@@ -73,7 +59,7 @@ repos:
7359
hooks:
7460
- id: markdown-link-check
7561
args: ["-q", "--config", "ci/markdown-link-check-config.json"]
76-
exclude: "^(src/nat/meta/pypi\\.md|CHANGELOG\\.md)$"
62+
exclude: "^(packages/nvidia_nat_core/src/nat/meta/pypi\\.md|CHANGELOG\\.md)$"
7763

7864
default_language_version:
7965
python: python3

.pytest.ini

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,6 @@ markers =
1313
integration: Integration tests which do not use mocks and may require external services
1414
requires_cache: Tests that require a reverse-proxy cache to be running
1515
slow: Slow tests
16-
filterwarnings =
17-
# Work-around for a warning emitted by strands https://github.com/strands-agents/sdk-python/issues/1236
18-
ignore:^These events have been moved to production.*strands:DeprecationWarning
1916
asyncio_mode = auto
2017
asyncio_default_fixture_loop_scope = session
2118

ci/release/update-version.sh

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@ function sed_runner() {
5454
# Currently only the pypi.md file for the nvidia-nat package contains links to documentation
5555
# Replace this with a `find ./ -name "pypi.md"` if this is needed for the other pypi.md files
5656
if [[ -z "${SKIP_MD_UPDATE}" ]]; then
57-
sed_runner "s|https:\/\/docs.nvidia.com\/nemo\/agent-toolkit\/\([0-9|\.]\+\)|https:\/\/docs.nvidia.com\/nemo\/agent-toolkit\/${NEXT_SHORT_TAG}|g" src/nat/meta/pypi.md
57+
sed_runner "s|https:\/\/docs.nvidia.com\/nemo\/agent-toolkit\/\([0-9|\.]\+\)|https:\/\/docs.nvidia.com\/nemo\/agent-toolkit\/${NEXT_SHORT_TAG}|g" \
58+
"${PROJECT_ROOT}/packages/nvidia_nat_core/src/nat/meta/pypi.md"
5859
fi
5960

6061
mapfile -t NAT_NOTEBOOKS < <(find ./examples/notebooks -name "*.ipynb" | sort)

ci/scripts/copyright.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828

2929
FilesToCheck = [
3030
# Get all of these extensions and templates (*.in)
31-
re.compile(r"[.](cmake|cpp|cc|css|cu|cuh|h|hpp|md|rst|sh|pxd|py|pyx|yml|yaml)(\.in)?$"),
31+
re.compile(r"[.](cmake|cpp|cc|css|cu|cuh|h|hpp|md|rst|sh|pxd|py|pyx|toml|yml|yaml)(\.in)?$"),
3232
# And files with a particular file/extension combo
3333
re.compile(r"CMakeLists[.]txt$"),
3434
re.compile(r"setup[.]cfg$"),
@@ -48,6 +48,7 @@
4848
re.compile(r"[^ \/\n]*conda/environments/.*\.yaml$"), # Ignore generated environment files
4949
re.compile(r"LICENSE\.md$"), # Ignore the license file itself
5050
re.compile(r"^examples/.*/data/.*.md$"), # Ignore data files in examples
51+
re.compile(r"^\.nspect-allowlist\.toml$"), # Ignore the nspect allowlist file
5152
]
5253

5354
# this will break starting at year 10000, which is probably OK :)
@@ -457,6 +458,7 @@ def _main():
457458
'pyx': A2_LIC_HASH,
458459
'rst': A2_LIC_RST,
459460
'sh': A2_LIC_HASH,
461+
'toml': A2_LIC_HASH,
460462
'txt': A2_LIC_HASH,
461463
'yaml': A2_LIC_HASH,
462464
'yml': A2_LIC_HASH,

ci/scripts/github/build_wheel.sh

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ GITHUB_SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd
2121
source ${GITHUB_SCRIPT_DIR}/common.sh
2222
WHEELS_BASE_DIR="${WORKSPACE_TMP}/wheels"
2323
WHEELS_DIR="${WHEELS_BASE_DIR}/nvidia-nat"
24+
PIP_REPORTS_DIR="${WORKSPACE_TMP}/pip_reports"
25+
mkdir -p "${PIP_REPORTS_DIR}"
2426

2527
GIT_TAG=$(get_git_tag)
2628
rapids-logger "Git Version: ${GIT_TAG}"
@@ -57,6 +59,18 @@ deactivate
5759
TEMP_INSTALL_LOCATION="${WORKSPACE_TMP}/wheel_test_env"
5860
install_python_versions
5961

62+
function create_package_report_tarball() {
63+
local tarball_path="${WORKSPACE_TMP}/package_listings.tar.bz2"
64+
tar -cjf "${tarball_path}" -C "${PIP_REPORTS_DIR}" .
65+
66+
# Clean out the reports directory, in CI this doesn't have an impact, but if running locally it prevents old
67+
# reports from being included in future tarballs
68+
rm -rf "${PIP_REPORTS_DIR}"
69+
echo "${tarball_path}"
70+
}
71+
72+
trap create_package_report_tarball EXIT
73+
6074
for whl in "${MOVED_WHEELS[@]}"; do
6175

6276
for pyver in "${SUPPORTED_PYTHON_VERSIONS[@]}"; do
@@ -76,6 +90,10 @@ for whl in "${MOVED_WHEELS[@]}"; do
7690
UV_PIP_OUT=$(uv pip install -q --prerelease=allow --find-links "${WHEELS_BASE_DIR}" "${whl}" 2>&1)
7791
INSTALL_RESULT=$?
7892

93+
# Report the packages in the environment regardless of install success
94+
rapids-logger "Installed wheel ${whl} with Python ${pyver}, pip install exit code ${INSTALL_RESULT}"
95+
uv pip list --format json > "${PIP_REPORTS_DIR}/$(basename "${whl}" .whl)_py${pyver}_packages.json"
96+
7997
if [[ ${INSTALL_RESULT} -ne 0 ]]; then
8098
rapids-logger "Error, failed to install wheel ${whl} with Python ${pyver}"
8199
echo "${UV_PIP_OUT}"
@@ -119,3 +137,5 @@ for whl in "${MOVED_WHEELS[@]}"; do
119137
rm -rf "${TEMP_INSTALL_LOCATION}"
120138
done
121139
done
140+
141+
exit 0

ci/scripts/gitlab/artifactory_upload.sh

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,8 @@ if [[ -z "${URM_USER}" || -z "${URM_API_KEY}" ]]; then
5454
exit 1
5555
fi
5656

57-
if [[ -z "${AIQ_ARTIFACTORY_URL}" || -z "${AIQ_ARTIFACTORY_NAME}" ]]; then
58-
echo "Error: AIQ_ARTIFACTORY_URL or AIQ_ARTIFACTORY_NAME is not set. Exiting."
57+
if [[ -z "${NAT_ARTIFACTORY_URL}" || -z "${NAT_ARTIFACTORY_NAME}" ]]; then
58+
echo "Error: NAT_ARTIFACTORY_URL or NAT_ARTIFACTORY_NAME is not set. Exiting."
5959
exit 1
6060
fi
6161

@@ -113,11 +113,11 @@ if [[ "${UPLOAD_TO_ARTIFACTORY}" == "true" ]]; then
113113
# as this is an already established path in artifactory
114114
RELATIVE_PATH="${WHEEL_FILE#${WHEELS_BASE_DIR}/}"
115115
RELATIVE_PATH=$(echo "${RELATIVE_PATH}" | sed -e 's|^nvidia-nat/|aiqtoolkit/|' | sed -e 's|^nat/|aiqtoolkit/|')
116-
ARTIFACTORY_PATH="${AIQ_ARTIFACTORY_NAME}/${RELATIVE_PATH}"
116+
ARTIFACTORY_PATH="${NAT_ARTIFACTORY_NAME}/${RELATIVE_PATH}"
117117

118118
echo "Uploading ${WHEEL_FILE} to ${ARTIFACTORY_PATH}..."
119119

120-
CI=true jf rt u --fail-no-op --url="${AIQ_ARTIFACTORY_URL}" \
120+
CI=true jf rt u --fail-no-op --url="${NAT_ARTIFACTORY_URL}" \
121121
--user="${URM_USER}" --password="${URM_API_KEY}" \
122122
--flat=false "${WHEEL_FILE}" "${ARTIFACTORY_PATH}" \
123123
--target-props "arch=${NAT_ARCH};os=${NAT_OS};branch=${GIT_TAG};component_name=${ARTIFACTORY_COMPONENT_FIXED_NAME};version=${GIT_TAG};release_approver=${RELEASE_APPROVER};release_status=${RELEASE_STATUS}"
@@ -131,8 +131,8 @@ fi
131131

132132
# List Artifactory contents (disabled by default as the output is very verbose)
133133
if [[ "${LIST_ARTIFACTORY_CONTENTS}" == "true" ]]; then
134-
echo "Listing contents of Artifactory (${AIQ_ARTIFACTORY_NAME}):"
135-
CI=true jf rt s --url="${AIQ_ARTIFACTORY_URL}" \
134+
echo "Listing contents of Artifactory (${NAT_ARTIFACTORY_NAME}):"
135+
CI=true jf rt s --url="${NAT_ARTIFACTORY_URL}" \
136136
--user="${URM_USER}" --password="${URM_API_KEY}" \
137-
"${AIQ_ARTIFACTORY_NAME}/*/${GIT_TAG}/" --recursive
137+
"${NAT_ARTIFACTORY_NAME}/*/${GIT_TAG}/" --recursive
138138
fi

0 commit comments

Comments
 (0)