Skip to content

fix(api): honor async submit tool and agent availability - #385

Merged
rapids-bot[bot] merged 3 commits into
NVIDIA-AI-Blueprints:release/2.2from
tanleach:fix/release-2.2-async-submit-data-sources
Jul 23, 2026
Merged

rapids-bot[bot] merged 3 commits into
NVIDIA-AI-Blueprints:release/2.2from
tanleach:fix/release-2.2-async-submit-data-sources

Conversation

@tanleach

@tanleach tanleach commented Jul 23, 2026 •

Copy link
Copy Markdown
Collaborator

Fix async submit data-source validation for inherited agent tools and reject unconfigured public agents consistently.

Overview

POST /v1/jobs/async/submit rejected valid registered data sources on v2.2.0-rc3 and rc4 when an agent omitted its tools field. Typed researcher configs normalize the omitted field to tools=[], which means "inherit all tools from the data-source registry." Submit validation instead treated only None as inheritance, resolved no tools, and classified every requested source as unavailable.

The global agent catalog also advertised agents absent from the active workflow. Selecting such an agent could return an unstructured HTTP 500 or enqueue an unusable job when source validation was skipped.

This change:

  • Aligns submit validation with deep and shallow runtime behavior: empty tool lists inherit registry tools, while explicit non-empty lists override inheritance.
  • Applies exact-name tool exclusions after wrapper resolution.
  • Keeps a source available when at least one mapped tool survives exclusion.
  • Rejects registered-but-unconfigured public agents with a stable structured HTTP 400 before source validation or job submission.
  • Limits GET /v1/jobs/async/agents to public agents configured in the active workflow.
  • Preserves omitted, null, empty, unknown-source, fully-excluded-source, cancellation, and unexpected-error behavior.
  • Adds CI-collected regression coverage and updates the REST API documentation.

For config_domain_routing_and_skills.yml, deep_researcher now accepts web_search: although web_search_tool is excluded, advanced_web_search_tool survives and remains mapped to the source. The globally registered but unconfigured shallow_researcher now returns:

{
  "detail": {
    "code": "agent_not_configured",
    "message": "Agent 'shallow_researcher' is not configured in the active workflow",
    "agent_type": "shallow_researcher",
    "config_name": "shallow_research_agent"
  }
}

DCO sign-off for the squash commit

Signed-off-by: Tanner Leach tleach@nvidia.com

Validation

Automated checks:

uv run pytest tests/aiq_agent/fastapi_extensions/test_job_agent_availability.py -q
3 passed

uv run pytest frontends/aiq_api/tests/test_job_submit_data_sources.py -q
33 passed

uv run pytest frontends/aiq_api/tests/test_agent_registry_visibility.py -q
5 passed

uv run pytest tests/aiq_agent/jobs/test_runner.py tests/aiq_agent/common/test_data_source_registry.py -q
145 passed

uv run pytest frontends/aiq_api/tests -q
329 passed, 1 skipped

uv run pytest
1847 passed, 13 skipped

uv run ruff check .
All checks passed

uv run ruff format --check .
373 files already formatted

uv run --extra docs sphinx-build -M html docs/source docs/build
Build succeeded

Live REST validation with a deep-only workflow:

Request Result
GET /v1/jobs/async/agents HTTP 200; deep listed, shallow omitted
Deep with omitted data_sources HTTP 200
Deep with data_sources: null HTTP 200
Deep with data_sources: [] HTTP 200
Deep with data_sources: ["web_search"] HTTP 200
Deep with data_sources: ["does_not_exist"] Structured HTTP 422
Shallow with omitted sources Structured HTTP 400
Shallow with null sources Structured HTTP 400
Shallow with empty sources Structured HTTP 400
Shallow with selected sources Structured HTTP 400

Live validation with both agents configured confirmed that deep and shallow both accept data_sources: ["web_search"]. A meaningful shallow query also completed successfully with a cited report.

  • 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.
  • I replaced the DCO sign-off placeholder with my GitHub commit identity and kept the required angle brackets around the email address.

Where should reviewers start?

Start with:

  • frontends/aiq_api/src/aiq_api/routes/jobs.py
    • _get_configured_agent_function_config
    • _get_agent_available_source_ids
    • list_agents
    • submit_job
  • tests/aiq_agent/fastapi_extensions/test_job_agent_availability.py for the CI-collected contract coverage.
  • frontends/aiq_api/tests/test_job_submit_data_sources.py for the complete deep/shallow and source-selection matrix.

The key design decision is that empty typed tools lists preserve the existing runtime inheritance contract; this change does not reinterpret tools=[] as "no tools" or introduce a new shared resolver.

Summary by CodeRabbit

  • Documentation
    • Updated async job REST API docs and README to clarify that agent listings return only public agents configured in the active workflow.
    • Expanded job submission documentation for data_sources availability and added/updated structured error cases (including 400 agent_not_configured).
  • Bug Fixes
    • Tightened async agent listing to exclude internal-only and workflow-unconfigured agents.
    • Improved job submission validation: returns 400 agent_not_configured with a structured payload when the agent isn’t configured.
    • Refined data-source validation to follow the selected agent’s configured tools and inheritance/exclusions.
  • Tests
    • Expanded and updated unit/integration coverage for agent visibility, unconfigured-agent rejections, and data-source edge cases.

Treat empty tool lists as inherited and limit async agents to those configured
in the active workflow.

Signed-off-by: Tanner Leach <tleach@nvidia.com>
@tanleach
tanleach requested a review from a team July 23, 2026 01:04
@coderabbitai

coderabbitai Bot commented Jul 23, 2026 •

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: 2c0a50d4-e939-41cd-9172-70621f14f7fc

📥 Commits

Reviewing files that changed from the base of the PR and between 6437501 and 13cbd03.

📒 Files selected for processing (2)
  • frontends/aiq_api/src/aiq_api/routes/jobs.py
  • frontends/aiq_api/tests/test_content_encryption_routes.py
📜 Recent review details
⏰ Context from checks skipped due to timeout. (2)
  • GitHub Check: Pytest and Coverage
  • GitHub Check: Script Validation
🧰 Additional context used
📓 Path-based instructions (3)
**/*.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:

  • frontends/aiq_api/tests/test_content_encryption_routes.py
  • frontends/aiq_api/src/aiq_api/routes/jobs.py
**/*test*.py

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Run pytest for all behavior changes in Python code

Files:

  • frontends/aiq_api/tests/test_content_encryption_routes.py
{src/aiq_agent/fastapi_extensions/**,frontends/aiq_api/src/aiq_api/**}

⚙️ CodeRabbit configuration file

{src/aiq_agent/fastapi_extensions/**,frontends/aiq_api/src/aiq_api/**}: Treat API, auth, and job-runner changes as externally visible contracts. Check authorization boundaries,
request tracing, async job lifecycle, websocket reconnect behavior, error responses, and cross-user data isolation.
Require tests for route behavior, access decisions, and job state transitions when those surfaces change.

Files:

  • frontends/aiq_api/src/aiq_api/routes/jobs.py
🧠 Learnings (1)
📚 Learning: 2026-06-14T17:49:00.640Z
Learnt from: torkian
Repo: NVIDIA-AI-Blueprints/aiq PR: 273
File: frontends/aiq_api/tests/test_sse_reconnect_cursor.py:384-401
Timestamp: 2026-06-14T17:49:00.640Z
Learning: When using `unittest.mock.patch` for code that imports dependencies inside functions/generators (e.g., inside `aiq_api.routes.jobs`), don’t patch via an attribute that doesn’t exist on the consuming module. If the generator does `from ..jobs.event_store import EventStore` inside the generator body, then `aiq_api.routes.jobs` will not have an `EventStore` attribute; patch the source class/method in its defining module instead (e.g., `aiq_api.jobs.event_store.EventStore.get_events_async`). Patching `aiq_api.routes.jobs.EventStore...` would raise `AttributeError` because that symbol is not present at module scope.

Applied to files:

  • frontends/aiq_api/tests/test_content_encryption_routes.py
🔇 Additional comments (2)
frontends/aiq_api/src/aiq_api/routes/jobs.py (1)

221-229: LGTM!

Also applies to: 231-248, 279-282, 295-298, 469-469, 630-640, 699-699, 709-710, 727-738, 759-764

frontends/aiq_api/tests/test_content_encryption_routes.py (1)

462-466: LGTM!


Walkthrough

Async job routes now list only public agents configured in the active workflow and reject unconfigured agents with structured 400 errors. Data-source validation uses resolved function configurations, with tests and REST/OpenAPI documentation updated for the new behavior.

Changes

Configured Agent Availability

Layer / File(s) Summary
Agent resolution and submission gating
frontends/aiq_api/src/aiq_api/routes/jobs.py, frontends/aiq_api/tests/test_agent_registry_visibility.py, tests/aiq_agent/fastapi_extensions/test_job_agent_availability.py
Routes resolve active function configurations, exclude missing configurations from agent listings, and reject unconfigured submissions with agent_not_configured.
Function-configured data-source validation
frontends/aiq_api/src/aiq_api/routes/jobs.py, frontends/aiq_api/tests/test_job_submit_data_sources.py, tests/aiq_agent/fastapi_extensions/test_job_agent_availability.py
Data-source availability now uses configured tools, inheritance, and exclusions from typed function configurations; tests cover unavailable sources, inherited tools, and error paths.
API contract and documentation updates
docs/source/integration/rest-api.md, frontends/aiq_api/README.md, frontends/aiq_api/tests/test_content_encryption_routes.py
Documentation and OpenAPI assertions describe configured public agents, 422 data-source failures, and expanded submission error responses.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant AsyncJobsAPI
  participant WorkflowBuilder
  participant JobSubmission
  Client->>AsyncJobsAPI: POST /v1/jobs/async/submit
  AsyncJobsAPI->>WorkflowBuilder: Resolve agent function config
  WorkflowBuilder-->>AsyncJobsAPI: Configured function config
  AsyncJobsAPI->>WorkflowBuilder: Resolve configured tools and data sources
  WorkflowBuilder-->>AsyncJobsAPI: Available source IDs
  AsyncJobsAPI->>JobSubmission: Submit validated job
  JobSubmission-->>Client: Job response
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% 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, stays under 72 characters, and accurately summarizes the async submit agent/tool availability fix.
Description check ✅ Passed The description matches the template sections and includes overview, DCO, validation, and reviewer guidance; only Related Issues is missing.
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.

@tanleach tanleach self-assigned this Jul 23, 2026
@tanleach tanleach added bug Something isn't working AIQ2.2 READY FOR REVIEW labels Jul 23, 2026
@tanleach

Copy link
Copy Markdown
Collaborator Author

/ok to test a07f6dd

@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 `@docs/source/integration/rest-api.md`:
- Around line 108-126: Update the 500 response description in the jobs route’s
OpenAPI responses mapping to include unexpected agent/tool configuration lookup
failures alongside encryption and authorization persistence failures. Update the
matching assertion in test_content_encryption_routes.py to expect the expanded
description, keeping the documented causes consistent across the schema and
test.
🪄 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: e40664b2-6cbe-4e74-b9aa-b591f2c23101

📥 Commits

Reviewing files that changed from the base of the PR and between fabe7e1 and 6437501.

📒 Files selected for processing (7)
  • docs/source/integration/rest-api.md
  • frontends/aiq_api/README.md
  • frontends/aiq_api/src/aiq_api/routes/jobs.py
  • frontends/aiq_api/tests/test_agent_registry_visibility.py
  • frontends/aiq_api/tests/test_content_encryption_routes.py
  • frontends/aiq_api/tests/test_job_submit_data_sources.py
  • tests/aiq_agent/fastapi_extensions/test_job_agent_availability.py
📜 Review details
⏰ Context from checks skipped due to timeout. (2)
  • GitHub Check: Pytest and Coverage
  • GitHub Check: Script Validation
🧰 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:

  • frontends/aiq_api/tests/test_content_encryption_routes.py
  • tests/aiq_agent/fastapi_extensions/test_job_agent_availability.py
  • frontends/aiq_api/tests/test_agent_registry_visibility.py
  • frontends/aiq_api/src/aiq_api/routes/jobs.py
  • frontends/aiq_api/tests/test_job_submit_data_sources.py
**/*test*.py

📄 CodeRabbit inference engine (CONTRIBUTING.md)

Run pytest for all behavior changes in Python code

Files:

  • frontends/aiq_api/tests/test_content_encryption_routes.py
  • tests/aiq_agent/fastapi_extensions/test_job_agent_availability.py
  • frontends/aiq_api/tests/test_agent_registry_visibility.py
  • frontends/aiq_api/tests/test_job_submit_data_sources.py
docs/source/**/*

📄 CodeRabbit inference engine (AGENTS.md)

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

Files:

  • docs/source/integration/rest-api.md
{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/integration/rest-api.md
{src/aiq_agent/fastapi_extensions/**,frontends/aiq_api/src/aiq_api/**}

⚙️ CodeRabbit configuration file

{src/aiq_agent/fastapi_extensions/**,frontends/aiq_api/src/aiq_api/**}: Treat API, auth, and job-runner changes as externally visible contracts. Check authorization boundaries,
request tracing, async job lifecycle, websocket reconnect behavior, error responses, and cross-user data isolation.
Require tests for route behavior, access decisions, and job state transitions when those surfaces change.

Files:

  • frontends/aiq_api/src/aiq_api/routes/jobs.py
🧠 Learnings (1)
📚 Learning: 2026-06-14T17:49:00.640Z
Learnt from: torkian
Repo: NVIDIA-AI-Blueprints/aiq PR: 273
File: frontends/aiq_api/tests/test_sse_reconnect_cursor.py:384-401
Timestamp: 2026-06-14T17:49:00.640Z
Learning: When using `unittest.mock.patch` for code that imports dependencies inside functions/generators (e.g., inside `aiq_api.routes.jobs`), don’t patch via an attribute that doesn’t exist on the consuming module. If the generator does `from ..jobs.event_store import EventStore` inside the generator body, then `aiq_api.routes.jobs` will not have an `EventStore` attribute; patch the source class/method in its defining module instead (e.g., `aiq_api.jobs.event_store.EventStore.get_events_async`). Patching `aiq_api.routes.jobs.EventStore...` would raise `AttributeError` because that symbol is not present at module scope.

Applied to files:

  • frontends/aiq_api/tests/test_content_encryption_routes.py
  • frontends/aiq_api/tests/test_agent_registry_visibility.py
  • frontends/aiq_api/tests/test_job_submit_data_sources.py
🔇 Additional comments (15)
frontends/aiq_api/src/aiq_api/routes/jobs.py (7)

625-641: Downstream effect of the helper's fragility, covered at Line 221-228.

The lack of per-agent exception isolation here is addressed in the comment on _get_configured_agent_function_config (Line 221-228); no separate action needed here beyond that fix.


231-274: LGTM!


277-353: LGTM!


466-469: LGTM!


690-737: LGTM! Structured agent_not_configured 400 payload and ordering (public check → configured check → auth) match the test expectations precisely.


757-764: LGTM!


221-228: 🩺 Stability & Availability

No issue here This just centralizes the existing missing-function check; the same ValueError text is already used by the agent-availability path and tests, and get_function_config() is called synchronously here.

			> Likely an incorrect or invalid review comment.
frontends/aiq_api/tests/test_agent_registry_visibility.py (2)

13-23: LGTM!


61-159: LGTM!

frontends/aiq_api/tests/test_job_submit_data_sources.py (2)

30-31: LGTM!

Also applies to: 39-59, 63-133


158-177: LGTM! Exclusion-list changes and new unconfigured-agent tests correctly track the updated fn_config-based validation logic.

Also applies to: 276-334, 403-620, 747-813

tests/aiq_agent/fastapi_extensions/test_job_agent_availability.py (1)

1-181: LGTM!

docs/source/integration/rest-api.md (1)

29-54: LGTM!

Also applies to: 92-92, 476-476

frontends/aiq_api/README.md (1)

70-70: LGTM!

Also applies to: 81-85, 109-123

frontends/aiq_api/tests/test_content_encryption_routes.py (1)

457-467: LGTM!

Comment thread docs/source/integration/rest-api.md Resolved

@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

Signed-off-by: Tanner Leach <tleach@nvidia.com>
@tanleach

Copy link
Copy Markdown
Collaborator Author

/ok to test 13cbd03

@tanleach

Copy link
Copy Markdown
Collaborator Author

/merge

@rapids-bot
rapids-bot Bot merged commit 380a801 into NVIDIA-AI-Blueprints:release/2.2 Jul 23, 2026
11 checks passed
@coderabbitai coderabbitai Bot mentioned this pull request Jul 29, 2026
16 tasks done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

AIQ2.2 bug Something isn't working READY FOR REVIEW

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants