Skip to content

feat(knowledge): add Azure AI Search backend#308

Merged
AjayThorve merged 28 commits into
NVIDIA-AI-Blueprints:developfrom
harmke:feat/azure-ai-search-knowledge-layer
Jul 14, 2026
Merged

feat(knowledge): add Azure AI Search backend#308
AjayThorve merged 28 commits into
NVIDIA-AI-Blueprints:developfrom
harmke:feat/azure-ai-search-knowledge-layer

Conversation

@harmke

@harmke harmke commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Overview

Adds Azure AI Search as a Knowledge Layer backend for AI-Q. This gives deployments a managed alternative to the existing LlamaIndex/ChromaDB and Foundational RAG backends while preserving the shared Knowledge API, NAT function registration, document summaries, and citation formatting.

The adapter generates embeddings client-side through the existing NVIDIA embedding integration and stores document chunks in one Azure AI Search index per logical collection.

This PR includes:

  • azure_ai_search retriever and ingestor adapters with vector, hybrid, and opt-in semantic-ranked retrieval.
  • API-key authentication through AZURE_SEARCH_API_KEY or Azure identity authentication through DefaultAzureCredential.
  • Managed-identity setup guidance for the required Search Service Contributor and Search Index Data Contributor roles.
  • Shared embedding defaults through AIQ_EMBED_BASE_URL and AIQ_EMBED_MODEL, with Azure index dimensions configured through AIQ_EMBED_DIM.
  • Collision-safe physical index names and ownership/schema markers so AI-Q only lists or mutates indexes it owns.
  • PDF, DOCX, TXT, and Markdown ingestion through LlamaIndex readers, including chunk metadata, page-aware citations, and optional summaries.
  • Canonical UUID file IDs, asynchronous ingestion status, same-name replacement handling, batch-size enforcement, upload rollback, delete retries, eventual-consistency-aware validation, pagination, and TTL cleanup.
  • Azure-specific installation, configuration, and operating documentation.
  • Focused unit tests and adapter compliance coverage.

This PR does not provision Azure infrastructure. The Azure AI Search service, required permissions, and embedding endpoint must already exist.

Validation

All commands were run from the repository root unless noted.

$ uv run pytest tests/knowledge_layer_tests/test_azure_ai_search.py -q
..................................                                       [100%]
34 passed in 12.96s

$ uv run ruff check sources/knowledge_layer/src/register.py sources/knowledge_layer/src/azure_ai_search tests/knowledge_layer_tests/test_azure_ai_search.py tests/knowledge_layer_tests/run_adapter_compliance.py
All checks passed!

$ uv run ruff format --check sources/knowledge_layer/src/register.py sources/knowledge_layer/src/azure_ai_search tests/knowledge_layer_tests/test_azure_ai_search.py tests/knowledge_layer_tests/run_adapter_compliance.py
5 files already formatted

Adapter registration and factory compliance:

$ uv run python tests/knowledge_layer_tests/run_adapter_compliance.py --backend azure_ai_search --quick --config '{"endpoint":"https://example.search.windows.net","start_ttl_cleanup":false}'
Summary: 4/4 passed, 0 failed
All tests PASSED - Adapter is compliant!

Documentation build:

$ cd docs
$ uv run make html
build succeeded, 3 warnings.

The three Sphinx warnings are unresolved cross-reference warnings in unrelated existing pages (architecture/agents/sandbox.md and integration/agent-skills.md).

Live Azure service validation was also completed against a Basic-tier Azure AI Search service using NVIDIA-hosted nvidia/nv-embed-v1 embeddings (4096 dimensions). The full adapter compliance flow passed 14/14 under admin-key authentication, covering collection creation, TXT ingestion, asynchronous status polling, file listing, hybrid retrieval with semantic ranking, chunk normalization, file deletion, and collection cleanup. DefaultAzureCredential also selected a system-assigned managed identity in Azure Container Apps, and index creation/deletion, document upload/deletion, and querying all succeeded with the documented Search Service Contributor and Search Index Data Contributor roles.

  • I ran the relevant local checks or explained why they are not applicable.
  • I added or updated tests for behavior changes.
  • I updated documentation for user-facing or contributor-facing changes.
  • I confirmed this PR does not include secrets, credentials, or internal-only data.
  • I certify this contribution under the Developer Certificate of Origin (DCO) and signed my commits with git commit -s or an equivalent sign-off.

Where should reviewers start?

Start with sources/knowledge_layer/src/azure_ai_search/adapter.py for index ownership, schema validation, ingestion, replacement, and retrieval behavior. Then review sources/knowledge_layer/src/register.py for NAT configuration and authentication defaults, followed by tests/knowledge_layer_tests/test_azure_ai_search.py for the expected lifecycle and failure handling.

The main design decision is that AI-Q creates and manages only namespaced indexes carrying its ownership marker; unmanaged or incompatible indexes are ignored rather than modified.

Related Issues

  • None.

Summary by CodeRabbit

  • New Features
    • Added Azure AI Search as a knowledge-retrieval backend, including installation extras and YAML configuration support.
    • Included Azure authentication modes (API key or managed identity), embedding dimension settings, index-prefix isolation, and collection TTL/cleanup controls.
  • Documentation
    • Updated configuration reference and Knowledge Layer setup with Azure AI Search backend options and environment variables.
    • Added an end-to-end Azure AI Search example, backend README, and new Web-mode provided configuration profile.
    • Updated Examples navigation to include the Azure AI Search knowledge layer.
  • Tests
    • Added Azure AI Search adapter tests and expanded adapter compliance coverage.

@copy-pr-bot

copy-pr-bot Bot commented Jul 3, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@coderabbitai

coderabbitai Bot commented Jul 3, 2026

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

An error occurred during the review process. Please try again later.

Walkthrough

Adds Azure AI Search as a knowledge-layer backend with configuration and packaging support, hybrid retrieval, ingestion and lifecycle operations, compliance tests, Web API configuration, and operational documentation.

Changes

Azure AI Search Backend

Layer / File(s) Summary
Backend configuration and packaging
sources/knowledge_layer/src/register.py, sources/knowledge_layer/pyproject.toml, sources/knowledge_layer/src/azure_ai_search/*, deploy/.env.example, tests/knowledge_layer_tests/run_adapter_compliance.py
Registers azure_ai_search, adds validated endpoint, credential, prefix, and embedding settings, packages the optional backend extra, and extends compliance support.
Index configuration and schema enforcement
sources/knowledge_layer/src/azure_ai_search/adapter.py
Adds credential selection, deterministic index naming, ownership markers, Azure schema creation, batching, and strict existing-index validation.
Hybrid retrieval adapter
sources/knowledge_layer/src/azure_ai_search/adapter.py
Performs manifest-gated, collection-scoped hybrid text/vector retrieval and normalizes Azure hits into knowledge-layer chunks.
Ingestion and lifecycle operations
sources/knowledge_layer/src/azure_ai_search/adapter.py
Adds parsing, fixed chunking, embeddings, job tracking, batched uploads with rollback, summaries, TTL cleanup, and collection/file CRUD.
Adapter and lifecycle validation
tests/knowledge_layer_tests/test_azure_ai_search.py
Tests configuration, schema, retrieval, ingestion, rollback, deletion, duplicate files, TTL cleanup, summaries, health checks, and helper behavior.
Backend documentation and examples
docs/source/**/*.md, sources/knowledge_layer/**/*.md, configs/config_web_azure_ai_search.yml, .secrets.baseline
Documents installation, authentication, Azure roles, indexing and retrieval behavior, lifecycle settings, supported files, and Web API setup.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant AzureAISearchIngestor
  participant SearchClient
  participant AzureAISearchRetriever
  Caller->>AzureAISearchIngestor: submit ingestion job
  AzureAISearchIngestor->>SearchClient: upload embedded chunks
  SearchClient-->>AzureAISearchIngestor: return upload results
  Caller->>AzureAISearchRetriever: retrieve query
  AzureAISearchRetriever->>SearchClient: execute scoped hybrid search
  SearchClient-->>AzureAISearchRetriever: return matching chunks
  AzureAISearchRetriever-->>Caller: return normalized results
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 4.52% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title follows Conventional Commits and clearly summarizes the Azure AI Search backend addition.
Description check ✅ Passed The description includes the required Overview, Validation, reviewers-start, and Related Issues sections with concrete implementation and test details.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

@coderabbitai

coderabbitai Bot commented Jul 3, 2026

Copy link
Copy Markdown

Caution

Failed to replace (edit) comment. This is likely due to insufficient permissions or the comment being deleted.

Error details
{}

@AjayThorve AjayThorve requested review from AjayThorve and KyleZheng1284 and removed request for KyleZheng1284 July 6, 2026 17:15
@KyleZheng1284

Copy link
Copy Markdown
Contributor

/ok to test 1232f19

@KyleZheng1284

Copy link
Copy Markdown
Contributor

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Jul 6, 2026

Copy link
Copy Markdown
✅ Action performed

Full review finished.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🤖 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/customization/configuration-reference.md`:
- Around line 279-291: The configuration table currently shows
`azure_search_auth_mode` defaulting to `Auto`, which does not match the actual
`KnowledgeRetrievalConfig` behavior and can mislead users copying YAML. Update
the wording in the `configuration-reference.md` table entry for
`azure_search_auth_mode` to reflect the real default/auth selection logic, and
make it clear that only `managed_identity` and `api_key` are valid modes rather
than presenting `Auto` as a user-settable default.

In `@docs/source/customization/knowledge-layer.md`:
- Around line 159-189: The Azure AI Search example in knowledge-layer.md needs
blank lines separating the prose from the fenced YAML block to satisfy
markdownlint MD031. Update the section around the Azure AI Search example so the
fence is surrounded by empty lines, keeping the surrounding explanatory text and
the code block in the same place.

In `@sources/knowledge_layer/src/azure_ai_search/adapter.py`:
- Around line 1013-1020: The `_collection_info` helper is doing an expensive
full index walk by calling `list_files(name)` just to compute `file_count`,
which makes `list_collections` scale poorly. Update `_collection_info` in the
Azure AI Search adapter to avoid enumerating all documents for metadata; derive
`file_count` from cheaper indexed data such as a `file_id` facet or stored
marker metadata, and keep `get_document_count()` only for chunk counts. Leave
the full document iteration in `list_files` for explicit file listing only.
- Around line 492-493: The Azure AI Search adapter is forwarding
filters["$filter"] from retrieve() directly into client.search() without any
validation, so the filtering path in the adapter needs to constrain or sanitize
that OData before use. Update the filter handling near the
search_params["filter"] assignment to validate against an allowlist of supported
fields/operators, or otherwise reject unsafe expressions before passing them
onward. Keep the logic localized in the retrieve/search_params construction flow
so the existing filters dict handling remains intact.

In `@sources/knowledge_layer/src/register.py`:
- Around line 42-45: _update _url_from_env in register.py so an explicitly empty
environment value is treated like “unset” and does not override the fallback
default. Adjust the logic in _url_from_env to distinguish between missing and
empty values, and make sure callers like embed_base_url still receive the
intended default URL when AIQ_EMBED_BASE_URL is blank. Preserve the current
behavior for optional settings such as azure_search_endpoint while fixing the
fallback path used by non-optional URL fields.

In `@tests/knowledge_layer_tests/test_azure_ai_search.py`:
- Around line 276-294: The test data in
test_setup_backend_preserves_secrets_and_prefix is being flagged by
detect-secrets because of the inline api key literals. Add an inline pragma:
allowlist secret to the specific placeholder secret assignments in this test so
the scanner ignores them, while keeping the assertions that _setup_backend
preserves SecretStr handling and the index_prefix value.
🪄 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: ASSERTIVE

Plan: Enterprise

Run ID: f0dc80cd-5107-4735-b4af-4c0152a48533

📥 Commits

Reviewing files that changed from the base of the PR and between db86f8f and 1232f19.

⛔ Files ignored due to path filters (1)
  • uv.lock is excluded by !**/*.lock
📒 Files selected for processing (15)
  • docs/source/customization/configuration-reference.md
  • docs/source/customization/knowledge-layer.md
  • docs/source/examples/azure-ai-search.md
  • docs/source/examples/index.md
  • docs/source/index.md
  • sources/knowledge_layer/KNOWLEDGE-LAYER-SETUP.md
  • sources/knowledge_layer/README.md
  • sources/knowledge_layer/pyproject.toml
  • sources/knowledge_layer/src/__init__.py
  • sources/knowledge_layer/src/azure_ai_search/README.md
  • sources/knowledge_layer/src/azure_ai_search/__init__.py
  • sources/knowledge_layer/src/azure_ai_search/adapter.py
  • sources/knowledge_layer/src/register.py
  • tests/knowledge_layer_tests/run_adapter_compliance.py
  • tests/knowledge_layer_tests/test_azure_ai_search.py
📜 Review details
⚠️ CI failures not shown inline (4)

GitHub Actions: AIQ CI / 0_Lint and Hooks.txt: docs(knowledge): document Azure Search managed identity roles

Conclusion: failure

View job details

##[group]Run . .venv/bin/activate
 �[36;1m. .venv/bin/activate�[0m
 �[36;1mSKIP=ruff-check,ruff-format,pytest,helm-lint pre-commit run --all-files�[0m
 shell: /usr/bin/bash -e {0}
 env:
   pythonLocation: /opt/hostedtoolcache/Python/3.13.14/x64
   PKG_CONFIG_PATH: /opt/hostedtoolcache/Python/3.13.14/x64/lib/pkgconfig
   Python_ROOT_DIR: /opt/hostedtoolcache/Python/3.13.14/x64
   Python2_ROOT_DIR: /opt/hostedtoolcache/Python/3.13.14/x64
   Python3_ROOT_DIR: /opt/hostedtoolcache/Python/3.13.14/x64
   LD_LIBRARY_PATH: /opt/hostedtoolcache/Python/3.13.14/x64/lib
   UV_CACHE_DIR: /home/runner/work/_temp/setup-uv-cache
 ##[endgroup]
 [WARNING] hook id `helm-lint` uses deprecated stage names (push) which will be removed in a future version.  run: `pre-commit migrate-config` to automatically fix this.
 [WARNING] hook id `pytest` uses deprecated stage names (push) which will be removed in a future version.  run: `pre-commit migrate-config` to automatically fix this.
 [INFO] Initializing environment for https://github.com/astral-sh/ruff-pre-commit.
 [INFO] Initializing environment for https://github.com/astral-sh/uv-pre-commit.
 [INFO] Initializing environment for https://github.com/pre-commit/pre-commit-hooks.
 [WARNING] repo `https://github.com/pre-commit/pre-commit-hooks` uses deprecated stage names (commit, push) which will be removed in a future version.  Hint: often `pre-commit autoupdate --repo https://github.com/pre-commit/pre-commit-hooks` will fix this.  if it does not -- consider reporting an issue to that repo.
 [INFO] Initializing environment for https://github.com/Yelp/detect-secrets.
 [INFO] Initializing environment for local:pyyaml==6.0.3.
 [INFO] Initializing environment for https://github.com/tcort/markdown-link-check.
 [WARNING] repo `https://github.com/tcort/markdown-link-check` uses deprecated stage names (commit, push) which will be removed in a future version.  Hint: often `pre-commit autoupdate --repo https://github.com/tcort/markdown-link-check` wi...

GitHub Actions: AIQ CI / Script Validation: docs(knowledge): document Azure Search managed identity roles

Conclusion: failure

View job details

##[group]Run . .venv/bin/activate
 �[36;1m. .venv/bin/activate�[0m
 �[36;1mchmod +x ci/scripts/test_scripts.sh�[0m
 �[36;1mci/scripts/test_scripts.sh --skip-setup�[0m
 shell: /usr/bin/bash -e {0}
 env:
   pythonLocation: /opt/hostedtoolcache/Python/3.13.14/x64
   PKG_CONFIG_PATH: /opt/hostedtoolcache/Python/3.13.14/x64/lib/pkgconfig
   Python_ROOT_DIR: /opt/hostedtoolcache/Python/3.13.14/x64
   Python2_ROOT_DIR: /opt/hostedtoolcache/Python/3.13.14/x64
   Python3_ROOT_DIR: /opt/hostedtoolcache/Python/3.13.14/x64
   LD_LIBRARY_PATH: /opt/hostedtoolcache/Python/3.13.14/x64/lib
   UV_CACHE_DIR: /home/runner/work/_temp/setup-uv-cache
 ##[endgroup]
 ================================================
   AI-Q Blueprint - Script Tests
 ================================================
 Repository: /home/runner/work/aiq/aiq
 Scripts:    /home/runner/work/aiq/aiq/scripts
 ============================================
   Testing Bash Syntax
 ============================================
 �[0;32m✅ PASS�[0m: dev.sh - valid bash syntax
 �[0;32m✅ PASS�[0m: setup.sh - valid bash syntax
 �[0;32m✅ PASS�[0m: setup_openshell.sh - valid bash syntax
 �[0;32m✅ PASS�[0m: start_as_skill.sh - valid bash syntax
 �[0;32m✅ PASS�[0m: start_cli.sh - valid bash syntax
 �[0;32m✅ PASS�[0m: start_e2e.sh - valid bash syntax
 �[0;32m✅ PASS�[0m: start_server_in_debug_mode.sh - valid bash syntax
 �[1;33m⏭️  SKIP�[0m: setup.sh - skipped (--skip-setup flag)
 ============================================
   Testing --help Flags
 ============================================
 �[0;32m✅ PASS�[0m: start_cli.sh --help
 �[0;32m✅ PASS�[0m: start_server_in_debug_mode.sh --help
 ============================================
   Testing Virtual Environment Checks
 ============================================
 �[0;32m✅ PASS�[0m: start_cli.sh - venv check works
 �[0;32m✅ PASS�[0m: start_server_in_debug_mode.sh - venv check works
 ============================================
   Testing Pytest Integration
 =====================...

GitHub Actions: AIQ CI / Lint and Hooks: docs(knowledge): document Azure Search managed identity roles

Conclusion: failure

View job details

##[group]Run . .venv/bin/activate
 �[36;1m. .venv/bin/activate�[0m
 �[36;1mSKIP=ruff-check,ruff-format,pytest,helm-lint pre-commit run --all-files�[0m
 shell: /usr/bin/bash -e {0}
 env:
   pythonLocation: /opt/hostedtoolcache/Python/3.13.14/x64
   PKG_CONFIG_PATH: /opt/hostedtoolcache/Python/3.13.14/x64/lib/pkgconfig
   Python_ROOT_DIR: /opt/hostedtoolcache/Python/3.13.14/x64
   Python2_ROOT_DIR: /opt/hostedtoolcache/Python/3.13.14/x64
   Python3_ROOT_DIR: /opt/hostedtoolcache/Python/3.13.14/x64
   LD_LIBRARY_PATH: /opt/hostedtoolcache/Python/3.13.14/x64/lib
   UV_CACHE_DIR: /home/runner/work/_temp/setup-uv-cache
 ##[endgroup]
 [WARNING] hook id `helm-lint` uses deprecated stage names (push) which will be removed in a future version.  run: `pre-commit migrate-config` to automatically fix this.
 [WARNING] hook id `pytest` uses deprecated stage names (push) which will be removed in a future version.  run: `pre-commit migrate-config` to automatically fix this.
 [INFO] Initializing environment for https://github.com/astral-sh/ruff-pre-commit.
 [INFO] Initializing environment for https://github.com/astral-sh/uv-pre-commit.
 [INFO] Initializing environment for https://github.com/pre-commit/pre-commit-hooks.
 [WARNING] repo `https://github.com/pre-commit/pre-commit-hooks` uses deprecated stage names (commit, push) which will be removed in a future version.  Hint: often `pre-commit autoupdate --repo https://github.com/pre-commit/pre-commit-hooks` will fix this.  if it does not -- consider reporting an issue to that repo.
 [INFO] Initializing environment for https://github.com/Yelp/detect-secrets.
 [INFO] Initializing environment for local:pyyaml==6.0.3.
 [INFO] Initializing environment for https://github.com/tcort/markdown-link-check.
 [WARNING] repo `https://github.com/tcort/markdown-link-check` uses deprecated stage names (commit, push) which will be removed in a future version.  Hint: often `pre-commit autoupdate --repo https://github.com/tcort/markdown-link-check` wi...

GitHub Actions: AIQ CI / 3_Script Validation.txt: docs(knowledge): document Azure Search managed identity roles

Conclusion: failure

View job details

Current runner version: '2.335.1'
 ##[group]Runner Image Provisioner
 Hosted Compute Agent
 Version: 20260624.560
 Commit: 925d229a51159bc391ae97e54a2dd1fe20af789d
 Build Date:
 Worker ID: {0d9b6db0-89fd-4c3b-a3c0-cd2e35295af9}
 Azure Region: northcentralus
 ##[endgroup]
 ##[group]Operating System
 Ubuntu
 24.04.4
 LTS
 ##[endgroup]
 ##[group]Runner Image
 Image: ubuntu-24.04
 Version: 20260628.225.1
 Included Software: https://github.com/actions/runner-images/blob/ubuntu24/20260628.225/images/ubuntu/Ubuntu2404-Readme.md
 Image Release: https://github.com/actions/runner-images/releases/tag/ubuntu24%2F20260628.225
 ##[endgroup]
 ##[group]GITHUB_TOKEN Permissions
 Contents: read
 Metadata: read
 ##[endgroup]
 Secret source: Actions
 Prepare workflow directory
 Prepare all required actions
 Getting action download info
 Download action repository 'actions/checkout@v4' (SHA:34e114876b0b11c390a56381ad16ebd13914f8d5)
 Download action repository 'actions/setup-python@v5' (SHA:a26af69be951a213d495a4c3e4e4022e16d87065)
 Download action repository 'astral-sh/setup-uv@v4' (SHA:38f3f104447c67c051c4a08e39b64a148898af3a)
 Complete job name: Script Validation
 Node 20 is being deprecated. This workflow is running with Node 24 by default. If you need to temporarily use Node 20, you can set the ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION=true environment variable. For more information see: https://github.blog/changelog/2025-09-19-deprecation-of-node-20-on-github-actions-runners/
 ##[group]Run actions/checkout@v4
 with:
   repository: NVIDIA-AI-Blueprints/aiq
   ***REDACTED***
   ssh-strict: true
   ssh-user: git
   persist-credentials: true
   clean: true
   sparse-checkout-cone-mode: true
   fetch-depth: 1
   fetch-tags: false
   show-progress: true
   lfs: false
   submodules: false
   set-safe-directory: true
 ##[endgroup]
 Syncing repository: NVIDIA-AI-Blueprints/aiq
 ##[group]Getting Git version info
 Working directory is '/home/runner/work/aiq/aiq'
 [command]/usr/bin/git versio...
🧰 Additional context used
📓 Path-based instructions (7)
docs/source/**/*

📄 CodeRabbit inference engine (AGENTS.md)

Update the docs under docs/source/ when behavior, configuration, or workflows change

Files:

  • docs/source/examples/index.md
  • docs/source/index.md
  • docs/source/customization/knowledge-layer.md
  • docs/source/customization/configuration-reference.md
  • docs/source/examples/azure-ai-search.md
**

⚙️ CodeRabbit configuration file

**:

AI-Q Agent Guidance

Repository-global instructions for coding agents and for humans reviewing
agent-authored changes. These rules apply to every task in this repository.
Task-specific runbooks live in .agents/skills/ — load the
relevant skill before starting a workflow it covers.

Project overview

AI-Q is an NVIDIA AI Blueprint: an enterprise research agent built on the
NeMo Agent Toolkit (NAT). The deployed product is a research blueprint, not
a general skill runtime. New retrieval sources and tools are NAT functions;
agent behavior is driven by workflow YAML, Jinja2 prompts, and a data-source
registry — not by hard-coded logic.

Primary boundaries:

  • Backend Python package: src/aiq_agent/.
  • Data-source and tool packages: sources/ (each is its own package).
  • Frontends and tooling: frontends/ (web UI in frontends/ui/, eval harnesses
    in frontends/benchmarks/).
  • Configs, deployment, docs: configs/, deploy/, docs/.

Stay inside this repository. If your workspace also contains adjacent repos
(for example a sibling NeMo-Relay checkout), do not edit them as part of an AI-Q
change. Treat sources/* as independent packages: prefer the smallest change
scoped to the package you are touching.

Repository structure

Path Purpose
src/aiq_agent/ Backend agent, FastAPI extensions, auth, observability, knowledge
sources/ Data-source / tool packages (e.g. tavily_web_search, google_scholar_paper_search)
configs/ Workflow YAML configs (e.g. config_cli_default.yml)
frontends/ui/ Next.js / React / TypeScript / Tailwind / KUI web UI
frontends/benchmarks/ Eval harnesses: freshqa, deepsearch_qa, deepresearch_bench
deploy/ Docker Compose and Helm/Kubernetes assets; deploy/.env for secrets
docs/source/ ...

Files:

  • docs/source/examples/index.md
  • sources/knowledge_layer/src/azure_ai_search/__init__.py
  • docs/source/index.md
  • sources/knowledge_layer/pyproject.toml
  • sources/knowledge_layer/src/azure_ai_search/README.md
  • sources/knowledge_layer/src/__init__.py
  • sources/knowledge_layer/KNOWLEDGE-LAYER-SETUP.md
  • docs/source/customization/knowledge-layer.md
  • tests/knowledge_layer_tests/run_adapter_compliance.py
  • docs/source/customization/configuration-reference.md
  • sources/knowledge_layer/README.md
  • sources/knowledge_layer/src/register.py
  • tests/knowledge_layer_tests/test_azure_ai_search.py
  • docs/source/examples/azure-ai-search.md
  • sources/knowledge_layer/src/azure_ai_search/adapter.py
{docs/**,README.md,CONTRIBUTING.md,SECURITY.md,CODE-OF-CONDUCT.md}

⚙️ CodeRabbit configuration file

{docs/**,README.md,CONTRIBUTING.md,SECURITY.md,CODE-OF-CONDUCT.md}: Review documentation for command accuracy, branch-name consistency, current CI and copy-pr-bot behavior, public
vs internal boundary clarity, stale examples, and links that no longer match the repository layout.

Files:

  • docs/source/examples/index.md
  • docs/source/index.md
  • docs/source/customization/knowledge-layer.md
  • docs/source/customization/configuration-reference.md
  • docs/source/examples/azure-ai-search.md
**/*.py

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Run ruff check and ruff format validation for Python code changes

**/*.py: Python code must be linted and formatted with Ruff using line length 120, target Python 3.11, rule sets E,F,W,I,PL,UP, and isort force-single-line configuration
Never commit secrets, tokens, or environment-specific hostnames; use environment variables and SecretStr instead, resolving API keys at runtime
Never print or log secret values, including in tool output or error messages
Missing-secret paths must degrade gracefully (stub/skip), not crash or leak
Do not hand-reformat unrelated code when making changes; match the existing import and formatting style

Files:

  • sources/knowledge_layer/src/azure_ai_search/__init__.py
  • sources/knowledge_layer/src/__init__.py
  • tests/knowledge_layer_tests/run_adapter_compliance.py
  • sources/knowledge_layer/src/register.py
  • tests/knowledge_layer_tests/test_azure_ai_search.py
  • sources/knowledge_layer/src/azure_ai_search/adapter.py
sources/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

New tools and data sources must be NAT functions registered with @register_function decorator

Files:

  • sources/knowledge_layer/src/azure_ai_search/__init__.py
  • sources/knowledge_layer/src/__init__.py
  • sources/knowledge_layer/src/register.py
  • sources/knowledge_layer/src/azure_ai_search/adapter.py
{src/aiq_agent/knowledge/**,sources/**}

⚙️ CodeRabbit configuration file

{src/aiq_agent/knowledge/**,sources/**}: Review data-source and knowledge-layer changes for optional dependency boundaries, external API error handling,
retry/rate-limit behavior, deterministic tests, and registration consistency. New source packages should include
package metadata, plugin registration when applicable, and source-level tests.

Files:

  • sources/knowledge_layer/src/azure_ai_search/__init__.py
  • sources/knowledge_layer/pyproject.toml
  • sources/knowledge_layer/src/azure_ai_search/README.md
  • sources/knowledge_layer/src/__init__.py
  • sources/knowledge_layer/KNOWLEDGE-LAYER-SETUP.md
  • sources/knowledge_layer/README.md
  • sources/knowledge_layer/src/register.py
  • sources/knowledge_layer/src/azure_ai_search/adapter.py
**/*test*.py

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Run pytest for all behavior changes in Python code

Files:

  • tests/knowledge_layer_tests/test_azure_ai_search.py
🪛 ast-grep (0.44.1)
tests/knowledge_layer_tests/test_azure_ai_search.py

[warning] 52-52: Regex pattern passed to re is built from a non-literal (variable, call, concatenation, or f-string) value. If that value is attacker-controlled it can introduce a malicious pattern with catastrophic backtracking (ReDoS). Use a hardcoded literal pattern, or validate/escape untrusted input with re.escape() and bound the regex complexity before compiling.
Context: re.search(rf"{field} {operator} '((?:''|[^'])*)'", filter_text)
Note: [CWE-1333] Inefficient Regular Expression Complexity.

(redos-non-literal-regex-python)

sources/knowledge_layer/src/azure_ai_search/adapter.py

[info] 175-175: use jsonify instead of json.dumps for JSON output
Context: json.dumps(marker, separators=(",", ":"), sort_keys=True)
Note: [CWE-116] Improper Encoding or Escaping of Output.

(use-jsonify)


[info] 250-250: use jsonify instead of json.dumps for JSON output
Context: json.dumps(payload, default=_json_default, ensure_ascii=False, separators=(",", ":"))
Note: [CWE-116] Improper Encoding or Escaping of Output.

(use-jsonify)


[info] 770-770: use jsonify instead of json.dumps for JSON output
Context: json.dumps(metadata, separators=(",", ":"), sort_keys=True)
Note: [CWE-116] Improper Encoding or Escaping of Output.

(use-jsonify)

🪛 GitHub Actions: AIQ CI / 0_Lint and Hooks.txt
tests/knowledge_layer_tests/test_azure_ai_search.py

[error] 283-283: detect-secrets failed (exit code 3): Potential secret detected (Secret Keyword) at tests/knowledge_layer_tests/test_azure_ai_search.py:283.


[error] 284-284: detect-secrets failed (exit code 3): Potential secret detected (Secret Keyword) at tests/knowledge_layer_tests/test_azure_ai_search.py:284.

🪛 GitHub Actions: AIQ CI / Lint and Hooks
tests/knowledge_layer_tests/test_azure_ai_search.py

[error] 283-283: pre-commit hook 'detect-secrets' failed (exit code 3). Potential secret detected (Secret Type: Secret Keyword) at tests/knowledge_layer_tests/test_azure_ai_search.py:283.


[error] 284-284: pre-commit hook 'detect-secrets' failed (exit code 3). Potential secret detected (Secret Type: Secret Keyword) at tests/knowledge_layer_tests/test_azure_ai_search.py:284.

🪛 markdownlint-cli2 (0.22.1)
docs/source/customization/knowledge-layer.md

[warning] 160-160: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)

🔇 Additional comments (24)
tests/knowledge_layer_tests/test_azure_ai_search.py (2)

50-54: Skip: ReDoS hint is a false positive in this test helper.

_literal's field/operator args are only ever called with hardcoded literals ("file_id", "file_name", "id", "gt") from within this test file, not attacker-controlled input, so the flagged pattern-injection risk doesn't apply here.


1-49: LGTM!

Also applies to: 55-275, 296-765

tests/knowledge_layer_tests/run_adapter_compliance.py (1)

21-22: LGTM!

Also applies to: 97-97, 393-405, 458-463

sources/knowledge_layer/src/azure_ai_search/adapter.py (5)

239-264: LGTM!


814-845: LGTM!


80-115: LGTM!


847-874: LGTM!


977-982: 🩺 Stability & Availability

Confirm the delete/read-after-delete contract here. delete_collection() only returns True if an immediate get_index() raises ResourceNotFoundError; if Azure Search can briefly expose a stale index after delete_index(), this will report a false failure. Either treat delete_index() as authoritative or replace the reread with bounded polling.

sources/knowledge_layer/src/register.py (3)

100-104: LGTM!

Also applies to: 109-135, 136-172


218-241: azure_ai_search branch and unknown-backend message look correct.

Consistent with the BackendType literal and existing branch style for llamaindex/foundational_rag.


92-99: 🎯 Functional Correctness

Recheck azure_search_auth_mode inference for explicit keys. If azure_search_api_key can be provided without azure_search_auth_mode, the model still defaults to managed_identity and can skip the key path; handle that in the model validator or make the default depend on the supplied key.

sources/knowledge_layer/pyproject.toml (2)

21-26: LGTM!


60-68: 📐 Maintainability & Code Quality

Align the shared dependency ranges across extras
Keep llama-index-core, docx2txt, and pypdf on the same constraints in azure_ai_search and llamaindex; all pulls both extras together, so mismatched pins can make resolution fragile.

sources/knowledge_layer/src/__init__.py (1)

25-25: LGTM!

sources/knowledge_layer/src/azure_ai_search/__init__.py (1)

1-9: LGTM!

sources/knowledge_layer/README.md (1)

15-33: LGTM!

sources/knowledge_layer/src/azure_ai_search/README.md (2)

22-27: 📐 Maintainability & Code Quality | 💤 Low value

Doc's auth guidance doesn't mention the auth-mode/api-key coupling gap flagged in register.py.

Once the register.py default-inference fix (see companion comment) lands, worth a one-line note here that azure_search_auth_mode: api_key should be set explicitly when supplying AZURE_SEARCH_API_KEY outside the documented env-var flow.


1-92: LGTM!

docs/source/customization/configuration-reference.md (1)

220-221: LGTM!

Also applies to: 251-268

docs/source/customization/knowledge-layer.md (1)

46-46: LGTM!

Also applies to: 56-57, 76-76, 250-256, 437-438

docs/source/examples/azure-ai-search.md (1)

1-82: LGTM!

docs/source/examples/index.md (1)

15-15: LGTM!

docs/source/index.md (1)

142-142: LGTM!

sources/knowledge_layer/KNOWLEDGE-LAYER-SETUP.md (1)

38-48: LGTM!

Also applies to: 65-65, 858-863

Comment thread docs/source/customization/configuration-reference.md Outdated
Comment thread docs/source/customization/knowledge-layer.md
Comment thread sources/knowledge_layer/src/azure_ai_search/adapter.py Outdated
Comment thread sources/knowledge_layer/src/azure_ai_search/adapter.py Outdated
Comment thread sources/knowledge_layer/src/register.py
Comment thread tests/knowledge_layer_tests/test_azure_ai_search.py

@KyleZheng1284 KyleZheng1284 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few questions and suggestions on my end

Comment thread sources/knowledge_layer/src/azure_ai_search/adapter.py Outdated
Comment thread sources/knowledge_layer/src/azure_ai_search/adapter.py Outdated
Comment thread sources/knowledge_layer/pyproject.toml Outdated
Comment thread sources/knowledge_layer/src/azure_ai_search/adapter.py Outdated
Comment thread sources/knowledge_layer/src/azure_ai_search/adapter.py Outdated
Comment thread sources/knowledge_layer/src/azure_ai_search/adapter.py
Comment thread sources/knowledge_layer/src/register.py Outdated
Comment thread sources/knowledge_layer/src/azure_ai_search/adapter.py
Comment thread sources/knowledge_layer/src/azure_ai_search/adapter.py Outdated
Comment thread docs/source/examples/azure-ai-search.md
Comment thread docs/source/customization/configuration-reference.md Outdated
harmke added 16 commits July 7, 2026 10:34
Signed-off-by: Harmke Alkemade <halkemade@nvidia.com>
Signed-off-by: Harmke Alkemade <halkemade@nvidia.com>
Signed-off-by: Harmke Alkemade <halkemade@nvidia.com>
Signed-off-by: Harmke Alkemade <halkemade@nvidia.com>
Signed-off-by: Harmke Alkemade <halkemade@nvidia.com>
Signed-off-by: Harmke Alkemade <halkemade@nvidia.com>
Signed-off-by: Harmke Alkemade <halkemade@nvidia.com>
Signed-off-by: Harmke Alkemade <halkemade@nvidia.com>
Signed-off-by: Harmke Alkemade <halkemade@nvidia.com>
Signed-off-by: Harmke Alkemade <halkemade@nvidia.com>
Signed-off-by: Harmke Alkemade <halkemade@nvidia.com>
Signed-off-by: Harmke Alkemade <halkemade@nvidia.com>
Signed-off-by: Harmke Alkemade <halkemade@nvidia.com>
Signed-off-by: Harmke Alkemade <halkemade@nvidia.com>
Signed-off-by: Harmke Alkemade <halkemade@nvidia.com>
Signed-off-by: Harmke Alkemade <halkemade@nvidia.com>
Comment thread docs/source/examples/azure-ai-search.md Outdated
Comment thread docs/source/examples/azure-ai-search.md Outdated
Signed-off-by: Kyle Zheng <kyzheng@nvidia.com>
@KyleZheng1284

Copy link
Copy Markdown
Contributor

@harmke everything worked great E2E, could you please address the remaining comments would love to get this into the 2.2 release!

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 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/customization/knowledge-layer.md`:
- Around line 179-183: Correct the migration wording in the Azure
knowledge-layer documentation and the duplicate Azure AI Search example
documentation: do not state that schema-version-1 indexes are ignored; describe
only unsupported or legacy schema versions as requiring re-ingestion, while
preserving that the current adapter uses schema version 1 and generates
knowledge-v1 indexes.

In `@sources/knowledge_layer/KNOWLEDGE-LAYER-SETUP.md`:
- Around line 1047-1052: Add AZURE_CLIENT_ID to the environment-variable
reference table near the other Azure configuration variables, describing it as
the client ID for the user-assigned managed identity used by
DefaultAzureCredential.

In `@sources/knowledge_layer/src/azure_ai_search/adapter.py`:
- Around line 620-629: Move the synchronous collection lifecycle operations out
of async event-loop handlers: update the collection route handlers to invoke
ingestor.create_collection() and ingestor.delete_collection() via
asyncio.to_thread or an executor, or convert those handlers to synchronous
functions. Ensure all affected create/delete paths in the collections routes no
longer directly call these methods, which may block in _wait_for_search_state().
🪄 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: ASSERTIVE

Plan: Enterprise

Run ID: b44dca8a-e418-4bac-b746-1f552dfac181

📥 Commits

Reviewing files that changed from the base of the PR and between 4c546fc and e74b76e.

📒 Files selected for processing (11)
  • .secrets.baseline
  • docs/source/customization/configuration-reference.md
  • docs/source/customization/knowledge-layer.md
  • docs/source/examples/azure-ai-search.md
  • docs/source/examples/index.md
  • sources/knowledge_layer/KNOWLEDGE-LAYER-SETUP.md
  • sources/knowledge_layer/README.md
  • sources/knowledge_layer/src/azure_ai_search/README.md
  • sources/knowledge_layer/src/azure_ai_search/adapter.py
  • sources/knowledge_layer/src/register.py
  • tests/knowledge_layer_tests/test_azure_ai_search.py
📜 Review details
🧰 Additional context used
📓 Path-based instructions (7)
docs/source/**/*

📄 CodeRabbit inference engine (AGENTS.md)

Update the docs under docs/source/ when behavior, configuration, or workflows change

Files:

  • docs/source/examples/index.md
  • docs/source/customization/configuration-reference.md
  • docs/source/examples/azure-ai-search.md
  • docs/source/customization/knowledge-layer.md
**

⚙️ CodeRabbit configuration file

**:

AI-Q Agent Guidance

Repository-global instructions for coding agents and for humans reviewing
agent-authored changes. These rules apply to every task in this repository.
Task-specific runbooks live in .agents/skills/ — load the
relevant skill before starting a workflow it covers.

Project overview

AI-Q is an NVIDIA AI Blueprint: an enterprise research agent built on the
NeMo Agent Toolkit (NAT). The deployed product is a research blueprint, not
a general skill runtime. New retrieval sources and tools are NAT functions;
agent behavior is driven by workflow YAML, Jinja2 prompts, and a data-source
registry — not by hard-coded logic.

Primary boundaries:

  • Backend Python package: src/aiq_agent/.
  • Data-source and tool packages: sources/ (each is its own package).
  • Frontends and tooling: frontends/ (web UI in frontends/ui/, eval harnesses
    in frontends/benchmarks/).
  • Configs, deployment, docs: configs/, deploy/, docs/.

Stay inside this repository. If your workspace also contains adjacent repos
(for example a sibling NeMo-Relay checkout), do not edit them as part of an AI-Q
change. Treat sources/* as independent packages: prefer the smallest change
scoped to the package you are touching.

Repository structure

Path Purpose
src/aiq_agent/ Backend agent, FastAPI extensions, auth, observability, knowledge
sources/ Data-source / tool packages (e.g. tavily_web_search, google_scholar_paper_search)
configs/ Workflow YAML configs (e.g. config_cli_default.yml)
frontends/ui/ Next.js / React / TypeScript / Tailwind / KUI web UI
frontends/benchmarks/ Eval harnesses: freshqa, deepsearch_qa, deepresearch_bench
deploy/ Docker Compose and Helm/Kubernetes assets; deploy/.env for secrets
docs/source/ ...

Files:

  • docs/source/examples/index.md
  • sources/knowledge_layer/README.md
  • docs/source/customization/configuration-reference.md
  • sources/knowledge_layer/src/azure_ai_search/README.md
  • docs/source/examples/azure-ai-search.md
  • sources/knowledge_layer/KNOWLEDGE-LAYER-SETUP.md
  • docs/source/customization/knowledge-layer.md
  • tests/knowledge_layer_tests/test_azure_ai_search.py
  • sources/knowledge_layer/src/register.py
  • sources/knowledge_layer/src/azure_ai_search/adapter.py
{docs/**,README.md,CONTRIBUTING.md,SECURITY.md,CODE-OF-CONDUCT.md}

⚙️ CodeRabbit configuration file

{docs/**,README.md,CONTRIBUTING.md,SECURITY.md,CODE-OF-CONDUCT.md}: Review documentation for command accuracy, branch-name consistency, current CI and copy-pr-bot behavior, public
vs internal boundary clarity, stale examples, and links that no longer match the repository layout.

Files:

  • docs/source/examples/index.md
  • docs/source/customization/configuration-reference.md
  • docs/source/examples/azure-ai-search.md
  • docs/source/customization/knowledge-layer.md
{src/aiq_agent/knowledge/**,sources/**}

⚙️ CodeRabbit configuration file

{src/aiq_agent/knowledge/**,sources/**}: Review data-source and knowledge-layer changes for optional dependency boundaries, external API error handling,
retry/rate-limit behavior, deterministic tests, and registration consistency. New source packages should include
package metadata, plugin registration when applicable, and source-level tests.

Files:

  • sources/knowledge_layer/README.md
  • sources/knowledge_layer/src/azure_ai_search/README.md
  • sources/knowledge_layer/KNOWLEDGE-LAYER-SETUP.md
  • sources/knowledge_layer/src/register.py
  • sources/knowledge_layer/src/azure_ai_search/adapter.py
**/*.py

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Run ruff check and ruff format validation for Python code changes

**/*.py: Python code must be linted and formatted with Ruff using line length 120, target Python 3.11, rule sets E,F,W,I,PL,UP, and isort force-single-line configuration
Never commit secrets, tokens, or environment-specific hostnames; use environment variables and SecretStr instead, resolving API keys at runtime
Never print or log secret values, including in tool output or error messages
Missing-secret paths must degrade gracefully (stub/skip), not crash or leak
Do not hand-reformat unrelated code when making changes; match the existing import and formatting style

Files:

  • tests/knowledge_layer_tests/test_azure_ai_search.py
  • sources/knowledge_layer/src/register.py
  • sources/knowledge_layer/src/azure_ai_search/adapter.py
**/*test*.py

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Run pytest for all behavior changes in Python code

Files:

  • tests/knowledge_layer_tests/test_azure_ai_search.py
sources/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

New tools and data sources must be NAT functions registered with @register_function decorator

Files:

  • sources/knowledge_layer/src/register.py
  • sources/knowledge_layer/src/azure_ai_search/adapter.py
🪛 ast-grep (0.44.1)
sources/knowledge_layer/src/azure_ai_search/adapter.py

[info] 651-651: use jsonify instead of json.dumps for JSON output
Context: json.dumps(merged_metadata, separators=(",", ":"), sort_keys=True)
Note: [CWE-116] Improper Encoding or Escaping of Output.

(use-jsonify)


[info] 692-692: use jsonify instead of json.dumps for JSON output
Context: json.dumps(metadata, separators=(",", ":"), sort_keys=True)
Note: [CWE-116] Improper Encoding or Escaping of Output.

(use-jsonify)

🔇 Additional comments (22)
.secrets.baseline (1)

244-244: LGTM!

Also applies to: 293-293

docs/source/customization/configuration-reference.md (1)

220-221: LGTM!

Also applies to: 251-282

docs/source/customization/knowledge-layer.md (1)

46-46: LGTM!

Also applies to: 56-57, 76-76, 159-177, 185-189, 250-256, 437-438

docs/source/examples/azure-ai-search.md (1)

1-85: LGTM!

docs/source/examples/index.md (1)

15-15: LGTM!

sources/knowledge_layer/KNOWLEDGE-LAYER-SETUP.md (1)

12-12: LGTM!

Also applies to: 39-49, 71-71, 191-191

sources/knowledge_layer/README.md (1)

18-20: LGTM!

Also applies to: 30-30, 36-37

sources/knowledge_layer/src/azure_ai_search/README.md (1)

1-81: LGTM!

tests/knowledge_layer_tests/test_azure_ai_search.py (11)

24-24: LGTM!

Also applies to: 51-59, 67-157


241-274: LGTM!


295-307: LGTM!

Also applies to: 332-342


404-432: LGTM!

Also applies to: 446-484


496-506: LGTM!

Also applies to: 542-561


575-598: LGTM!

Also applies to: 624-654, 700-710


713-753: LGTM!

Also applies to: 756-785, 788-826


828-890: LGTM!

Also applies to: 905-940


943-976: LGTM!


992-1008: LGTM!


391-401: 🔒 Security & Privacy

No issue: azure_search_api_key uses NAT’s OptionalSecretStr, so JSON dumps emit the underlying string for config reload rather than a masked SecretStr.

			> Likely an incorrect or invalid review comment.
sources/knowledge_layer/src/azure_ai_search/adapter.py (2)

518-525: filters other than $filter are silently dropped.

Raw $filter is rejected, but a structured filter such as {"file_name": "report.pdf"} is neither applied nor rejected — the query silently runs unfiltered, unlike OpenSearch/Foundational RAG which honor the shared metadata-filter contract. Either apply supported keys or reject any non-empty unsupported filters.


85-103: LGTM!

Also applies to: 141-150, 347-403, 447-500, 751-820, 904-959, 961-1033, 1121-1177, 1205-1267

sources/knowledge_layer/src/register.py (1)

37-37: LGTM!

Also applies to: 259-283, 332-336, 531-531

Comment thread docs/source/customization/knowledge-layer.md Outdated
Comment thread sources/knowledge_layer/KNOWLEDGE-LAYER-SETUP.md
Comment thread sources/knowledge_layer/src/azure_ai_search/adapter.py
@KyleZheng1284

Copy link
Copy Markdown
Contributor

/ok to test e74b76e

harmke added 4 commits July 13, 2026 13:33
Signed-off-by: Harmke Alkemade <halkemade@nvidia.com>
Signed-off-by: Harmke Alkemade <halkemade@nvidia.com>
Signed-off-by: Harmke Alkemade <halkemade@nvidia.com>
Signed-off-by: Harmke Alkemade <halkemade@nvidia.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
tests/knowledge_layer_tests/run_adapter_compliance.py (1)

405-407: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Verify deletion by file_id, not filename.

The adapter permits same-name files with distinct IDs. The name-based check at Lines 413-417 reports a successful deletion as failed when another generation of that filename remains.

Proposed fix
-        remaining_names = [f.file_name for f in remaining]
+        remaining_ids = {f.file_id for f in remaining}

-        if filename in remaining_names:
-            return False, f"File '{filename}' still exists after deletion"
+        if file_id in remaining_ids:
+            return False, f"File '{filename}' still exists after deletion"
🤖 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 `@tests/knowledge_layer_tests/run_adapter_compliance.py` around lines 405 -
407, Update the deletion verification in the test flow around
self.ingestor.delete_file to locate the deleted file by file_id rather than
filename. Keep same-name files with different IDs valid, and assert that the
specific file_id is absent after deletion while preserving the existing
success/failure behavior.
🤖 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 `@configs/config_web_azure_ai_search.yml`:
- Around line 1-4: Update the feature summary in the Web mode configuration
comments to describe Paper search as optional rather than enabled by default,
matching the commented-out paper search source and paper_search_tool entries.

In `@tests/knowledge_layer_tests/run_adapter_compliance.py`:
- Around line 30-34: Update the adapter compliance example command in
run_adapter_compliance.py documentation to invoke the script through uv run
instead of bare python, while preserving the existing backend and config
arguments.

---

Outside diff comments:
In `@tests/knowledge_layer_tests/run_adapter_compliance.py`:
- Around line 405-407: Update the deletion verification in the test flow around
self.ingestor.delete_file to locate the deleted file by file_id rather than
filename. Keep same-name files with different IDs valid, and assert that the
specific file_id is absent after deletion while preserving the existing
success/failure behavior.
🪄 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: ASSERTIVE

Plan: Enterprise

Run ID: 7ae9ed76-8e45-45f4-86cd-507203814e55

📥 Commits

Reviewing files that changed from the base of the PR and between e74b76e and aebac16.

📒 Files selected for processing (10)
  • configs/config_web_azure_ai_search.yml
  • deploy/.env.example
  • docs/source/customization/configuration-reference.md
  • docs/source/customization/knowledge-layer.md
  • docs/source/examples/azure-ai-search.md
  • docs/source/examples/index.md
  • sources/knowledge_layer/KNOWLEDGE-LAYER-SETUP.md
  • sources/knowledge_layer/src/azure_ai_search/adapter.py
  • tests/knowledge_layer_tests/run_adapter_compliance.py
  • tests/knowledge_layer_tests/test_azure_ai_search.py
📜 Review details
🧰 Additional context used
📓 Path-based instructions (8)
docs/source/**/*

📄 CodeRabbit inference engine (AGENTS.md)

Update the docs under docs/source/ when behavior, configuration, or workflows change

Files:

  • docs/source/examples/index.md
  • docs/source/customization/knowledge-layer.md
  • docs/source/examples/azure-ai-search.md
  • docs/source/customization/configuration-reference.md
**

⚙️ CodeRabbit configuration file

**:

AI-Q Agent Guidance

Repository-global instructions for coding agents and for humans reviewing
agent-authored changes. These rules apply to every task in this repository.
Task-specific runbooks live in .agents/skills/ — load the
relevant skill before starting a workflow it covers.

Project overview

AI-Q is an NVIDIA AI Blueprint: an enterprise research agent built on the
NeMo Agent Toolkit (NAT). The deployed product is a research blueprint, not
a general skill runtime. New retrieval sources and tools are NAT functions;
agent behavior is driven by workflow YAML, Jinja2 prompts, and a data-source
registry — not by hard-coded logic.

Primary boundaries:

  • Backend Python package: src/aiq_agent/.
  • Data-source and tool packages: sources/ (each is its own package).
  • Frontends and tooling: frontends/ (web UI in frontends/ui/, eval harnesses
    in frontends/benchmarks/).
  • Configs, deployment, docs: configs/, deploy/, docs/.

Stay inside this repository. If your workspace also contains adjacent repos
(for example a sibling NeMo-Relay checkout), do not edit them as part of an AI-Q
change. Treat sources/* as independent packages: prefer the smallest change
scoped to the package you are touching.

Repository structure

Path Purpose
src/aiq_agent/ Backend agent, FastAPI extensions, auth, observability, knowledge
sources/ Data-source / tool packages (e.g. tavily_web_search, google_scholar_paper_search)
configs/ Workflow YAML configs (e.g. config_cli_default.yml)
frontends/ui/ Next.js / React / TypeScript / Tailwind / KUI web UI
frontends/benchmarks/ Eval harnesses: freshqa, deepsearch_qa, deepresearch_bench
deploy/ Docker Compose and Helm/Kubernetes assets; deploy/.env for secrets
docs/source/ ...

Files:

  • docs/source/examples/index.md
  • configs/config_web_azure_ai_search.yml
  • docs/source/customization/knowledge-layer.md
  • docs/source/examples/azure-ai-search.md
  • tests/knowledge_layer_tests/run_adapter_compliance.py
  • docs/source/customization/configuration-reference.md
  • sources/knowledge_layer/KNOWLEDGE-LAYER-SETUP.md
  • tests/knowledge_layer_tests/test_azure_ai_search.py
  • sources/knowledge_layer/src/azure_ai_search/adapter.py
{docs/**,README.md,CONTRIBUTING.md,SECURITY.md,CODE-OF-CONDUCT.md}

⚙️ CodeRabbit configuration file

{docs/**,README.md,CONTRIBUTING.md,SECURITY.md,CODE-OF-CONDUCT.md}: Review documentation for command accuracy, branch-name consistency, current CI and copy-pr-bot behavior, public
vs internal boundary clarity, stale examples, and links that no longer match the repository layout.

Files:

  • docs/source/examples/index.md
  • docs/source/customization/knowledge-layer.md
  • docs/source/examples/azure-ai-search.md
  • docs/source/customization/configuration-reference.md
{deploy/**,configs/**}

⚙️ CodeRabbit configuration file

{deploy/**,configs/**}: Review deployment and config changes for secret separation, safe defaults, local-vs-production behavior, Helm and
Docker portability, and documentation parity. Flag committed credentials, environment-specific NVIDIA internals in
public defaults, and changes that make examples diverge from CI-tested paths.

Files:

  • configs/config_web_azure_ai_search.yml
**/*.py

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Run ruff check and ruff format validation for Python code changes

**/*.py: Python code must be linted and formatted with Ruff using line length 120, target Python 3.11, rule sets E,F,W,I,PL,UP, and isort force-single-line configuration
Never commit secrets, tokens, or environment-specific hostnames; use environment variables and SecretStr instead, resolving API keys at runtime
Never print or log secret values, including in tool output or error messages
Missing-secret paths must degrade gracefully (stub/skip), not crash or leak
Do not hand-reformat unrelated code when making changes; match the existing import and formatting style

Files:

  • tests/knowledge_layer_tests/run_adapter_compliance.py
  • tests/knowledge_layer_tests/test_azure_ai_search.py
  • sources/knowledge_layer/src/azure_ai_search/adapter.py
{src/aiq_agent/knowledge/**,sources/**}

⚙️ CodeRabbit configuration file

{src/aiq_agent/knowledge/**,sources/**}: Review data-source and knowledge-layer changes for optional dependency boundaries, external API error handling,
retry/rate-limit behavior, deterministic tests, and registration consistency. New source packages should include
package metadata, plugin registration when applicable, and source-level tests.

Files:

  • sources/knowledge_layer/KNOWLEDGE-LAYER-SETUP.md
  • sources/knowledge_layer/src/azure_ai_search/adapter.py
**/*test*.py

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Run pytest for all behavior changes in Python code

Files:

  • tests/knowledge_layer_tests/test_azure_ai_search.py
sources/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

New tools and data sources must be NAT functions registered with @register_function decorator

Files:

  • sources/knowledge_layer/src/azure_ai_search/adapter.py
🔇 Additional comments (11)
deploy/.env.example (1)

169-178: LGTM!

tests/knowledge_layer_tests/run_adapter_compliance.py (1)

109-109: LGTM!

Also applies to: 474-474

sources/knowledge_layer/src/azure_ai_search/adapter.py (2)

518-524: LGTM!


1233-1237: LGTM!

tests/knowledge_layer_tests/test_azure_ai_search.py (1)

417-422: 📐 Maintainability & Code Quality

Run the Python validation for the touched files. uv run ruff check, uv run ruff format --check, and uv run pytest tests/knowledge_layer_tests for sources/knowledge_layer/src/azure_ai_search/adapter.py, tests/knowledge_layer_tests/run_adapter_compliance.py, and tests/knowledge_layer_tests/test_azure_ai_search.py.

docs/source/customization/configuration-reference.md (1)

220-282: LGTM!

Also applies to: 539-539

docs/source/customization/knowledge-layer.md (1)

46-57: LGTM!

Also applies to: 76-76, 159-188, 249-255, 436-437

docs/source/examples/azure-ai-search.md (1)

27-44: LGTM!

Also applies to: 59-88

docs/source/examples/index.md (1)

15-15: LGTM!

sources/knowledge_layer/KNOWLEDGE-LAYER-SETUP.md (1)

12-12: LGTM!

Also applies to: 39-49, 71-71, 191-191, 1049-1053

configs/config_web_azure_ai_search.yml (1)

6-211: LGTM!

Comment thread configs/config_web_azure_ai_search.yml Outdated
Comment thread tests/knowledge_layer_tests/run_adapter_compliance.py
Signed-off-by: Harmke Alkemade <halkemade@nvidia.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 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 `@sources/knowledge_layer/src/azure_ai_search/adapter.py`:
- Around line 845-873: Track whether the setup flow created the collection
manifest in the block around _get_collection_manifest and
_write_collection_manifest. In the exception rollback path, when that flag is
set, delete the corresponding collection manifest along with the existing
_RECORD_FILE cleanup, while preserving rollback error reporting and behavior for
pre-existing collections.
🪄 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: ASSERTIVE

Plan: Enterprise

Run ID: 191d085b-149d-4912-b384-d73a0b798bb4

📥 Commits

Reviewing files that changed from the base of the PR and between aebac16 and 8cd3733.

📒 Files selected for processing (2)
  • sources/knowledge_layer/src/azure_ai_search/adapter.py
  • tests/knowledge_layer_tests/test_azure_ai_search.py
📜 Review details
🧰 Additional context used
📓 Path-based instructions (5)
**/*.py

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Run ruff check and ruff format validation for Python code changes

**/*.py: Python code must be linted and formatted with Ruff using line length 120, target Python 3.11, rule sets E,F,W,I,PL,UP, and isort force-single-line configuration
Never commit secrets, tokens, or environment-specific hostnames; use environment variables and SecretStr instead, resolving API keys at runtime
Never print or log secret values, including in tool output or error messages
Missing-secret paths must degrade gracefully (stub/skip), not crash or leak
Do not hand-reformat unrelated code when making changes; match the existing import and formatting style

Files:

  • tests/knowledge_layer_tests/test_azure_ai_search.py
  • sources/knowledge_layer/src/azure_ai_search/adapter.py
**/*test*.py

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Run pytest for all behavior changes in Python code

Files:

  • tests/knowledge_layer_tests/test_azure_ai_search.py
**

⚙️ CodeRabbit configuration file

**:

AI-Q Agent Guidance

Repository-global instructions for coding agents and for humans reviewing
agent-authored changes. These rules apply to every task in this repository.
Task-specific runbooks live in .agents/skills/ — load the
relevant skill before starting a workflow it covers.

Project overview

AI-Q is an NVIDIA AI Blueprint: an enterprise research agent built on the
NeMo Agent Toolkit (NAT). The deployed product is a research blueprint, not
a general skill runtime. New retrieval sources and tools are NAT functions;
agent behavior is driven by workflow YAML, Jinja2 prompts, and a data-source
registry — not by hard-coded logic.

Primary boundaries:

  • Backend Python package: src/aiq_agent/.
  • Data-source and tool packages: sources/ (each is its own package).
  • Frontends and tooling: frontends/ (web UI in frontends/ui/, eval harnesses
    in frontends/benchmarks/).
  • Configs, deployment, docs: configs/, deploy/, docs/.

Stay inside this repository. If your workspace also contains adjacent repos
(for example a sibling NeMo-Relay checkout), do not edit them as part of an AI-Q
change. Treat sources/* as independent packages: prefer the smallest change
scoped to the package you are touching.

Repository structure

Path Purpose
src/aiq_agent/ Backend agent, FastAPI extensions, auth, observability, knowledge
sources/ Data-source / tool packages (e.g. tavily_web_search, google_scholar_paper_search)
configs/ Workflow YAML configs (e.g. config_cli_default.yml)
frontends/ui/ Next.js / React / TypeScript / Tailwind / KUI web UI
frontends/benchmarks/ Eval harnesses: freshqa, deepsearch_qa, deepresearch_bench
deploy/ Docker Compose and Helm/Kubernetes assets; deploy/.env for secrets
docs/source/ ...

Files:

  • tests/knowledge_layer_tests/test_azure_ai_search.py
  • sources/knowledge_layer/src/azure_ai_search/adapter.py
sources/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

New tools and data sources must be NAT functions registered with @register_function decorator

Files:

  • sources/knowledge_layer/src/azure_ai_search/adapter.py
{src/aiq_agent/knowledge/**,sources/**}

⚙️ CodeRabbit configuration file

{src/aiq_agent/knowledge/**,sources/**}: Review data-source and knowledge-layer changes for optional dependency boundaries, external API error handling,
retry/rate-limit behavior, deterministic tests, and registration consistency. New source packages should include
package metadata, plugin registration when applicable, and source-level tests.

Files:

  • sources/knowledge_layer/src/azure_ai_search/adapter.py
🔇 Additional comments (4)
sources/knowledge_layer/src/azure_ai_search/adapter.py (3)

780-805: LGTM!


806-819: LGTM!


1079-1102: LGTM!

tests/knowledge_layer_tests/test_azure_ai_search.py (1)

598-602: LGTM!

Also applies to: 605-652, 655-676

Comment thread sources/knowledge_layer/src/azure_ai_search/adapter.py
Signed-off-by: Harmke Alkemade <halkemade@nvidia.com>
@KyleZheng1284

Copy link
Copy Markdown
Contributor

/ok to test 4f7fdc7

Signed-off-by: Kyle Zheng <kyzheng@nvidia.com>
Signed-off-by: Kyle Zheng <kyzheng@nvidia.com>
@KyleZheng1284

Copy link
Copy Markdown
Contributor

/ok to test 5a00cf6

@KyleZheng1284 KyleZheng1284 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@KyleZheng1284

KyleZheng1284 commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 13, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
sources/knowledge_layer/src/azure_ai_search/adapter.py (3)

759-762: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Unhandled metadata-serialization error breaks submit_job's never-raise contract.

json.dumps(file_metadata, ...) here validates JSON-serializability but discards the result and isn't wrapped in a try/except. Every other failure path in submit_job (invalid paths, thread-start failure) gracefully records a FAILED job and returns job_id; a non-serializable metadata dict instead raises TypeError straight out of submit_job, which can crash the caller (e.g. upload_file, an HTTP route) instead of surfacing a normal failed-job result.

🐛 Proposed fix
-        file_metadata = job_config.get("metadata") or {}
-        json.dumps(file_metadata, separators=(",", ":"), sort_keys=True)
+        file_metadata = job_config.get("metadata") or {}
+        try:
+            json.dumps(file_metadata, separators=(",", ":"), sort_keys=True)
+        except TypeError as error:
+            with self._jobs_lock:
+                self._jobs[job_id] = IngestionJobStatus(
+                    job_id=job_id,
+                    status=JobState.FAILED,
+                    collection_name=collection_name,
+                    backend=_BACKEND_NAME,
+                    submitted_at=_utc_now(),
+                    completed_at=_utc_now(),
+                    total_files=len(file_paths),
+                    error_message=f"Metadata is not JSON-serializable: {error}",
+                )
+            return job_id
🤖 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 `@sources/knowledge_layer/src/azure_ai_search/adapter.py` around lines 759 -
762, Update submit_job around the file_metadata JSON validation to catch
serialization failures such as TypeError, record the job as FAILED using the
existing failure-handling path, and return job_id without raising. Preserve the
current compact/sorted serialization validation for valid metadata and the
existing behavior for other submit_job failures.

1240-1249: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Possible IndexError if the file disappears between upload_file's check and submit_job's validation.

upload_file checks path.is_file() at Line 1232, but submit_job re-checks Path(path).is_file() (Line 760) and skips paths that fail. If the file is removed in that narrow window, submit_job returns a job with total_files=1 but file_details=[] (the "No valid file paths provided" branch), and self._jobs[job_id].file_details[0] here raises IndexError instead of returning a graceful FailStatus.FAILED FileInfo like the pre-check at Line 1232-1239 does.

🛡️ Proposed guard
         with self._jobs_lock:
-            file_id = self._jobs[job_id].file_details[0].file_id
+            job = self._jobs[job_id]
+            if not job.file_details:
+                return FileInfo(
+                    file_id=str(uuid.uuid4()),
+                    file_name=path.name,
+                    collection_name=collection_name,
+                    status=FileStatus.FAILED,
+                    error_message=job.error_message or f"File not found: {file_path}",
+                )
+            file_id = job.file_details[0].file_id
             info = self._files[file_id].model_copy(deep=True)
🤖 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 `@sources/knowledge_layer/src/azure_ai_search/adapter.py` around lines 1240 -
1249, Guard the file_details access in upload_file after submit_job, before
indexing file_details[0]. If the submitted job has no file details, return the
same graceful FailStatus.FAILED FileInfo used by the earlier path validation
instead of raising IndexError; retain the existing metadata and job_id
population for valid submissions.

1057-1068: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

No timeout around the summary LLM call.

self._summary_llm.invoke(prompt) runs synchronously inside the per-file ingestion path with no timeout. A hung LLM call blocks the ingestion worker thread indefinitely, leaving the file stuck at INGESTING with no way to recover short of restarting the process.

🤖 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 `@sources/knowledge_layer/src/azure_ai_search/adapter.py` around lines 1057 -
1068, The synchronous call in _generate_summary must have a bounded timeout so a
hung summary request cannot block ingestion indefinitely. Configure or pass the
supported timeout through self._summary_llm.invoke(prompt), preserving the
existing exception logging and None fallback when the call exceeds the limit or
otherwise fails.
🤖 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/customization/configuration-reference.md`:
- Around line 597-605: Update the top-level workflow configuration count in the
introduction of the configuration reference to match the ten profiles listed in
the table, or remove the hard-coded count while preserving the repository paths
and examples.
- Around line 305-308: Keep Azure embedding configuration consistent across all
documented tables: in docs/source/customization/configuration-reference.md lines
305-308, mark embed_model and embed_base_url as Azure-supported alongside
embed_dim; in lines 322-323, extend the embedding model and endpoint rows to
include Azure; and in docs/source/customization/knowledge-layer.md line 499, add
Azure to the embedding environment-variable scope and document AIQ_EMBED_DIM.

In `@docs/source/customization/knowledge-layer.md`:
- Around line 57-58: Update the azure_ai_search feature summary in the
knowledge-layer documentation to describe hybrid retrieval only, removing the
unsupported vector and semantic-ranked retrieval claims while preserving the
existing embedding and namespaced-index details.

---

Outside diff comments:
In `@sources/knowledge_layer/src/azure_ai_search/adapter.py`:
- Around line 759-762: Update submit_job around the file_metadata JSON
validation to catch serialization failures such as TypeError, record the job as
FAILED using the existing failure-handling path, and return job_id without
raising. Preserve the current compact/sorted serialization validation for valid
metadata and the existing behavior for other submit_job failures.
- Around line 1240-1249: Guard the file_details access in upload_file after
submit_job, before indexing file_details[0]. If the submitted job has no file
details, return the same graceful FailStatus.FAILED FileInfo used by the earlier
path validation instead of raising IndexError; retain the existing metadata and
job_id population for valid submissions.
- Around line 1057-1068: The synchronous call in _generate_summary must have a
bounded timeout so a hung summary request cannot block ingestion indefinitely.
Configure or pass the supported timeout through
self._summary_llm.invoke(prompt), preserving the existing exception logging and
None fallback when the call exceeds the limit or otherwise fails.
🪄 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: ASSERTIVE

Plan: Enterprise

Run ID: ef20def1-d9fe-41c1-90cb-278e60aa3f69

📥 Commits

Reviewing files that changed from the base of the PR and between aebac16 and 5a00cf6.

⛔ Files ignored due to path filters (1)
  • uv.lock is excluded by !**/*.lock
📒 Files selected for processing (9)
  • .secrets.baseline
  • configs/config_web_azure_ai_search.yml
  • deploy/.env.example
  • docs/source/customization/configuration-reference.md
  • docs/source/customization/knowledge-layer.md
  • docs/source/examples/index.md
  • docs/source/index.md
  • sources/knowledge_layer/src/azure_ai_search/adapter.py
  • tests/knowledge_layer_tests/test_azure_ai_search.py
📜 Review details
🧰 Additional context used
📓 Path-based instructions (8)
docs/source/**/*

📄 CodeRabbit inference engine (AGENTS.md)

Update the docs under docs/source/ when behavior, configuration, or workflows change

Files:

  • docs/source/examples/index.md
  • docs/source/index.md
  • docs/source/customization/configuration-reference.md
  • docs/source/customization/knowledge-layer.md
**

⚙️ CodeRabbit configuration file

**:

AI-Q Agent Guidance

Repository-global instructions for coding agents and for humans reviewing
agent-authored changes. These rules apply to every task in this repository.
Task-specific runbooks live in .agents/skills/ — load the
relevant skill before starting a workflow it covers.

Project overview

AI-Q is an NVIDIA AI Blueprint: an enterprise research agent built on the
NeMo Agent Toolkit (NAT). The deployed product is a research blueprint, not
a general skill runtime. New retrieval sources and tools are NAT functions;
agent behavior is driven by workflow YAML, Jinja2 prompts, and a data-source
registry — not by hard-coded logic.

Primary boundaries:

  • Backend Python package: src/aiq_agent/.
  • Data-source and tool packages: sources/ (each is its own package).
  • Frontends and tooling: frontends/ (web UI in frontends/ui/, eval harnesses
    in frontends/benchmarks/).
  • Configs, deployment, docs: configs/, deploy/, docs/.

Stay inside this repository. If your workspace also contains adjacent repos
(for example a sibling NeMo-Relay checkout), do not edit them as part of an AI-Q
change. Treat sources/* as independent packages: prefer the smallest change
scoped to the package you are touching.

Repository structure

Path Purpose
src/aiq_agent/ Backend agent, FastAPI extensions, auth, observability, knowledge
sources/ Data-source / tool packages (e.g. tavily_web_search, google_scholar_paper_search)
configs/ Workflow YAML configs (e.g. config_cli_default.yml)
frontends/ui/ Next.js / React / TypeScript / Tailwind / KUI web UI
frontends/benchmarks/ Eval harnesses: freshqa, deepsearch_qa, deepresearch_bench
deploy/ Docker Compose and Helm/Kubernetes assets; deploy/.env for secrets
docs/source/ ...

Files:

  • docs/source/examples/index.md
  • docs/source/index.md
  • configs/config_web_azure_ai_search.yml
  • docs/source/customization/configuration-reference.md
  • docs/source/customization/knowledge-layer.md
  • tests/knowledge_layer_tests/test_azure_ai_search.py
  • sources/knowledge_layer/src/azure_ai_search/adapter.py
{docs/**,README.md,CONTRIBUTING.md,SECURITY.md,CODE-OF-CONDUCT.md}

⚙️ CodeRabbit configuration file

{docs/**,README.md,CONTRIBUTING.md,SECURITY.md,CODE-OF-CONDUCT.md}: Review documentation for command accuracy, branch-name consistency, current CI and copy-pr-bot behavior, public
vs internal boundary clarity, stale examples, and links that no longer match the repository layout.

Files:

  • docs/source/examples/index.md
  • docs/source/index.md
  • docs/source/customization/configuration-reference.md
  • docs/source/customization/knowledge-layer.md
{deploy/**,configs/**}

⚙️ CodeRabbit configuration file

{deploy/**,configs/**}: Review deployment and config changes for secret separation, safe defaults, local-vs-production behavior, Helm and
Docker portability, and documentation parity. Flag committed credentials, environment-specific NVIDIA internals in
public defaults, and changes that make examples diverge from CI-tested paths.

Files:

  • configs/config_web_azure_ai_search.yml
**/*.py

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Run ruff check and ruff format validation for Python code changes

**/*.py: Python code must be linted and formatted with Ruff using line length 120, target Python 3.11, rule sets E,F,W,I,PL,UP, and isort force-single-line configuration
Never commit secrets, tokens, or environment-specific hostnames; use environment variables and SecretStr instead, resolving API keys at runtime
Never print or log secret values, including in tool output or error messages
Missing-secret paths must degrade gracefully (stub/skip), not crash or leak
Do not hand-reformat unrelated code when making changes; match the existing import and formatting style

Files:

  • tests/knowledge_layer_tests/test_azure_ai_search.py
  • sources/knowledge_layer/src/azure_ai_search/adapter.py
**/*test*.py

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Run pytest for all behavior changes in Python code

Files:

  • tests/knowledge_layer_tests/test_azure_ai_search.py
sources/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

New tools and data sources must be NAT functions registered with @register_function decorator

Files:

  • sources/knowledge_layer/src/azure_ai_search/adapter.py
{src/aiq_agent/knowledge/**,sources/**}

⚙️ CodeRabbit configuration file

{src/aiq_agent/knowledge/**,sources/**}: Review data-source and knowledge-layer changes for optional dependency boundaries, external API error handling,
retry/rate-limit behavior, deterministic tests, and registration consistency. New source packages should include
package metadata, plugin registration when applicable, and source-level tests.

Files:

  • sources/knowledge_layer/src/azure_ai_search/adapter.py
🪛 Betterleaks (1.6.1)
.secrets.baseline

[high] 206-206: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


[high] 213-213: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


[high] 220-220: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


[high] 227-227: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


[high] 234-234: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


[high] 243-243: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


[high] 250-250: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


[high] 257-257: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


[high] 264-264: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


[high] 271-271: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


[high] 280-280: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)

🪛 LanguageTool
docs/source/customization/configuration-reference.md

[style] ~442-~442: Consider using “incompatible” to avoid wordiness.
Context: ...only when the active source formats are not compatible with verification. | | skills | objec...

(NOT_ABLE_PREMIUM)

🔇 Additional comments (11)
docs/source/customization/configuration-reference.md (1)

82-82: LGTM!

Also applies to: 155-158, 207-232, 259-259, 275-290, 294-294, 309-321, 325-326, 371-371, 403-405, 416-427, 438-455, 487-491, 606-612

docs/source/customization/knowledge-layer.md (2)

46-46: LGTM!

Also applies to: 81-81, 171-190, 195-200, 301-307, 488-489


18-18: 🎯 Functional Correctness

Clarify Azure support in the shared capability docs. If Azure supports UI-created s_<uuid> collections, add it to the backend-agnostic and session-collection lists; otherwise state that limitation explicitly.

docs/source/examples/index.md (1)

15-15: LGTM!

docs/source/index.md (1)

16-16: LGTM!

Also applies to: 102-102, 145-145

configs/config_web_azure_ai_search.yml (1)

4-4: LGTM!

.secrets.baseline (1)

136-136: LGTM!

Also applies to: 145-145, 172-172, 202-274, 276-283, 300-300, 309-309, 354-354, 358-358

sources/knowledge_layer/src/azure_ai_search/adapter.py (2)

845-873: Auto-created collection manifest is still not rolled back on setup failure.

This is the same code flagged in a prior review: when collection is None at Line 850, _write_collection_manifest(collection_name) creates a new active manifest, but the except block's rollback (Lines 858-869) only deletes _RECORD_FILE ids from job.file_details — it never deletes the collection manifest it just created. A later failure (e.g. the first _write_file_manifest call) leaves an empty, orphaned active collection visible via list_collections()/get_collection().

Per the prior thread, this was acknowledged and deferred rather than fixed; flagging again since the current diff still contains the exact gap and no tracking issue evidence is present in this context.


1-83: LGTM!

Also applies to: 85-234, 237-403, 406-469, 591-630, 631-750, 821-834, 926-1055, 1070-1151, 1153-1224, 1251-1325

deploy/.env.example (1)

173-182: LGTM!

tests/knowledge_layer_tests/test_azure_ai_search.py (1)

598-602: LGTM!

Also applies to: 605-652, 655-676

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
sources/knowledge_layer/src/azure_ai_search/adapter.py (3)

759-762: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Unhandled metadata-serialization error breaks submit_job's never-raise contract.

json.dumps(file_metadata, ...) here validates JSON-serializability but discards the result and isn't wrapped in a try/except. Every other failure path in submit_job (invalid paths, thread-start failure) gracefully records a FAILED job and returns job_id; a non-serializable metadata dict instead raises TypeError straight out of submit_job, which can crash the caller (e.g. upload_file, an HTTP route) instead of surfacing a normal failed-job result.

🐛 Proposed fix
-        file_metadata = job_config.get("metadata") or {}
-        json.dumps(file_metadata, separators=(",", ":"), sort_keys=True)
+        file_metadata = job_config.get("metadata") or {}
+        try:
+            json.dumps(file_metadata, separators=(",", ":"), sort_keys=True)
+        except TypeError as error:
+            with self._jobs_lock:
+                self._jobs[job_id] = IngestionJobStatus(
+                    job_id=job_id,
+                    status=JobState.FAILED,
+                    collection_name=collection_name,
+                    backend=_BACKEND_NAME,
+                    submitted_at=_utc_now(),
+                    completed_at=_utc_now(),
+                    total_files=len(file_paths),
+                    error_message=f"Metadata is not JSON-serializable: {error}",
+                )
+            return job_id
🤖 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 `@sources/knowledge_layer/src/azure_ai_search/adapter.py` around lines 759 -
762, Update submit_job around the file_metadata JSON validation to catch
serialization failures such as TypeError, record the job as FAILED using the
existing failure-handling path, and return job_id without raising. Preserve the
current compact/sorted serialization validation for valid metadata and the
existing behavior for other submit_job failures.

1240-1249: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Possible IndexError if the file disappears between upload_file's check and submit_job's validation.

upload_file checks path.is_file() at Line 1232, but submit_job re-checks Path(path).is_file() (Line 760) and skips paths that fail. If the file is removed in that narrow window, submit_job returns a job with total_files=1 but file_details=[] (the "No valid file paths provided" branch), and self._jobs[job_id].file_details[0] here raises IndexError instead of returning a graceful FailStatus.FAILED FileInfo like the pre-check at Line 1232-1239 does.

🛡️ Proposed guard
         with self._jobs_lock:
-            file_id = self._jobs[job_id].file_details[0].file_id
+            job = self._jobs[job_id]
+            if not job.file_details:
+                return FileInfo(
+                    file_id=str(uuid.uuid4()),
+                    file_name=path.name,
+                    collection_name=collection_name,
+                    status=FileStatus.FAILED,
+                    error_message=job.error_message or f"File not found: {file_path}",
+                )
+            file_id = job.file_details[0].file_id
             info = self._files[file_id].model_copy(deep=True)
🤖 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 `@sources/knowledge_layer/src/azure_ai_search/adapter.py` around lines 1240 -
1249, Guard the file_details access in upload_file after submit_job, before
indexing file_details[0]. If the submitted job has no file details, return the
same graceful FailStatus.FAILED FileInfo used by the earlier path validation
instead of raising IndexError; retain the existing metadata and job_id
population for valid submissions.

1057-1068: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

No timeout around the summary LLM call.

self._summary_llm.invoke(prompt) runs synchronously inside the per-file ingestion path with no timeout. A hung LLM call blocks the ingestion worker thread indefinitely, leaving the file stuck at INGESTING with no way to recover short of restarting the process.

🤖 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 `@sources/knowledge_layer/src/azure_ai_search/adapter.py` around lines 1057 -
1068, The synchronous call in _generate_summary must have a bounded timeout so a
hung summary request cannot block ingestion indefinitely. Configure or pass the
supported timeout through self._summary_llm.invoke(prompt), preserving the
existing exception logging and None fallback when the call exceeds the limit or
otherwise fails.
🤖 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/customization/configuration-reference.md`:
- Around line 597-605: Update the top-level workflow configuration count in the
introduction of the configuration reference to match the ten profiles listed in
the table, or remove the hard-coded count while preserving the repository paths
and examples.
- Around line 305-308: Keep Azure embedding configuration consistent across all
documented tables: in docs/source/customization/configuration-reference.md lines
305-308, mark embed_model and embed_base_url as Azure-supported alongside
embed_dim; in lines 322-323, extend the embedding model and endpoint rows to
include Azure; and in docs/source/customization/knowledge-layer.md line 499, add
Azure to the embedding environment-variable scope and document AIQ_EMBED_DIM.

In `@docs/source/customization/knowledge-layer.md`:
- Around line 57-58: Update the azure_ai_search feature summary in the
knowledge-layer documentation to describe hybrid retrieval only, removing the
unsupported vector and semantic-ranked retrieval claims while preserving the
existing embedding and namespaced-index details.

---

Outside diff comments:
In `@sources/knowledge_layer/src/azure_ai_search/adapter.py`:
- Around line 759-762: Update submit_job around the file_metadata JSON
validation to catch serialization failures such as TypeError, record the job as
FAILED using the existing failure-handling path, and return job_id without
raising. Preserve the current compact/sorted serialization validation for valid
metadata and the existing behavior for other submit_job failures.
- Around line 1240-1249: Guard the file_details access in upload_file after
submit_job, before indexing file_details[0]. If the submitted job has no file
details, return the same graceful FailStatus.FAILED FileInfo used by the earlier
path validation instead of raising IndexError; retain the existing metadata and
job_id population for valid submissions.
- Around line 1057-1068: The synchronous call in _generate_summary must have a
bounded timeout so a hung summary request cannot block ingestion indefinitely.
Configure or pass the supported timeout through
self._summary_llm.invoke(prompt), preserving the existing exception logging and
None fallback when the call exceeds the limit or otherwise fails.
🪄 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: ASSERTIVE

Plan: Enterprise

Run ID: ef20def1-d9fe-41c1-90cb-278e60aa3f69

📥 Commits

Reviewing files that changed from the base of the PR and between aebac16 and 5a00cf6.

⛔ Files ignored due to path filters (1)
  • uv.lock is excluded by !**/*.lock
📒 Files selected for processing (9)
  • .secrets.baseline
  • configs/config_web_azure_ai_search.yml
  • deploy/.env.example
  • docs/source/customization/configuration-reference.md
  • docs/source/customization/knowledge-layer.md
  • docs/source/examples/index.md
  • docs/source/index.md
  • sources/knowledge_layer/src/azure_ai_search/adapter.py
  • tests/knowledge_layer_tests/test_azure_ai_search.py
📜 Review details
🔇 Additional comments (11)
docs/source/customization/configuration-reference.md (1)

82-82: LGTM!

Also applies to: 155-158, 207-232, 259-259, 275-290, 294-294, 309-321, 325-326, 371-371, 403-405, 416-427, 438-455, 487-491, 606-612

docs/source/customization/knowledge-layer.md (2)

46-46: LGTM!

Also applies to: 81-81, 171-190, 195-200, 301-307, 488-489


18-18: 🎯 Functional Correctness

Clarify Azure support in the shared capability docs. If Azure supports UI-created s_<uuid> collections, add it to the backend-agnostic and session-collection lists; otherwise state that limitation explicitly.

docs/source/examples/index.md (1)

15-15: LGTM!

docs/source/index.md (1)

16-16: LGTM!

Also applies to: 102-102, 145-145

configs/config_web_azure_ai_search.yml (1)

4-4: LGTM!

.secrets.baseline (1)

136-136: LGTM!

Also applies to: 145-145, 172-172, 202-274, 276-283, 300-300, 309-309, 354-354, 358-358

sources/knowledge_layer/src/azure_ai_search/adapter.py (2)

845-873: Auto-created collection manifest is still not rolled back on setup failure.

This is the same code flagged in a prior review: when collection is None at Line 850, _write_collection_manifest(collection_name) creates a new active manifest, but the except block's rollback (Lines 858-869) only deletes _RECORD_FILE ids from job.file_details — it never deletes the collection manifest it just created. A later failure (e.g. the first _write_file_manifest call) leaves an empty, orphaned active collection visible via list_collections()/get_collection().

Per the prior thread, this was acknowledged and deferred rather than fixed; flagging again since the current diff still contains the exact gap and no tracking issue evidence is present in this context.


1-83: LGTM!

Also applies to: 85-234, 237-403, 406-469, 591-630, 631-750, 821-834, 926-1055, 1070-1151, 1153-1224, 1251-1325

deploy/.env.example (1)

173-182: LGTM!

tests/knowledge_layer_tests/test_azure_ai_search.py (1)

598-602: LGTM!

Also applies to: 605-652, 655-676

🛑 Comments failed to post (3)
docs/source/customization/configuration-reference.md (2)

305-308: 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Keep Azure embedding configuration consistent across both documentation tables.

The runtime passes the embedding model, endpoint, and dimension into Azure, but the documentation scopes these settings to other backends or omits them.

  • docs/source/customization/configuration-reference.md#L305-L308: Mark embed_model and embed_base_url as Azure-supported alongside embed_dim.
  • docs/source/customization/configuration-reference.md#L322-L323: Extend the backend scope of the embedding model and endpoint rows to include Azure.
  • docs/source/customization/knowledge-layer.md#L499-L499: Add Azure to the embedding environment-variable scope and document AIQ_EMBED_DIM.
📍 Affects 2 files
  • docs/source/customization/configuration-reference.md#L305-L308 (this comment)
  • docs/source/customization/configuration-reference.md#L322-L323
  • docs/source/customization/knowledge-layer.md#L499-L499
🤖 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/customization/configuration-reference.md` around lines 305 - 308,
Keep Azure embedding configuration consistent across all documented tables: in
docs/source/customization/configuration-reference.md lines 305-308, mark
embed_model and embed_base_url as Azure-supported alongside embed_dim; in lines
322-323, extend the embedding model and endpoint rows to include Azure; and in
docs/source/customization/knowledge-layer.md line 499, add Azure to the
embedding environment-variable scope and document AIQ_EMBED_DIM.

Source: Path instructions


597-605: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Correct the provided-config count.

The introduction says there are nine top-level workflow configurations, but the table now lists ten, including config_web_azure_ai_search.yml. Update the count to 10 or avoid hard-coding it.

As per path instructions, documentation must keep repository-layout references and examples accurate.

🤖 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/customization/configuration-reference.md` around lines 597 - 605,
Update the top-level workflow configuration count in the introduction of the
configuration reference to match the ten profiles listed in the table, or remove
the hard-coded count while preserving the repository paths and examples.

Source: Path instructions

docs/source/customization/knowledge-layer.md (1)

57-58: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

set -euo pipefail
file='docs/source/customization/knowledge-layer.md'
wc -l "$file"
printf '\n--- lines 1-260 ---\n'
sed -n '1,260p' "$file" | cat -n
printf '\n--- search Azure retrieval wording ---\n'
rg -n "azure_ai_search|vector, hybrid, semantic|always hybrid|hybrid retrieval|semantic-ranked" docs/source source configs -S

Repository: NVIDIA-AI-Blueprints/aiq

Length of output: 16860


🏁 Script executed:

set -euo pipefail

printf '%s\n' '--- Azure example doc excerpt ---'
sed -n '70,110p' docs/source/examples/azure-ai-search.md | cat -n

printf '\n%s\n' '--- locate Azure implementation ---'
fd -a "azure" sources/knowledge_layer/src

printf '\n%s\n' '--- search mode/retrieval symbols in Azure source ---'
rg -n "semantic|hybrid|vector|retriev|search mode|query_type|search_type|top_k" sources/knowledge_layer/src -S

Repository: NVIDIA-AI-Blueprints/aiq

Length of output: 27369


Clarify the Azure retrieval mode. docs/source/customization/knowledge-layer.md:57-58 should not promise vector, hybrid, and semantic-ranked retrieval when the rest of the Azure docs describe the backend as hybrid-only. Keep the feature summary aligned with the adapter contract.

🤖 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/customization/knowledge-layer.md` around lines 57 - 58, Update
the azure_ai_search feature summary in the knowledge-layer documentation to
describe hybrid retrieval only, removing the unsupported vector and
semantic-ranked retrieval claims while preserving the existing embedding and
namespaced-index details.

Source: Path instructions

@KyleZheng1284

Copy link
Copy Markdown
Contributor

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Jul 13, 2026

Copy link
Copy Markdown
✅ Action performed

Full review finished.

@KyleZheng1284

Copy link
Copy Markdown
Contributor

/ok to test 5a00cf6

@AjayThorve AjayThorve merged commit bfd71b6 into NVIDIA-AI-Blueprints:develop Jul 14, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants